web-dev-qa-db-fra.com

La formation de réseau de neurones avec PyBrain ne convergera pas

J'ai le code suivant, tiré du didacticiel PyBrain:

from pybrain.datasets import SupervisedDataSet
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure.modules import TanhLayer

ds = SupervisedDataSet(2, 1)
ds.addSample((0,0), (0,))
ds.addSample((0,1), (1,))
ds.addSample((1,0), (1,))
ds.addSample((1,1), (0,))

net     = buildNetwork(2, 3, 1, bias=True, hiddenclass=TanhLayer)
trainer = BackpropTrainer(net, ds)

for inp, tar in ds:
     print [net.activate(inp), tar]

errors  = trainer.trainUntilConvergence()

for inp, tar in ds:
     print [net.activate(inp), tar]

Cependant, le résultat est un réseau de neurones mal formé. Lorsque le résultat d'erreur est affiché, le réseau est correctement formé, mais il utilise l'argument 'continueEpochs' pour en former davantage et le réseau fonctionne encore moins bien. Le réseau converge donc, mais il n’ya aucun moyen d’obtenir le réseau le mieux formé. La documentation de PyBrain implique que le réseau renvoyé est celui qui est le mieux formé, mais il renvoie un tuple d'erreurs.

Lorsque je termine continuEpochs sur 0, j'obtiens une erreur (ValueError: max () arg est une séquence vide), donc continueEpochs doit être supérieur à 0.

PyBrain est-il réellement maintenu car il semble qu'il existe une grande différence dans la documentation et le code. 

32
avanwieringen

Après avoir approfondi mes connaissances, j'ai trouvé que l'exemple du didacticiel de PyBrain était complètement déplacé.

Lorsque nous examinons la signature de la méthode dans le code source, nous trouvons:

def trainUntilConvergence(self, dataset=None, maxEpochs=None, verbose=None, continueEpochs=10, validationProportion=0.25):

Cela signifie que 25% de l'ensemble de formation est utilisé pour la validation. Bien que ce soit une méthode très valable pour former un réseau sur des données, vous ne le ferez pas si vous disposez de toutes les possibilités, à savoir une solution à 4 rangées XOR à deux entrées. ensemble. Lorsque vous souhaitez former un ensemble XOR et que vous supprimez une des lignes pour la validation, cela a pour conséquence immédiate d'obtenir un ensemble d'apprentissage très clairsemé dans lequel l'une des combinaisons possibles est omise, ce qui entraîne automatiquement la non-pondération qualifié.

Normalement, lorsque vous omettez 25% des données pour la validation, vous procédez ainsi en supposant que ces 25% couvrent "la plupart" de l'espace de solution déjà plus ou moins rencontré par le réseau. Dans ce cas, cela n’est pas vrai et couvre 25% de l’espace de la solution complètement inconnu du réseau puisque vous l’avez retiré pour validation.

Ainsi, le formateur entraînait correctement le réseau, mais en supprimant 25% du problème XOR, il en résulte un réseau mal formé.

Un exemple différent sur le site Web PyBrain en tant que quickstart serait très pratique, car cet exemple est tout simplement faux dans ce cas particulier XOR. Vous pourriez vous demander s'ils ont eux-mêmes essayé l'exemple, car il ne génère que des réseaux aléatoires mal entraînés.

35
avanwieringen

J'ai suivi l'excellente classe Machine Learning de Coursera , enseignée par Andrew Ng, et une partie de la classe a consisté à former un petit réseau neuronal pour reconnaître xor. Je suis donc un peu troublé par l'exemple pybrain basé sur des parties du quickstart qui ne convergent pas.

Je pense qu'il y a de nombreuses raisons, y compris celle ci-dessus concernant le jeu de données minimal divisé en formation et validation. À un moment donné, Andrew a déclaré: "Ce n'est pas la personne qui a le meilleur algorithme qui gagne, mais celle qui contient le plus de données. Il a ensuite expliqué que l'explosion de la disponibilité des données dans les années 2000 était l'une des raisons de la résurgence de l'intelligence artificielle, maintenant appelée apprentissage machine.

Donc, avec tout cela à l'esprit, j'ai trouvé que

  1. le jeu de validation peut avoir 4 échantillons, car cela vient après la phase de formation.
  2. le réseau n'a besoin que de 2 nœuds dans la couche cachée, comme je l'ai appris en classe,
  3. dans ce cas, le taux d’apprentissage doit être assez faible, comme 0,005, sinon la formation omettra parfois la réponse (c’est un point important de la classe que j’ai confirmé en jouant avec les chiffres).
  4. plus le taux d'apprentissage est petit, plus les maxEpochs peuvent être petits. Un faible taux d'apprentissage signifie que la convergence effectue de plus petites étapes le long du gradient vers la minimisation. Si sa taille est plus grande, vous avez besoin d'un plus grand maxEpochs afin qu'il attende plus longtemps avant de décider qu'il a atteint un minimum.
  5. Vous avez besoin d'un biais = True sur le réseau (qui ajoute un nœud constant à la couche d'entrée et aux couches masquées). Lisez les réponses à cette question sur les préjugés.
  6. Enfin, et le plus important, vous avez besoin d’un grand ensemble d’entraînement. 1000 ont convergé vers la bonne réponse environ 75% du temps. Je soupçonne que cela a à voir avec l'algorithme de minimisation. Des nombres plus petits échoueraient fréquemment.

Alors, voici un code qui fonctionne:

from pybrain.datasets import SupervisedDataSet

dataModel = [
    [(0,0), (0,)],
    [(0,1), (1,)],
    [(1,0), (1,)],
    [(1,1), (0,)],
]

ds = SupervisedDataSet(2, 1)
for input, target in dataModel:
    ds.addSample(input, target)

# create a large random data set
import random
random.seed()
trainingSet = SupervisedDataSet(2, 1);
for ri in range(0,1000):
    input,target = dataModel[random.getrandbits(2)];
    trainingSet.addSample(input, target)

from pybrain.tools.shortcuts import buildNetwork
net = buildNetwork(2, 2, 1, bias=True)

from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(net, ds, learningrate = 0.001, momentum = 0.99)
trainer.trainUntilConvergence(verbose=True,
                              trainingData=trainingSet,
                              validationData=ds,
                              maxEpochs=10)

print '0,0->', net.activate([0,0])
print '0,1->', net.activate([0,1])
print '1,0->', net.activate([1,0])
print '1,1->', net.activate([1,1])
17
toddInPortland
trainer = BackpropTrainer(net, ds, learningrate = 0.9, momentum=0.0, weightdecay=0.0, verbose=True) 
trainer.trainEpochs(epochs=1000)

Cette façon peut converger. Si le taux d'apprentissage est trop petit (par exemple 0,01), il a perdu au minimum local. Comme je l’ai testé, le taux d’apprentissage en 0,3-30 peut converger.

2
lym

Ce qui suit semble donner systématiquement les bons résultats:

from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure import TanhLayer
from pybrain.datasets import SupervisedDataSet
from pybrain.supervised.trainers import BackpropTrainer

#net = buildNetwork(2, 3, 1, bias=True, hiddenclass=TanhLayer)
net = buildNetwork(2, 3, 1, bias=True)

ds = SupervisedDataSet(2, 1)
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))

trainer = BackpropTrainer(net, ds, learningrate=0.001, momentum=0.99)

trainer.trainUntilConvergence(verbose=True)

print net.activate([0,0])
print net.activate([0,1])
print net.activate([1,0])
print net.activate([1,1])
0
bkanber