Gradientes de las capas ocultas

Esquema de la red

Para calcular la derivada parcial de la función de coste con respecto a los parámetros de las capas ocultas no tenemos más que "jugar" con las derivadas parciales y la regla de la cadena. Para empezar, obtengamos la relación entre del "delta" de una capa n-1 (δn-1) y el "delta" de la capa n (δn), siendo "delta" la derivada parcial de la función de coste con respecto a los valores z de una capa:

Relación entre el delta de la capa n-1 y el delta de la capa n

Recordemos que las capas se numeran de izquierda a derecha, lo que significa que la capa n queda a la derecha de la capa n-1.

La derivada de z con respecto al valor a es igual al peso del enlace del que se trate, y la derivada de a con respecto a z es igual a la derivada de la función de activación. Es decir:

Relación entre el delta de la capa n-1 y el delta de la capa n

Y una vez obtenido el valor de delta para la capa n-1, podemos calcular las derivadas parciales de la función de coste con respecto a un bias o a un peso de dicha capa tal y como hemos hecho para la capa de salida. Concretamente, para una capa dada consideramos los valores z de la capa anterior:

z = z_layers[-layer]

...y el resultado de la aplicación de la derivada de la función de activación a dichos valores:

sp = sigmoid_derivative(z)

Calculamos el producto de las matrices de pesos y de la matriz delta de la iteración anterior, y multiplicamos el resultado por la derivada sp calculada:

delta = np.dot(self.weights[-layer + 1].transpose(), delta) * sp

La derivada parcial de la función de coste con respecto a los bias coincide con "delta", y la derivada parcial con respecto a los pesos coincide con el producto de "delta" y los valores "a", tal y como hemos visto:

grad_b[-layer] = delta
grad_w[-layer] = np.dot(delta, a_layers[-layer - 1].transpose())

Este cálculo tendremos que realizarlo para todas las capas ocultas quedando, por tanto, el código de la siguiente forma:

for layer in range(2, self.num_layers):
    z = z_layers[-layer]
    sp = sigmoid_derivative(z)
    delta = np.dot(self.weights[-layer + 1].transpose(), delta) * sp
    grad_b[-layer] = delta
    grad_w[-layer] = np.dot(delta, a_layers[-layer - 1].transpose())