12.3 Gradientinis nusileidimas

Šiame skyrelyje pristatysime pagrindines gradientinio nusileidimo sąvokas. Nors giliajame mokymesi jis naudojamas retai tiesiogiai, gradientinio nusileidimo supratimas yra raktas į stochastinio gradientinio nusileidimo algoritmų supratimą. Pavyzdžiui, optimizavimo uždavinys gali diverguoti dėl pernelyg didelio mokymosi greičio. Šį reiškinį galima pastebėti jau gradientiniame nusileidime. Panašiai pradinių sąlygų tikrinimas yra įprastas gradientinio nusileidimo metodas ir perkeliamas į pažangesnius algoritmus. Pradėkime nuo paprasto ypatingo atvejo.

12.3.1 Vienmatis gradientinis nusileidimas

Gradientinis nusileidimas vienoje dimensijoje yra puikus pavyzdys paaiškinti, kodėl gradientinio nusileidimo algoritmas gali sumažinti tikslo funkcijos reikšmę. Panagrinėkime tam tikrą tolydžiai diferencijuojamą realiųjų reikšmių funkciją f:R→Rf: \mathbb{R} \rightarrow \mathbb{R}. Naudodami Teiloro skleidinį gauname

f(x+ϵ)=f(x)+ϵf′(x)+O(ϵ2).(12.3.1)f(x + \epsilon) = f(x) + \epsilon f'(x) + \mathcal{O}(\epsilon^2). \tag{12.3.1}

Tai yra, pirmos eilės aproksimacijoje f(x+ϵ)f(x+\epsilon) nusako funkcijos reikšmė f(x)f(x) ir pirmoji išvestinė f′(x)f'(x) taške xx. Nėra nepagrįsta daryti prielaidą, kad mažiems ϵ\epsilon judėjimas neigiamo gradiento kryptimi sumažins ff. Kad viskas būtų paprasta, pasirenkame fiksuotą žingsnio dydį η>0\eta > 0 ir parenkame ϵ=−ηf′(x)\epsilon = -\eta f'(x). Įstatę tai į aukščiau pateiktą Teiloro skleidinį, gauname

