[PYTHON] Implémentez le Perceptron multicouche de manière très soignée

Qu'est-ce que c'est ça

J'ai eu la chance de gratter le Perceptron multicouche en Python, alors je vais le laisser.

Ce qui suit est un exemple où la somme logique exclusive (XOR) est entraînée avec un perceptron multicouche. Si vous n'êtes pas chanceux, l'apprentissage ne convergera pas, mais si vous le répétez, vous constaterez qu'il est fait correctement.

L'image de Perceptron reprise cette fois-ci est comme ça.

スクリーンショット 2019-10-30 15.17.18.png

C'est le programme actuel.

perceptron.py



import numpy as np

#Vectorisé(Traité pour chaque élément de la liste)Fonction Sigmaid
@np.vectorize
def sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))

# [0,0,0]Ou[[0,0,0]]Une liste du formulaire[[0],[0],[0]]Fonction de conversion au format


def verticalize(row):
    return np.reshape(row, (1, len(row)))


#Taux d'apprentissage
rho = 1
#Des données d'entrée
#Ces données épuisent tous les modèles d'entrée
x = np.array([[0, 0, -1], [0, 1, -1], [1, 0, -1], [1, 1, -1]])
#Données des enseignants
# 0,La sortie de 1 correspond à l'index
#Où 1 est la signification de l'étiquette de réponse correcte
y = np.array([[1, 0], [0, 1], [0, 1], [1, 0]])

#Déterminez le poids au hasard
w1 = np.random.randn(3, 2)
w2 = np.random.randn(3, 2)

#Cette fois, nous allons préparer deux neurones de couche de sortie et le réduire à un problème de classification à deux classes de savoir si la sortie est 0 ou 1.
#Cela permet d'appliquer des calculs généraux de perceptron multicouche.

#Si vous le répétez 50000 fois, il semble suffisamment converger, alors apprenons ce nombre de fois
for i in range(50000):
    # x(Des données d'entrée)Est m*matrice n.
    #Chaque ligne représente un élément de données et chaque colonne représente une fonctionnalité
    #Retirez une ligne à la fois et mettez à jour le poids(Apprentissage en ligne)
    for p in range(len(x)):
        #Changer x verticalement pour le calcul matriciel
        # [[x1], [x2], [b1]]Se sentir comme
        xp = verticalize(x[p])
        yp = y[p]
        #Le produit matriciel des données d'entrée et des poids de la couche d'entrée à la couche cachée passant par la fonction sigmoïde
        #Ce résultat est la valeur de sortie de chaque neurone dans la couche cachée
        g1 = sigmoid(xp @ w1)
        #Ajouter un terme de biais au résultat ci-dessus et organiser verticalement
        # [[h1],[h2],[b2]]Se sentir comme
        #Le terme de biais est toujours-Sortie 1
        g1 = verticalize(np.hstack((g1[0], [-1])))
        #Sortie de couche cachée+Sortie de biais et produit matriciel des poids de la couche de sortie à la couche cachée via la fonction sigmoïde
        #Ce résultat est la valeur de sortie de chaque neurone dans la couche de sortie
        g2 = sigmoid(g1 @ w2)
        #Calculer l'erreur de poids de la couche masquée à la couche de sortie par la méthode de propagation de retour d'erreur
        eps_out = (g2 - yp) * g2 * (1 - g2)
        #Calculer l'erreur de poids de la couche masquée à la couche d'entrée par la méthode de propagation de l'erreur de retour
        #Le terme de biais est mélangé dans le calcul, supprimez-le donc.
        eps_hidden = np.delete(np.sum(eps_out*w2, axis=1)*g1*(1 - g1), -1, 1)
        #Mise à jour du poids
        w2 -= rho * g1.T @ eps_out
        w1 -= rho * xp.T @ eps_hidden

#Vérifiez le résultat(Prévoir)
#Calculez seulement l'avant et voyez la valeur de sortie
for p in range(len(x)):
    xp = verticalize(x[p])
    yp = y[p]
    g1 = sigmoid(xp @ w1)
    g1 = verticalize(np.hstack((g1[0], [-1])))
    g2 = sigmoid(g1 @ w2)
    #Vérifiez la valeur de sortie de la couche de sortie
    print(g2[0])
    #Sortie de l'index avec la valeur la plus élevée dans la couche de sortie
    #J'ai appris à classer en fonction de l'index, cela peut donc déterminer la classe
    print(np.argmax(g2))

Les points sont la fonction sigmoïde vectorisée et l'opérateur @, qui équivaut à np.dot. Vous pouvez désormais l'implémenter proprement sans imbrication.

De plus, si vous modifiez la couche de poids de manière appropriée, je pense que vous pouvez obtenir de la polyvalence.

Je pense que cela semble assez bon.

Si vous omettez le commentaire, cela ressemble à ceci.

perceptron.py



import numpy as np

@np.vectorize
def sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))

def verticalize(row):
    return np.reshape(row, (1, len(row)))

rho = 1

x = np.array([[0, 0, -1], [0, 1, -1], [1, 0, -1], [1, 1, -1]])
y = np.array([[1, 0], [0, 1], [0, 1], [1, 0]])

w1 = np.random.randn(3, 2)
w2 = np.random.randn(3, 2)

for i in range(50000):
    for p in range(len(x)):
        xp = verticalize(x[p])
        yp = y[p]
        g1 = sigmoid(xp @ w1)
        g1 = verticalize(np.hstack((g1[0], [-1])))
        g2 = sigmoid(g1 @ w2)
        eps_out = (g2 - yp) * g2 * (1 - g2)
        eps_hidden = np.delete(np.sum(eps_out*w2, axis=1)*g1*(1 - g1), -1, 1)
        w2 -= rho * g1.T @ eps_out
        w1 -= rho * xp.T @ eps_hidden

for p in range(len(x)):
    xp = verticalize(x[p])
    yp = y[p]
    g1 = sigmoid(xp @ w1)
    g1 = verticalize(np.hstack((g1[0], [-1])))
    g2 = sigmoid(g1 @ w2)
    print(g2[0])
    print(np.argmax(g2))

Résumé

Utilisons scikit-learn! (Je ne peux pas dire ça parce que c'est un problème universitaire)

11/25 post-scriptum

J'ai également écrit quelque chose qui a été implémenté en tant que classe avec une polyvalence accrue, je vais donc l'ajouter! Votre perceptron multicouche est sale

Recommended Posts

Implémentez le Perceptron multicouche de manière très soignée
Visualisez la valeur limite du perceptron multicouche
Mettre en œuvre REPL
Votre Perceptron multicouche est sale