Font size
  • A-
  • A
  • A+
Site color
  • R
  • A
  • A
  • A
Skip to main content
AI4VET AI4VET
  • Home
  • Calendar
  • More
You are currently using guest access
Log in
AI4VET
Home Calendar
Expand all Collapse all
  1. AI/ML Fundamentals
  2. AIML-SK
  3. 3. Training Models (SK)
  4. Cvičenie 5.2: Gradientný zostup

Cvičenie 5.2: Gradientný zostup

Gradientný zostup

Open In Colab

Tento poznámkový blok sleduje obsah lekcie o prechodovom zostupe. V ňom môžete spustiť simuláciu gradientného zostupu a vyskúšať, čo sa stane s rôznymi nastaveniami rýchlosti učenia. Môžete experimentovať s hodnotami iných nastavení a lepšie pochopiť, ako tento algoritmus funguje.

Najprv načítajte knižnice, ktoré budú potrebné na ďalšiu prácu.

import numpy as np
from matplotlib import pyplot as plt
 

Intuícia gradientného zostupu

V nasledujúcich dvoch bunkách je definovaná funkcia \(f(x)=(x-1)^2\) a jej derivácia \(f'(x)=2x-2\). Vykonajte ich, aby ste mohli funkcie ďalej používať.

 def f(x):
  return (x-1)**2
 
f(3)
Out[3]:
4
 def f_izvod(x):
  return 2*x-2
 
f(1)
Out[5]:
0

Nasledujúca časť vám umožní sledovať, čo sa deje v jednotlivých krokoch stúpania.

V tejto bunke môžete nastaviť počiatočnú hodnotu bodu x0 a rýchlosť učenia alfa. Zakaždým, keď niečo zmeníte, spustite aj bunky nižšie.

 x0 = 3
alfa = 0.25
 

Body points budú obsahovať hodnoty získané jednotlivými krokmi zostupu. Budeme ich môcť zobraziť pomocou funkcie show_graph.

points = [x0]
 
def show_graph(f, iteration=0, show_transition=False):
  x = np.linspace(-4, 6, 100, endpoint=True)
  y = f(x)

  plt.xticks(np.arange(-4, 6), np.arange(-4, 6))
  plt.plot(x, y)

  for t in points:
    plt.scatter(t, f(t), color='red')

  if show_transition == True:
    num_points = len(points)
    for i in range(0, num_points-1):
      plt.plot([points[i], points[i+1]], [f(points[i]), f(points[i+1])], linestyle='--', color='gray')

  plt.title('Iteration number: {iteration}: '.format(iteration=iteration))
  plt.show()
 

Funkcia one_step_descent vypočíta hodnotu pre x, na ktorú sa presunieme v jednom kroku gradientného zostupu. Spustite bunku, aby ste ju mohli používať.

def one_step_descent(f, f_derivative, x, alpha):
  x_new = x - alpha * f_derivative(x)

  return x_new
 

Postupným vykonaním bunky nižšie môžete sledovať zostup smerom k minimu funkcie.

iteration = 1
 
# calculate the new point
x = one_step_descent(f, f_izvod, x0, alfa)

# add the point to the list of points
points.append(x)

# display the graph
show_graph(f, iteration, show_transition=False)

# increment the iteration number
iteration = iteration + 1

# set the position for the next descent
x0 = x
No description has been provided for this image 

Teraz sa môžete vrátiť na začiatok a vyskúšať nasledujúce hodnoty:

  • x0=3 a alfa=0.05 - bude to skúška trpezlivosti kvôli pomalému klesaniu!
  • x0=3 a alfa=1.05 - to bude prekvapenie, pretože v skutočnosti nie je žiadny kles!
  • x0=5 a alfa=0.9 - to vám ukáže, čo znamená kľukatá pasca!

V týchto experimentoch nezabudnite vo funkcii show_graphnastaviť argument show_transition na hodnotu True, aby ste mohli sledovať cestu bodu.

Algoritmus gradientného zostupu

Táto bunka obsahuje všetky nastavenia funkcie prechodového zostupu.

x0 = 3
alpha = 0.1
epsilon = 0.001
max_iterations = 100
 

Táto bunka obsahuje implementáciu funkcie gradientného zostupu. Keď ho vykonáte, budete môcť okamžite vidieť, pre ktoré x je hodnota funkcie najmenšia. Nezabudnite preskúmať, ako sa mení výsledok pre rôzne nastavenia tohto algoritmu. Napríklad pri niektorých kombináciách učebných krokov a východiskových bodov bude zostup veľmi pomalý.

 def gradient_descent(f, f_derivative, x, alpha, epsilon, max_iterations):

    # set the initial value for x
    x_old = x

    # in each iteration ...
    for i in range(0, max_iterations):

        # calculate the current value for x
        x_new = x_old - alpha * f_derivative(x_old)

        # and then check if the stopping criterion is met
        if np.abs(f(x_new) - f(x_old)) < epsilon:
            break

        # if the criterion is not met, prepare x for the next iteration
        x_old = x_new

    # at the end of the whole process, prepare a report with information:
    # whether the algorithm stops,
    # how many iterations it lasted,
    # and what value of x was found
    report = {}
    report['stops'] = i != max_iterations
    report['num_iterations'] = i
    report['x_min'] = x_old

    return report
 
 

Správa o funkcii nám hovorí, či sa algoritmus zastavil (t. j. či sa dosiahla požadovaná presnosť výpočtu), koľko iterácií trval a v akom bode je hodnota funkcie najmenšia. Vykonajte nasledujúce bunky na vygenerovanie zostavy.

report = gradient_descent(f, f_izvod, x0, alfa, epsilon, max_iterations)
 
report
Out[15]:
{'stops': True, 'num_iterations': 6, 'x_min': 1.03125} 

Vyhľadajte parametre β0 a β1

Vyhľadajte parametre \( \beta_0 \) a \(\beta_1\) 

Ako sme sa dozvedeli, pre danú množinu bodov \((x, y)\) sa stredná druhá mocnina chyby vypočíta ako súčet štvorcov rozdielov medzi očakávanými hodnotami a predikciami modelu pomocou vzorca \(\frac{1}{N}\sum_{i=1}^N (y_i - (\beta_0 + \beta_1x_i))^2\) alebo \(\frac{1}{N} \sum_{i=1}^N (y_i -\beta_0 - \beta_1x_i)^2\). Naším cieľom je určiť hodnoty parametrov \(\beta_0\) a \(\beta_1\), pre ktoré je hodnota tejto funkcie najmenšia. Je zrejmé, že funkcia \(\frac{1}{2N} \sum_{i=1}^N (y_i -\beta_0 - \beta_1x_i)^2\) bude mať pre tieto parametre najmenšiu hodnotu, takže jej forma sa oveľa častejšie používa kvôli jemnejším tvarom gradientu. Preto ho použijeme v pokračovaní.

Podľa tohto vzorca funkcia mean_squared_error pre dané argumenty \(\beta_0\), \(\beta_1\), \(x\) a \(y\) vypočíta hodnotu strednej druhej štvorcovej chyby. Toto je tiež funkcia, pre ktorú chceme nájsť minimum pomocou techniky gradientného zostupu.

 def mean_squared_error(beta0, beta1, x, y):
    return 0.5 * np.average((y - beta0 - beta1 * x) ** 2)

Minimalizácia chýb by sa mala vykonať s ohľadom na parametre \(\beta_0\) a \(\beta_1\). Preto budeme potrebovať aj gradienty tejto funkcie vzhľadom na \(\beta_0\) a \(\beta_1\). Dá sa overiť, že ide o vektor \([-\frac{1}{N} \sum_{i=1}^{N}(y_i - \beta_0-\beta_1x_i), -\frac{1}{N} \sum_{i=1}^{N}(y_i - \beta_0 -\beta_1x_i)\cdot x_i]\). Ak prejdeme súčtom s mínusom pre jednoduchší výpočet, dostaneme vektor \([\frac{1}{N} \sum_{i=1}^{N}(\beta_0 + \beta_1x_i - y_i), \frac{1}{N} \sum_{i=1}^{N}(\beta_0 + \beta_1x_i - y_i)\cdot x_i]\).

Teraz sa pustíme do práce na prispôsobení funkcie gradientného zostupu pre úlohu lineárnej regresie. Musíme mať na pamäti, že máme dve premenné beta0a beta1 a že funkcia, ktorej minimum hľadáme, je stredná štvorcová chyba.

 def gradient_descent_linear_regression(x, y, mean_squared_error, beta0, beta1, alpha, epsilon, max_iterations, plot=False):

    # set the initial value for beta0 and beta1
    beta0_old = beta0
    beta1_old = beta1

    # calculate the initial value of the error function
    error_old = mean_squared_error(beta0_old, beta1_old, x, y)

    # to be able to track how the value of the error function changes
    # we will store all calculated values in the errors array
    errors = [error_old]

    # in each iteration ...
    for i in np.arange(0, max_iterations):

        # calculate the current value for beta0 and beta1 by:

        # first calculate the gradient directions
        beta0_correction = np.average(beta0_old + beta1_old * x - y)
        beta1_correction = np.average((beta0_old + beta1_old * x - y) * x)

        # and then update the values for beta0 and beta1
        beta0_new = beta0_old - alpha * beta0_correction
        beta1_new = beta1_old - alpha * beta1_correction

        # for these calculated values, calculate the value
        # of the mean squared error
        error_new = mean_squared_error(beta0_new, beta1_new, x, y)

        # and then check if the stopping criterion is met
        if np.abs(error_new - error_old) < epsilon:
            break

        # alternatively, the stopping criterion can be that
        # the value of the gradient is less than some predefined value
        # if np.linalg.norm(np.array([beta0_correction, beta1_correction])) < epsilon:
        #   break

        # if the criterion is not met, prepare beta0 and beta1 for the next iteration
        beta0_old = beta0_new
        beta1_old = beta1_new

        # prepare the value of the error function
        error_old = error_new

        # and add it to the array with all errors
        errors.append(error_new)

    # at the end of the whole process, prepare a report with information:
    # whether the algorithm stops,
    # how many iterations it lasted,
    # and what value of beta0 and beta1 was found

    report = {}

    report['stops'] = i != max_iterations - 1
    report['num_iterations'] = i
    report['b_min'] = (beta0_old, beta1_old)

    # if the plot argument is set
    # we will also plot the error function during the parameter search
    if plot == True:
        plt.title('Error Function')
        plt.xlabel('Number of iterations')
        plt.ylabel('Mean Squared Error')
        plt.plot(np.arange(0, len(errors)), np.log(errors))

    return report
 

Teraz nastavíme hodnoty pre x a y tak, aby zodpovedali hodnotám oblastí nehnuteľností a ich cenám z predchádzajúceho príkladu.

x = np.array([43, 25, 66, 80, 105, 70, 40, 85, 84, 102])
y = np.array([60, 32.1, 88.4, 111.4, 120.32, 72.1, 46.3, 90.1, 99.6, 139.2])
 

Vyberieme tiež niektoré počiatočné hodnoty pre parametre, ktoré figurujú v algoritme. Teraz je táto úloha oveľa ťažšia, pretože nemáme jasnú predstavu o tom, kam sa umiestniť alebo aké hodnoty parametrov zvoliť.

 
beta0 = 2.5
beta1 = 1.5
alpha = 0.00001
epsilon = 0.000001
max_iterations = 200
 

Potom začneme vyhľadávanie volaním funkcie, ktorú sme pripravili.

gradient_descent_linear_regression(x, y, mean_squared_error, beta0, beta1, alpha, epsilon, max_iterations, plot=False)
 
{'stops': np.True_,
 'num_iterations': np.int64(151),
 'b_min': (np.float64(2.4960466912761294), np.float64(1.1930132064518595))}

Nezabudnite vyskúšať, čo sa stane, keď zmeníte niektoré hodnoty. Opäť môžete očakávať pomalý klesanie, kľukatú pascu alebo proces, ktorý vás neprivedie k riešeniu.

 

V praxi sa častejšie používajú varianty gradientného zostupu s variabilnou rýchlosťou učenia. Tieto varianty sa riadia logikou, že keď sme si istí, že sa pohybujeme správnym smerom, môžeme robiť väčšie kroky, zatiaľ čo keď sme menej sebavedomí, môžeme robiť menšie kroky a byť opatrnejší. Bežnou praxou je tiež použitie techník štandardizácie údajov v týchto algoritmoch, aby bol celý proces numericky stabilnejší.

 
 
Completion requirements:
  • Make a submission
Previous activity Cvičenie 5.1: Lineárna regresia
Next activity Cvičenie 6: Logistická regresia
You are currently using guest access (Log in)
Data retention summary
Get the mobile app
Get the mobile app
Play Store App Store
Powered by Moodle

This theme was proudly developed by

Conecti.me