f(x−ηf′(x))=f(x)−ηf′2(x)+O(η2f′2(x)).(12.3.2)f(x - \eta f'(x)) = f(x) - \eta f'^2(x) + \mathcal{O}(\eta^2 f'^2(x)). \tag{12.3.2}

Jei išvestinė f′(x)≠0f'(x) \neq 0 neišnyksta, darome pažangą, nes ηf′2(x)>0\eta f'^2(x)>0. Be to, visada galime pasirinkti pakankamai mažą η\eta, kad aukštesnės eilės nariai taptų nesvarbūs. Taigi gauname

f(x−ηf′(x))⪅f(x).f(x - \eta f'(x)) \lessapprox f(x).

Tai reiškia, kad jei naudojame

x←x−ηf′(x)x \leftarrow x - \eta f'(x)

xx iteracijoms, funkcijos f(x)f(x) reikšmė gali mažėti. Todėl gradientiniame nusileidime pirmiausia pasirenkame pradinę reikšmę xx ir konstantą η>0\eta > 0, o paskui jas naudojame nuolat iteruodami xx, kol pasiekiama sustojimo sąlyga, pavyzdžiui, kai gradiento dydis ∣f′(x)∣|f'(x)| yra pakankamai mažas arba iteracijų skaičius pasiekė tam tikrą reikšmę.

Paprastumo dėlei pasirenkame tikslo funkciją f(x)=x2f(x)=x^2, kad iliustruotume, kaip įgyvendinti gradientinį nusileidimą. Nors žinome, kad x=0x=0 yra f(x)f(x) minimizavimo sprendinys, vis tiek naudojame šią paprastą funkciją stebėti, kaip kinta xx.

%matplotlib inline
from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()
%matplotlib inline
from d2l import torch as d2l
import numpy as np
import torch
%matplotlib inline
from d2l import tensorflow as d2l
import numpy as np
import tensorflow as tf
def f(x):  # Objective function
    return x ** 2

def f_grad(x):  # Gradient (derivative) of the objective function
    return 2 * x

Toliau kaip pradinę reikšmę naudojame x=10x=10 ir tarkime, kad η=0.2\eta=0.2. Naudodami gradientinį nusileidimą xx iteruoti 10 kartų, matome, kad galiausiai xx reikšmė artėja prie optimalaus sprendinio.

def gd(eta, f_grad):
    x = 10.0
    results = [x]
    for i in range(10):
        x -= eta * f_grad(x)
        results.append(float(x))
    print(f'epoch 10, x: {x:f}')
    return results

results = gd(0.2, f_grad)

Optimizavimo per xx eigą galima nubraižyti taip.

def show_trace(results, f):
    n = max(abs(min(results)), abs(max(results)))
    f_line = d2l.arange(-n, n, 0.01)
    d2l.set_figsize()
    d2l.plot([f_line, results], [[f(x) for x in f_line], [
        f(x) for x in results]], 'x', 'f(x)', fmts=['-', '-o'])

show_trace(results, f)

12.3.1.1 Mokymosi greitis

Mokymosi greitį η\eta gali nustatyti algoritmo kūrėjas. Jei naudojame pernelyg mažą mokymosi greitį, xx atnaujinamas labai lėtai, todėl reikia daugiau iteracijų geresniam sprendiniui gauti. Kad parodytume, kas nutinka tokiu atveju, panagrinėkime pažangą tame pačiame optimizavimo uždavinyje, kai η=0.05\eta = 0.05. Kaip matome, net po 10 žingsnių vis dar esame labai toli nuo optimalaus sprendinio.

show_trace(gd(0.05, f_grad), f)

Ir atvirkščiai, jei naudojame pernelyg didelį mokymosi greitį, ∣ηf′(x)∣\left|\eta f'(x)\right| gali būti per didelis pirmos eilės Teiloro skleidinio formulei. Tai yra, narys O(η2f′2(x))\mathcal{O}(\eta^2 f'^2(x)) (12.3.2) gali tapti reikšmingas. Tokiu atveju negalime garantuoti, kad xx iteravimas sumažins f(x)f(x) reikšmę. Pavyzdžiui, kai mokymosi greitį nustatome η=1.1\eta=1.1, xx peršoka optimalų sprendinį x=0x=0 ir palaipsniui diverguoja.

show_trace(gd(1.1, f_grad), f)

12.3.1.2 Lokalieji minimumai

Kad iliustruotume, kas nutinka neiškiliosioms funkcijoms, panagrinėkime atvejį f(x)=x⋅cos⁡(cx)f(x) = x \cdot \cos(cx) su tam tikra konstanta cc. Ši funkcija turi be galo daug lokaliųjų minimumų. Priklausomai nuo mokymosi greičio pasirinkimo ir nuo to, kiek gerai sąlygotas uždavinys, galime baigti viename iš daugelio sprendinių. Toliau pateiktas pavyzdys iliustruoja, kaip (nerealiai) didelis mokymosi greitis lems prastą lokalųjį minimumą.

c = d2l.tensor(0.15 * np.pi)

def f(x):  # Objective function
    return x * d2l.cos(c * x)

def f_grad(x):  # Gradient of the objective function
    return d2l.cos(c * x) - c * x * d2l.sin(c * x)

show_trace(gd(2, f_grad), f)

12.3.2 Daugiamatis gradientinis nusileidimas

Dabar, kai geriau intuityviai suprantame vienmatį atvejį, panagrinėkime situaciją, kai x=[x1,x2,…,xd]⊤\mathbf{x} = [x_1, x_2, \ldots, x_d]^\top. Tai yra, tikslo funkcija f:Rd→Rf: \mathbb{R}^d \to \mathbb{R} atvaizduoja vektorius į skaliarus. Atitinkamai jos gradientas taip pat yra daugiamatis. Tai vektorius, sudarytas iš dd dalinių išvestinių:

∇f(x)=[∂f(x)∂x1,∂f(x)∂x2,…,∂f(x)∂xd]⊤.\nabla f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_d}\bigg]^\top.

