Gradient Descent en Python: implementaci贸n y teor铆a

    Introducci贸n

    Este tutorial es una introducci贸n a una t茅cnica de optimizaci贸n simple llamada descenso de gradiente, que ha tenido una aplicaci贸n importante en modelos de Machine Learning de 煤ltima generaci贸n.

    Desarrollaremos una rutina de prop贸sito general para implementar el descenso de gradientes y aplicarlo para resolver diferentes problemas, incluida la clasificaci贸n a trav茅s del aprendizaje supervisado.

    En este proceso, obtendremos una idea del funcionamiento de este algoritmo y estudiaremos el efecto de varios hiperpar谩metros en su rendimiento. Tambi茅n repasaremos variantes de descenso de gradiente estoc谩stico y por lotes como ejemplos.

    驴Qu茅 es Gradient Descent?

    El descenso de gradientes es una t茅cnica de optimizaci贸n que puede encontrar el m铆nimo de un funci贸n objetiva. Es una t茅cnica codiciosa que encuentra la soluci贸n 贸ptima dando un paso en la direcci贸n de la tasa m谩xima de disminuci贸n de la funci贸n.

    Por el contrario, Gradient Ascent es una contraparte cercana que encuentra el m谩ximo de una funci贸n siguiendo la direcci贸n de la tasa m谩xima de aumento de la funci贸n.

    Para comprender c贸mo funciona el descenso de gradientes, considere una funci贸n de m煤ltiples variables (f ( textbf {w}) ), donde ( textbf w = [w_1, w_2, ldots, w_n]^ T ). Para encontrar el ( textbf {w} ) en el que esta funci贸n alcanza un m铆nimo, el descenso de gradiente utiliza los siguientes pasos:

    • Elija un valor aleatorio inicial de ( textbf {w} )
    • Elija el n煤mero m谩ximo de iteraciones T
    • Elija un valor para el tasa de aprendizaje ( eta en [a,b] )
    • Repita los siguientes dos pasos hasta que (f ) no cambie o las iteraciones excedan T

      a.C谩lculo: ( Delta textbf {w} = – eta nabla_ textbf {w} f ( textbf {w}) )

      segundo. actualizar ( textbf {w} ) como: ( textbf {w} leftarrow textbf {w} + Delta textbf {w} )

      El s铆mbolo de la flecha izquierda es una forma matem谩ticamente correcta de escribir una declaraci贸n de asignaci贸n.

    Aqu铆 ( nabla_ textbf {w} f ) denota el gradiente de (f ) dado por:
    $$
    nabla_ textbf {w} f ( textbf {w}) =
    begin {bmatrix}
    frac { parcial f ( textbf {w})} { parcial w_1}
    frac { parcial f ( textbf {w})} { parcial w_2}
    vdots
    frac { parcial f ( textbf {w})} { parcial w_n}
    end {bmatrix}
    $$

    Considere una funci贸n de ejemplo de dos variables (f (w_1, w_2) = w_1 ^ 2 + w_2 ^ 2 ), luego en cada iteraci贸n ((w_1, w_2) ) se actualiza como:

    $$
    begin {bmatrix}
    w_1 w_2
    end {bmatrix} leftarrow
    begin {bmatrix}
    w_1 w_2
    end {bmatrix} – eta
    begin {bmatrix}
    2w_1 2w_2
    end {bmatrix}
    $$

    La siguiente figura muestra c贸mo funciona el descenso de gradientes en esta funci贸n.

    Los c铆rculos son los contornos de esta funci贸n. Si nos movemos a lo largo de un contorno, el valor de la funci贸n no cambiar铆a y seguir铆a siendo un constante.

    Esto se opone a la direcci贸n del gradiente, donde la funci贸n cambia a una velocidad m谩xima. Por lo tanto, la direcci贸n del gradiente de la funci贸n en cualquier punto es normal a la tangente del contorno en ese punto.

    En t茅rminos simples, el gradiente se puede tomar como una flecha que apunta en la direcci贸n donde la funci贸n cambia m谩s.

    Seguir la direcci贸n del gradiente negativo conducir铆a a puntos donde el valor de la funci贸n disminuye a una velocidad m谩xima. los tasa de aprendizaje, tambi茅n llamado el Numero de pie, dicta qu茅 tan r谩pido o lento nos movemos a lo largo de la direcci贸n del gradiente.

    A帽adiendo impulso

    Cuando usamos el descenso de gradientes, nos encontramos con los siguientes problemas:

    • Quedar atrapado en un m铆nimo local, que es una consecuencia directa de que este algoritmo sea codicioso
    • Sobrepasar y perder el 贸ptimo global, esto es un resultado directo de moverse demasiado r谩pido a lo largo de la direcci贸n del gradiente
    • Oscilaci贸n, este es un fen贸meno que ocurre cuando el valor de la funci贸n no cambia significativamente sin importar la direcci贸n en la que avanza. Puedes pensar en ello como navegar por una meseta, est谩s a la misma altura sin importar a d贸nde vayas

    Para combatir estos problemas, se agrega un t茅rmino de impulso ( alpha ) a la expresi贸n para ( Delta textbf {w} ) para estabilizar la tasa de aprendizaje cuando se avanza hacia el valor 贸ptimo global.

    A continuaci贸n, usamos el super铆ndice (i ) para denotar el n煤mero de iteraci贸n:
    $$
    Delta textbf {w} ^ i = – eta nabla_ textbf {w} f ( textbf {w} ^ i) + alpha textbf {w} ^ {i-1}
    $$

    Implementando Gradient Descent en Python

    Antes de comenzar a escribir el c贸digo real para el descenso de gradientes, importemos algunas bibliotecas que utilizaremos para ayudarnos:

    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt
    import sklearn.datasets as dt
    from sklearn.model_selection import train_test_split
    

    Ahora, con eso fuera del camino, sigamos adelante y definamos un gradient_descent() funci贸n. En esta funci贸n, el ciclo termina cuando:

    • El n煤mero de iteraciones supera un valor m谩ximo
    • La diferencia en los valores de la funci贸n entre dos iteraciones sucesivas cae por debajo de un cierto umbral

    Los par谩metros se actualizan en cada iteraci贸n de acuerdo con el gradiente de la funci贸n objetivo.

    La funci贸n aceptar谩 los siguientes par谩metros:

    • max_iterations: N煤mero m谩ximo de iteraciones para ejecutar
    • threshold: Det茅ngase si la diferencia en los valores de la funci贸n entre dos iteraciones sucesivas cae por debajo de este umbral
    • w_init: Punto inicial desde donde comenzar el descenso de gradiente
    • obj_func: Referencia a la funci贸n que calcula la funci贸n objetivo
    • grad_func: Referencia a la funci贸n que calcula el gradiente de la funci贸n
    • extra_param: Par谩metros adicionales (si es necesario) para obj_func y grad_func
    • learning_rate: Tama帽o de paso para descenso en pendiente. Deber铆a estar en [0,1]
    • momentum: Momentum para usar. Deber铆a estar en [0,1]

    Adem谩s, la funci贸n devolver谩:

    • w_history: Todos los puntos en el espacio, visitados por descenso de gradiente en los que se evalu贸 la funci贸n objetivo
    • f_history: Valor correspondiente de la funci贸n objetivo calculada en cada punto
    # Make threshold a -ve value if you want to run exactly
    # max_iterations.
    def gradient_descent(max_iterations,threshold,w_init,
                         obj_func,grad_func,extra_param = [],
                         learning_rate=0.05,momentum=0.8):
        
        w = w_init
        w_history = w
        f_history = obj_func(w,extra_param)
        delta_w = np.zeros(w.shape)
        i = 0
        diff = 1.0e10
        
        while  i<max_iterations and diff>threshold:
            delta_w = -learning_rate*grad_func(w,extra_param) + momentum*delta_w
            w = w+delta_w
            
            # store the history of w and f
            w_history = np.vstack((w_history,w))
            f_history = np.vstack((f_history,obj_func(w,extra_param)))
            
            # update iteration number and diff between successive values
            # of objective function
            i+=1
            diff = np.absolute(f_history[-1]-f_history[-2])
        
        return w_history,f_history
    

    Optimizaci贸n de funciones con pendiente descendente

    Ahora que tenemos una implementaci贸n de prop贸sito general del descenso de gradiente, ejecut茅mosla en nuestra funci贸n 2D de ejemplo (f (w_1, w_2) = w_1 ^ 2 + w_2 ^ 2 ) con contornos circulares.

    La funci贸n tiene un valor m铆nimo de cero en el origen. Primero visualicemos la funci贸n y luego encontremos su valor m铆nimo.

    Visualizaci贸n de la funci贸n objetivo f (x)

    los visualize_fw() funci贸n a continuaci贸n, genera 2500 puntos igualmente espaciados en una cuadr铆cula y calcula el valor de la funci贸n en cada punto.

    los function_plot() La funci贸n muestra todos los puntos en diferentes colores, dependiendo del valor de (f ( textbf w) ) en ese punto. Todos los puntos en los que el valor de la funci贸n es el mismo, tienen el mismo color:

    def visualize_fw():
        xcoord = np.linspace(-10.0,10.0,50)
        ycoord = np.linspace(-10.0,10.0,50)
        w1,w2 = np.meshgrid(xcoord,ycoord)
        pts = np.vstack((w1.flatten(),w2.flatten()))
        
        # All 2D points on the grid
        pts = pts.transpose()
        
        # Function value at each point
        f_vals = np.sum(pts*pts,axis=1)
        function_plot(pts,f_vals)
        plt.title('Objective Function Shown in Color')
        plt.show()
        return pts,f_vals
    
    # Helper function to annotate a single point
    def annotate_pt(text,xy,xytext,color):
        plt.plot(xy[0],xy[1],marker="P",markersize=10,c=color)
        plt.annotate(text,xy=xy,xytext=xytext,
                     # color=color,
                     arrowprops=dict(arrowstyle="->",
                     color = color,
                     connectionstyle="arc3"))
    
    # Plot the function
    # Pts are 2D points and f_val is the corresponding function value
    def function_plot(pts,f_val):
        f_plot = plt.scatter(pts[:,0],pts[:,1],
                             c=f_val,vmin=min(f_val),vmax=max(f_val),
                             cmap='RdBu_r')
        plt.colorbar(f_plot)
        # Show the optimal point
        annotate_pt('global minimum',(0,0),(-5,-7),'yellow')    
    
    pts,f_vals = visualize_fw()
    

    Ejecuci贸n de Gradient Descent con diferentes hiperpar谩metros

    Ahora es el momento de ejecutar el descenso de gradiente para minimizar nuestra funci贸n objetivo. Llamar gradient_descent(), definimos dos funciones:

    • f(): Calcula la funci贸n objetivo en cualquier punto w
    • grad(): Calcula el gradiente en cualquier punto w

    Para comprender el efecto de varios hiperpar谩metros en el descenso de gradientes, la funci贸n solve_fw() llamadas gradient_descent() con 5 iteraciones para diferentes valores de velocidad e impulso de aprendizaje.

    La funci贸n visualize_learning(), traza los valores de ((w_1, w_2) ), con los valores de la funci贸n mostrados en diferentes colores. Las flechas en el gr谩fico facilitan el seguimiento de qu茅 punto se actualiz贸 desde el 煤ltimo:

    # Objective function
    def f(w,extra=[]):
        return np.sum(w*w)
    
    # Function to compute the gradient
    def grad(w,extra=[]):
        return 2*w
    
    # Function to plot the objective function
    # and learning history annotated by arrows
    # to show how learning proceeded
    def visualize_learning(w_history):  
        
        # Make the function plot
        function_plot(pts,f_vals)
        
        # Plot the history
        plt.plot(w_history[:,0],w_history[:,1],marker="o",c="magenta") 
        
        # Annotate the point found at last iteration
        annotate_pt('minimum found',
                    (w_history[-1,0],w_history[-1,1]),
                    (-1,7),'green')
        iter = w_history.shape[0]
        for w,i in zip(w_history,range(iter-1)):
            # Annotate with arrows to show history
            plt.annotate("",
                        xy=w, xycoords="data",
                        xytext=w_history[i+1,:], textcoords="data",
                        arrowprops=dict(arrowstyle="<-",
                                connectionstyle="angle3"))     
        
    def solve_fw():
        # Setting up
        rand = np.random.RandomState(19)
        w_init = rand.uniform(-10,10,2)
        fig, ax = plt.subplots(nrows=4, ncols=4, figsize=(18, 12))
        learning_rates = [0.05,0.2,0.5,0.8]
        momentum = [0,0.5,0.9]
        ind = 1
        
        # Iteration through all possible parameter combinations
        for alpha in momentum:
            for eta,col in zip(learning_rates,[0,1,2,3]):
                plt.subplot(3,4,ind)        
                w_history,f_history = gradient_descent(5,-1,w_init, f,grad,[],eta,alpha)
                
                visualize_learning(w_history)
                ind = ind+1
                plt.text(-9, 12,'Learning Rate="+str(eta),fontsize=13)
                if col==1:
                    plt.text(10,15,"momentum = ' + str(alpha),fontsize=20)
    
        fig.subplots_adjust(hspace=0.5, wspace=.3)
        plt.show()
    

    Corramos solve_fw() y vea c贸mo la tasa de aprendizaje y el impulso afectan el descenso del gradiente:

    solve_fw()
    

    Este ejemplo aclara el papel tanto del impulso como de la tasa de aprendizaje.

    En la primera gr谩fica, con impulso cero y tasa de aprendizaje establecida en 0.05, el aprendizaje es lento y el algoritmo no alcanza el m铆nimo global. Aumentar el impulso acelera el aprendizaje, como podemos ver en los gr谩ficos de la primera columna. El otro extremo es la 煤ltima columna, donde la tasa de aprendizaje se mantiene alta. Esto provoca oscilaciones, que pueden controlarse hasta cierto punto a帽adiendo impulso.

    La pauta general para el descenso de gradientes es utilizar valores peque帽os de tasa de aprendizaje y valores m谩s altos de impulso.

    Descenso de gradiente para minimizar el error cuadr谩tico medio

    El descenso de gradientes es una t茅cnica sencilla y agradable para minimizar el error cuadr谩tico medio en un problema de regresi贸n o clasificaci贸n supervisada.

    Supongamos que se nos dan (m ) ejemplos de entrenamiento ([x_{ij}]) con (i = 1 ldots m ), donde cada ejemplo tiene (n ) caracter铆sticas, es decir, (j = 1 ldots n ). Si los valores objetivo y de salida correspondientes para cada ejemplo son (t_i ) y (o_i ) respectivamente, entonces la funci贸n de error cuadr谩tico medio (E ) (en este caso nuestra funci贸n de objeto) se define como:

    $$
    E = frac {1} {m} Sigma_ {i = 1} ^ m (t_i – o_i) ^ 2
    $$

    Donde la salida (o_i ) est谩 determinada por una combinaci贸n lineal ponderada de entradas, dada por:

    $$
    o_i = w_0 + w_1 x_ {i1} + w_2 x_ {i2} + ldots + w_n x_ {in}
    $$

    El par谩metro desconocido en la ecuaci贸n anterior es el vector de peso ( textbf w = [w_0,w_1,ldots,w_n]^ T ).

    La funci贸n objetivo en este caso es el error cuadr谩tico medio con un gradiente dado por:

    $$
    nabla _ { textbf w} E ( textbf w) = – Sigma_ {i = 1} ^ {m} (t_i – o_i) textbf {x} _i
    $$

    Donde (x_ {i} ) es el i-茅simo ejemplo. o una serie de caracter铆sticas de tama帽o n.

    Todo lo que necesitamos ahora es una funci贸n para calcular el gradiente y una funci贸n para calcular el error cuadr谩tico medio.

    los gradient_descent() La funci贸n se puede utilizar tal cual. Tenga en cuenta que todos los ejemplos de entrenamiento se procesan juntos al calcular el gradiente. Por lo tanto, esta versi贸n de descenso de gradiente para actualizar pesos se conoce como actualizaci贸n por lotes o aprendizaje por lotes:

    # Input argument is weight and a tuple (train_data, target)
    def grad_mse(w,xy):
        (x,y) = xy
        (rows,cols) = x.shape
        
        # Compute the output
        o = np.sum(x*w,axis=1)
        diff = y-o
        diff = diff.reshape((rows,1))    
        diff = np.tile(diff, (1, cols))
        grad = diff*x
        grad = -np.sum(grad,axis=0)
        return grad
    
    # Input argument is weight and a tuple (train_data, target)
    def mse(w,xy):
        (x,y) = xy
        
        # Compute output
        # keep in mind that wer're using mse and not mse/m
        # because it would be relevant to the end result
        o = np.sum(x*w,axis=1)
        mse = np.sum((y-o)*(y-o))
        mse = mse/2
        return mse    
    

    Ejecuci贸n de Gradient Descent en OCR

    Para ilustrar el descenso de gradiente en un problema de clasificaci贸n, hemos elegido los conjuntos de datos de d铆gitos incluidos en sklearn.datasets.

    Para simplificar las cosas, hagamos una prueba de descenso de gradiente en un problema de dos clases (d铆gito 0 frente a d铆gito 1). El siguiente c贸digo carga los d铆gitos y muestra los primeros 10 d铆gitos. Esto nos da una idea de la naturaleza de los puntos de entrenamiento:

    # Load the digits dataset with two classes
    digits,target = dt.load_digits(n_class=2,return_X_y=True)
    fig,ax = plt.subplots(nrows=1, ncols=10,figsize=(12,4),subplot_kw=dict(xticks=[], yticks=[]))
    
    # Plot some images of digits
    for i in np.arange(10):
        ax[i].imshow(digits[i,:].reshape(8,8),cmap=plt.cm.gray)   
    plt.show()
    

    Tambi茅n necesitamos el m茅todo train_test_split desde sklearn.model_selection para dividir los datos de entrenamiento en un tren y un conjunto de prueba. El siguiente c贸digo ejecuta el descenso de gradiente en el conjunto de entrenamiento, aprende los pesos y traza el error cuadr谩tico medio en diferentes iteraciones.

    Al ejecutar el descenso de gradiente, mantendremos la velocidad de aprendizaje y el impulso muy peque帽os, ya que las entradas no est谩n normalizadas ni estandarizadas. Adem谩s, la versi贸n por lotes del descenso de gradientes requiere una tasa de aprendizaje menor:

    # Split into train and test set
    x_train, x_test, y_train, y_test = train_test_split(
                            digits, target, test_size=0.2, random_state=10)
    
    # Add a column of ones to account for bias in train and test
    x_train = np.hstack((np.ones((y_train.size,1)),x_train))
    x_test  = np.hstack((np.ones((y_test.size,1)),x_test))
    
    # Initialize the weights and call gradient descent
    rand = np.random.RandomState(19)
    w_init = rand.uniform(-1,1,x_train.shape[1])*.000001
    w_history,mse_history = gradient_descent(100,0.1,w_init,
                                  mse,grad_mse,(x_train,y_train),
                                 learning_rate=1e-6,momentum=0.7)
    
    # Plot the MSE
    plt.plot(np.arange(mse_history.size),mse_history)
    plt.xlabel('Iteration No.')
    plt.ylabel('Mean Square Error')
    plt.title('Gradient Descent on Digits Data (Batch Version)')
    plt.show()
    

    隆Esto luce genial! Comprobemos la tasa de error de nuestro OCR en los datos de entrenamiento y prueba. A continuaci贸n se muestra una peque帽a funci贸n para calcular la tasa de error de clasificaci贸n, que se llama en el conjunto de entrenamiento y prueba:

    # Returns error rate of classifier
    # total miclassifications/total*100
    def error(w,xy):
        (x,y) = xy
        o = np.sum(x*w,axis=1)
        
        #map the output values to 0/1 class labels
        ind_1 = np.where(o>0.5)
        ind_0 = np.where(o<=0.5)
        o[ind_1] = 1
        o[ind_0] = 0
        return np.sum((o-y)*(o-y))/y.size*100
        
    train_error = error(w_history[-1],(x_train,y_train))
    test_error = error(w_history[-1],(x_test,y_test))
    
    print("Train Error Rate: " + "{:.2f}".format(train_error))
    print("Test Error Rate: " + "{:.2f}".format(test_error))
    
    Train Error Rate: 0.69
    Test Error Rate: 1.39
    

    Descenso de gradiente estoc谩stico en Python

    En la secci贸n anterior, usamos el esquema de actualizaci贸n por lotes para el descenso de gradientes.

    Otra versi贸n del descenso de gradientes es el en l铆nea o estoc谩stico esquema de actualizaci贸n, donde cada ejemplo de entrenamiento se toma uno a la vez para actualizar los pesos.

    Una vez que se completan todos los ejemplos de entrenamiento, decimos que se completa una 茅poca. Los ejemplos de entrenamiento se barajan antes de cada 茅poca para obtener mejores resultados.

    El siguiente fragmento de c贸digo es una peque帽a modificaci贸n del gradient_descent() funci贸n para incorporar su contraparte estoc谩stica. Esta funci贸n toma el (conjunto de entrenamiento, objetivo) como par谩metro en lugar del par谩metro adicional. El t茅rmino ‘iteraciones’ ha sido renombrado a ‘茅pocas’:

    # (xy) is the (training_set,target) pair
    def stochastic_gradient_descent(max_epochs,threshold,w_init,
                                    obj_func,grad_func,xy,
                                    learning_rate=0.05,momentum=0.8):
        (x_train,y_train) = xy
        w = w_init
        w_history = w
        f_history = obj_func(w,xy)
        delta_w = np.zeros(w.shape)
        i = 0
        diff = 1.0e10
        rows = x_train.shape[0]
        
        # Run epochs
        while  i<max_epochs and diff>threshold:
            # Shuffle rows using a fixed seed to reproduce the results
            np.random.seed(i)
            p = np.random.permutation(rows)
            
            # Run for each instance/example in training set
            for x,y in zip(x_train[p,:],y_train[p]):
                delta_w = -learning_rate*grad_func(w,(np.array([x]),y)) + momentum*delta_w
                w = w+delta_w
                
            i+=1
            w_history = np.vstack((w_history,w))
            f_history = np.vstack((f_history,obj_func(w,xy)))
            diff = np.absolute(f_history[-1]-f_history[-2])
            
        return w_history,f_history
    

    Ejecutemos el c贸digo para ver c贸mo son los resultados para la versi贸n estoc谩stica del descenso de gradiente:

    rand = np.random.RandomState(19)
    w_init = rand.uniform(-1,1,x_train.shape[1])*.000001
    w_history_stoch,mse_history_stoch = stochastic_gradient_descent(
                                    100,0.1,w_init,
                                  mse,grad_mse,(x_train,y_train),
                                 learning_rate=1e-6,momentum=0.7)
    
    # Plot the MSE
    plt.plot(np.arange(mse_history_stoch.size),mse_history_stoch)
    plt.xlabel('Iteration No.')
    plt.ylabel('Mean Square Error')
    plt.title('Gradient Descent on Digits Data (Stochastic Version)')
    
    plt.show()
    

    Revisemos tambi茅n la tasa de error:

    train_error_stochastic = error(w_history_stoch[-1],(x_train,y_train))
    test_error_stochastic = error(w_history_stoch[-1],(x_test,y_test))
    
    print("Train Error rate with Stochastic Gradient Descent: " + 
          "{:.2f}".format(train_error_stochastic))
    print("Test Error rate with Stochastic Gradient Descent: "  
          + "{:.2f}".format(test_error_stochastic))
    
    Train Error rate with Stochastic Gradient Descent: 0.35
    Test Error rate with Stochastic Gradient Descent: 1.39
    

    Comparaci贸n de versiones por lotes y estoc谩sticas

    Comparemos ahora las versiones por lotes y estoc谩sticas del descenso de gradiente.

    Fijaremos la tasa de aprendizaje para ambas versiones en el mismo valor y variaremos el impulso para ver qu茅 tan r谩pido convergen ambas. Los pesos iniciales y los criterios de detenci贸n para ambos algoritmos siguen siendo los mismos:

    fig, ax = plt.subplots(nrows=3, ncols=1, figsize=(10,3))
    
    rand = np.random.RandomState(11)
    w_init = rand.uniform(-1,1,x_train.shape[1])*.000001
    eta = 1e-6
    for alpha,ind in zip([0,0.5,0.9],[1,2,3]):
    	w_history,mse_history = gradient_descent(
                                    100,0.01,w_init,
                                  mse,grad_mse,(x_train,y_train),
                                 learning_rate=eta,momentum=alpha)
    
        w_history_stoch,mse_history_stoch = stochastic_gradient_descent(
                                    100,0.01,w_init,
                                  mse,grad_mse,(x_train,y_train),
                                 learning_rate=eta,momentum=alpha)
        
        # Plot the MSE
        plt.subplot(130+ind)
        plt.plot(np.arange(mse_history.size),mse_history,color="green")
        plt.plot(np.arange(mse_history_stoch.size),mse_history_stoch,color="blue")
        plt.legend(['batch','stochastic'])
        
        # Display total iterations
        plt.text(3,-30,'Batch: Iterations="+
                 str(mse_history.size) )
        plt.text(3,-45,"Stochastic: Iterations="+
                 str(mse_history_stoch.size))
        plt.title("Momentum = ' + str(alpha))   
        
        # Display the error rates
        train_error = error(w_history[-1],(x_train,y_train))
        test_error = error(w_history[-1],(x_test,y_test))
        
        train_error_stochastic = error(w_history_stoch[-1],(x_train,y_train))
        test_error_stochastic = error(w_history_stoch[-1],(x_test,y_test))
        
        print ('Momentum = '+str(alpha))
        
        print ('tBatch:')
        print ('ttTrain error: ' + "{:.2f}".format(train_error) )
        print ('ttTest error: ' + "{:.2f}".format(test_error) )
        
        print ('tStochastic:')
        print ('ttTrain error: ' + "{:.2f}".format(train_error_stochastic) )
        print ('ttTest error: ' + "{:.2f}".format(test_error_stochastic) )
        
            
    plt.show()
    
    Momentum = 0
    	Batch:
    		Train error: 0.35
    		Test error: 1.39
    	Stochastic:
    		Train error: 0.35
    		Test error: 1.39
    Momentum = 0.5
    	Batch:
    		Train error: 0.00
    		Test error: 1.39
    	Stochastic:
    		Train error: 0.35
    		Test error: 1.39
    Momentum = 0.9
    	Batch:
    		Train error: 0.00
    		Test error: 1.39
    	Stochastic:
    		Train error: 0.00
    		Test error: 1.39
    

    Si bien no hay una diferencia significativa en la precisi贸n entre las dos versiones del clasificador, la versi贸n estoc谩stica es un claro ganador cuando se trata de la velocidad de convergencia. Se necesitan menos iteraciones para lograr el mismo resultado que su contraparte por lotes.

    Conclusiones

    El descenso de gradientes es una t茅cnica simple y f谩cil de implementar.

    En este tutorial, ilustramos el descenso de gradientes en funci贸n de dos variables con contornos circulares. Luego ampliamos nuestro ejemplo para minimizar el error cuadr谩tico medio en un problema de clasificaci贸n y construimos un sistema OCR simple. Tambi茅n discutimos la versi贸n estoc谩stica del descenso de gradiente.

    En este tutorial se desarroll贸 una funci贸n de prop贸sito general para implementar el descenso de gradientes. Animamos a los lectores a utilizar esta funci贸n en diferentes problemas de regresi贸n y clasificaci贸n, con distintos hiperpar谩metros, para una mejor comprensi贸n de su funcionamiento.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *