una tutorial redes practicos paso neuronales neuronal implementacion hacer ejemplos desde crear como cero python algorithm numpy matrix derivative

tutorial - redes neuronales python pdf



Atascado implementando una red neuronal simple (1)

He estado golpeando mi cabeza contra esta pared de ladrillo por lo que parece una eternidad, y parece que no puedo entenderlo. Estoy tratando de implementar un autoencoder usando solo numpy y multiplicación de matrices. No se permiten trucos theano o keras.

Describiré el problema y todos sus detalles. Al principio es un poco complejo ya que hay muchas variables, pero en realidad es bastante sencillo.

Lo que sabemos

1) X es una matriz de m por n que es nuestra entrada. Las entradas son filas de esta matriz. Cada entrada es un vector de fila n dimensiones, y tenemos m de ellas.

2) El número de neuronas en nuestra (única) capa oculta, que es k .

3) La función de activación de nuestras neuronas (sigmoide, se denotará como g(x) ) y su derivada g''(x)

Lo que no sabemos y queremos encontrar

En general, nuestro objetivo es encontrar 6 matrices: w1 que es n por k , b1 que es m por k , w2 que es k por n , b2 que es m por n , w3 que es n por n b3 que es m por n .

Se inician aleatoriamente y encontramos la mejor solución usando el descenso de gradiente.

El proceso

Todo el proceso se ve algo como esto

Primero calculamos z1 = Xw1+b1 . Es m por k y es la entrada a nuestra capa oculta. Luego calculamos h1 = g(z1) , que simplemente aplica la función sigmoidea a todos los elementos de z1 . naturalmente también es m por k y es la salida de nuestra capa oculta.

Luego calculamos z2 = h1w2+b2 que es m por n y es la entrada a la capa de salida de nuestra red neuronal. Luego calculamos h2 = g(z2) que de nuevo también es naturalmente m by n y es la salida de nuestra red neuronal.

Finalmente, tomamos esta salida y realizamos un operador lineal sobre ella: Xhat = h2w3+b3 que también es m by n y es nuestro resultado final.

Donde estoy atascado

La función de costo que quiero minimizar es el error cuadrático medio. Ya lo implementé en código numpy

def cost(x, xhat): return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T))

El problema es encontrar los derivados del costo con respecto a w1,b1,w2,b2,w3,b3 . Vamos a llamar el costo S

Después de derivarme y controlarme numéricamente , he establecido los siguientes hechos:

1) dSdxhat = (1/m) * np.dot(xhat-x)

2) dSdw3 = np.dot(h2.T,dSdxhat)

3) dSdb3 = dSdxhat

4) dSdh2 = np.dot(dSdxhat, w3.T)

Pero no puedo, por la vida de mí, descubrir dSdz2. Es una pared de ladrillo.

Desde la regla de cadena, debería ser que dSdz2 = dSdh2 * dh2dz2 pero las dimensiones no coinciden.

¿Cuál es la fórmula para calcular la derivada de S con respecto a z2?

Editar : este es mi código para la operación de avance completo del autoencoder.

import numpy as np def g(x): #sigmoid activation functions return 1/(1+np.exp(-x)) #same shape as x! def gGradient(x): #gradient of sigmoid return g(x)*(1-g(x)) #same shape as x! def cost(x, xhat): #mean squared error between x the data and xhat the output of the machine return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T)) #Just small random numbers so we can test that it''s working small scale m = 5 #num of examples n = 2 #num of features in each example k = 2 #num of neurons in the hidden layer of the autoencoder x = np.random.rand(m, n) #the data, shape (m, n) w1 = np.random.rand(n, k) #weights from input layer to hidden layer, shape (n, k) b1 = np.random.rand(m, k) #bias term from input layer to hidden layer (m, k) z1 = np.dot(x,w1)+b1 #output of the input layer, shape (m, k) h1 = g(z1) #input of hidden layer, shape (m, k) w2 = np.random.rand(k, n) #weights from hidden layer to output layer of the autoencoder, shape (k, n) b2 = np.random.rand(m, n) #bias term from hidden layer to output layer of autoencoder, shape (m, n) z2 = np.dot(h1, w2)+b2 #output of the hidden layer, shape (m, n) h2 = g(z2) #Output of the entire autoencoder. The output layer of the autoencoder. shape (m, n) w3 = np.random.rand(n, n) #weights from output layer of autoencoder to entire output of the machine, shape (n, n) b3 = np.random.rand(m, n) #bias term from output layer of autoencoder to entire output of the machine, shape (m, n) xhat = np.dot(h2, w3)+b3 #the output of the machine, which hopefully resembles the original data x, shape (m, n)


OK, aquí hay una sugerencia. En el caso del vector, si usted tiene x como un vector de longitud n , entonces g(x) también es un vector de longitud n . Sin embargo, g''(x) no es un vector, es la matriz jacobiana , y será de tamaño n X n . De manera similar, en el caso minibatch, donde X es una matriz de tamaño m X n , g(X) es m X n pero g''(X) es n X n . Tratar:

def gGradient(x): #gradient of sigmoid return np.dot(g(x).T, 1 - g(x))

@Paul tiene razón en que los términos de sesgo deberían ser vectores, no matrices. Deberías:

b1 = np.random.rand(k) #bias term from input layer to hidden layer (k,) b2 = np.random.rand(n) #bias term from hidden layer to output layer of autoencoder, shape (n,) b3 = np.random.rand(n) #bias term from output layer of autoencoder to entire output of the machine, shape (n,)

La transmisión de Numpy significa que no tiene que cambiar su cálculo de xhat .

Entonces (¡creo!) Puedes calcular derivados como este:

dSdxhat = (1/float(m)) * (xhat-x) dSdw3 = np.dot(h2.T,dSdxhat) dSdb3 = dSdxhat.mean(axis=0) dSdh2 = np.dot(dSdxhat, w3.T) dSdz2 = np.dot(dSdh2, gGradient(z2)) dSdb2 = dSdz2.mean(axis=0) dSdw2 = np.dot(h1.T,dSdz2) dSdh1 = np.dot(dSdz2, w2.T) dSdz1 = np.dot(dSdh1, gGradient(z1)) dSdb1 = dSdz1.mean(axis=0) dSdw1 = np.dot(x.T,dSdz1)

¿Esto funciona para tí?

Editar

He decidido que no estoy seguro de que se gGradient que gGradient es una matriz. Qué tal si:

dSdxhat = (xhat-x) / m dSdw3 = np.dot(h2.T,dSdxhat) dSdb3 = dSdxhat.sum(axis=0) dSdh2 = np.dot(dSdxhat, w3.T) dSdz2 = h2 * (1-h2) * dSdh2 dSdb2 = dSdz2.sum(axis=0) dSdw2 = np.dot(h1.T,dSdz2) dSdh1 = np.dot(dSdz2, w2.T) dSdz1 = h1 * (1-h1) * dSdh1 dSdb1 = dSdz1.sum(axis=0) dSdw1 = np.dot(x.T,dSdz1)