Kiekvienas gradiento dalinės išvestinės elementas ∂f(x)/∂xi\partial f(\mathbf{x})/\partial x_i nurodo ff kitimo spartą taške x\mathbf{x} įvesties xix_i atžvilgiu. Kaip ir anksčiau vienmačiu atveju, galime naudoti atitinkamą daugelio kintamųjų funkcijų Teiloro aproksimaciją, kad gautume supratimą, ką turėtume daryti. Visų pirma turime, kad

f(x+ϵ)=f(x)+ϵ⊤∇f(x)+O(∥ϵ∥2).(12.3.3)f(\mathbf{x} + \boldsymbol{\epsilon}) = f(\mathbf{x}) + \mathbf{\boldsymbol{\epsilon}}^\top \nabla f(\mathbf{x}) + \mathcal{O}(\|\boldsymbol{\epsilon}\|^2). \tag{12.3.3}

Kitaip tariant, iki antros eilės narių ϵ\boldsymbol{\epsilon} atžvilgiu staigiausio nusileidimo kryptį nusako neigiamas gradientas −∇f(x)-\nabla f(\mathbf{x}). Pasirinkus tinkamą mokymosi greitį η>0\eta > 0, gaunamas prototipinis gradientinio nusileidimo algoritmas:

x←x−η∇f(x).\mathbf{x} \leftarrow \mathbf{x} - \eta \nabla f(\mathbf{x}).

Kad pamatytume, kaip algoritmas elgiasi praktikoje, sukonstruokime tikslo funkciją f(x)=x12+2x22f(\mathbf{x})=x_1^2+2x_2^2, kurios įvestis yra dvimatis vektorius x=[x1,x2]⊤\mathbf{x} = [x_1, x_2]^\top, o išvestis – skaliaras. Gradientas yra ∇f(x)=[2x1,4x2]⊤\nabla f(\mathbf{x}) = [2x_1, 4x_2]^\top. Stebėsime x\mathbf{x} trajektoriją gradientinio nusileidimo metu, pradedant nuo pradinės padėties [−5,−2][-5, -2].

Pirmiausia mums reikia dar dviejų pagalbinių funkcijų. Pirmoji naudoja atnaujinimo funkciją ir taiko ją 20 kartų pradinei reikšmei. Antroji pagalbinė funkcija vizualizuoja x\mathbf{x} trajektoriją.

def train_2d(trainer, steps=20, f_grad=None):  #@save
    """Optimize a 2D objective function with a customized trainer."""
    # `s1` and `s2` are internal state variables that will be used in Momentum, adagrad, RMSProp
    x1, x2, s1, s2 = -5, -2, 0, 0
    results = [(x1, x2)]
    for i in range(steps):
        if f_grad:
            x1, x2, s1, s2 = trainer(x1, x2, s1, s2, f_grad)
        else:
            x1, x2, s1, s2 = trainer(x1, x2, s1, s2)
        results.append((x1, x2))
    print(f'epoch {i + 1}, x1: {float(x1):f}, x2: {float(x2):f}')
    return results
def show_trace_2d(f, results):  #@save
    """Show the trace of 2D variables during optimization."""
    d2l.set_figsize()
    d2l.plt.plot(*zip(*results), '-o', color='#ff7f0e')
    x1, x2 = d2l.meshgrid(d2l.arange(-55, 1, 1),
                          d2l.arange(-30, 1, 1))
    x1, x2 = x1.asnumpy()*0.1, x2.asnumpy()*0.1
    d2l.plt.contour(x1, x2, f(x1, x2), colors='#1f77b4')
    d2l.plt.xlabel('x1')
    d2l.plt.ylabel('x2')
def show_trace_2d(f, results):  #@save
    """Show the trace of 2D variables during optimization."""
    d2l.set_figsize()
    d2l.plt.plot(*zip(*results), '-o', color='#ff7f0e')
    x1, x2 = d2l.meshgrid(d2l.arange(-5.5, 1.0, 0.1),
                          d2l.arange(-3.0, 1.0, 0.1))
    d2l.plt.contour(x1, x2, f(x1, x2), colors='#1f77b4')
    d2l.plt.xlabel('x1')
    d2l.plt.ylabel('x2')
