{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### Uczenie maszynowe\n",
    "# 12. Metody optymalizacji"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 12.1. 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 uczącego:\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, jak zmienia się wartość funkcji kosztu podczas optymalizacji:\n",
    "\n",
    "<img src=\"https://miro.medium.com/max/1400/1*R12QVNFn-46IPewAMxde2w.png\" style=\"margin: auto;\" width=\"100%\" />"
   ]
  },
  {
   "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": [
    "## 12.2. 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": [
    "### Przyspieszony 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",
    "* 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=\"60%\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "<img src=\"saddle_point_evaluation_optimizers.gif\" style=\"margin: auto;\" width=\"60%\" />"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.6"
  },
  "livereveal": {
   "start_slideshow_at": "selected",
   "theme": "white"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}