scratch neural network from feedforward example python machine-learning neural-network

from - feedforward neural network python



Problemas con ANN BackProp/Gradient Checking. (1)

No soy muy competente para leer el código de Python, pero tu lista de gradientes para XOR contiene 3 elementos, correspondientes a 3 ponderaciones. Supongo que estas son dos entradas y un sesgo para una sola neurona. Si es verdadero, dicha red no puede aprender XOR (mínimo NN que puede aprender XOR necesita dos neuronas ocultas y una unidad de salida). Ahora, mirando la función Feedforward, si np.dot calcula lo que dice su nombre (es decir, un producto de punto de dos vectores), y sigmoid es escalar, entonces esto siempre corresponderá a la salida de una neurona y no veo la forma en que puede agregar más neuronas a las capas con este código.

Los siguientes consejos podrían ser útiles para depurar cualquier NN recién implementado:

1) No empieces con MNIST o incluso XOR. Una implementación perfectamente buena puede fallar al aprender XOR porque puede caer fácilmente en los mínimos locales y puede pasar mucho tiempo buscando un error inexistente. Un buen punto de partida será la función Y, que se puede aprender con una sola neurona

2) Verifique el paso de cálculo hacia adelante computando los resultados manualmente en algunos ejemplos. eso es fácil de hacer con un pequeño número de pesos. Luego intenta entrenarlo con un gradiente numérico. Si falla, entonces su gradiente numérico es incorrecto (verifíquelo a mano) o el procedimiento de entrenamiento es incorrecto. (Puede no funcionar si configura una velocidad de aprendizaje demasiado grande, pero de lo contrario el entrenamiento debe converger ya que la superficie de error es convexa).

3) una vez que pueda entrenarlo con graduación numérica, depure sus gradientes analíticos (compruebe gradiente por neurona, y luego gradiente para pesos individuales). Eso también se puede calcular manualmente y comparar con lo que ves.

4) Al finalizar el paso 3, si todo funciona bien, agregue una capa oculta y repita los pasos 2 y 3 con la función AND.

5) después de que todo funciona con AND, puede pasar a la función XOR y otras tareas más complicadas.

Este procedimiento puede parecer lento, pero casi siempre resulta en trabajar NN al final

Acabo de escribir mi primera clase de red neuronal en python. Todo lo que puedo decir debería funcionar, pero hay algunos errores que no puedo encontrar (Probablemente mirándome directamente). Primero probé con 10.000 ejemplos de los datos de MNIST, luego nuevamente cuando trato de replicar la función de firmar, y nuevamente cuando trato de replicar una XOR Gate. Cada vez, independientemente del # de épocas, siempre produce salida de todas las neuronas de salida (independientemente de cuántas puede haber) que tengan aproximadamente el mismo valor, pero la función de costo parece estar disminuyendo. Estoy usando un gradiente de gradiente por lotes, todo hecho usando vectores (sin ciclo para cada ejemplo de entrenamiento).