def show_trace_2d(f, results):  #@save
    """Show the trace of 2D variables during optimization."""
    d2l.set_figsize()
    d2l.plt.plot(*zip(*results), '-o', color='#ff7f0e')
    x1, x2 = d2l.meshgrid(d2l.arange(-5.5, 1.0, 0.1),
                          d2l.arange(-3.0, 1.0, 0.1), indexing='ij')
    d2l.plt.contour(x1, x2, f(x1, x2), colors='#1f77b4')
    d2l.plt.xlabel('x1')
    d2l.plt.ylabel('x2')

Toliau stebime optimizavimo kintamojo x\mathbf{x} trajektoriją, kai mokymosi greitis η=0.1\eta = 0.1. Matome, kad po 20 žingsnių x\mathbf{x} reikšmė artėja prie savo minimumo [0,0][0, 0]. Pažanga gana tvarkinga, nors ir gana lėta.

def f_2d(x1, x2):  # Objective function
    return x1 ** 2 + 2 * x2 ** 2

def f_2d_grad(x1, x2):  # Gradient of the objective function
    return (2 * x1, 4 * x2)

def gd_2d(x1, x2, s1, s2, f_grad):
    g1, g2 = f_grad(x1, x2)
    return (x1 - eta * g1, x2 - eta * g2, 0, 0)

eta = 0.1
show_trace_2d(f_2d, train_2d(gd_2d, f_grad=f_2d_grad))

12.3.3 Adaptyvieji metodai

Kaip matėme 12.3.1.1 skyrelis, mokymosi greitį η\eta pasirinkti „tiksliai tinkamą“ yra sudėtinga. Jei pasirenkame per mažą, darome mažai pažangos. Jei pasirenkame per didelį, sprendinys svyruoja, o blogiausiu atveju gali net diverguoti. Ką, jei galėtume nustatyti η\eta automatiškai arba išvis atsikratytume poreikio rinktis mokymosi greitį? Antros eilės metodai, kurie žiūri ne tik į tikslo funkcijos reikšmę ir gradientą, bet ir į jos kreivumą, gali padėti šiuo atveju. Nors šių metodų negalima tiesiogiai taikyti giliajam mokymuisi dėl skaičiavimo kainos, jie suteikia naudingos intuicijos, kaip projektuoti pažangius optimizavimo algoritmus, imituojančius daugelį toliau aprašytų algoritmų pageidaujamų savybių.

12.3.3.1 Niutono metodas

Peržiūrėdami kokios nors funkcijos f:Rd→Rf: \mathbb{R}^d \rightarrow \mathbb{R} Teiloro skleidinį, nematome priežasties sustoti po pirmojo nario. Iš tikrųjų galime jį užrašyti kaip

f(x+ϵ)=f(x)+ϵ⊤∇f(x)+12ϵ⊤∇2f(x)ϵ+O(∥ϵ∥3).(12.3.4)f(\mathbf{x} + \boldsymbol{\epsilon}) = f(\mathbf{x}) + \boldsymbol{\epsilon}^\top \nabla f(\mathbf{x}) + \frac{1}{2} \boldsymbol{\epsilon}^\top \nabla^2 f(\mathbf{x}) \boldsymbol{\epsilon} + \mathcal{O}(\|\boldsymbol{\epsilon}\|^3). \tag{12.3.4}

Kad išvengtume sudėtingo žymėjimo, apibrėžiame H=def∇2f(x)\mathbf{H} \stackrel{\textrm{def}}{=} \nabla^2 f(\mathbf{x}) kaip ff Hesės matricą, kuri yra d×dd \times d matrica. Mažiems dd ir paprastiems uždaviniams H\mathbf{H} lengva apskaičiuoti. Tačiau giliesiems neuroniniams tinklams H\mathbf{H} gali būti nepriimtinai didelė dėl O(d2)\mathcal{O}(d^2) elementų saugojimo kainos. Be to, ją gali būti pernelyg brangu apskaičiuoti atgaliniu sklidimu. Kol kas nekreipkime dėmesio į tokius svarstymus ir pažiūrėkime, koks algoritmas gautųsi.

Juk ff minimumas tenkina ∇f=0\nabla f = 0. Laikydamiesi diferencialinio skaičiavimo taisyklių 2.4.3 skyrelis, išvestinę (12.3.4) ϵ\boldsymbol{\epsilon} atžvilgiu ir ignoruodami aukštesnės eilės narius, gauname

