Theano - Exemple de formation trivial

Theano est très utile dans la formation de réseaux de neurones où nous devons calculer à plusieurs reprises le coût et les gradients pour atteindre un optimum. Sur les grands ensembles de données, cela devient intensif en calcul. Theano le fait efficacement grâce à ses optimisations internes du graphe de calcul que nous avons vu précédemment.

Énoncé du problème

Nous allons maintenant apprendre à utiliser la bibliothèque Theano pour former un réseau. Nous allons prendre un cas simple où nous commençons avec un jeu de données à quatre entités. Nous calculons la somme de ces caractéristiques après avoir appliqué un certain poids (importance) à chaque caractéristique.

Le but de la formation est de modifier les pondérations attribuées à chaque fonctionnalité afin que la somme atteigne une valeur cible de 100.

sum = f1 * w1 + f2 * w2 + f3 * w3 + f4 * w4

f1, f2, ... sont les valeurs des caractéristiques et w1, w2, ... sont les poids.

Permettez-moi de quantifier l'exemple pour une meilleure compréhension de l'énoncé du problème. Nous supposerons une valeur initiale de 1,0 pour chaque fonctionnalité et nous prendrons w1 égal0.1, w2 équivaut à 0.25, w3 équivaut à 0.15, et w4 équivaut à 0.3. Il n'y a pas de logique définie dans l'attribution des valeurs de poids, c'est juste notre intuition. Ainsi, la somme initiale est la suivante -

sum = 1.0 * 0.1 + 1.0 * 0.25 + 1.0 * 0.15 + 1.0 * 0.3

Qui somme à 0.8. Maintenant, nous allons continuer à modifier l'affectation de poids pour que cette somme approche 100. La valeur résultante actuelle de0.8 est loin de la valeur cible souhaitée de 100. En termes d'apprentissage automatique, nous définissons costcomme la différence entre la valeur cible moins la valeur de sortie actuelle, généralement au carré pour faire exploser l'erreur. Nous réduisons ce coût à chaque itération en calculant les gradients et en mettant à jour notre vecteur de poids.

Voyons comment toute cette logique est implémentée dans Theano.

Déclaration de variables

Nous déclarons d'abord notre vecteur d'entrée x comme suit -

x = tensor.fvector('x')

x est un tableau unidimensionnel de valeurs flottantes.

Nous définissons un scalaire target variable comme indiqué ci-dessous -

target = tensor.fscalar('target')

Ensuite, nous créons un tenseur de poids W avec les valeurs initiales décrites ci-dessus -

W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')

Définition de l'expression Theano

Nous calculons maintenant la sortie en utilisant l'expression suivante -

y = (x * W).sum()

Notez que dans la déclaration ci-dessus x et Wsont les vecteurs et non de simples variables scalaires. Nous calculons maintenant l'erreur (coût) avec l'expression suivante -

cost = tensor.sqr(target - y)

Le coût est la différence entre la valeur cible et la sortie de courant, au carré.

Pour calculer le gradient qui nous indique à quelle distance nous sommes de la cible, nous utilisons la fonction intégrée grad méthode comme suit -

gradients = tensor.grad(cost, [W])

Nous mettons maintenant à jour le weights vecteur en prenant un taux d'apprentissage de 0.1 comme suit -

W_updated = W - (0.1 * gradients[0])

Ensuite, nous devons mettre à jour notre vecteur de poids en utilisant les valeurs ci-dessus. Nous faisons cela dans la déclaration suivante -

updates = [(W, W_updated)]

Définition / appel de la fonction Theano

Enfin, nous définissons un function dans Theano pour calculer la somme.

f = function([x, target], y, updates=updates)

Pour invoquer la fonction ci-dessus un certain nombre de fois, nous créons un for boucle comme suit -

for i in range(10):
output = f([1.0, 1.0, 1.0, 1.0], 100.0)

Comme indiqué précédemment, l'entrée de la fonction est un vecteur contenant les valeurs initiales des quatre caractéristiques - nous attribuons la valeur de 1.0à chaque fonctionnalité sans aucune raison spécifique. Vous pouvez attribuer différentes valeurs de votre choix et vérifier si la fonction converge finalement. Nous imprimerons les valeurs du vecteur de poids et la sortie correspondante à chaque itération. Il est indiqué dans le code ci-dessous -

print ("iteration: ", i)
print ("Modified Weights: ", W.get_value())
print ("Output: ", output)

Liste complète du programme

La liste complète du programme est reproduite ici pour votre référence rapide -

from theano import *
import numpy

x = tensor.fvector('x')
target = tensor.fscalar('target')

W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
print ("Weights: ", W.get_value())

y = (x * W).sum()
cost = tensor.sqr(target - y)
gradients = tensor.grad(cost, [W])
W_updated = W - (0.1 * gradients[0])
updates = [(W, W_updated)]

f = function([x, target], y, updates=updates)
for i in range(10):
   output = f([1.0, 1.0, 1.0, 1.0], 100.0)
   print ("iteration: ", i)
   print ("Modified Weights: ", W.get_value())
   print ("Output: ", output)

Lorsque vous exécutez le programme, vous verrez la sortie suivante -

Weights: [0.1 0.25 0.15 0.3 ]
iteration: 0
Modified Weights: [19.94 20.09 19.99 20.14]
Output: 0.8
iteration: 1
Modified Weights: [23.908 24.058 23.958 24.108]
Output: 80.16000000000001
iteration: 2
Modified Weights: [24.7016 24.8516 24.7516 24.9016]
Output: 96.03200000000001
iteration: 3
Modified Weights: [24.86032 25.01032 24.91032 25.06032]
Output: 99.2064
iteration: 4
Modified Weights: [24.892064 25.042064 24.942064 25.092064]
Output: 99.84128
iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]
Output: 99.968256
iteration: 6
Modified Weights: [24.89968256 25.04968256 24.94968256 25.09968256]
Output: 99.9936512
iteration: 7
Modified Weights: [24.89993651 25.04993651 24.94993651 25.09993651]
Output: 99.99873024
iteration: 8
Modified Weights: [24.8999873 25.0499873 24.9499873 25.0999873]
Output: 99.99974604799999
iteration: 9
Modified Weights: [24.89999746 25.04999746 24.94999746 25.09999746]
Output: 99.99994920960002

Observez qu'après quatre itérations, la sortie est 99.96 et après cinq itérations, c'est 99.99, qui est proche de notre objectif souhaité de 100.0.

En fonction de la précision souhaitée, vous pouvez conclure en toute sécurité que le réseau est formé en 4 à 5 itérations. Une fois la formation terminée, recherchez le vecteur de poids, qui, après 5 itérations, prend les valeurs suivantes -

iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]

Vous pouvez maintenant utiliser ces valeurs dans votre réseau pour déployer le modèle.