Création continue,Accélérer la croissance!C'est ma participation「Nouveau plan de la Journée des Nuggets · 6 Le défi de la lune」De31Oh, mon Dieu.,Cliquez pour voir les détails de l'événement
Dans cet article,Prêt à l'emploi Python Mise en place d'un réseau neuronal entièrement connecté à partir de zéro.Vous pourriez demander,Pourquoi faut - il le faire soi - même?,Il y a beaucoup de bibliothèques et de cadres pour faire ça pour nous.,Par exemple, Tensorflow、Pytorch Attendez..Je veux juste dire que je l'ai fait moi - même.,C'est le sien..
Pensez à ce que vous avez fait aujourd'hui, du contact au travail sur les réseaux neuronaux 2、3 Ça fait un an.,Et j'ai essayé d'utiliser tensorflow Ou pytorch Cadre pour mettre en œuvre certains réseaux classiques.Mais le mécanisme derrière la Rétropropagation est encore flou.
Le Gradient est la direction de la fonction qui augmente le plus rapidement,La direction la plus rapide, c'est - à - dire la fonction de direction, est très raide.,C'est la direction dans laquelle la fonction diminue le plus rapidement..
Bien que certaines théories、La disparition du gradient et la saturation des noeuds peuvent produire un 1、2、3 Mais il n'y a toujours pas de base.,Après tout, je n'a i pas mis en place un processus de Rétropropagation et d'entraînement complet..C'est comme ça qu'on se sent toujours à la surface.,Et pourtant.
Parce qu'il y a eu un temps libre récemment、 L'utilisation de ce temps de repos va donc permettre d'organiser cette partie des connaissances 、 En savoir plus
Nous connaissons tous le processus de formation des réseaux neuronaux , Est de mettre à jour les paramètres du réseau , La direction de la mise à jour est de réduire la valeur de la fonction de perte . C'est - à - dire transformer un problème d'apprentissage en un problème d'optimisation . Comment mettre à jour les paramètres ? Nous devons calculer la dérivée des paramètres de formation impliqués par rapport à la fonction de perte , Et ensuite résoudre le gradient , Ensuite, utilisez la méthode de descente par Gradient pour mettre à jour les paramètres , Itérer ce processus , Une solution optimale peut être trouvée pour minimiser la fonction de perte .
Nous savons que la Rétropropagation est principalement utilisée pour régler les dérivés de la fonction de perte par rapport au poids et au biais
J'ai peut - être entendu ou lu , Beaucoup d'informations sur la transmission d'erreurs par Rétropropagation sur le réseau . Et ensuite, selon les neurones w Et b L'ampleur de la contribution à l'écart . C'est - à - dire que l'erreur est attribuée à chaque neurone . Mais l'erreur ici (error)Qu'est - ce que ça veut dire?? Quelle est la définition exacte de cette erreur ? La réponse est que ces erreurs sont dues à chaque couche du réseau neuronal , Et l'erreur d'une couche est répartie sur la base de l'erreur de la couche suivante ,Dans le réseau l L'erreur de couche est utilisée pour δl Pour représenter.
La Rétropropagation est basée sur 4 Des équations de base , Ces équations permettent de calculer les erreurs δL Et la fonction de perte, Voici ce que 4 Les équations sont énumérées une par une
δ(L)=∇aC⊙σ′(zL)(BP1)δl=((wl)Tδl+1)⊙σ′(zl)(BP1)∂bjl∂C=δjl(BP3)∂wjkl∂C=akl−1δjl(BP4)Comment interpréter ça 4 Les équations, Ensuite, j'aimerais utiliser un numéro de partage pour illustrer .
class NeuralNetwork(object):
def __init__(self):
pass
def forward(self,x):
# Retour à propagation vers l'avant Z C'est - à - dire w Et b Combinaison linéaire, Saisissez la valeur avant d'activer la fonction
# Renvoie la valeur de sortie de la fonction active A
# z_s , a_s
pass
def backward(self,y,z_s,a_s):
# Renvoie la dérivée du paramètre d'apprentissage dans la propagation vers l'avant dw db
pass
def train(self,x,y,batch_size=10,epochs=100,lr=0.001):
pass
Nous sommes tous des processus d'apprentissage en réseau neuronal , C'est le processus d'entraînement .Il y a deux étapes principalesPropagation vers l'avantEtRétropropagation
def __init__(self,layers = [2 , 10, 1], activations=['sigmoid', 'sigmoid']):
assert(len(layers) == len(activations)+1)
self.layers = layers
self.activations = activations
self.weights = []
self.biases = []
for i in range(len(layers)-1):
self.weights.append(np.random.randn(layers[i+1], layers[i]))
self.biases.append(np.random.randn(layers[i+1], 1))
Lisez simplement le Code assert(len(layers) == len(activations)+1)
for i in range(len(layers)-1):
self.weights.append(np.random.randn(layers[i+1], layers[i]))
self.biases.append(np.random.randn(layers[i+1], 1))
Parce que les poids relient chaque couche de neurones w Et b , C'est juste l'équation entre deux couches , Le code ci - dessus est correct
Dans la propagation vers l'avant,Entrée X Entrée dans a_s Moyenne,z=wx+b Et ensuite calculer la sortie a=σ(z),
def feedforward(self, x):
# Renvoie la valeur de propagation vers l'avant
a = np.copy(x)
z_s = []
a_s = [a]
for i in range(len(self.weights)):
activation_function = self.getActivationFunction(self.activations[i])
z_s.append(self.weights[i].dot(a) + self.biases[i])
a = activation_function(z_s[-1])
a_s.append(a)
return (z_s, a_s)
Activez la fonction ici , La valeur de retour de cette fonction est une fonction ,In python Avec lambda
Pour retourner une fonction , Ici Jane a laissé un stylo , Il sera ensuite modifié .
@staticmethod
def getActivationFunction(name):
if(name == 'sigmoid'):
return lambda x : np.exp(x)/(1+np.exp(x))
elif(name == 'linear'):
return lambda x : x
elif(name == 'relu'):
def relu(x):
y = np.copy(x)
y[y<0] = 0
return y
return relu
else:
print('Unknown activation function. linear is used')
return lambda x: x
[@staticmethod]
def getDerivitiveActivationFunction(name):
if(name == 'sigmoid'):
sig = lambda x : np.exp(x)/(1+np.exp(x))
return lambda x :sig(x)*(1-sig(x))
elif(name == 'linear'):
return lambda x: 1
elif(name == 'relu'):
def relu_diff(x):
y = np.copy(x)
y[y>=0] = 1
y[y<0] = 0
return y
return relu_diff
else:
print('Unknown activation function. linear is used')
return lambda x: 1
C'est l'objet de ce partage
def backpropagation(self,y, z_s, a_s):
dw = [] # dC/dW
db = [] # dC/dB
deltas = [None] * len(self.weights) # delta = dC/dZ Calculer l'erreur pour chaque couche
# Erreur de dernière couche
deltas[-1] = ((y-a_s[-1])*(self.getDerivitiveActivationFunction(self.activations[-1]))(z_s[-1]))
# Rétropropagation
for i in reversed(range(len(deltas)-1)):
deltas[i] = self.weights[i+1].T.dot(deltas[i+1])*(self.getDerivitiveActivationFunction(self.activations[i])(z_s[i]))
#a= [print(d.shape) for d in deltas]
batch_size = y.shape[1]
db = [d.dot(np.ones((batch_size,1)))/float(batch_size) for d in deltas]
dw = [d.dot(a_s[i].T)/float(batch_size) for i,d in enumerate(deltas)]
# Retour au poids (weight)Matrice and Vecteur offset(biases)
return dw, db
Calculer d'abord l'erreur de la dernière couche basée sur BP1 L'équation donne l'équation suivante
deltas[-1] = ((y-a_s[-1])*(self.getDerivitiveActivationFunction(self.activations[-1]))(z_s[-1]))
La prochaine étape est basée sur δl+1 Erreur pour calculer la couche courante δl
δl=((wl)Tδl+1)⊙σ′(zl)(BP1)batch_size = y.shape[1]
db = [d.dot(np.ones((batch_size,1)))/float(batch_size) for d in deltas]
dw = [d.dot(a_s[i].T)/float(batch_size) for i,d in enumerate(deltas)]
∂bjl∂C=δjl(BP3)∂wjkl∂C=akl−1δjl(BP4) def train(self, x, y, batch_size=10, epochs=100, lr = 0.01):
# update weights and biases based on the output
for e in range(epochs):
i=0
while(i<len(y)):
x_batch = x[i:i+batch_size]
y_batch = y[i:i+batch_size]
i = i+batch_size
z_s, a_s = self.feedforward(x_batch)
dw, db = self.backpropagation(y_batch, z_s, a_s)
self.weights = [w+lr*dweight for w,dweight in zip(self.weights, dw)]
self.biases = [w+lr*dbias for w,dbias in zip(self.biases, db)]
# print("loss = {}".format(np.linalg.norm(a_s[-1]-y_batch) ))