∇f(x)+Hϵ=0 and hence ϵ=−H−1∇f(x).\nabla f(\mathbf{x}) + \mathbf{H} \boldsymbol{\epsilon} = 0 \textrm{ and hence } \boldsymbol{\epsilon} = -\mathbf{H}^{-1} \nabla f(\mathbf{x}).

Tai yra, kaip optimizavimo uždavinio dalį turime invertuoti Hesės matricą H\mathbf{H}.

Kaip paprastas pavyzdys, kai f(x)=12x2f(x) = \frac{1}{2} x^2, turime ∇f(x)=x\nabla f(x) = x ir H=1\mathbf{H} = 1. Taigi bet kuriam xx gauname ϵ=−x\epsilon = -x. Kitaip tariant, vieno žingsnio pakanka tobulai konverguoti, nereikia jokio koregavimo! Deja, čia mums šiek tiek pasisekė: Teiloro skleidinys buvo tikslus, nes f(x+ϵ)=12x2+ϵx+12ϵ2f(x+\epsilon)= \frac{1}{2} x^2 + \epsilon x + \frac{1}{2} \epsilon^2.

Pažiūrėkime, kas nutinka kituose uždaviniuose. Turint iškilią hiperbolinio kosinuso funkciją f(x)=cosh⁡(cx)f(x) = \cosh(cx) su tam tikra konstanta cc, matome, kad globalusis minimumas taške x=0x=0 pasiekiamas po kelių iteracijų.

c = d2l.tensor(0.5)

def f(x):  # Objective function
    return d2l.cosh(c * x)

def f_grad(x):  # Gradient of the objective function
    return c * d2l.sinh(c * x)

def f_hess(x):  # Hessian of the objective function
    return c**2 * d2l.cosh(c * x)

def newton(eta=1):
    x = 10.0
    results = [x]
    for i in range(10):
        x -= eta * f_grad(x) / f_hess(x)
        results.append(float(x))
    print('epoch 10, x:', x)
    return results

show_trace(newton(), f)

Dabar panagrinėkime neiškiliąją funkciją, pavyzdžiui, f(x)=xcos⁡(cx)f(x) = x \cos(c x) su tam tikra konstanta cc. Juk atkreipkite dėmesį, kad Niutono metode galiausiai dalijame iš Hesės matricos. Tai reiškia, kad jei antroji išvestinė yra neigiama, galime eiti didėjančios ff reikšmės kryptimi. Tai lemtinga algoritmo yda. Pažiūrėkime, kas nutinka praktikoje.

c = d2l.tensor(0.15 * np.pi)

def f(x):  # Objective function
    return x * d2l.cos(c * x)

def f_grad(x):  # Gradient of the objective function
    return d2l.cos(c * x) - c * x * d2l.sin(c * x)

def f_hess(x):  # Hessian of the objective function
    return - 2 * c * d2l.sin(c * x) - x * c**2 * d2l.cos(c * x)

show_trace(newton(), f)

Tai nepavyko spektakliškai. Kaip tai ištaisyti? Vienas būdas būtų „ištaisyti“ Hesės matricą vietoj jos paėmus jos absoliutinę reikšmę. Kita strategija yra grąžinti mokymosi greitį. Atrodo, kad tai paneigia tikslą, bet ne visai. Turėdami antros eilės informaciją, galime būti atsargūs, kai kreivumas didelis, ir daryti ilgesnius žingsnius, kai tikslo funkcija plokštesnė. Pažiūrėkime, kaip tai veikia su kiek mažesniu mokymosi greičiu, tarkime, η=0.5\eta = 0.5. Kaip matome, turime gana efektyvų algoritmą.

show_trace(newton(0.5), f)

12.3.3.2 Konvergavimo analizė

Analizuojame tik Niutono metodo konvergavimo greitį kokiai nors iškiliajai ir tris kartus diferencijuojamai tikslo funkcijai ff, kurios antroji išvestinė nelygi nuliui, t. y. f′′>0f'' > 0. Daugiamatis įrodymas yra paprastas toliau pateikto vienmačio argumento plėtinys ir praleidžiamas, nes jis mums daug nepadeda intuicijos požiūriu.

