1806 lines
114 KiB
Plaintext
1806 lines
114 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Uczenie maszynowe\n",
|
||
"# 3. Metody ewaluacji i optymalizacji"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.1. Metodologia testowania"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W uczeniu maszynowym bardzo ważna jest ewaluacja budowanego modelu. Dlatego dobrze jest podzielić posiadane dane na odrębne zbiory – osobny zbiór danych do uczenia i osobny do testowania. W niektórych przypadkach potrzeba będzie dodatkowo wyodrębnić tzw. zbiór walidacyjny."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór uczący a zbiór testowy"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"* Na zbiorze uczącym (treningowym) uczymy algorytmy, a na zbiorze testowym sprawdzamy ich poprawność.\n",
|
||
"* Zbiór uczący powinien być kilkukrotnie większy od testowego (np. 4:1, 9:1 itp.).\n",
|
||
"* Zbiór testowy często jest nieznany.\n",
|
||
"* Należy unikać mieszania danych testowych i treningowych – nie wolno „zanieczyszczać” danych treningowych danymi testowymi!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Czasami potrzebujemy dobrać parametry modelu, np. $\\alpha$ – który zbiór wykorzystać do tego celu?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór walidacyjny"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Do doboru parametrów najlepiej użyć jeszcze innego zbioru – jest to tzw. **zbiór walidacyjny**"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Zbiór walidacyjny powinien mieć wielkość zbliżoną do wielkości zbioru testowego, czyli np. dane można podzielić na te trzy zbiory w proporcjach 3:1:1, 8:1:1 itp."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Którą część danych wydzielić jako zbiór walidacyjny tak, żeby było „najlepiej”?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Niech każda partia danych pełni tę rolę naprzemiennie!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"<img width=\"100%\" src=\"https://chrisjmccormick.files.wordpress.com/2013/07/10_fold_cv.png\"/>\n",
|
||
"Żródło: https://chrisjmccormick.wordpress.com/2013/07/31/k-fold-cross-validation-with-matlab-code/"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa\n",
|
||
"\n",
|
||
"* Podziel dane $D = \\left\\{ (x^{(1)}, y^{(1)}), \\ldots, (x^{(m)}, y^{(m)})\\right\\} $ na $N$ rozłącznych zbiorów $T_1,\\ldots,T_N$\n",
|
||
"* Dla $i=1,\\ldots,N$, wykonaj:\n",
|
||
" * Użyj $T_i$ do walidacji i zbiór $S_i$ do trenowania, gdzie $S_i = D \\smallsetminus T_i$. \n",
|
||
" * Zapisz model $\\theta_i$.\n",
|
||
"* Akumuluj wyniki dla modeli $\\theta_i$ dla zbiorów $T_i$.\n",
|
||
"* Ustalaj parametry uczenia na akumulowanych wynikach."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Walidacja krzyżowa – wskazówki\n",
|
||
"\n",
|
||
"* Zazwyczaj ustala się $N$ w przedziale od $4$ do $10$, tzw. $N$-krotna walidacja krzyżowa (*$N$-fold cross validation*). \n",
|
||
"* Zbiór $D$ warto zrandomizować przed podziałem.\n",
|
||
"* W jaki sposób akumulować wyniki dla wszystkich zbiórow $T_i$?\n",
|
||
"* Po ustaleniu parametrów dla każdego $T_i$, trenujemy model na całych danych treningowych z ustalonymi parametrami.\n",
|
||
"* Testujemy na zbiorze testowym (jeśli nim dysponujemy)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### _Leave-one-out_\n",
|
||
"\n",
|
||
"Jest to szczególny przypadek walidacji krzyżowej, w której $N = m$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"* Jaki jest rozmiar pojedynczego zbioru $T_i$?\n",
|
||
"* Jakie są zalety i wady tej metody?\n",
|
||
"* Kiedy może być przydatna?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Zbiór walidujący a algorytmy optymalizacji\n",
|
||
"\n",
|
||
"* Gdy błąd rośnie na zbiorze uczącym, mamy źle dobrany parametr $\\alpha$. Należy go wtedy zmniejszyć.\n",
|
||
"* Gdy błąd zmniejsza się na zbiorze trenującym, ale rośnie na zbiorze walidującym, mamy do czynienia ze zjawiskiem **nadmiernego dopasowania** (*overfitting*).\n",
|
||
"* Należy wtedy przerwać optymalizację. Automatyzacja tego procesu to _early stopping_."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.2. Miary jakości"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Aby przeprowadzić ewaluację modelu, musimy wybrać **miarę** (**metrykę**), jakiej będziemy używać.\n",
|
||
"\n",
|
||
"Jakiej miary użyc najlepiej?\n",
|
||
" * To zależy od rodzaju zadania.\n",
|
||
" * Innych metryk używa się do regresji, a innych do klasyfikacji"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Metryki dla zadań regresji\n",
|
||
"\n",
|
||
"Dla zadań regresji możemy zastosować np.:\n",
|
||
" * błąd średniokwadratowy (*root-mean-square error*, RMSE):\n",
|
||
" $$ \\mathrm{RMSE} \\, = \\, \\sqrt{ \\frac{1}{m} \\sum_{i=1}^{m} \\left( \\hat{y}^{(i)} - y^{(i)} \\right)^2 } $$\n",
|
||
" * średni błąd bezwzględny (*mean absolute error*, MAE):\n",
|
||
" $$ \\mathrm{MAE} \\, = \\, \\frac{1}{m} \\sum_{i=1}^{m} \\left| \\hat{y}^{(i)} - y^{(i)} \\right| $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W powyższych wzorach $y^{(i)}$ oznacza **oczekiwaną** wartości zmiennej $y$ w $i$-tym przykładzie, a $\\hat{y}^{(i)}$ oznacza wartość zmiennej $y$ w $i$-tym przykładzie wyliczoną (**przewidzianą**) przez nasz model."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Metryki dla zadań klasyfikacji\n",
|
||
"\n",
|
||
"Aby przedstawić kilka najpopularniejszych metryk stosowanych dla zadań klasyfikacyjnych, posłużmy się następującym przykładem:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przydatne importy\n",
|
||
"\n",
|
||
"import ipywidgets as widgets\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"import pandas\n",
|
||
"import random\n",
|
||
"import seaborn\n",
|
||
"\n",
|
||
"%matplotlib inline"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def powerme(x1,x2,n):\n",
|
||
" \"\"\"Funkcja, która generuje n potęg dla zmiennych x1 i x2 oraz ich iloczynów\"\"\"\n",
|
||
" X = []\n",
|
||
" for m in range(n+1):\n",
|
||
" for i in range(m+1):\n",
|
||
" X.append(np.multiply(np.power(x1,i),np.power(x2,(m-i))))\n",
|
||
" return np.hstack(X)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def plot_data_for_classification(X, Y, xlabel=None, ylabel=None, Y_predicted=[], highlight=None):\n",
|
||
" \"\"\"Wykres danych dla zadania klasyfikacji\"\"\"\n",
|
||
" fig = plt.figure(figsize=(16*.6, 9*.6))\n",
|
||
" ax = fig.add_subplot(111)\n",
|
||
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
||
" X = X.tolist()\n",
|
||
" Y = Y.tolist()\n",
|
||
" X1n = [x[1] for x, y in zip(X, Y) if y[0] == 0]\n",
|
||
" X1p = [x[1] for x, y in zip(X, Y) if y[0] == 1]\n",
|
||
" X2n = [x[2] for x, y in zip(X, Y) if y[0] == 0]\n",
|
||
" X2p = [x[2] for x, y in zip(X, Y) if y[0] == 1]\n",
|
||
" \n",
|
||
" if len(Y_predicted) > 0:\n",
|
||
" Y_predicted = Y_predicted.tolist()\n",
|
||
" X1tn = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 0]\n",
|
||
" X1fn = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 0]\n",
|
||
" X1tp = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 1]\n",
|
||
" X1fp = [x[1] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 1]\n",
|
||
" X2tn = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 0]\n",
|
||
" X2fn = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 0]\n",
|
||
" X2tp = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 1 and yp[0] == 1]\n",
|
||
" X2fp = [x[2] for x, y, yp in zip(X, Y, Y_predicted) if y[0] == 0 and yp[0] == 1]\n",
|
||
" \n",
|
||
" if highlight == 'tn':\n",
|
||
" ax.scatter(X1tn, X2tn, c='r', marker='x', s=100, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'fn':\n",
|
||
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='g', marker='o', s=100, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'tp':\n",
|
||
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='g', marker='o', s=100, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='k', marker='x', s=50, label='Dane')\n",
|
||
" elif highlight == 'fp':\n",
|
||
" ax.scatter(X1tn, X2tn, c='k', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='k', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='r', marker='x', s=100, label='Dane')\n",
|
||
" else:\n",
|
||
" ax.scatter(X1tn, X2tn, c='r', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fn, X2fn, c='g', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1tp, X2tp, c='g', marker='o', s=50, label='Dane')\n",
|
||
" ax.scatter(X1fp, X2fp, c='r', marker='x', s=50, label='Dane')\n",
|
||
"\n",
|
||
" else:\n",
|
||
" ax.scatter(X1n, X2n, c='r', marker='x', s=50, label='Dane')\n",
|
||
" ax.scatter(X1p, X2p, c='g', marker='o', s=50, label='Dane')\n",
|
||
" \n",
|
||
" if xlabel:\n",
|
||
" ax.set_xlabel(xlabel)\n",
|
||
" if ylabel:\n",
|
||
" ax.set_ylabel(ylabel)\n",
|
||
" \n",
|
||
" ax.margins(.05, .05)\n",
|
||
" return fig"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Wczytanie danych\n",
|
||
"import pandas\n",
|
||
"import numpy as np\n",
|
||
"\n",
|
||
"alldata = pandas.read_csv('data-metrics.tsv', sep='\\t')\n",
|
||
"data = np.matrix(alldata)\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"\n",
|
||
"X2 = powerme(data[:, 1], data[:, 2], n)\n",
|
||
"Y2 = np.matrix(data[:, 0]).reshape(m, 1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAm0AAAFmCAYAAAA/JK3gAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3dfXRc9X3n8c9XYDkbWS22cVLH4EBqNQ04u0BVmm18KkIDIfoDDw6JTMiWtM5ySJPiAu3inHSbHNKcQrInirKlaalDQ3d9YCiRhbtV6uWxPd4NKYLlwYZDpJAtuGKDY5N0rDSSyHz3j3uvfTWakUb2zH2Yeb/OmaO5v3tn/Js7dzyfuff3YO4uAAAAZFtH2hUAAADA4ghtAAAAOUBoAwAAyAFCGwAAQA4Q2gAAAHKA0AYAAJADp6ZdgTScfvrpftZZZ6VdDQAAgDmeeOKJH7j7mmrr2jK0nXXWWRobG0u7GgAAAHOY2T/VWsflUQAAgBwgtAEAAOQAoQ0AACAHCG0AAAA5kInQZmZ3mtmrZra/xnozs6+Y2YSZPWNmF8TWXWNm4+HtmuRqDQAAkJxMhDZJX5d02QLr3y+pJ7xdK+mrkmRmqyR9RtKvSLpQ0mfMbGVTawoAAJCCTIQ2d/8HSUcW2GSzpL/ywGOSTjOztZLeJ+kBdz/i7q9JekALhz8AAIBcykRoq8M6SS/Hlg+GZbXKAQAAWkpeQptVKfMFyuc/gdm1ZjZmZmOHDh1qaOUAAACaLS+h7aCkM2PLZ0iaXKB8Hne/w9173b13zZqqs0MAAABkVl5C2x5JvxH2In2XpB+5+yuS9kq61MxWhh0QLg3LAMS5S7t3B3/rKQcAZE4mQpuZ3S3pW5LebmYHzWybmV1nZteFm4xKelHShKS/kPTbkuTuRyR9TtLj4e2WsAxA3MiItGWLdMMNxwOae7C8ZUuwHgCQaZmYMN7dr1pkvUv6RI11d0q6sxn1AlpGoSBt3y4NDQXLg4NBYBsaCsoLhXTrBwBYVCZCG4AmMwuCmhQEtSi8bd8elFu1Pj0AgCwxb8O2LL29vT42NpZ2NYDkuUsdsVYR5TKBDQAyxMyecPfeausy0aYNQAKiNmxx8TZuAIBMI7QB7SAKbFEbtnL5eBs3ghsA5AJt2oB2MDJyPLBFbdjibdz6+qQrrki3jgCABRHagHZQKEjDw8HfqA1bFNz6+ug9CgA5QGgD2oFZ9TNptcoBAJlDmzYAAIAcILQBAADkAKENAAAgBwhtAAAAOUBoAwAAyAFCGwAAQA4Q2gAAAHKAcdoAAKhQmi6peKCo8cPj6lndo4FzB9S9vDvtaqHNEdoAAIjZ99I+9e/qV9nLmpqdUteyLt2490aNXj2qTes3pV09tDEujwIAECpNl9S/q1+lmZKmZqckSVOzUyrNBOVHZ46mXEO0M0IbAACh4oGiyl6uuq7sZRX3FxOuEXAcoQ0AgND44fFjZ9gqTc1OaeLIRMI1Ao4jtAEAEOpZtUFdtrzqui5brg2rfj7hGgHHEdoAAAgNfK9LHT+Zrrqu4yfTGnjxjQnXCDiO0AYAQKj7A1dpdPpKdU9LXR4MsNDlp6p7WhqdvlIrPnBVyjVEO2PIDwAAImba9F/u1eQNn1Dx776qiVXShiOva+DXPq4Vg7dLZmnXEG3M3D3tOiSut7fXx8bG0q4GACCr3KWO2MWocpnAhkSY2RPu3lttHZdHAQCIc5duuGFu2Q03BOVAightAABEosA2NCRt3x6cYdu+PVgmuCFltGkDACAyMnI8sA0OBpdEBweDdUNDUl+fdMUV6dYRbSsToc3MLpM0JOkUSTvd/daK9YOS3hMuvlHSm9z9tHDdTyU9G657yd0vT6bWAICWUyhIw8PB36gNWxTc+vqCciAlqXdEMLNTJH1H0iWSDkp6XNJV7v5cje1/R9L57v5b4fJRd1+xlH+TjggAACCLst4R4UJJE+7+orvPSLpH0uYFtr9K0t2J1AwAACAjshDa1kl6ObZ8MCybx8zeKulsSQ/Hit9gZmNm9piZcd4aQHLcpd275zdOr1UOACchC6Gt2sA3tf6n2yrpPnf/aaxsfXga8cOSvmxmVSeGM7Nrw3A3dujQoZOrMQBIQaP1LVvm9iqMeh9u2RKsB4AGyUJoOyjpzNjyGZIma2y7VRWXRt19Mvz7oqRHJZ1f7YHufoe797p775o1a062zgAQNEqvHA4iPlwEjdYBNFAWeo8+LqnHzM6W9M8KgtmHKzcys7dLWinpW7GylZJ+7O7TZna6pHdL+kIitQaAyuEghoaC+/HhIgCgQVI/0+bur0v6pKS9kp6XdK+7HzCzW8wsPnzHVZLu8bndXd8haczMnpb0iKRba/U6BYCmiAe3CIENQBNk4Uyb3H1U0mhF2R9WLH+2yuP+t6R3NrVyALCQWlMeEdwANFjqZ9oAILeY8ghAgjJxpg0AcokpjwAkiNAGACeKKY8AJIjQBgAnyqz6mbRa5QBwEmjTBgAAkAOENgAAgBwgtAEAAOQAoQ0AACAHCG0AAAA5QGgDAADIAUIbAABADhDaAAAAcoDQBgAAkAOENgAAgBwgtAEAAOQAoQ0AACAHCG0AAAA5QGgDAADIAUIbAABADhDaAAAAcoDQBgAAkAOENgAAgBwgtAEAAOQAoQ0AACAHCG0AAAA5QGgDAADIAUIbAABADmQitJnZZWb2gplNmNmOKus/amaHzOyp8Pax2LprzGw8vF2TbM0BAACScWraFTCzUyTdLukSSQclPW5me9z9uYpNi+7+yYrHrpL0GUm9klzSE+FjX0ug6gAAAInJwpm2CyVNuPuL7j4j6R5Jm+t87PskPeDuR8Kg9oCky5pUTwAAgNRkIbStk/RybPlgWFbpA2b2jJndZ2ZnLvGxMrNrzWzMzMYOHTrUiHoDAAAkJguhzaqUecXy30g6y93/raQHJd21hMcGhe53uHuvu/euWbPmhCsLpK00XdLOJ3fq5gdu1s4nd6o0XUq7SgCABKTepk3B2bEzY8tnSJqMb+Duh2OLfyHptthjL6p47KMNryGQEfte2qf+Xf0qe1lTs1PqWtalG/feqNGrR7Vp/aa0qwcAaKIsnGl7XFKPmZ1tZp2StkraE9/AzNbGFi+X9Hx4f6+kS81spZmtlHRpWAa0nNJ0Sf27+lWaKWlqdkqSNDU7pdJMUH505mjKNQQANFPqoc3dX5f0SQVh63lJ97r7ATO7xcwuDze73swOmNnTkq6X9NHwsUckfU5B8Htc0i1hGdByigeKKnu56rqyl1XcX0y4RgCAJGXh8qjcfVTSaEXZH8buf0rSp2o89k5Jdza1gkAGjB8eP3aGrdLU7JQmjkwkXCMAQJJSP9MGoD49q3vUtayr6rquZV3asGpDwjUCACSJ0AbkxMC5A+qw6h/ZDuvQwMaBhGtUhbu0e3fwt55yAEDdCG1ATnQv79bo1aPq7uw+dsata1mXujuD8hWdK1KuoaSREWnLFumGG44HNPdgecuWYD0A4IRkok0bgPpsWr9JkzdNqri/qIkjE9qwaoMGNg5kI7BJUqEgbd8uDQ0Fy4ODQWAbGgrKC4V06wcAOWbehpcrent7fWxsLO1qAK0pOrMWBTcpCGyDg5JVGw8bABAxsyfcvbfqOkIbgIZzlzpirS/KZQIbANRhodBGm7ZWRqNwpCE60xYXb+MGADghhLZWRqNwJC1+aXT79uAMW9TGjeAGACeFjgitjEbhSNrIyPHjK2rDNjgYrBsakvr6pCuuSLeOAJBTtGlrdTQKR5Lcg+BWKMw9vmqVAwDmoCNChbYKbRKNwgEAyAk6IrQzGoUDANASCG2tjEbhAAC0DDoitDIahQMA0DIIba2sUJCGh+c2/o6CW18fvUcBAMgRLo+2MrPgTFplp4Na5WhvDMYMAJlGaAOg0nRJO7/2Cd38p1u08+ZLVPrJvwQrGIy55ZWmS9r55E7d/MDN2vnkTpWmS2lXCUANDPkBtLl9L+1T/65+lb2sqdkpdU1LHZ3LNPqbD2nT4Dfmt4tEy5j33i/rUod1aPTqUW1avynt6jUf4woigxjyA0BVpemS+nf1qzRT0tTslCRparlUsln1//mv6ehXCWytqup7Pzul0kxQfnTmaMo1TABT/SFnCG1AGyseKKrs5arrypKK54rA1qIWfO+9rOL+YsI1SkF8qr8ouDHVHzKM0Aa0sfHD48fOslSaWi5NrBJj+rWoBd/72SlNHJlIuEYpiHrTR8Gto4PmAMg0QhvQxnpW96hrWVfVdV3LurThgl9nMOYWteh7v2pDwjVKSXz8ygiBDRlFaAPa2MC5A+qw6v8NdFiHBj63+/hZCNr3tJRF3/uNAwnXKCVM9YccIbQBbax7ebdGrx5Vd2f3sbMuXcu61N0ZlK9Y3h2cdYgGaUbLWPS971yRcg0TwFR/yBmG/ACgozNHVdxf1MSRCW1YtUEDGwfa40sb7f3e794d9BKNt2GLB7nhYab6Q+IWGvKD0AYwVhPQnvjsI4MyP06bmV1mZi+Y2YSZ7aiy/kYze87MnjGzh8zsrbF1PzWzp8LbnmRrjpbAWE1Ae2KqP+RM6hPGm9kpkm6XdImkg5IeN7M97v5cbLP/I6nX3X9sZh+X9AVJUSvZf3X38xKtNFpLfKwmKbhMwlhNAICMST20SbpQ0oS7vyhJZnaPpM2SjoU2d38ktv1jkj6SaA3R2uJd/oeGjoc3xmoCAGRIFi6PrpP0cmz5YFhWyzZJ34wtv8HMxszsMTPjlAhODGM1AQAyLguhrdq3YtXeEWb2EUm9kr4YK14fNtj7sKQvm9nP13jstWG4Gzt06NDJ1hmthrGaAAAZl4XQdlDSmbHlMyRNVm5kZu+V9GlJl7v7dFTu7pPh3xclPSrp/Gr/iLvf4e697t67Zs2axtUe+cdYTQCAHMhCaHtcUo+ZnW1mnZK2SprTC9TMzpf05woC26ux8pVmtjy8f7qkdyvWFg6oy8jI/PkG4/MR0nsUAJABqYc2d39d0icl7ZX0vKR73f2Amd1iZpeHm31R0gpJf10xtMc7JI2Z2dOSHpF0a0WvUyzEPRhcsvJMUq3yVlUoBINoxtuwRcGNmQAAoP1k9PuRwXXbGaOBAwAwX4rfjwsNrpuFIT+QFsYnAwBgvox+P3Kmrd3FfzlEGJ8MqKk0XVLxQFHjh8fVs7pHA+cOqHt5d9rVAtBoKX0/MvdoBUJbBXepI9a8sVwmsAFV7Htpn/p39avsZU3NTqlrWZc6rEOjV49q0/pNaVcPQKOl8P2Y+blHkSLGJwPqUpouqX9Xv0ozJU3NTkmSpmanVJoJyo/OHE25hgAaKoPfj4S2dsb4ZEDdigeKKnu56rqyl1XcX0y4RgCaJqPfj3REaGe1xieTgvK+PnqPAqHxw+PHzrBVmpqd0sSRiYRrBKBpMvr9SGhrZ9H4ZIXC/PHJ+vroPQrE9KzuUdeyrqrBrWtZlzas2pBCrQA0RUa/H+mIAAB1KE2XtO5L61SaKc1b193ZrcmbJrWic0UKNQPQSuiIAAAnqXt5t0avHlV3Z7e6lnVJCs6wdXcG5QQ2AM3G5VEAqNOm9Zs0edOkivuLmjgyoQ2rNmhg4wCBDUAiCG0AsAQrOldo2wXb0q4GgDbE5VEAAIAcILQBAADkAKENAAAgBwhtSJ+7tHv3/BGma5UDANCGCG1I38iItGXL3KlBoilEtmwJ1gMA0OYIbUhfoTB/Trf4nG/MzAAAOBktckWH0Ib0RVODRMGto2P+nG8AAJyoFrmiQ2hDNsQn440Q2AAAjdAiV3QIbciG6AMUF/9FBADAiWqRKzqENqSv8hdPuTz/FxEAACejBa7oENqQvpGR+b944r+IctLWAACQYS1wRYfQhvQVCtLw8NxfPFFwGx7OTVsDAEBGtcgVHSaMR/rMpCuuqL8cAIClqHVFRwrK+/py8X1DaAMAAK0tuqJTKMy/otPXl5srOoQ2AADQ2lrkig5t2gAAAHIgE6HNzC4zsxfMbMLMdlRZv9zMiuH6b5vZWbF1nwrLXzCz9yVZbwAAgKSkHtrM7BRJt0t6v6RzJF1lZudUbLZN0mvuvkHSoKTbwseeI2mrpHMlXSbpT8PnAwAAaClZaNN2oaQJd39RkszsHkmbJT0X22azpM+G9++T9CdmZmH5Pe4+Lel7ZjYRPt+3Eqo7ALS10nRJxQNFjR8eV8/qHg2cO6Du5d1pVwtoSXWHNjO7RNKHJN3u7k+Z2bXufkcD6rBO0sux5YOSfqXWNu7+upn9SNLqsPyxiseua0CdAACL2PfSPvXv6lfZy5qanVLXsi7duPdGjV49qk3rN6VdPaDlLOXy6G9L+n1JHzGziyWd16A6VJs/onKUu1rb1PPY4AnMrjWzMTMbO3To0BKrCACIK02X1L+rX6WZkqZmpyRJU7NTKs0E5UdnjqZcQ6D1LCW0HXL3H7r770m6VNIvN6gOByWdGVs+Q9JkrW3M7FRJPyvpSJ2PlSS5+x3u3uvuvWvWrGlQ1QGgPRUPFFX2ctV1ZS+ruL+YcI2A1reU0Pa30R133yHprxpUh8cl9ZjZ2WbWqaBjwZ6KbfZIuia8f6Wkh93dw/KtYe/SsyX1SPrHBtULAFDD+OHxY2fYKk3NTmniyETCNQJa36Khzcy+bGbm7vfHy939vzaiAu7+uqRPStor6XlJ97r7ATO7xcwuDzf7mqTVYUeDGyXtCB97QNK9Cjot/J2kT7j7TxtRLwBAbT2re9S1rKvquq5lXdqwakPCNQJan/kik6Sa2R9J+neSBtz9x2Z2qaTPuPu7k6hgM/T29vrY2Fja1QCA3CpNl7TuS+tUminNW9fd2a3Jmya1onNFCjUD8s3MnnD33mrrFj3T5u5/IOluSX9vZvsk3aTwTBcAoD11L+/W6NWj6u7sPnbGrWtZl7o7g3ICG06au7R7d/C3nvI2sOiQH2b265L+o6QpSWslbXP3F5pdMQBAtm1av0mTN02quL+oiSMT2rBqgwY2DhDY0BgjI9KWLdL27cHE7mZBULvhBmloKJgAPkfzhjZCPeO0fVrSf3b3fWb2TklFM7vR3R9uct0AABm3onOFtl2wLe1qoBUVCkFgGxoKlgcHjwe27duD9W1m0dDm7hfH7j9rZu+X9A1Jv9rMigEAgDZmFgQ1KQhqUXiLn3lrM4t2RKj6ILN/4+7/2oT6JIKOCAAA5IS71BFrgl8ut3RgO6mOCNXkObABwMkoTZe088mduvmBm7XzyZ0qTc/vPQmgQaI2bHE33NCWnRCkbEwYDwC5wFybQILinQ6iS6LRstSWl0hP6EwbALQb5toEEjYyMjewRW3cos4JIyNp1zBxhDYAqANzbQIJKxSCYT3iZ9Si4DY8TO9RAEB1zLUJJMys+jhstcrbAGfaAKAOzLUJIG2ENgCow8C5A+qw6v9ldliHBjYOJFwjAO2G0JYE5k8Dco+5NpPBkCpAbSc0uG7eJT647u7dzJ8GtIijM0eZa7NJqg2p0mEdDKmCtrLQ4LqEtiQsNNZMG0/HAQCR0nRJ6760TqWZ+WfWuju7NXnTJOEYbaHhMyJgiSrHlunoILABQAxDqgCLI7QlJT7xbYTABgCSGFIFqAehLSnMnwYANTGkCrA4QlsSKtu0lcvHL5US3ACAIVWAOhDaksD8aQCwIIZUARZH79EkuAfBrFCY24atVnm7Y38BbYshVdDuGPKjQuKhDUvDuHYAgDbFkB/Il0Jhfpu/eJvAQiHtGgIAGomZg+pCaEP2MK4dALSXkZHgCku8c170g33LFtp+hwhtyCbGtQOA9sEVlroQ2pCsek+BM65dNnEJA0AzcIWlLoQ2JKueU+CMa5ddXMIA0CxcYVlUqqHNzFaZ2QNmNh7+XVllm/PM7FtmdsDMnjGzgdi6r5vZ98zsqfB2XrKvIGPycBaknlPgjGuXXVzCANAsXGFZnLundpP0BUk7wvs7JN1WZZtfkNQT3n+LpFcknRYuf13SlUv9d3/pl37JW9LwsLvkvn27e7kclJXLwbIUrM+CeJ2iW2Wdh4ePL8cfV60cyVrs/QOApYr/vxL9f1K53CYkjXmt3FRrRRI3SS9IWhveXyvphToe83QsxBHa4vJ00JfLc7/0s1S3E9FuQbPV3j8A6crLSYcELBTa0m7T9mZ3f0WSwr9vWmhjM7tQUqek78aKPx9eNh00s+XNq2oO5KUhp7fgKfB2auvViu8fgHQVCsHA6fHvqug7bXiYpheRWmmuUTdJD0raX+W2WdIPK7Z9bYHnWavgzNy7KspM0nJJd0n6wwUef62kMUlj69evb3gyzpQsnwXJ09nApWjV11WpXV4nAKREeb88KulnJD0p6YMLPNdFkv5HPf9uy14edc9+e6NWPgWe9X3fCK38/gFABiwU2lKde9TMvijpsLvfamY7JK1y9/9UsU2npG9K+ht3/3LFurXu/oqZmaRBST9x9x2L/bstO/eoV/TkGxycv5z2JVJv8cng3YPL0pFyOd+vp1Krv38AkLLMThhvZqsl3StpvaSXFJxJO2JmvZKuc/ePmdlHJP2lpAOxh37U3Z8ys4clrVFwifSp8DFHF/t3Wza0MdF6uuL7OpKVsAwAyIXMhra0tGxo4yxIevJwlhMAkHkLhbZTk64Mmsis+pm0WuVonFoDAktBeV8f7wEA4KSkPeQH0Brorg4gSzwHM+RgyQhtQCNEZzMrL4HWKgeAZmqnsSPbCJdHAQBoNfF5gqX57Ww5+59LhDYAAFpNZbvaKLzRMSrX6D0KAECravWxI1vQQr1HadMGAEAritqwxTFPcK4R2gAAaDWVY0eWy8fbuBHccos2bQAAtBrGjmxJhDa0pNJ0ScUDRY0fHlfP6h4NnDug7uXdaVcLAJIRjR0ZnwknCm59ffQezSk6IqDl7Htpn/p39avsZU3NTqlrWZc6rEOjV49q0/pNaVcPAICa6IiAtlGaLql/V79KMyVNzU5JkqZmp1SaCcqPzhxNuYYAAJwYQhtaSvFAUWUvV11X9rKK+4sJ1wgAgMYgtKGljB8eP3aGrdLU7JQmjkwkXCMAABqD0IaW0rO6R13Luqqu61rWpQ2rNiRcIwAAGoPQhpYycO6AOqz6Yd1hHRrYOJBwjQAAaAxCG1pK9/JujV49qu7O7mNn3LqWdam7Myhf0bki5RoCAHBiGKcNLWfT+k2avGlSxf1FTRyZ0IZVGzSwcYDABqClMT5l62OcNgAAco7xKVsH47ThOHdp9+75887VKgcAZBrjU7YPQlu7GRmRtmyZO2FwNLHwli3BegBAbjA+ZfugTVu7KRSCCYSHhoLlwcEgsEUTCzMfHQDkCuNTtg9CW7uJJgyWgqAWhbft24PyaGJhAEAuRONTVgtujE/ZWuiI0K7cpY7Y1fFymcAGADlUmi5p3ZfWqTRTmreuu7NbkzdN0ns+R+iIgLmiNmxx8TZuAIDcYHzK9sHl0XYTBbaoDVu8TZvEJVIAyCHGp2wPqYY2M1slqSjpLEn/V9KH3P21Ktv9VNKz4eJL7n55WH62pHskrZL0pKT/4O4zza95jo2MzA1slW3c+vqkK65Irj7uQZ0KhblhsVY5AKCqFZ0rtO2CbWlXA02U9uXRHZIecvceSQ+Fy9X8q7ufF94uj5XfJmkwfPxrkjhaF1MoSMPDc8+oRcFteDj53qMMQQIAQF3SDm2bJd0V3r9LUt2JwcxM0sWS7juRx7cts+BMWuXZq1rlzRYfgiQKbgxBAgDAPGm3aXuzu78iSe7+ipm9qcZ2bzCzMUmvS7rV3UckrZb0Q3d/PdzmoKR1Ta8xGoshSAAAqEvTQ5uZPSjp56qs+vQSnma9u0+a2dskPWxmz0r6lyrb1ez+aGbXSrpWktavX7+EfxpNFwW3KLBJBDYAACo0/fKou7/X3TdWud0v6ftmtlaSwr+v1niOyfDvi5IelXS+pB9IOs3MouB5hqTJBepxh7v3unvvmjVrGvb60AAMQQIAwKLSbtO2R9I14f1rJN1fuYGZrTSz5eH90yW9W9JzHowK/IikKxd6PDKusg1buTy/jRsAAEg9tN0q6RIzG5d0SbgsM+s1s53hNu+QNGZmTysIabe6+3Phupsl3WhmEwrauH0t0drj5NUagiQKbvQeBQBAEtNYIW2M0wYAyIoMfCcxjRWyK2tDkAAA2lfGxw5Ne8gPABlTmi6peKCo8cPj6lndo4FzB9S9vDvtagFA88XHDpXmTvWYgbFDuTwK4Jh9L+1T/65+lb2sqdkpdS3rUod1aPTqUW1avynt6gFA88U7yEUSHDt0ocujhDYAkoIzbOu+tE6lmdK8dd2d3Zq8aZLJpwG0B3epI9aCrFxOrLkObdoALKp4oKiyl6uuK3tZxf3FhGsEACnI8NihhDYAkqTxw+Oamp2qum5qdkoTRyYSrhEAJCzjY4cS2hrJXdq9e/6bWqscyJCe1T3qWtZVdV3Xsi5tWLUh4RoBQMIyPnYooa2RMt5VGFjIwLkD6rDq/yV0WIcGNg4kXCMASFihIA0Pz+10EAW34eHUe48S2hop3lU4Cm4Z6ioMLKR7ebdGrx5Vd2f3sTNuXcu61N0ZlNMJAUDLy/jYofQebbSUuwoDJ+vozFEV9xc1cWRCG1Zt0MDGAQJbI2VgxHUA2cWQHxWaPuRHil2FAWTc7t1Bc4n4j7n4j73h4eAXPbKJ0I0mY8iPJGW4qzCADKAZReOk0fmLtstIEaGtkTLeVRhABlT2RuvomN9bDfVJI0ARupEiLo82Epc9ANSLZhQnrzIwVc4T2awQTNtlNBFt2io0LbTR1gFAPfjSb5y09iWhG01Cm7akZLyrMIAMoBlFY0WXm+OSCGy0XUYKCG0AkKSMj7ieO0kHKEI3UkRoA4AkZXzE9VxJI0ARupEi2rQBAPIpjc5ftF1Gk9ERoQKhDQBaAAEKLWih0HZq0pUBAKAhok5e9ZYDOUebNgAAgBwgtAEAgGSkMfVYCyG0AQCAZDB360mhTRsAAEhGfO5Waf7UYwx5syBCGwAASEZ8BouhoePhjWnc6sKQHwAAIFnM3VpTZuceNbNVZvaAmY2Hf1dW2eY9ZvZU7PYTMyuE675uZt+LrTsv+VcBAADqxtytJyztjl7wUusAAA2HSURBVAg7JD3k7j2SHgqX53D3R9z9PHc/T9LFkn4s6X/GNvn9aL27P5VIrQEAwNIxd+tJSbtN22ZJF4X375L0qKSbF9j+SknfdPcfN7daAACg4WrN3SoF5X19DIy8gLTPtL3Z3V+RpPDvmxbZfqukuyvKPm9mz5jZoJktb0YlAQBAAxQKwZyw8U4HUXAbHqb36CKaHtrM7EEz21/ltnmJz7NW0jsl7Y0Vf0rSL0r6ZUmrtMBZOjO71szGzGzs0KFDJ/BKgCViEElgLj4TiKYYq+x0UKscczQ9tLn7e919Y5Xb/ZK+H4axKJS9usBTfUjSbnefjT33Kx6YlvSXki5coB53uHuvu/euWbOmMS8OWAiDSAKBKJTt3j33M+EenF353d/lMwHUIe02bXskXSPp1vDv/Qtse5WCM2vHmNlad3/FzExSQdL+ZlUUWDIGkQQC0Q+Y668PbkNDx3/IfOUrwV8+E8CiUh2nzcxWS7pX0npJL0n6oLsfMbNeSde5+8fC7c6S9L8knenu5djjH5a0RpJJeip8zNHF/l3GaUNi4j2lIgwiiXYT/xxcf31QFoU1KSj78pf5TABaeJw2BtcFmo1BJIHqP2AifCaAYzI7uC7Q8hhEEgjEh3aoxGcCqAuhDWgWBpEEjnMPOhzExdu48ZkAFkVoA5ql1iCSUXCjpxzaRfQDJmrHFoW1+DKfCWBRafceBVpXNIhkoTB/EMm+PnrKoX1EP2Cuv37uiPdmQfk3viFddBGfCWARdEQAADSXexDc4j9gFioH2thCHRE40wYAaK5otPt6ywFURZs2AACAHCC0AQAA5AChDQAAIAcIbQDQaNEE6ZUdvWqVA0AdCG0A0GjRBOnxAWOjscq2bGE8MgAnhN6jANBohcLxQZSlYGy++OwYjEcG4AQQ2gCg0eLzbA4NHQ9v8dkxAGCJuDwKAM1QbYL0vAQ22uQBmURoA4BmiNqwxeVlUnTa5AGZRGgDgEaLAk7Uhq1cPt7GLQ/BLd4mL6ovbfKA1NGmDQAaLZogPd6GLd7GLT5pehbRJg/IJCaMB4BGa5UJ0t2ljtgFmXI5H/VGc7XK8Z1RC00Yz+VRAGi0aCL0yi+uWuVZlOc2eWiuZrZ5pBPMgghtAIC58t4mD83VzDaPdIJZEG3aAABz5b1NHpqrmW0eGZh6QbRpAwDMRZsl1KNZbR7jZ+4ibdQJhjZtANDultJWqBXa5KG5mtnmMc8DUzcZoQ0A2gFthdAozW7zSCeYmghtANAOGDAXjVKrzWN0fJ1s71E6wdREmzYAaBdt3lYIDdLMNo+7dwdnfuPHZfy4HR5u+U4wC7VpI7QBQBYk1fifAXORZXSCyW5HBDP7oJkdMLOymVWtYLjdZWb2gplNmNmOWPnZZvZtMxs3s6KZdSZTcwBosCTanNFWCFlHJ5gFpd2mbb+kLZL+odYGZnaKpNslvV/SOZKuMrNzwtW3SRp09x5Jr0na1tzqAkCTNLvNGW2FgNxLdXBdd39ekmzh5HyhpAl3fzHc9h5Jm83seUkXS/pwuN1dkj4r6avNqi8ANE2zJ2lnwFwg99I+01aPdZJeji0fDMtWS/qhu79eUQ4A+dTM8akKhaARd/z5on9veJjeo0AOND20mdmDZra/ym1zvU9RpcwXKK9Vj2vNbMzMxg4dOlTnPw0ACWr2gKW0FQJyremhzd3f6+4bq9zur/MpDko6M7Z8hqRJST+QdJqZnVpRXqsed7h7r7v3rlmz5kReCgA0D23OACwiD5dHH5fUE/YU7ZS0VdIeD8YqeUTSleF210iqNwgCQLY0c8BSAC0h7SE/rjCzg5L+vaS/NbO9YflbzGxUksI2a5+UtFfS85LudfcD4VPcLOlGM5tQ0Mbta0m/BgBoCNqcAVgEg+sCAABkRGYH1wUAAEB9CG0AAAA5QGgDAADIAUIbAABADhDaAAAAcoDQBgAAkAOENgAAgBwgtAEAAOQAoQ0AACAHCG0AAAA50JbTWJnZIUn/1OCnPV3SDxr8nHnDPmAfSOwDiX0QYT+wDyT2gbS0ffBWd19TbUVbhrZmMLOxWnOFtQv2AftAYh9I7IMI+4F9ILEPpMbtAy6PAgAA5AChDQAAIAcIbY1zR9oVyAD2AftAYh9I7IMI+4F9ILEPpAbtA9q0AQAA5ABn2gAAAHKA0LYEZvZBMztgZmUzq9kLxMwuM7MXzGzCzHbEys82s2+b2biZFc2sM5maN46ZrTKzB8LX8ICZrayyzXvM7KnY7SdmVgjXfd3Mvhdbd17yr+Lk1LMPwu1+Gnude2Ll7XIcnGdm3wo/M8+Y2UBsXW6Pg1qf79j65eH7OhG+z2fF1n0qLH/BzN6XZL0bqY59cKOZPRe+7w+Z2Vtj66p+LvKmjn3wUTM7FHutH4utuyb87Iyb2TXJ1rxx6tgHg7HX/x0z+2FsXascB3ea2atmtr/GejOzr4T76BkzuyC2bunHgbtzq/Mm6R2S3i7pUUm9NbY5RdJ3Jb1NUqekpyWdE667V9LW8P6fSfp42q/pBPbBFyTtCO/vkHTbItuvknRE0hvD5a9LujLt15HEPpB0tEZ5WxwHkn5BUk94/y2SXpF0Wp6Pg4U+37FtflvSn4X3t0oqhvfPCbdfLuns8HlOSfs1NWkfvCf2mf94tA/C5aqfizzd6twHH5X0J1Ueu0rSi+HfleH9lWm/pmbsg4rtf0fSna10HISv49ckXSBpf431/ZK+KckkvUvSt0/mOOBM2xK4+/Pu/sIim10oacLdX3T3GUn3SNpsZibpYkn3hdvdJanQvNo2zWYFdZfqew1XSvqmu/+4qbVK1lL3wTHtdBy4+3fcfTy8PynpVUlVB4zMkaqf74pt4vvmPkm/Hr7vmyXd4+7T7v49SRPh8+XNovvA3R+JfeYfk3RGwnVstnqOg1reJ+kBdz/i7q9JekDSZU2qZzMtdR9cJenuRGqWIHf/BwUnJmrZLOmvPPCYpNPMbK1O8DggtDXeOkkvx5YPhmWrJf3Q3V+vKM+bN7v7K5IU/n3TIttv1fwP6ufD08SDZra8GZVssnr3wRvMbMzMHosuD6tNjwMzu1DBr/HvxorzeBzU+nxX3SZ8n3+k4H2v57F5sNTXsU3BmYZItc9F3tS7Dz4QHuP3mdmZS3xs1tX9OsLL42dLejhW3ArHQT1q7acTOg5ObWjVWoCZPSjp56qs+rS731/PU1Qp8wXKM2ehfbDE51kr6Z2S9saKPyXp/yn4Ar9D0s2SbjmxmjZPg/bBenefNLO3SXrYzJ6V9C9VtmuH4+C/SbrG3cthcS6Ogyrq+Rzn/v+ARdT9OszsI5J6JfXFiud9Ltz9u9Uen2H17IO/kXS3u0+b2XUKzr5eXOdj82Apr2OrpPvc/aexslY4DurR0P8PCG0V3P29J/kUByWdGVs+Q9KkgjnHTjOzU8Nf31F55iy0D8zs+2a21t1fCb+MX13gqT4kabe7z8ae+5Xw7rSZ/aWk32tIpRusEfsgvCQod3/RzB6VdL6kb6iNjgMz+xlJfyvpD8JLA9Fz5+I4qKLW57vaNgfN7FRJP6vg8kk9j82Dul6Hmb1XQcDvc/fpqLzG5yJvX9aL7gN3Pxxb/AtJt8Uee1HFYx9teA2bbynH81ZJn4gXtMhxUI9a++mEjgMujzbe45J6LOgh2KngYN3jQcvDRxS08ZKkayTVc+Yua/YoqLu0+GuY14Yh/IKP2nYVJFXtcZNxi+4DM1sZXfIzs9MlvVvSc+10HITH/24F7Tn+umJdXo+Dqp/vim3i++ZKSQ+H7/seSVst6F16tqQeSf+YUL0badF9YGbnS/pzSZe7+6ux8qqfi8Rq3jj17IO1scXLJT0f3t8r6dJwX6yUdKnmXo3Ii3o+CzKztytoaP+tWFmrHAf12CPpN8JepO+S9KPwR+uJHQdp97zI003SFQrS8bSk70vaG5a/RdJobLt+Sd9R8Kvh07Hytyn4T3pC0l9LWp72azqBfbBa0kOSxsO/q8LyXkk7Y9udJemfJXVUPP5hSc8q+JL+75JWpP2amrEPJP1q+DqfDv9ua7fjQNJHJM1Keip2Oy/vx0G1z7eCS7uXh/ffEL6vE+H7/LbYYz8dPu4FSe9P+7U0cR88GP4fGb3ve8Lymp+LvN3q2Ad/LOlA+FofkfSLscf+Vnh8TEj6zbRfS7P2Qbj8WUm3VjyulY6DuxX0jJ9VkA+2SbpO0nXhepN0e7iPnlVs5IkTOQ6YEQEAACAHuDwKAACQA4Q2AACAHCC0AQAA5AChDQAAIAcIbQAAADlAaAMAAMgBQhsAAEAOENoAYAnM7BEzuyS8/0dm9pW06wSgPTD3KAAszWck3WJmb1IwX+LlKdcHQJtgRgQAWCIz+3tJKyRd5O4lM3ubgimqftbdr1z40QBwYrg8CgBLYGbvlLRW0rS7lyTJ3V90923p1gxAqyO0AUCdzGytpF2SNkuaMrP3pVwlAG2E0AYAdTCzN0oalnSTuz8v6XOSPptqpQC0Fdq0AcBJMrPVkj4v6RJJO939j1OuEoAWRGgDAADIAS6PAgAA5AChDQAAIAcIbQAAADlAaAMAAMgBQhsAAEAOENoAAABygNAGAACQA4Q2AACAHCC0AQAA5MD/B4P4jzzet+KNAAAAAElFTkSuQmCC\n",
|
||
"text/plain": [
|
||
"<Figure size 691.2x388.8 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {
|
||
"needs_background": "light"
|
||
},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data_for_classification(X2, Y2, xlabel=r'$x_1$', ylabel=r'$x_2$')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def safeSigmoid(x, eps=0):\n",
|
||
" \"\"\"Funkcja sigmoidalna zmodyfikowana w taki sposób, \n",
|
||
" żeby wartości zawsze były odległe od asymptot o co najmniej eps\n",
|
||
" \"\"\"\n",
|
||
" y = 1.0/(1.0 + np.exp(-x))\n",
|
||
" if eps > 0:\n",
|
||
" y[y < eps] = eps\n",
|
||
" y[y > 1 - eps] = 1 - eps\n",
|
||
" return y\n",
|
||
"\n",
|
||
"def h(theta, X, eps=0.0):\n",
|
||
" \"\"\"Funkcja hipotezy (regresja logistyczna)\"\"\"\n",
|
||
" return safeSigmoid(X*theta, eps)\n",
|
||
"\n",
|
||
"def J(h,theta,X,y, lamb=0):\n",
|
||
" \"\"\"Funkcja kosztu dla regresji logistycznej\"\"\"\n",
|
||
" m = len(y)\n",
|
||
" f = h(theta, X, eps=10**-7)\n",
|
||
" j = -np.sum(np.multiply(y, np.log(f)) + \n",
|
||
" np.multiply(1 - y, np.log(1 - f)), axis=0)/m\n",
|
||
" if lamb > 0:\n",
|
||
" j += lamb/(2*m) * np.sum(np.power(theta[1:],2))\n",
|
||
" return j\n",
|
||
"\n",
|
||
"def dJ(h,theta,X,y,lamb=0):\n",
|
||
" \"\"\"Gradient funkcji kosztu\"\"\"\n",
|
||
" g = 1.0/y.shape[0]*(X.T*(h(theta,X)-y))\n",
|
||
" if lamb > 0:\n",
|
||
" g[1:] += lamb/float(y.shape[0]) * theta[1:] \n",
|
||
" return g\n",
|
||
"\n",
|
||
"def classifyBi(theta, X):\n",
|
||
" \"\"\"Funkcja predykcji - klasyfikacja dwuklasowa\"\"\"\n",
|
||
" prob = h(theta, X)\n",
|
||
" return prob"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def GD(h, fJ, fdJ, theta, X, y, alpha=0.01, eps=10**-3, maxSteps=10000):\n",
|
||
" \"\"\"Metoda gradientu prostego dla regresji logistycznej\"\"\"\n",
|
||
" errorCurr = fJ(h, theta, X, y)\n",
|
||
" errors = [[errorCurr, theta]]\n",
|
||
" while True:\n",
|
||
" # oblicz nowe theta\n",
|
||
" theta = theta - alpha * fdJ(h, theta, X, y)\n",
|
||
" # raportuj poziom błędu\n",
|
||
" errorCurr, errorPrev = fJ(h, theta, X, y), errorCurr\n",
|
||
" # kryteria stopu\n",
|
||
" if abs(errorPrev - errorCurr) <= eps:\n",
|
||
" break\n",
|
||
" if len(errors) > maxSteps:\n",
|
||
" break\n",
|
||
" errors.append([errorCurr, theta]) \n",
|
||
" return theta, errors"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"theta = [[ 1.37136167]\n",
|
||
" [ 0.90128948]\n",
|
||
" [ 0.54708112]\n",
|
||
" [-5.9929264 ]\n",
|
||
" [ 2.64435168]\n",
|
||
" [-4.27978238]]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Uruchomienie metody gradientu prostego dla regresji logistycznej\n",
|
||
"theta_start = np.matrix(np.zeros(X2.shape[1])).reshape(X2.shape[1],1)\n",
|
||
"theta, errors = GD(h, J, dJ, theta_start, X2, Y2, \n",
|
||
" alpha=0.1, eps=10**-7, maxSteps=10000)\n",
|
||
"print('theta = {}'.format(theta))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def plot_decision_boundary(fig, theta, X):\n",
|
||
" \"\"\"Wykres granicy klas\"\"\"\n",
|
||
" ax = fig.axes[0]\n",
|
||
" xx, yy = np.meshgrid(np.arange(-1.0, 1.0, 0.02),\n",
|
||
" np.arange(-1.0, 1.0, 0.02))\n",
|
||
" l = len(xx.ravel())\n",
|
||
" C = powerme(xx.reshape(l, 1), yy.reshape(l, 1), n)\n",
|
||
" z = classifyBi(theta, C).reshape(int(np.sqrt(l)), int(np.sqrt(l)))\n",
|
||
"\n",
|
||
" plt.contour(xx, yy, z, levels=[0.5], lw=3);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"Y_expected = Y2.astype(int)\n",
|
||
"Y_predicted = (classifyBi(theta, X2) > 0.5).astype(int)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przygotowanie interaktywnego wykresu\n",
|
||
"\n",
|
||
"dropdown_highlight = widgets.Dropdown(options=['all', 'tp', 'fp', 'tn', 'fn'], value='all', description='highlight')\n",
|
||
"\n",
|
||
"def interactive_classification(highlight):\n",
|
||
" fig = plot_data_for_classification(X2, Y2, xlabel=r'$x_1$', ylabel=r'$x_2$',\n",
|
||
" Y_predicted=Y_predicted, highlight=highlight)\n",
|
||
" plot_decision_boundary(fig, theta, X2)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/home/pawel/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:10: UserWarning: The following kwargs were not used by contour: 'lw'\n",
|
||
" # Remove the CWD from sys.path while we load stuff.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"image/png": "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\n",
|
||
"text/plain": [
|
||
"<Figure size 691.2x388.8 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {
|
||
"needs_background": "light"
|
||
},
|
||
"output_type": "display_data"
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<function __main__.interactive_classification(highlight)>"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"widgets.interact(interactive_classification, highlight=dropdown_highlight)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Zadanie klasyfikacyjne z powyższego przykładu polega na przypisaniu punktów do jednej z dwóch kategorii:\n",
|
||
" 0. <font color=\"red\">czerwone krzyżyki</font>\n",
|
||
" 1. <font color=\"green\">zielone kółka</font>\n",
|
||
"\n",
|
||
"W tym celu zastosowano regresję logistyczną."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"W rezultacie otrzymano model, który dzieli płaszczyznę na dwa obszary:\n",
|
||
" 0. <font color=\"red\">na zewnątrz granatowej krzywej</font>\n",
|
||
" 1. <font color=\"green\">wewnątrz granatowej krzywej</font>\n",
|
||
" \n",
|
||
"Model przewiduje klasę <font color=\"red\">0 („czerwoną”)</font> dla punktów znajdujący się w obszarze na zewnątrz krzywej, natomiast klasę <font color=\"green\">1 („zieloną”)</font> dla punktów znajdujących sie w obszarze wewnąrz krzywej."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Wszysktie obserwacje możemy podzielić zatem na cztery grupy:\n",
|
||
" * **true positives (TP)** – prawidłowo sklasyfikowane pozytywne przykłady (<font color=\"green\">zielone kółka</font> w <font color=\"green\">wewnętrznym obszarze</font>)\n",
|
||
" * **true negatives (TN)** – prawidłowo sklasyfikowane negatywne przykłady (<font color=\"red\">czerwone krzyżyki</font> w <font color=\"red\">zewnętrznym obszarze</font>)\n",
|
||
" * **false positives (FP)** – negatywne przykłady sklasyfikowane jako pozytywne (<font color=\"red\">czerwone krzyżyki</font> w <font color=\"green\">wewnętrznym obszarze</font>)\n",
|
||
" * **false negatives (FN)** – pozytywne przykłady sklasyfikowane jako negatywne (<font color=\"green\">zielone kółka</font> w <font color=\"red\">zewnętrznym obszarze</font>)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Innymi słowy:\n",
|
||
"\n",
|
||
"<img width=\"50%\" src=\"https://blog.aimultiple.com/wp-content/uploads/2019/07/positive-negative-true-false-matrix.png\">"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "skip"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"TP = 5\n",
|
||
"TN = 35\n",
|
||
"FP = 3\n",
|
||
"FN = 6\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Obliczmy TP, TN, FP i FN\n",
|
||
"\n",
|
||
"tp = 0\n",
|
||
"tn = 0\n",
|
||
"fp = 0\n",
|
||
"fn = 0\n",
|
||
"\n",
|
||
"for i in range(len(Y_expected)):\n",
|
||
" if Y_expected[i] == 1 and Y_predicted[i] == 1:\n",
|
||
" tp += 1\n",
|
||
" elif Y_expected[i] == 0 and Y_predicted[i] == 0:\n",
|
||
" tn += 1\n",
|
||
" elif Y_expected[i] == 0 and Y_predicted[i] == 1:\n",
|
||
" fp += 1\n",
|
||
" elif Y_expected[i] == 1 and Y_predicted[i] == 0:\n",
|
||
" fn += 1\n",
|
||
" \n",
|
||
"print('TP =', tp)\n",
|
||
"print('TN =', tn)\n",
|
||
"print('FP =', fp)\n",
|
||
"print('FN =', fn)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "skip"
|
||
}
|
||
},
|
||
"source": [
|
||
"Możemy teraz zdefiniować następujące metryki:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Dokładność (*accuracy*)\n",
|
||
"$$ \\mbox{accuracy} = \\frac{\\mbox{przypadki poprawnie sklasyfikowane}}{\\mbox{wszystkie przypadki}} = \\frac{TP + TN}{TP + TN + FP + FN} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Dokładność otrzymujemy przez podzielenie liczby przypadków poprawnie sklasyfikowanych przez liczbę wszystkich przypadków:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Accuracy: 0.8163265306122449\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"accuracy = (tp + tn) / (tp + tn + fp + fn)\n",
|
||
"print('Accuracy:', accuracy)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"**Uwaga:** Nie zawsze dokładność będzie dobrą miarą, zwłaszcza gdy klasy są bardzo asymetryczne!\n",
|
||
"\n",
|
||
"*Przykład:* Wyobraźmy sobie test na koronawirusa, który **zawsze** zwraca wynik negatywny. Jaką przydatność będzie miał taki test w praktyce? Żadną. A jaka będzie jego *dokładność*? Policzmy:\n",
|
||
"$$ \\mbox{accuracy} \\, = \\, \\frac{\\mbox{szacowana liczba osób zdrowych na świecie}}{\\mbox{populacja Ziemi}} \\, \\approx \\, \\frac{7\\,700\\,000\\,000 - 600\\,000}{7\\,700\\,000\\,000} \\, \\approx \\, 0.99992 $$\n",
|
||
"(zaokrąglone dane z 27 marca 2020)\n",
|
||
"\n",
|
||
"Powyższy wynik jest tak wysoki, ponieważ zdecydowana większość osób na świecie nie jest zakażona, więc biorąc losowego Ziemianina możemy w ciemno strzelać, że nie ma koronawirusa.\n",
|
||
"\n",
|
||
"W tym przypadku duża różnica w liczności obu zbiorów (zakażeni/niezakażeni) powoduje, że *accuracy* nie jest dobrą metryką.\n",
|
||
"\n",
|
||
"Dlatego dysponujemy również innymi metrykami:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Precyzja (*precision*)\n",
|
||
"$$ \\mbox{precision} = \\frac{TP}{TP + FP} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Precision: 0.625\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"precision = tp / (tp + fp)\n",
|
||
"print('Precision:', precision)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Precyzja określa, jaka część przykładów sklasyfikowanych jako pozytywne to faktycznie przykłady pozytywne."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Pokrycie (czułość, *recall*)\n",
|
||
"$$ \\mbox{recall} = \\frac{TP}{TP + FN} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Recall: 0.45454545454545453\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"recall = tp / (tp + fn)\n",
|
||
"print('Recall:', recall)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Pokrycie mówi nam, jaka część przykładów pozytywnych została poprawnie sklasyfikowana."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### *$F$-measure* (*$F$-score*)\n",
|
||
"$$ F = \\frac{2 \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\mbox{precision} + \\mbox{recall}} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"F-score: 0.5263157894736842\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"fscore = (2 * precision * recall) / (precision + recall)\n",
|
||
"print('F-score:', fscore)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"$F$-_measure_ jest kompromisem między precyzją a pokryciem (a ściślej: jest średnią harmoniczną precyzji i pokrycia)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"$F$-_measure_ jest szczególnym przypadkiem ogólniejszej miary:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"*$F_\\beta$-measure*:\n",
|
||
"$$ F_\\beta = \\frac{(1 + \\beta) \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\beta^2 \\cdot \\mbox{precision} + \\mbox{recall}} $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"Dla $\\beta = 1$ otrzymujemy:\n",
|
||
"$$ F_1 \\, = \\, \\frac{(1 + 1) \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{1^2 \\cdot \\mbox{precision} + \\mbox{recall}} \\, = \\, \\frac{2 \\cdot \\mbox{precision} \\cdot \\mbox{recall}}{\\mbox{precision} + \\mbox{recall}} \\, = \\, F $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.3. Obserwacje odstające"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"**Obserwacje odstające** (*outliers*) – to wszelkie obserwacje posiadające nietypową wartość.\n",
|
||
"\n",
|
||
"Mogą być na przykład rezultatem błędnego pomiaru albo pomyłki przy wprowadzaniu danych do bazy, ale nie tylko.\n",
|
||
"\n",
|
||
"Obserwacje odstające mogą niekiedy znacząco wpłynąć na parametry modelu, dlatego ważne jest, żeby takie obserwacje odrzucić zanim przystąpi się do tworzenia modelu."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"W poniższym przykładzie można zobaczyć wpływ obserwacji odstających na wynik modelowania na przykładzie danych dotyczących cen mieszkań zebranych z ogłoszeń na portalu Gratka.pl: tutaj przykładem obserwacji odstającej może być ogłoszenie, w którym podano cenę w tys. zł zamiast ceny w zł."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Przydatne funkcje\n",
|
||
"\n",
|
||
"def h_linear(Theta, x):\n",
|
||
" \"\"\"Funkcja regresji liniowej\"\"\"\n",
|
||
" return x * Theta\n",
|
||
"\n",
|
||
"def linear_regression(theta):\n",
|
||
" \"\"\"Ta funkcja zwraca funkcję regresji liniowej dla danego wektora parametrów theta\"\"\"\n",
|
||
" return lambda x: h_linear(theta, x)\n",
|
||
"\n",
|
||
"def cost(theta, X, y):\n",
|
||
" \"\"\"Wersja macierzowa funkcji kosztu\"\"\"\n",
|
||
" m = len(y)\n",
|
||
" J = 1.0 / (2.0 * m) * ((X * theta - y).T * (X * theta - y))\n",
|
||
" return J.item()\n",
|
||
"\n",
|
||
"def gradient(theta, X, y):\n",
|
||
" \"\"\"Wersja macierzowa gradientu funkcji kosztu\"\"\"\n",
|
||
" return 1.0 / len(y) * (X.T * (X * theta - y)) \n",
|
||
"\n",
|
||
"def gradient_descent(fJ, fdJ, theta, X, y, alpha=0.1, eps=10**-5):\n",
|
||
" \"\"\"Algorytm gradientu prostego (wersja macierzowa)\"\"\"\n",
|
||
" current_cost = fJ(theta, X, y)\n",
|
||
" logs = [[current_cost, theta]]\n",
|
||
" while True:\n",
|
||
" theta = theta - alpha * fdJ(theta, X, y)\n",
|
||
" current_cost, prev_cost = fJ(theta, X, y), current_cost\n",
|
||
" if abs(prev_cost - current_cost) > 10**15:\n",
|
||
" print('Algorithm does not converge!')\n",
|
||
" break\n",
|
||
" if abs(prev_cost - current_cost) <= eps:\n",
|
||
" break\n",
|
||
" logs.append([current_cost, theta]) \n",
|
||
" return theta, logs\n",
|
||
"\n",
|
||
"def plot_data(X, y, xlabel, ylabel):\n",
|
||
" \"\"\"Wykres danych (wersja macierzowa)\"\"\"\n",
|
||
" fig = plt.figure(figsize=(16*.6, 9*.6))\n",
|
||
" ax = fig.add_subplot(111)\n",
|
||
" fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)\n",
|
||
" ax.scatter([X[:, 1]], [y], c='r', s=50, label='Dane')\n",
|
||
" \n",
|
||
" ax.set_xlabel(xlabel)\n",
|
||
" ax.set_ylabel(ylabel)\n",
|
||
" ax.margins(.05, .05)\n",
|
||
" plt.ylim(y.min() - 1, y.max() + 1)\n",
|
||
" plt.xlim(np.min(X[:, 1]) - 1, np.max(X[:, 1]) + 1)\n",
|
||
" return fig\n",
|
||
"\n",
|
||
"def plot_regression(fig, fun, theta, X):\n",
|
||
" \"\"\"Wykres krzywej regresji (wersja macierzowa)\"\"\"\n",
|
||
" ax = fig.axes[0]\n",
|
||
" x0 = np.min(X[:, 1]) - 1.0\n",
|
||
" x1 = np.max(X[:, 1]) + 1.0\n",
|
||
" L = [x0, x1]\n",
|
||
" LX = np.matrix([1, x0, 1, x1]).reshape(2, 2)\n",
|
||
" ax.plot(L, fun(theta, LX), linewidth='2',\n",
|
||
" label=(r'$y={theta0:.2}{op}{theta1:.2}x$'.format(\n",
|
||
" theta0=float(theta[0][0]),\n",
|
||
" theta1=(float(theta[1][0]) if theta[1][0] >= 0 else float(-theta[1][0])),\n",
|
||
" op='+' if theta[1][0] >= 0 else '-')))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Wczytanie danych (mieszkania) przy pomocy biblioteki pandas\n",
|
||
"\n",
|
||
"alldata = pandas.read_csv('data_flats_with_outliers.tsv', sep='\\t',\n",
|
||
" names=['price', 'isNew', 'rooms', 'floor', 'location', 'sqrMetres'])\n",
|
||
"data = np.matrix(alldata[['price', 'sqrMetres']])\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"Xn = data[:, 0:n]\n",
|
||
"\n",
|
||
"Xo = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n + 1)\n",
|
||
"yo = np.matrix(data[:, -1]).reshape(m, 1)\n",
|
||
"\n",
|
||
"Xo /= np.amax(Xo, axis=0)\n",
|
||
"yo /= np.amax(yo, axis=0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "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\n",
|
||
"text/plain": [
|
||
"<Figure size 691.2x388.8 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {
|
||
"needs_background": "light"
|
||
},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data(Xo, yo, xlabel=u'metraż', ylabel=u'cena')\n",
|
||
"theta_start = np.matrix([0.0, 0.0]).reshape(2, 1)\n",
|
||
"theta, logs = gradient_descent(cost, gradient, theta_start, Xo, yo, alpha=0.01)\n",
|
||
"plot_regression(fig, h_linear, theta, Xo)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Na powyższym przykładzie obserwacja odstająca jawi sie jako pojedynczy punkt po prawej stronie wykresu. Widzimy, że otrzymana krzywa regresji zamiast odwzorowywać ogólny trend, próbuje „dopasować się” do tej pojedynczej obserwacji.\n",
|
||
"\n",
|
||
"Dlatego taką obserwację należy usunąć ze zbioru danych (zobacz ponizej)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Odrzućmy obserwacje odstające\n",
|
||
"alldata_no_outliers = [\n",
|
||
" (index, item) for index, item in alldata.iterrows() \n",
|
||
" if item.price > 100 and item.sqrMetres > 10]\n",
|
||
"\n",
|
||
"alldata_no_outliers = alldata.loc[(alldata['price'] > 100) & (alldata['sqrMetres'] > 100)]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"data = np.matrix(alldata_no_outliers[['price', 'sqrMetres']])\n",
|
||
"\n",
|
||
"m, n_plus_1 = data.shape\n",
|
||
"n = n_plus_1 - 1\n",
|
||
"Xn = data[:, 0:n]\n",
|
||
"\n",
|
||
"Xo = np.matrix(np.concatenate((np.ones((m, 1)), Xn), axis=1)).reshape(m, n + 1)\n",
|
||
"yo = np.matrix(data[:, -1]).reshape(m, 1)\n",
|
||
"\n",
|
||
"Xo /= np.amax(Xo, axis=0)\n",
|
||
"yo /= np.amax(yo, axis=0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 23,
|
||
"metadata": {
|
||
"scrolled": true,
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"image/png": "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\n",
|
||
"text/plain": [
|
||
"<Figure size 691.2x388.8 with 1 Axes>"
|
||
]
|
||
},
|
||
"metadata": {
|
||
"needs_background": "light"
|
||
},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"fig = plot_data(Xo, yo, xlabel=u'metraż', ylabel=u'cena')\n",
|
||
"theta_start = np.matrix([0.0, 0.0]).reshape(2, 1)\n",
|
||
"theta, logs = gradient_descent(cost, gradient, theta_start, Xo, yo, alpha=0.01)\n",
|
||
"plot_regression(fig, h_linear, theta, Xo)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"Na powyższym wykresie widać, że po odrzuceniu obserwacji odstających otrzymujemy dużo bardziej „wiarygodną” krzywą regresji."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.4. Warianty metody gradientu prostego\n",
|
||
"\n",
|
||
"* Batch gradient descent\n",
|
||
"* Stochastic gradient descent\n",
|
||
"* Mini-batch gradient descent"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### _Batch gradient descent_\n",
|
||
"\n",
|
||
"* Klasyczna wersja metody gradientu prostego\n",
|
||
"* Obliczamy gradient funkcji kosztu względem całego zbioru treningowego:\n",
|
||
" $$ \\theta := \\theta - \\alpha \\cdot \\nabla_\\theta J(\\theta) $$\n",
|
||
"* Dlatego może działać bardzo powoli\n",
|
||
"* Nie można dodawać nowych przykładów na bieżąco w trakcie trenowania modelu (*online learning*)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### *Stochastic gradient descent* (SGD)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Algorytm\n",
|
||
"\n",
|
||
"Powtórz określoną liczbę razy (liczba epok):\n",
|
||
" 1. Randomizuj dane treningowe\n",
|
||
" 1. Powtórz dla każdego przykładu $i = 1, 2, \\ldots, m$:\n",
|
||
" $$ \\theta := \\theta - \\alpha \\cdot \\nabla_\\theta \\, J \\! \\left( \\theta, x^{(i)}, y^{(i)} \\right) $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "notes"
|
||
}
|
||
},
|
||
"source": [
|
||
"**Randomizacja danych** to losowe potasowanie przykładów uczących (wraz z odpowiedziami)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### SGD - zalety\n",
|
||
"\n",
|
||
"* Dużo szybszy niż _batch gradient descent_\n",
|
||
"* Można dodawać nowe przykłady na bieżąco w trakcie trenowania (*online learning*)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### SGD\n",
|
||
"\n",
|
||
"* Częsta aktualizacja parametrów z dużą wariancją:\n",
|
||
"\n",
|
||
"<img src=\"http://ruder.io/content/images/2016/09/sgd_fluctuation.png\" style=\"margin: auto;\" width=\"50%\" />\n",
|
||
"\n",
|
||
"* Z jednej strony dzięki temu nie utyka w złych minimach lokalnych, ale z drugiej strony może „wyskoczyć” z dobrego minimum"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### _Mini-batch gradient descent_"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Algorytm\n",
|
||
"\n",
|
||
"1. Ustal rozmiar \"paczki/wsadu\" (*batch*) $b \\leq m$.\n",
|
||
"2. Powtórz określoną liczbę razy (liczba epok):\n",
|
||
" 1. Powtórz dla każdego batcha (czyli dla $i = 1, 1 + b, 1 + 2 b, \\ldots$):\n",
|
||
" $$ \\theta := \\theta - \\alpha \\cdot \\nabla_\\theta \\, J \\left( \\theta, x^{(i : i+b)}, y^{(i : i+b)} \\right) $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### _Mini-batch gradient descent_\n",
|
||
"\n",
|
||
"* Kompromis między _batch gradient descent_ i SGD\n",
|
||
"* Stabilniejsza zbieżność dzięki redukcji wariancji aktualizacji parametrów\n",
|
||
"* Szybszy niż klasyczny _batch gradient descent_\n",
|
||
"* Typowa wielkość batcha: między kilka a kilkaset przykładów\n",
|
||
" * Im większy batch, tym bliżej do BGD; im mniejszy batch, tym bliżej do SGD\n",
|
||
" * BGD i SGD można traktować jako odmiany MBGD dla $b = m$ i $b = 1$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "skip"
|
||
}
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Mini-batch gradient descent - przykładowa implementacja\n",
|
||
"\n",
|
||
"def MiniBatchSGD(h, fJ, fdJ, theta, X, y, \n",
|
||
" alpha=0.001, maxEpochs=1.0, batchSize=100, \n",
|
||
" logError=True):\n",
|
||
" errorsX, errorsY = [], []\n",
|
||
" \n",
|
||
" m, n = X.shape\n",
|
||
" start, end = 0, batchSize\n",
|
||
" \n",
|
||
" maxSteps = (m * float(maxEpochs)) / batchSize\n",
|
||
" for i in range(int(maxSteps)):\n",
|
||
" XBatch, yBatch = X[start:end,:], y[start:end,:]\n",
|
||
"\n",
|
||
" theta = theta - alpha * fdJ(h, theta, XBatch, yBatch)\n",
|
||
" \n",
|
||
" if logError:\n",
|
||
" errorsX.append(float(i*batchSize)/m)\n",
|
||
" errorsY.append(fJ(h, theta, XBatch, yBatch).item())\n",
|
||
" \n",
|
||
" if start + batchSize < m:\n",
|
||
" start += batchSize\n",
|
||
" else:\n",
|
||
" start = 0\n",
|
||
" end = min(start + batchSize, m)\n",
|
||
" \n",
|
||
" return theta, (errorsX, errorsY)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Porównanie uśrednionych krzywych uczenia na przykładzie klasyfikacji dwuklasowej zbioru [MNIST](https://en.wikipedia.org/wiki/MNIST_database):\n",
|
||
"\n",
|
||
"<img src=\"sgd-comparison.png\" width=\"70%\" />"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Wady klasycznej metody gradientu prostego, czyli dlaczego potrzebujemy optymalizacji\n",
|
||
"\n",
|
||
"* Trudno dobrać właściwą szybkość uczenia (*learning rate*)\n",
|
||
"* Jedna ustalona wartość stałej uczenia się dla wszystkich parametrów\n",
|
||
"* Funkcja kosztu dla sieci neuronowych nie jest wypukła, więc uczenie może utknąć w złym minimum lokalnym lub punkcie siodłowym"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.5. Algorytmy optymalizacji metody gradientu\n",
|
||
"\n",
|
||
"* Momentum\n",
|
||
"* Nesterov Accelerated Gradient\n",
|
||
"* Adagrad\n",
|
||
"* Adadelta\n",
|
||
"* RMSprop\n",
|
||
"* Adam\n",
|
||
"* Nadam\n",
|
||
"* AMSGrad"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Momentum\n",
|
||
"\n",
|
||
"* SGD źle radzi sobie w „wąwozach” funkcji kosztu\n",
|
||
"* Momentum rozwiązuje ten problem przez dodanie współczynnika $\\gamma$, który można trakować jako „pęd” spadającej piłki:\n",
|
||
" $$ v_t := \\gamma \\, v_{t-1} + \\alpha \\, \\nabla_\\theta J(\\theta) $$\n",
|
||
" $$ \\theta := \\theta - v_t $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Przyspiesony gradient Nesterova (*Nesterov Accelerated Gradient*, NAG)\n",
|
||
"\n",
|
||
"* Momentum czasami powoduje niekontrolowane rozpędzanie się piłki, przez co staje się „mniej sterowna”\n",
|
||
"* Nesterov do piłki posiadającej pęd dodaje „hamulec”, który spowalnia piłkę przed wzniesieniem:\n",
|
||
" $$ v_t := \\gamma \\, v_{t-1} + \\alpha \\, \\nabla_\\theta J(\\theta - \\gamma \\, v_{t-1}) $$\n",
|
||
" $$ \\theta := \\theta - v_t $$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Adagrad\n",
|
||
"\n",
|
||
"* “<b>Ada</b>ptive <b>grad</b>ient”\n",
|
||
"* Adagrad dostosowuje współczynnik uczenia (*learning rate*) do parametrów: zmniejsza go dla cech występujących częściej, a zwiększa dla występujących rzadziej:\n",
|
||
"* Świetny do trenowania na rzadkich (*sparse*) zbiorach danych\n",
|
||
"* Wada: współczynnik uczenia może czasami gwałtownie maleć\n",
|
||
"* Wyniki badań pokazują, że często **starannie** dobrane $\\alpha$ daje lepsze wyniki na zbiorze testowym"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Adadelta i RMSprop\n",
|
||
"* Warianty algorytmu Adagrad, które radzą sobie z problemem gwałtownych zmian współczynnika uczenia"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Adam\n",
|
||
"\n",
|
||
"* “<b>Ada</b>ptive <b>m</b>oment estimation”\n",
|
||
"* Łączy zalety algorytmów RMSprop i Momentum\n",
|
||
"* Można go porównać do piłki mającej ciężar i opór\n",
|
||
"* Obecnie jeden z najpopularniejszych algorytmów optymalizacji"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Nadam\n",
|
||
"* “<b>N</b>esterov-accelerated <b>ada</b>ptive <b>m</b>oment estimation”\n",
|
||
"* Łączy zalety algorytmów Adam i Nesterov Accelerated Gradient"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### AMSGrad\n",
|
||
"* Wariant algorytmu Adam lepiej dostosowany do zadań takich jak rozpoznawanie obiektów czy tłumaczenie maszynowe"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"<img src=\"contours_evaluation_optimizers.gif\" style=\"margin: auto;\" width=\"80%\" />"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"<img src=\"saddle_point_evaluation_optimizers.gif\" style=\"margin: auto;\" width=\"80%\" />"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"## 3.6. Metody zbiorcze"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
" * **Metody zbiorcze** (*ensemble methods*) używają połączonych sił wielu modeli uczenia maszynowego w celu uzyskania lepszej skuteczności niż mogłaby być osiągnięta przez każdy z tych modeli z osobna."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Na metodę zbiorczą składa się:\n",
|
||
" * dobór modeli\n",
|
||
" * sposób agregacji wyników"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
" * Warto zastosować randomizację, czyli przetasować zbiór uczący przed trenowaniem każdego modelu."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Uśrednianie prawdopodobieństw"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Przykład\n",
|
||
"\n",
|
||
"Mamy 3 modele, które dla klas $c=1, 2, 3, 4, 5$ zwróciły prawdopodobieństwa:\n",
|
||
"\n",
|
||
"* $M_1$: [0.10, 0.40, **0.50**, 0.00, 0.00]\n",
|
||
"* $M_2$: [0.10, **0.60**, 0.20, 0.00, 0.10]\n",
|
||
"* $M_3$: [0.10, 0.30, **0.40**, 0.00, 0.20]\n",
|
||
"\n",
|
||
"Która klasa zostanie wybrana według średnich prawdopodobieństw dla każdej klasy?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Średnie prawdopodobieństwo: [0.10, **0.43**, 0.36, 0.00, 0.10]\n",
|
||
"\n",
|
||
"Została wybrana klasa $c = 2$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Głosowanie klas"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "fragment"
|
||
}
|
||
},
|
||
"source": [
|
||
"#### Przykład\n",
|
||
"\n",
|
||
"Mamy 3 modele, które dla klas $c=1, 2, 3, 4, 5$ zwróciły prawdopodobieństwa:\n",
|
||
"\n",
|
||
"* $M_1$: [0.10, 0.40, **0.50**, 0.00, 0.00]\n",
|
||
"* $M_2$: [0.10, **0.60**, 0.20, 0.00, 0.10]\n",
|
||
"* $M_3$: [0.10, 0.30, **0.40**, 0.00, 0.20]\n",
|
||
"\n",
|
||
"Która klasa zostanie wybrana według głosowania?"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "subslide"
|
||
}
|
||
},
|
||
"source": [
|
||
"Liczba głosów: [0, 1, **2**, 0, 0]\n",
|
||
"\n",
|
||
"Została wybrana klasa $c = 3$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {
|
||
"slideshow": {
|
||
"slide_type": "slide"
|
||
}
|
||
},
|
||
"source": [
|
||
"### Inne metody zbiorcze\n",
|
||
"\n",
|
||
" * Bagging\n",
|
||
" * Boostng\n",
|
||
" * Stacking\n",
|
||
" \n",
|
||
"https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"celltoolbar": "Slideshow",
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.8.3"
|
||
},
|
||
"livereveal": {
|
||
"start_slideshow_at": "selected",
|
||
"theme": "white"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|