#Neural Network Class import numpy as np class NeuralNetwork: #methods def __init__(self,layer_shape): #Useful Network Info self.__layer_shape = layer_shape self.__layers = len(layer_shape) #Initialize Random Weights self.__weights = [] self.__weight_sizes = [] for i in range(len(layer_shape)-1): current_weight_size = (layer_shape[i+1],layer_shape[i]+1) self.__weight_sizes.append(current_weight_size) self.__weights.append(np.random.normal(loc=0.1,scale=0.1,size=current_weight_size)) def sigmoid(self,z): return (1/(1+np.exp(-z))) def sig_prime(self,z): return np.multiply(self.sigmoid(z),(1-self.sigmoid(z))) def Feedforward(self,input,Train=False): self.__input_cases = np.shape(input)[0] #Empty list to hold the output of every layer. output_list = [] #Appends the output of the the 1st input layer. output_list.append(input) for i in range(self.__layers-1): if i == 0: output = self.sigmoid(np.dot(np.concatenate((np.ones((self.__input_cases,1)),input),1),self.__weights[0].T)) output_list.append(output) else: output = self.sigmoid(np.dot(np.concatenate((np.ones((self.__input_cases,1)),output),1),self.__weights[i].T)) output_list.append(output) #Returns the final output if not training. if Train == False: return output_list[-1] #Returns the entire output_list if need for training else: return output_list def CostFunction(self,input,target,error_func=1): """Gives the cost of using a particular weight matrix based off of the input and targeted output""" #Run the network to get output using current theta matrices. output = self.Feedforward(input) #####Allows user to choose Cost Functions.##### # #Log Based Error Function # if error_func == 0: error = np.multiply(-target,np.log(output))-np.multiply((1-target),np.log(1-output)) total_error = np.sum(np.sum(error)) # #Squared Error Cost Function # elif error_func == 1: error = (target - output)**2 total_error = 0.5 * np.sum(np.sum(error)) return total_error def Weight_Grad(self,input,target,output_list): #Finds the Error Deltas for Each Layer # deltas = [] for i in range(self.__layers - 1): #Finds Error Delta for the last layer if i == 0: error = (target-output_list[-1]) error_delta = -1*np.multiply(error,np.multiply(output_list[-1],(1-output_list[-1]))) deltas.append(error_delta) #Finds Error Delta for the hidden layers else: #Weight matrices have bias values removed error_delta = np.multiply(np.dot(deltas[-1],self.__weights[-i][:,1:]),output_list[-i-1]*(1-output_list[-i-1])) deltas.append(error_delta) # #Finds the Deltas for each Weight Matrix # Weight_Delta_List = [] deltas.reverse() for i in range(len(self.__weights)): current_weight_delta = (1/self.__input_cases) * np.dot(deltas[i].T,np.concatenate((np.ones((self.__input_cases,1)),output_list[i]),1)) Weight_Delta_List.append(current_weight_delta) #print("Weight",i,"Delta:","/n",current_weight_delta) #print() # #Combines all Weight Deltas into a single row vector # Weight_Delta_Vector = np.array([[]]) for i in Weight_Delta_List: Weight_Delta_Vector = np.concatenate((Weight_Delta_Vector,np.reshape(i,(1,-1))),1) return Weight_Delta_List def Train(self,input_data,target): # #Gradient Checking: # #First Get Gradients from first iteration of Back Propagation output_list = self.Feedforward(input_data,Train=True) self.__input_cases = np.shape(input_data)[0] Weight_Delta_List = self.Weight_Grad(input_data,target,output_list) #Creates List of Gradient Approx arrays set to zero. grad_approx_list = [] for i in self.__weight_sizes: current_grad_approx = np.zeros(i) grad_approx_list.append(current_grad_approx) #Compute Approx. Gradient for every Weight Change for W in range(len(self.__weights)): for index,value in np.ndenumerate(self.__weights[W]): orig_value = self.__weights[W][index] #Saves the Original Value print("Orig Value:", orig_value) #Sets weight to weight +/- epsilon self.__weights[W][index] = orig_value+.00001 cost_plusE = self.CostFunction(input_data, target) self.__weights[W][index] = orig_value-.00001 cost_minusE = self.CostFunction(input_data, target) #Solves for grad approx: grad_approx = (cost_plusE-cost_minusE)/(2*.00001) grad_approx_list[W][index] = grad_approx #Sets Weight Value back to its original value self.__weights[W][index] = orig_value # #Print Gradients from Back Prop. and Grad Approx. side-by-side: # print("Back Prop. Grad","/t","Grad. Approx") print("-"*15,"/t","-"*15) for W in range(len(self.__weights)): for index, value in np.ndenumerate(self.__weights[W]): print(self.__weights[W][index],"/t"*3,grad_approx_list[W][index]) print("/n"*3) input_ = input("Press Enter to continue:") # #Perform Weight Updates for X number of Iterations # for i in range(10000): #Run the network output_list = self.Feedforward(input_data,Train=True) self.__input_cases = np.shape(input_data)[0] Weight_Delta_List = self.Weight_Grad(input_data,target,output_list) for w in range(len(self.__weights)): #print(self.__weights[w]) #print(Weight_Delta_List[w]) self.__weights[w] = self.__weights[w] - (.01*Weight_Delta_List[w]) print("Done")`

Incluso implementé la Comprobación de gradiente y los valores son diferentes, y pensé que intentaría reemplazar las actualizaciones de Propagación inversa con Aprox. Valores de comprobación de gradiente, pero dieron los mismos resultados, lo que me hizo dudar incluso de mi código de comprobación de gradiente.

Estos son algunos de los valores que se producen al entrenar para XOR Gate:

Volver Prop. Grad: 0.0756102610697 0.261814503398 0.0292734023876 Grad Aprox .: 0.05302210631166 0.0416095559674 0.0246847342122 Costo: Antes del entrenamiento: 0.508019225507 Después del entrenamiento 0.50007095103 (Después de 10000 Epochs) Salida para 4 ejemplos diferentes (después del entrenamiento): [0.49317733] [0.49294556] [0.50489004] [0.50465824]

Entonces mi pregunta es, ¿hay algún problema obvio con mi Propagación Atrás, o mi verificación de gradiente? ¿Hay algún problema habitual cuando una ANN muestra estos síntomas (todos los productos son aproximadamente iguales / el costo baja)?