Pažymėkime x(k)x^{(k)} reikšmę xx kk-ojoje iteracijoje ir tegul e(k)=defx(k)−x∗e^{(k)} \stackrel{\textrm{def}}{=} x^{(k)} - x^* yra atstumas nuo optimumo kk-ojoje iteracijoje. Pagal Teiloro skleidinį sąlygą f′(x∗)=0f'(x^*) = 0 galima užrašyti kaip

0=f′(x(k)−e(k))=f′(x(k))−e(k)f′′(x(k))+12(e(k))2f′′′(ξ(k)),0 = f'(x^{(k)} - e^{(k)}) = f'(x^{(k)}) - e^{(k)} f''(x^{(k)}) + \frac{1}{2} (e^{(k)})^2 f'''(\xi^{(k)}),

kuri galioja tam tikram ξ(k)∈[x(k)−e(k),x(k)]\xi^{(k)} \in [x^{(k)} - e^{(k)}, x^{(k)}]. Padalijus aukščiau pateiktą skleidinį iš f′′(x(k))f''(x^{(k)}), gauname

e(k)−f′(x(k))f′′(x(k))=12(e(k))2f′′′(ξ(k))f′′(x(k)).e^{(k)} - \frac{f'(x^{(k)})}{f''(x^{(k)})} = \frac{1}{2} (e^{(k)})^2 \frac{f'''(\xi^{(k)})}{f''(x^{(k)})}.

Prisiminkite, kad turime atnaujinimą x(k+1)=x(k)−f′(x(k))/f′′(x(k))x^{(k+1)} = x^{(k)} - f'(x^{(k)}) / f''(x^{(k)}). Įstatę šią atnaujinimo lygtį ir paėmę abiejų pusių absoliutinę reikšmę, turime

