J'avais besoin d'expliquer le code du réseau de neurones (ci-après, NN), j'ai donc décidé de profiter de l'occasion pour le résumer brièvement. Ci-dessous, nous procéderons en supposant que les connaissances de base sur NN sont connues.
[Learning and Neural Network (Electronic Information and Communication Engineering Series)](http://www.amazon.co.jp/gp/product/4627702914/ref=as_li_tf_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=4627702914&linkCode=as2&tagao-shimash 22) <img src = "http://ir-jp.amazon-adsystem.com/e/ir?t=shimashimao06-22&l=as2&o=9&a=4627702914" width = "1" height = "1" border = " 0 "alt =" "style =" border: none! Important; margin: 0px! Important; "/>
Entrée sur le réseau: $ (x_ {1}, x_ {2}, ..., x_ {N}) $
Sortie du réseau: $ (y_ {1}, y_ {2}, ..., y_ {M}) $
Relation réseau entrée / sortie: $ (y_ {1}, y_ {2}, ..., y_ {M}) = F (x_ {1}, x_ {2}, ..., x_ {N}) $
Poids de jointure: {$ w_ {ij}
Le livre de référence ci-dessus a la description suivante des raisons pour lesquelles BP est devenu largement utilisé.
- Le calcul de la différenciation partielle de la fonction d'évaluation pour chaque paramètre a tendance à être compliqué dans un système non linéaire général, mais il existe une méthode de calcul systématique et systématique dans BP. De plus, les informations requises pour déterminer la quantité de correction de chaque paramètre peuvent être transmises à l'emplacement requis en utilisant la structure de connexion connue par le réseau. Cela signifie qu'il n'est pas nécessaire de fournir une ligne de communication spéciale pour l'apprentissage, ce qui est pratique pour simplifier l'algorithme et le matériel.
- La capacité d'approximation fonctionnelle du réseau est théoriquement garantie. Si un nombre suffisant d'éléments de couche intermédiaire est utilisé, toute fonction peut être arbitrairement approximée avec une grande précision en déterminant de manière appropriée les valeurs de paramètres (poids de connexion, valeur de seuil). Il n'est pas toujours possible de trouver une valeur de paramètre qui donne l'approximation optimale par BP, mais la preuve d'une sorte de théorème d'existence donne un sentiment de sécurité.
Effectuez les opérations suivantes.
Puisque la méthode d'apprentissage de mise à jour séquentielle est dérivée, la méthode de gradient est appliquée dans le but de réduire l'échelle d'évaluation de l'équation suivante pour chaque donnée d'entraînement ($ x ^ {(l)}, y ^ {(l)} $).
L'équation suivante est obtenue en différenciant l'échelle d'évaluation d'erreur $ E (w_0, w_1, ..., w_N) $ par $ w_n $.
Lorsque cela est différencié,
Pour résumer cela davantage,
En utilisant la valeur de $ \ partial E (w_0, w_1, ..., w_N) / \ partial w_n $ obtenue à partir de ce qui précède, le poids de connexion est corrigé à plusieurs reprises par l'équation suivante.
Le petit changement de x se propage au changement d'autres valeurs de variable dans une chaîne en fonction de la dépendance des variables dans la figure ci-dessus. Selon la règle de la chaîne, l'expression relationnelle suivante est valable entre les changements infimes de ces variables $ \ Delta x, \ Delta z_1, \ Delta x_2, \ Delta y $.
Pour résumer la formule ci-dessus,
Sur la base de la règle de chaîne ci-dessus, nous dériverons le BP de NN constitué de la couche d'entrée, de la couche intermédiaire et de la couche de sortie. Le nombre d'unités pour les trois couches est de 3 (4 unités pour la couche d'entrée et la couche intermédiaire, compte tenu du terme de polarisation). À partir de l'unité de la couche de sortie, numérotez la couche de sortie: {1,2,3}, la couche intermédiaire: {4,5,6} et la couche d'entrée: {7,8,9}. Et
BP est dérivée en utilisant ces deux cas comme exemples. Une image de chaque propagation est présentée ci-dessous.
La relation entre le montant de la variation dans $ w_2 $ $ \ Delta w_2 $ et le montant de la variation dans $ s_2 $ $ \ Delta s_2 $ est illustrée par l'équation suivante.
Cette modification de $ y_2 $ modifie la valeur de l'échelle d'évaluation des erreurs, et l'expression relationnelle suivante est valable.
A partir de l'équation ci-dessus, le coefficient différentiel partiel $ \ partial E / \ partial w_2 $ requis pour corriger $ w_2 $ par la méthode du gradient a été obtenu.
Aussi, à partir de $ \ Delta s_2 = y_4 \ Delta w_2 $
La relation entre le montant du changement lorsque $ w_4 $ est modifié est calculée par la formule suivante.
Le changement de $ y_4 $ qui se produit de cette manière affecte $ s_1, s_2, s_3 $ à la destination de la connexion. Par conséquent, l'expression relationnelle suivante s'applique entre les quantités de changement.
Le changement ci-dessus modifie également l'échelle d'évaluation des erreurs, comme indiqué dans l'équation suivante.
Organisez ceci et divisez les deux côtés par $ \ Delta s_4 $ en
Est recherché. On peut voir que la formule ci-dessus est une sorte de formule graduelle dans laquelle $ \ partial E / \ partial s_i $ dans la couche intermédiaire est obtenu par $ \ partial E / \ partial s_j $ dans la couche de sortie. De même, on peut voir que l'erreur peut être propagée aux couches inférieures en trouvant $ \ partial E / \ partial s $ de la couche finale pour n'importe quel nombre de NN.
Finalement,
Désolé pour le code assez sale, mais je vais le coller ci-dessous. Le seuil (biais) est fixé pour tous les neurones par souci de simplicité. Lors de la création du code, ajoutez un élément avec une valeur de 1 au début du vecteur d'entrée, ajoutez un élément de biais au vecteur de pondération et ajustez les paramètres dans le cadre du poids.
python
# coding: utf-8
import numpy as np
Afrom numpy.random import randint
import sys
class NN:
def __init__(self):
self.alph = 0.04
self.mu = 0.01
self.theta = 0.1
self.w = []
self.output = []
self.output_sigm = []
self.T = 0
def create_data(self, input_n_row, input_n_col, layer_sizes):
self.x = randint(2, size=(input_n_row, input_n_col))
self.y = randint(2, size=(input_n_row, layer_sizes[-1]))
for i_layer, size in enumerate(layer_sizes):
if i_layer == 0:
self.w.append(np.random.randn(input_n_col, size))
self.output.append(np.zeros((input_n_row, size)))
self.output_sigm.append(np.zeros((input_n_row ,size)))
else:
self.w.append(np.random.randn(layer_sizes[i_layer-1], size))
self.output.append(np.zeros((input_n_row, size)))
self.output_sigm.append(np.zeros((input_n_row ,size)))
def fit(self, eps=10e-6):
error = sys.maxint
self.forward()
while error>eps:
self.update( self.backword() )
self.forward()
error = self.calculate_error()
self.T += 1
print "T=", self.T
print "error", error
def calculate_error(self):
return np.sum( np.power(self.y - self.output_sigm[-1], 2) )
def forward(self):
for i_layer in xrange(len(self.output)):
if i_layer == 0:
self.output[i_layer] = self.x.dot(self.w[i_layer])
self.output_sigm[i_layer] = self.sigmoid(self.output[i_layer])
else:
self.output[i_layer] = self.output_sigm[i_layer-1].dot(self.w[i_layer])
self.output_sigm[i_layer] = self.sigmoid(self.output[i_layer])
def backword(self):
result = []
for i_layer in range(len(self.w))[::-1]:
if i_layer==len(self.w)-1:
result.insert(0, self.diff(self.output_sigm[i_layer], self.y) )
else:
result.insert(0, self.diff_mult( self.output_sigm[i_layer], result[0].dot(self.w[i_layer+1].T)) )
return result
def update(self, diff):
for i_layer in range(len(self.w))[::-1]:
if i_layer==0:
for i_row in xrange(len(diff[i_layer])):
self.w[i_layer] -= self.get_incremental_update_value(
self.x[i_row].reshape(len(self.w[i_layer]),1),
diff[i_layer][i_row,:].reshape(1,self.w[i_layer].shape[1])
)
else:
for i_row in xrange(len(diff[i_layer])):
self.w[i_layer] -= self.get_incremental_update_value(
self.output_sigm[i_layer-1][i_row,:].reshape(len(self.w[i_layer]),1),
diff[i_layer][i_row,:].reshape(1,self.w[i_layer].shape[1])
)
def get_incremental_update_value(self, input_data, diff):
return np.kron(input_data, self.mu*diff)
def diff(self, y, t):
return self.alph * 2*(y - t) * self.dsigmoid(y)
def diff_mult(self, y, prp_value):
return self.alph * self.dsigmoid(y) * prp_value
def sigmoid(self, s, alph=0.01):
return 1/(1+np.exp(-self.alph*(s-self.theta)))
def dsigmoid(self, y):
return y * (1 - y)
if __name__=='__main__':
layer_sizes = (4,3)
input_layer_size = 3
input_data_size = 1000
nn = NN()
nn.create_data(input_data_size, input_layer_size, layer_sizes)
nn.fit()
Nous vous prions de nous excuser pour la gêne occasionnée, mais nous vous serions reconnaissants de bien vouloir signaler toute erreur.
Recommended Posts