Hemos visto que para el cálculo de la salida de la red necesitamos una lista de matrices conteniendo los pesos de cada capa. Y cada matriz deberá tener tantas filas como neuronas tenga la capa y tantas columnas como neuronas tenga la capa anterior.
Es decir, necesitamos recorrer la lista sizes para ir creando la matriz de pesos para las capas que tienen índice 1 en adelante (recordemos que la capa de entrada no tiene pesos ni bias asociados). Podemos obtener para cada una de estas capas su número de neuronas y el número de neuronas de la capa anterior con una list comprehension. Por ejemplo, si la variable sizes contiene la lista [2, 3, 1]:
sizes = [2, 3, 1]
[(num_neuronas_capa, num_neuronas_capa_anterior)
for (num_neuronas_capa, num_neuronas_capa_anterior) in zip(sizes[1:], sizes[:-1])]
[(3, 2), (1, 3)]
Estamos recorriendo las capas desde el índice 1 en adelante (sizes[1:]) para obtener el número de neuronas que contienen y haciendo un recorrido en paralelo para las capas desde la primera (la capa de entrada con índice 0) hasta la penúltima (sizes[:-1]) para obtener el número de neuronas de la capa anterior, y estamos generando un iterador con ambos números usando la función integrada zip. A continuación, extraemos cada pareja de números con formato de tupla y devolvemos la lista resultante.
El resultado en nuestro ejemplo es una lista formada por las tuplas (3, 2) y (1, 3), indicando que la primera capa con pesos (la única capa oculta) tiene 3 neuronas y que la anterior (la capa de entrada) tiene 2, y que la última capa (la capa de salida) tiene una neurona y que la anterior (la capa oculta) tiene 3.
Una vez que sabemos para cada capa cuáles deben ser sus dimensiones ("num_neuronas_capa" filas y "num_neuronas_capa_anterior" columnas), podemos generar la matriz de valores aleatorios extraídos de una distribución gaussiana de media 0 y desviación estándar 1 -tal y como se ha comentado ya- con el siguiente código:
sizes = [2, 3, 1]
weights = [np.random.randn(num_neuronas_capa, num_neuronas_capa_anterior)
for (num_neuronas_capa, num_neuronas_capa_anterior) in zip(sizes[1:], sizes[:-1])]
weights
[array([[ 0.35452913, 1.30599676],
[-1.32388753, 0.84053059],
[-1.34443344, -1.26416169]]),
array([[-0.21518588, -0.43982342, -0.21412566]])]
Comprobamos que a la primera capa con pesos se le asigna una matriz que contiene tres filas -por sus tres neuronas- y dos columnas -por las dos neuronas de la capa anterior- (exactamente los valores que habíamos determinado) y que a la última capa se le asigna una matriz que contiene una fila -pues solo incluye una neurona- y tres columnas -por las tres neuronas de la capa anterior-.