∣e(k+1)∣=12(e(k))2∣f′′′(ξ(k))∣f′′(x(k)).\left|e^{(k+1)}\right| = \frac{1}{2}(e^{(k)})^2 \frac{\left|f'''(\xi^{(k)})\right|}{f''(x^{(k)})}.

Todėl, kai tik esame srityje, kurioje ∣f′′′(ξ(k))∣/(2f′′(x(k)))≤c\left|f'''(\xi^{(k)})\right| / (2f''(x^{(k)})) \leq c aprėžta, turime kvadratiškai mažėjančią paklaidą

∣e(k+1)∣≤c(e(k))2.\left|e^{(k+1)}\right| \leq c (e^{(k)})^2.

Pastebėkime, kad optimizavimo tyrėjai tai vadina tiesiniu konvergavimu, o tokia sąlyga kaip ∣e(k+1)∣≤α∣e(k)∣\left|e^{(k+1)}\right| \leq \alpha \left|e^{(k)}\right| būtų vadinama pastovia konvergavimo sparta. Atkreipkite dėmesį, kad ši analizė turi keletą išlygų. Pirma, iš tikrųjų neturime didelės garantijos, kada pasieksime greito konvergavimo sritį. Vietoj to žinome tik tai, kad kai ją pasieksime, konvergavimas bus labai greitas. Antra, ši analizė reikalauja, kad ff būtų gerai besielgianti iki aukštesnės eilės išvestinių. Tai susiveda į tai, kad ff neturėtų jokių „netikėtų“ savybių, susijusių su tuo, kaip ji gali keisti savo reikšmes.

12.3.3.3 Pradinių sąlygų tikrinimas

Visai nenuostabu, kad pilnos Hesės matricos skaičiavimas ir saugojimas yra labai brangus. Todėl pageidautina rasti alternatyvų. Vienas būdas pagerinti padėtį yra pradinių sąlygų tikrinimas. Jis vengia skaičiuoti visą Hesės matricą ir apskaičiuoja tik įstrižainės elementus. Tai veda prie tokios formos atnaujinimo algoritmų:

x←x−ηdiag(H)−1∇f(x).\mathbf{x} \leftarrow \mathbf{x} - \eta \textrm{diag}(\mathbf{H})^{-1} \nabla f(\mathbf{x}).

Nors tai nėra visai taip gerai kaip pilnas Niutono metodas, vis tiek tai daug geriau nei jo nenaudoti. Kad pamatytume, kodėl tai gali būti gera idėja, panagrinėkime situaciją, kai vienas kintamasis žymi aukštį milimetrais, o kitas – aukštį kilometrais. Darant prielaidą, kad abiem natūralus mastelis yra metrai, turime baisų parametrizacijų neatitikimą. Laimė, pradinių sąlygų tikrinimas tai pašalina. Efektyviai pradinių sąlygų tikrinimas su gradientiniu nusileidimu reiškia skirtingo mokymosi greičio pasirinkimą kiekvienam kintamajam (vektoriaus x\mathbf{x} koordinatei). Kaip pamatysime vėliau, pradinių sąlygų tikrinimas lemia dalį naujovių stochastinio gradientinio nusileidimo optimizavimo algoritmuose.

12.3.3.4 Gradientinis nusileidimas su tiesine paieška

Viena pagrindinių gradientinio nusileidimo problemų yra ta, kad galime peršokti tikslą arba padaryti nepakankamą pažangą. Paprastas problemos sprendimas yra naudoti tiesinę paiešką kartu su gradientiniu nusileidimu. Tai yra, naudojame kryptį, kurią nurodo ∇f(x)\nabla f(\mathbf{x}), o tada atliekame dvejetainę paiešką, kuris mokymosi greitis η\eta minimizuoja f(x−η∇f(x))f(\mathbf{x} - \eta \nabla f(\mathbf{x})).

Šis algoritmas konverguoja sparčiai (analizės ir įrodymo žr., pvz., (Stephen Boyd ir Lieven Vandenberghe, )). Tačiau giliojo mokymosi tikslais tai nėra visai įgyvendinama, nes kiekvienam tiesinės paieškos žingsniui reikėtų įvertinti tikslo funkciją visame duomenų rinkinyje. Tai pernelyg brangu.

12.3.4 Santrauka

  • Mokymosi greičiai svarbūs. Per dideli – diverguojame, per maži – nedarome pažangos.
  • Gradientinis nusileidimas gali įstrigti lokaliuosiuose minimumuose.
  • Didelėse dimensijose mokymosi greičio koregavimas yra sudėtingas.
  • Pradinių sąlygų tikrinimas gali padėti koreguoti mastelį.
  • Niutono metodas yra daug greitesnis, kai jis pradeda tinkamai veikti iškiliuosiuose uždaviniuose.
  • Būkite atsargūs naudodami Niutono metodą be jokių koregavimų neiškiliesiems uždaviniams.

12.3.5 Pratimai

  1. Eksperimentuokite su skirtingais mokymosi greičiais ir tikslo funkcijomis gradientiniam nusileidimui.
  2. Įgyvendinkite tiesinę paiešką iškiliajai funkcijai minimizuoti intervale [a,b][a, b].
    1. Ar dvejetainei paieškai reikia išvestinių, t. y. nuspręsti, ar rinktis [a,(a+b)/2][a, (a+b)/2], ar [(a+b)/2,b][(a+b)/2, b].
    2. Kokia sparti yra algoritmo konvergavimo sparta?
    3. Įgyvendinkite algoritmą ir pritaikykite jį log⁡(exp⁡(x)+exp⁡(−2x−3))\log (\exp(x) + \exp(-2x -3)) minimizavimui.
  3. Suprojektuokite tikslo funkciją, apibrėžtą R2\mathbb{R}^2, kuriai gradientinis nusileidimas yra nepaprastai lėtas. Užuomina: skirtingas koordinates keiskite skirtingu masteliu.
  4. Įgyvendinkite lengvą Niutono metodo versiją naudodami pradinių sąlygų tikrinimą:
    1. Kaip pradinių sąlygų tikrinimą naudokite įstrižainės Hesės matricą.
    2. Naudokite jos absoliutines reikšmes, o ne tikrąsias (galbūt su ženklu) reikšmes.
    3. Pritaikykite tai aukščiau pateiktam uždaviniui.
  5. Pritaikykite aukščiau pateiktą algoritmą daugeliui tikslo funkcijų (iškiliųjų ar ne). Kas nutinka, jei pasukate koordinates 4545 laipsniais?

Diskusijos