Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Implementación de Retropropagación | Red Neuronal Desde Cero
Introducción a las Redes Neuronales

bookImplementación de Retropropagación

Enfoque general

En la propagación hacia adelante, cada capa ll toma las salidas de la capa anterior, al1a^{l-1}, como entradas y calcula sus propias salidas. Por lo tanto, el método forward() de la clase Layer toma el vector de salidas previas como su único parámetro, mientras que el resto de la información necesaria se almacena dentro de la clase.

En la propagación hacia atrás, cada capa ll solo necesita dalda^l para calcular los gradientes respectivos y devolver dal1da^{l-1}, por lo que el método backward() toma el vector dalda^l como parámetro. El resto de la información requerida ya está almacenada en la clase Layer.

Derivadas de funciones de activación

Dado que las derivadas de las funciones de activación son necesarias para la retropropagación, funciones de activación como ReLU y sigmoide deben estructurarse como clases en lugar de funciones independientes. Esto nos permite definir tanto:

  1. La propia función de activación (implementada mediante el método __call__()), permitiendo que se aplique directamente en la clase Layer usando self.activation(z);
  2. Su derivada (implementada mediante el método derivative()), lo que permite una retropropagación eficiente y se utiliza en la clase Layer como self.activation.derivative(z).

Al estructurar las funciones de activación como objetos, podemos pasarlas fácilmente a la clase Layer y usarlas de manera dinámica.

ReLu

La derivada de la función de activación ReLU es la siguiente, donde ziz_i es un elemento del vector de preactivaciones zz:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoide

La derivada de la función de activación sigmoide es la siguiente:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Para ambas funciones de activación, se aplican al vector completo zz, y lo mismo ocurre con sus derivadas. NumPy aplica internamente la operación a cada elemento del vector. Por ejemplo, si el vector zz contiene 3 elementos, la derivación es la siguiente:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

El método backward()

El método backward() se encarga de calcular los gradientes utilizando las siguientes fórmulas:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} y zlz^l se almacenan como los atributos inputs y outputs en la clase Layer, respectivamente. La función de activación ff se almacena como el atributo activation.

Una vez que se han calculado todos los gradientes necesarios, los pesos y sesgos pueden actualizarse ya que no se requieren para cálculos posteriores:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Por lo tanto, learning_rate (α\alpha) es otro parámetro de este método.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Nota

El operador * realiza una multiplicación elemento a elemento, mientras que la función np.dot() realiza el producto punto en NumPy. El atributo .T transpone un arreglo.

question mark

¿Cuál de las siguientes opciones describe mejor el papel del método backward() en la clase Layer durante la retropropagación?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 2. Capítulo 8

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

Suggested prompts:

Can you explain how the backward() method uses the stored attributes in the Layer class?

What is the purpose of the activation function's derivative in backpropagation?

Could you provide an example of how to use these activation function classes in a neural network layer?

Awesome!

Completion rate improved to 4

bookImplementación de Retropropagación

Desliza para mostrar el menú

Enfoque general

En la propagación hacia adelante, cada capa ll toma las salidas de la capa anterior, al1a^{l-1}, como entradas y calcula sus propias salidas. Por lo tanto, el método forward() de la clase Layer toma el vector de salidas previas como su único parámetro, mientras que el resto de la información necesaria se almacena dentro de la clase.

En la propagación hacia atrás, cada capa ll solo necesita dalda^l para calcular los gradientes respectivos y devolver dal1da^{l-1}, por lo que el método backward() toma el vector dalda^l como parámetro. El resto de la información requerida ya está almacenada en la clase Layer.

Derivadas de funciones de activación

Dado que las derivadas de las funciones de activación son necesarias para la retropropagación, funciones de activación como ReLU y sigmoide deben estructurarse como clases en lugar de funciones independientes. Esto nos permite definir tanto:

  1. La propia función de activación (implementada mediante el método __call__()), permitiendo que se aplique directamente en la clase Layer usando self.activation(z);
  2. Su derivada (implementada mediante el método derivative()), lo que permite una retropropagación eficiente y se utiliza en la clase Layer como self.activation.derivative(z).

Al estructurar las funciones de activación como objetos, podemos pasarlas fácilmente a la clase Layer y usarlas de manera dinámica.

ReLu

La derivada de la función de activación ReLU es la siguiente, donde ziz_i es un elemento del vector de preactivaciones zz:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoide

La derivada de la función de activación sigmoide es la siguiente:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Para ambas funciones de activación, se aplican al vector completo zz, y lo mismo ocurre con sus derivadas. NumPy aplica internamente la operación a cada elemento del vector. Por ejemplo, si el vector zz contiene 3 elementos, la derivación es la siguiente:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

El método backward()

El método backward() se encarga de calcular los gradientes utilizando las siguientes fórmulas:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} y zlz^l se almacenan como los atributos inputs y outputs en la clase Layer, respectivamente. La función de activación ff se almacena como el atributo activation.

Una vez que se han calculado todos los gradientes necesarios, los pesos y sesgos pueden actualizarse ya que no se requieren para cálculos posteriores:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Por lo tanto, learning_rate (α\alpha) es otro parámetro de este método.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Nota

El operador * realiza una multiplicación elemento a elemento, mientras que la función np.dot() realiza el producto punto en NumPy. El atributo .T transpone un arreglo.

question mark

¿Cuál de las siguientes opciones describe mejor el papel del método backward() en la clase Layer durante la retropropagación?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 2. Capítulo 8
some-alt