Simple Perceptron est la base de l'apprentissage automatique, en particulier des réseaux de neurones. J'étudie également, mais commençons à implémenter un réseau de neurones avec un simple Perceptron et travaillons finalement dur pour implémenter le Deep Learning! (Je fais aussi de mon mieux)
Un réseau neuronal qui prend un tableau en entrée et renvoie un nombre 0 ou 1. Cet algorithme a commencé par imiter les cellules cérébrales. Une chose à garder à l'esprit est que ce n'est qu'une simple imitation, et c'est extrêmement simplifié. Les seuls éléments mathématiques qui apparaissent dans Simple Perceptron sont la multiplication et l'addition. Il y a un total de 2 lignes d'expressions à retenir, et le code source est d'environ 20 lignes pour l'algorithme d'apprentissage seul.
Cet article n'est pas profondément compris par moi et sera long si je prouve un algorithme d'apprentissage détaillé. En premier lieu, la quantité de formules elles-mêmes est petite et vous pouvez mémoriser les formules et les implémenter telles quelles, donc je n'expliquerai pas pourquoi vous pouvez apprendre avec cet algorithme. C'est juste une introduction, intensifiez. Je voudrais publier une explication détaillée séparément lorsque j'aurai une meilleure compréhension. (Je pensais que c'était plus long, car cela met l'accent sur la clarté)
Je décrirai brièvement la composition réelle des cellules cérébrales. L'entrée dans les cellules cérébrales est faite aux protubérances appelées protubérances dendritiques. Les protubérances dendritiques sont faciles à transmettre et difficiles à transmettre. Lorsqu'il est exprimé dans une expression, il s'agit simplement d'une multiplication. Soit i l'entrée et w la facilité de transmission.
i \times w
La facilité de transmission est appelée poids, elle est donc représentée par w. Il existe plusieurs protubérances dendritiques. Bien sûr, même avec un simple perceptron, l'entrée est un tableau de nombres. Par conséquent, ce calcul est effectué pour les éléments d'entrée. Par exemple, s'il y a 5 éléments
i_0 \times w_0\\
i_1 \times w_1\\
i_2 \times w_2\\
i_3 \times w_3\\
i_4 \times w_4\\
Ce sera. Les chiffres à côté sont des indices. i et w correspondent aux tableaux qui peuvent être placés dans le programme. Cela signifie i [0] * w [0]. Vous pouvez voir que le nombre d'éléments du poids et le nombre d'éléments de l'entrée correspondent, et les éléments du même indice dans chaque tableau sont multipliés.
L'entrée des cellules cérébrales était chaque processus dendritique. D'autre part, il n'a qu'une seule sortie et s'appelle un axone. Les processus dendritiques et les axones s'étendent de ce que l'on appelle le corps cellulaire. Les entrées de chaque processus dendritique fusionnent au niveau du corps de la cellule, et la sortie est effectuée du corps de la cellule vers un axone.
L'entrée et la transmission de signaux au processus dendritique pourraient simplement être exprimées par multiplication, comme dans l'équation ci-dessus. Ensuite, cette entrée doit fusionner au niveau du corps de la cellule. Il prend simplement la somme des entrées à travers le dendritique. En d'autres termes, il est réalisé en les additionnant.
i_0 \times w_0 + i_1 \times w_1 + i_2 \times w_2 + i_3 \times w_3 + i_4 \times w_4
Utilisez des abréviations car les formules sont longues. Sigma est utilisé pour l'abréviation de somme. Par exemple, la somme de 1 à 5 est indiquée ci-dessous.
\sum_{i=1}^{5} i = 1 + 2 + 3 + 4 + 5
sigma.py
tmp = 0
for i in range(1,6):
tmp += i
J'ai également montré le code source de python. Prière de se référer à. Sigma (Σ) est très simple, sous le sigma, entrez la variable et la valeur initiale de cette variable. C'est la partie de i = 1. Notez que le i ici est le i dans l'index, pas l'entrée. Les noms de variables peuvent être donnés librement autrement que i. Au-dessus du sigma se trouve le nombre de changements de la valeur de la variable i. La variable i est incrémentée d'exactement 1. Sigma montre qu'ils s'additionnent.
La formule d'entrée par le processus dendritique est également indiquée ci-dessous. J'utilise i comme variable pour l'entrée, alors utilisez j à la place.
\sum_{j=0}^{4} i_j \times w_j = i_0 \times w_0 + i_1 \times w_1 + i_2 \times w_2 + i_3 \times w_3 + i_4 \times w_4
sigma.py
#On suppose que i et w sont prédéfinis.
tmp = 0
for j in range(5):
tmp += i[j] * w[j]
Ce n'est pas pratique sans nom, nous allons donc nommer cette valeur une entrée pondérée. Le nom de la variable est z pour le moment. De plus, nous allons représenter le nombre d'éléments par n afin de pouvoir gérer le nombre d'éléments autres que 5.
z = \sum_{j=0}^{n-1} i_j w_j
Ceci conclut la formule d'entrée pondérée. Avec cela, l'entrée, la facilité de transmission de chaque entrée et leur résumé peuvent être exprimées sous forme d'expression. Enfin, la formule indique comment déterminer la sortie de cette somme.
Encore une fois, il imite de vraies cellules cérébrales. Dans les cellules cérébrales réelles, si l'entrée est supérieure à un certain niveau, elle transmettra un signal, et si elle est inférieure à un certain niveau, elle ne transmettra pas de signal. Lorsqu'un signal est généré au-dessus d'un certain niveau, il est appelé allumage.
Le Simple Perceptron est un modèle très simple. Par conséquent, cette formule est également simple. Soit z l'entrée pondérée et o la sortie.
o =
\begin{cases}
1 & \text{if } z > 0\\
0 & \text{if } z \leqq 0
\end{cases}
step.py
#Soit z prédéfini
if z > 0:
o = 1
elif z <= 0 :
o = 0
c'est tout. S'il est supérieur à 0, il se déclenchera (dites 1), sinon il ne se déclenchera pas (dites 0). À ce stade, ceux qui l'ont lu correctement peuvent se demander s'il faut tirer ou non en fonction de 0. En effet, il est clairement établi qu'un signal négatif entre dans le corps cellulaire.
Mais gardez à l'esprit que le Simple Perceptron est un modèle très simple. S'il est supérieur à 0, il s'enflamme, mais ce n'est qu'une spécification pour simplifier le Perceptron. Cela conclut ma discussion sur la sortie du Perceptron.
Pour résumer ce qui précède, le code python de la sortie de Simple Perceptron est le suivant.
output.py
#On suppose que i et w sont prédéfinis.
def dot(vec0,vec1):
tmp = 0
for i in range(len(vec0)):
tmp += vec0[i] * vec1[i]
return tmp
def step(num):
if num > 0:
return 1
else:
return 0
o = step(dot(i,w))
Les fonctions qui renvoient 1 si supérieur à 0 sont classées en mathématiques comme fonction d'étape. En outre, la fonction qui multiplie chaque élément et prend la somme est appelée le produit interne, également appelé produit scalaire en anglais. Le nom de la fonction du programme est pris à partir d'ici.
output.py
step(dot(i,w))
Si vous vous souvenez de la formule sur une ligne ci-dessus, vous devriez être capable d'écrire suffisamment d'algorithmes de sortie. Voici une autre ligne à retenir, la formule pour apprendre:
Comme indiqué au début, cet article n'explique pas pourquoi cet algorithme peut être utilisé pour l'entraînement. Le but est d'en faire un exercice de répétition pour le prochain réseau de neurones grâce à sa mise en œuvre. Le but est le Deep Learning. (J'ai beaucoup expliqué ...)
Cependant, je pense qu'il est difficile de tout mémoriser, alors j'aimerais ajouter quelques explications. Premièrement, l'objectif de Perceptron est de renvoyer la bonne sortie pour l'entrée. Pour cette raison, il est nécessaire de préparer des données qui définissent l'existence de données d'entrée et la sortie appropriée pour cette entrée. Une sortie appropriée s'appelle une étiquette d'enseignant.
De nos jours, le perceptron simple est ce que l'on appelle l'apprentissage supervisé dans le réseau neuronal. Dans l'apprentissage supervisé, vous avez besoin des données à former, de la sortie appropriée que vous voulez voir lorsque vous entrez ces données et de l'étiquette de l'enseignant. Sur la base de ces données, la mise à jour du poids et w est l'apprentissage dans le perceptron simple.
Cette fois, je vais vous expliquer en prenant comme exemple de formation et de fonctionnement logique. L'opération et est une opération qui reçoit deux nombres (0 ou 1 respectivement), produit 1 si les deux sont 1 et renvoie 0 dans le cas contraire, qui est la base d'un ordinateur.
a | b | a and b |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Préparons pour le moment les données de formation et l'étiquette de l'enseignant. Dans ce domaine, x et y sont souvent utilisés pour représenter chacun, alors appelons-les train_x et train_y.
data.py
train_x = [[0,0],[0,1],[1,0],[1,1]]
train_y = [0,0,0,1]
Il ne semble pas y avoir de problème particulier. Il peut être exprimé que 0 est sorti lorsque [0,0], [0,1], [1,0] et 1 est sorti lorsque [1,1].
Je pense que c'est une erreur.
Pourquoi? En fait, il manque quelque chose aux simples explications de Perceptron que j'ai données jusqu'à présent. L'existence du terme de biais. C'est correct.
data.py
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
Ajouté 1 à la fin de train_x. Le terme de biais est une valeur fixe pour tous les exemples d'entrée. Il peut être différent de 1 tant qu'il est fixe (par exemple, [[0,0,0.5], [0,1,0.5], [1,0,0.5], [1,1,0.5]]). Mais généralement 1 est ajouté comme terme de biais. Pourquoi avons-nous besoin d'un terme de biais?
Prenons le cas où le terme de biais est 1 à titre d'exemple. À ce stade, voyons ce qu'il advient de l'entrée pondérée z. C'est pourquoi i [n] et w [n] sont ajoutés.
z = \sum_{j=0}^{n-1} i_j w_j + i_n w_n
Ici, i [n] vaut 1 dans le terme de biais, c'est donc le cas.
z = \sum_{j=0}^{n-1} i_j w_j + w_n
En bref, l'ajout du terme de biais 1 revient à ajouter un poids. En apprentissage, ce w [n] est mis à jour de la même manière, et par conséquent, l'entrée pondérée z monte et descend par la variable w [n]. En effet, le poids peut prendre une valeur négative comme décrit ci-dessus. En d'autres termes, en ajoutant un terme de biais, l'entrée pondérée z peut être biaisée de chaque côté. (Le biais signifie le biais)
En termes de fonction réelle des cellules cérébrales, cela équivaut à modifier indirectement le seuil de déclenchement (émettre un signal lorsque l'entrée est au-dessus d'un certain niveau (appelé seuil)). Bien entendu, le seuil de la fonction échelon est 0, mais par exemple, lorsqu'il y a un biais de 0,5, il correspond indirectement au seuil devenant -0,5.
Changer le seuil signifie déterminer s'il est facile de sortir 1 ou 0, afin que vous puissiez voir que c'est un facteur important. Alors allons-y. Même lors de l'apprentissage et, cela ne fonctionnera que si un terme de biais est inclus. Mathématiquement, on peut expliquer (il semble) que s'il n'y a pas de section lors de la séparation dans un superplan, seul un graphe passant par l'origine peut être dessiné et l'expressivité est réduite, mais je l'omettrai. Je veux donner une preuve mathématique plus tard.
Retournons l'histoire. Il s'agissait d'apprendre le Perceptron simple. L'apprentissage met à jour les poids. Pour ce faire, j'ai noté que j'avais besoin d'un ensemble d'entrées et de sorties pour eux en tant que données d'enseignant. De quoi d'autre avons-nous besoin pour changer les pondérations pour renvoyer la sortie correcte pour l'entrée? Bien sûr, c'est le poids d'origine.
data.py
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
weight = [0,0,0]
J'ai essayé d'initialiser tous les vecteurs de poids avec 0 pour le moment. Un vecteur de poids est un poids. De nos jours, un tableau contenant uniquement des nombres est appelé un vecteur. À partir de maintenant, lorsque nous disons un vecteur, veuillez reconnaître que cela signifie un tableau.
De quoi d'autres avez-vous besoin? Afin de mettre à jour le vecteur de poids, il semble nécessaire de décider s'il faut mettre à jour le vecteur de poids en premier lieu. Puisqu'il est évident que le moment où le vecteur de poids doit être mis à jour est celui où la mauvaise sortie est sortie, la sortie o est requise.
data.py
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
weight = [0,0,0]
#Exemple: train_x[0]Sortie quand i est
o = step(dot(train_x[0],weight))
De quoi d'autres avez-vous besoin? En fait, c'est la fin. Avec les données ci-dessus, vous pouvez mettre à jour le vecteur de poids. C'est un mensonge. En réalité, il est normal d'inclure le coefficient d'apprentissage. Le coefficient d'apprentissage est un nombre qui représente à quel point le poids change lorsqu'il est mis à jour. Cependant, même si le coefficient d'apprentissage est 1, il converge (l'apprentissage se termine correctement), et lorsque tous les vecteurs de poids sont 0, le nombre de fois qu'il faut pour converger est le même quel que soit le coefficient d'apprentissage (il semble être affiché plus tard dans la référence). ), Vous pouvez donc l'omettre. Mais mettons-le pour le moment.
data.py
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
weight = [0,0,0]
#Exemple: train_x[0]Sortie quand i est
o = step(dot(train_x[0],weight))
#Exemple: coefficient d'apprentissage
eta = 0.1
Regardons en fait l'algorithme de mise à jour. Tout d'abord, il semble nécessaire de décider d'augmenter ou de diminuer le vecteur de poids lorsque la sortie est incorrecte. Lorsque vous voulez sortir 0, vous devez réduire le poids si vous sortez 1, et si vous voulez sortir 1, vous devez augmenter le poids si vous sortez 0. Bien sûr, s'ils correspondent, les poids ne changeront pas.
C'est à ce moment que la valeur que vous souhaitez afficher (libellé de l'enseignant) est y et que la sortie réelle est o.
y - o
Il peut être exprimé par. Montré dans le tableau.
y | o | y - o |
---|---|---|
0 | 0 | 0 |
0 | 1 | -1 |
1 | 0 | 1 |
1 | 1 | 0 |
Vous pouvez exprimer que lorsque o est grand, il est réduit de -1, et lorsque o est petit, il est augmenté de +1.
Cependant, il s'agit d'unités du vecteur de poids entier. Je vais vous expliquer ce que cela signifie. La formule ci-dessus est le code réel
y_o.py
#Exemple: s'entraîner lorsque l'indice est 0_x et former_Calculer en fonction de l'élément de y
y = train_y[0]
o = step(dot(train_x[0],weight))
y - o
Ce sera. Le fait est que y-o est calculé à partir du vecteur de poids entier. Cela nous indique s'il faut mettre à jour ce vecteur de poids, positif ou négatif, mais pas quel élément mettre à jour. Ce n'est évidemment pas bon, car si vous mettez à jour tous les poids de manière uniforme, tous les éléments du vecteur de poids auront la même valeur! Que devrais-je faire?
Revenons maintenant au comportement de Perceptron. Perceptron prend un vecteur d'entrée, multiplie chacun par un vecteur de poids, prend la somme, la donne à l'argument de la fonction step, et sort 0 ou 1. Donc, bien sûr, si vous donnez la même entrée, elle renverra la même sortie. Et si vous donnez différentes entrées, en particulier si vous donnez des données différentes pour l'étiquette de l'enseignant, il est souhaitable de renvoyer différentes sorties.
Renvoyer différentes sorties signifie que les entrées pondérées doivent être biaisées vers des nombres positifs ou négatifs. Cela est dû au fait que l'entrée pondérée est passée par la fonction step.
Lorsque l'étiquette de l'enseignant est une donnée, elle doit être biaisée vers un nombre positif, et lorsque l'étiquette de l'enseignant est 0, elle doit être biaisée vers un nombre négatif. En d'autres termes, en pensant simplement, les poids doivent avoir à la fois des poids positifs et négatifs. Vous ne pouvez pas avoir un poids uniforme.
Et, pour les pondérations positives, les données avec une étiquette d'enseignant de 1 devraient réussir, et pour les pondérations négatives, les données avec une étiquette d'enseignant de 0 devraient réussir. De cette façon, les données avec une étiquette d'enseignant de 1 qui a passé un poids positif produiront bien sûr 1, et les données avec une étiquette d'enseignant de 0 qui ont passé un poids négatif donneront bien sûr 0.
Cependant, même s'il s'agit d'un poids positif ou négatif, bien sûr, Perceptron passe le vecteur d'entrée à travers tous les poids, ce n'est donc pas une expression correcte. Alors, comment y parvenir? Considérez maintenant qu'il y avait un 0 dans les éléments du vecteur d'entrée.
Puisque l'entrée est 0, lorsque le produit intérieur est pris, le poids correspondant à l'entrée n'a aucun effet. 0 x poids = 0. Autrement dit, lorsque l'entrée est 0, les poids correspondants sont identiques à ceux ignorés lors du calcul de la sortie. Il semble que cela ne passe pas le poids.
Si l'entrée est 0, l'entrée ne transmet pas le poids. Par conséquent, le poids n'a pas besoin d'être mis à jour. De plus, par exemple, même si les données avec une étiquette d'enseignant de 1 ne passent pas par ce poids, les données avec une étiquette d'enseignant de 0 peuvent passer par ce poids, donc si vous mettez à jour un poids qui n'a pas besoin d'être mis à jour, le poids que l'autre partie passera. Il sera modifié (et dans votre propre direction) sans autorisation, ce qui aura l'effet inverse.
Tu sais déjà. Lors de la mise à jour du vecteur de poids, si l'entrée est 0, le poids ne doit pas être mis à jour, et si l'entrée est 1, le poids doit être mis à jour. Étant donné que l'entrée n'est pas nécessairement 0 ou 1, vous pouvez simplement penser que la quantité de mises à jour du vecteur de poids est proportionnelle à cette entrée.
Autrement dit, par exemple, la quantité de mise à jour de l'indice 0 du vecteur de poids est
(y - o) * i_0
Ce sera. Oups, vous avez oublié d'inclure le coefficient d'apprentissage.
(y - o) * i_0 * eta
De quoi d'autres avez-vous besoin ... Rien de nécessaire! Lors de la mise à jour de w [0], ce sont toutes les valeurs à ajouter. Si vous ajoutez un point au nouveau w [0] et que vous l'exprimez dans la formule, il ressemblera à ceci.
\dot{w}_0 = w_0 + (y - o) * i_0 * eta
Définissons-le sur j afin qu'il puisse être utilisé même lorsque l'indice est différent de 0.
\dot{w}_j = w_j + (y - o) * i_j * eta
C'est la fin de la deuxième formule à retenir. Le reste est un jeu digestif où vous venez d'écrire le programme. Merci beaucoup.
Implémentons-le un par un. On suppose que python peut être lu. Tout d'abord, vous aviez besoin d'une fonction pour calculer le produit interne et d'une fonction d'étape.
dot.py
def dot(vec0,vec1):
tmp = 0
for i, j in zip(vec0,vec1):
tmp += i * j
return tmp
La fonction zip est une fonction qui rassemble deux listes. Cela place les éléments de la liste collée dans i et j depuis le début. Il suffit de les multiplier et de les additionner. N'oubliez pas la fonction zip car c'est pratique.
step.py
def step(num):
if num > 0:
return 1
else:
return 0
Définissons plus de sortie. Je l'ai nommé feedforward. Séparément, la sortie est également acceptable.
feedforward.py
def feedforward(i,w):
return step(dot(i,w))
Ensuite, c'est l'apprentissage. Souvenez-vous de cette formule.
\dot{w}_j = w_j + (y - o) * i_j * eta
Pour le moment, si vous n'écrivez que les arguments que prend la fonction, ce sera comme ça.
train.py
def train(w,i,y,eta):
pass
i et y sont des éléments de train_x et train_y. Bien que train_x et train_y soient des données d'enseignant, nous formerons chaque élément des données d'enseignant un par un. C'est ce qu'on appelle l'apprentissage en ligne, l'apprentissage séquentiel. Calculons o pour le moment.
train.py
def train(w,i,y,eta):
o = feedforward(i,w)
Puisqu'il est nécessaire de mettre à jour tous les w [j], activez l'instruction for.
train.py
def train(w,i,y,eta):
o = feedforward(i,w)
for j in range(len(w)):
w[j] = w[j] + (y - o) * i[j] * eta
return w
Préparez les données de l'enseignant, le vecteur de poids et le taux d'apprentissage ...
data.py
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
weight = [0,0,0]
eta = 0.1
Laissez les données des enseignants être apprises une par une ...
main.py
for x,y in zip(train_x,train_y):
weight = train(weight,x,y,eta)
Si vous le répétez plusieurs fois ... (Le nombre de répétitions est appelé époque)
main.py
epoch = 100
for i in range(epoch):
for x,y in zip(train_x,train_y):
weight = train(weight,x,y,eta)
Achevée!
simple_perceptron.py
#produit intérieur
def dot(vec0,vec1):
tmp = 0
for i, j in zip(vec0,vec1):
tmp += i * j
return tmp
#fonction d'étape
def step(num):
if num > 0:
return 1
else:
return 0
#production
def feedforward(i,w):
return step(dot(i,w))
#Apprentissage séquentiel
def train(w,i,y,eta):
o = feedforward(i,w)
for j in range(len(w)):
w[j] = w[j] + (y - o) * i[j] * eta
return w
#traitement principal,Apprenez et.
if __name__ == "__main__":
train_x = [[0,0,1],[0,1,1],[1,0,1],[1,1,1]]
train_y = [0,0,0,1]
weight = [0,0,0]
eta = 0.1
epoch = 100
for i in range(epoch):
for x,y in zip(train_x,train_y):
weight = train(weight,x,y,eta)
#Vérification,0,0,0,Ce n'est pas grave si 1 est sorti
for x in train_x:
print(feedforward(x,weight))
Les données d'entrée peuvent être un tableau de nombres, c'est-à-dire n'importe quel vecteur. Vous pouvez également reconnaître les nombres en convertissant les images manuscrites 0 et 1 en un tableau unidimensionnel (vecteur). La précision est subtile, mais ...
Recommended Posts