Introduction à Tensorflow
J’avais un formidable logiciel de réseau de neurones amusant dans les années 90, et je suis impatient d’essayer de créer des utilisateurs de Tensorflow.
Le cadre de l’intelligence de la machine de Google est la nouvelle hotness actuellement. Et lorsque Tensorflow est devenu installable sur le PI de framboise, il est devenu très facile à faire. Dans peu de temps, j’ai fait un réseau de neurones qui comptent en binaire. Donc, j’ai pensé que je transmettais ce que j’ai appris jusqu’à présent. Espérons que cela facilite la tâche de quiconque qui veut l’essayer, ou pour quiconque veut simplement avoir un aperçu des réseaux de neurones.
Qu’est-ce que tensorflow?
Pour citer le site Web Tensorflow, Tensorflow est une “bibliothèque logicielle open source pour calcul numérique à l’aide de graphiques de flux de données”. Qu’entendons-nous par «graphiques de flux de données»? Eh bien, c’est la partie vraiment étonnante. Mais avant de pouvoir répondre à cela, nous devrons parler un peu de la structure d’un réseau de neurones simple.
Réseau binaire du compteur neuronal
Principes de base d’un réseau de neurones
Un réseau de neurones simple comporte certaines unités d’entrée dans lesquelles l’entrée va. Il a également des unités cachées, appelées par rapport à la perspective d’un utilisateur, ils sont littéralement cachés. Et il y a des unités de sortie, à partir desquelles nous obtenons les résultats. Les unités de biais sont également activées pour aider à contrôler les valeurs émises par les unités cachées et de sortie. Connexion Toutes ces unités sont un tas de poids, qui ne sont que des chiffres, chacun d’eux associé à deux unités.
La façon dont nous instillons intelligence dans ce réseau de neurones est d’attribuer des valeurs à tous ces poids. C’est ce que la formation d’un réseau de neurones, trouve des valeurs appropriées pour ces poids. Une fois formé, dans notre exemple, nous allons définir les unités d’entrée aux chiffres binaires 0, 0 et 0 respectivement, Tensorflow fera des trucs avec tout entre les deux et les unités de sortie contiennent comme par magie les chiffres binaires 0, 0 et 1 respectivement. Si vous avez manqué cela, il savait que le numéro suivant après 000 000 binaires était 001. Pour 001, il devrait cracher 010, et ainsi de suite jusqu’à 111, dans lequel cela va cracher 000. Une fois que ces poids sont fixés de manière appropriée, il “Je vais savoir compter.
Réseau binaire du réseau neuronal avec matrices
Une étape de “course” Le réseau neuronal est de multiplier la valeur de chaque poids par la valeur de son unité d’entrée, puis de stocker le résultat dans l’unité cachée associée.
Nous pouvons redessiner les unités et les poids en tant que tableaux ou quelles sont appelées listes dans Python. D’un point de vue des mathématiques, ils sont des matrices. Nous avons redessiné une seule partie dans le diagramme. Multiplier la matrice d’entrée avec la matrice de poids implique une simple multiplication matricielle, ce qui entraîne la matrice / la liste / la matrice cachée de cinq éléments.
Des matrices aux tenseurs
Dans TENSORFLOW, ces listes sont appelées tenseurs. Et la phase de multiplication matricielle est appelée une opération ou OP dans programmeur-parler, un terme que vous devrez vous utiliser si vous envisagez de lire la documentation Tensorflow. Le prenant plus loin, l’ensemble du réseau neuronal est une collection de tenseurs et des OP qui les utilisent. Au total, ils constituent un graphique.
Graphique complet du compteur binaire
couche1 expansée
Montré ici sont des instantanés pris de tensorboard, un outil permettant de visualiser le graphique et d’examiner les valeurs de tenseur pendant et après la formation. Les tenseurs sont les lignes et écrites sur les lignes sont les dimensions du tenseur. Connexion des tenseurs sont toutes les ops, bien que certaines des choses que vous voyez puissent être touchées à deux reprises afin de développer plus de détails, comme nous l’avons fait pour la couche1 dans le deuxième instantané.
Au fond est X, le nom que nous avons donné pour un OP d’espace réservé qui nous permet de fournir des valeurs pour le tenseur d’entrée. La ligne montante et à gauche de ce fait est le tenseur d’entrée. Continuez à suivre cette ligne et vous trouverez le MATMUL OP, qui fait la multiplication matricielle avec ce tenseur d’entrée et le tenseur qui est l’autre ligne menant à la MATMUL OP. Ce tenseur représente les poids.
Tout cela était juste pour vous donner une idée de ce qu’est un graphique et de ses tenseurs et de ses opérateurs, vous donnez une meilleure idée de ce que nous entendons par Tensorflow étant une “bibliothèque logicielle pour calcul numérique à l’aide de graphiques de flux de données”. Mais pourquoi nous voudrions créer ces graphiques?
Pourquoi créer des graphiques?
L’API qui est actuellement stable en est un pour Python, une langue interprétée. Les réseaux de neurones sont calculés intensives et un grand peut avoir des milliers de poids ou même des millions de poids. L’informatique en interprétant chaque étape prendrait pour toujours.
Nous créons donc plutôt un graphique composé de tenseurs et de OP, décrivant la disposition du réseau neuronal, toutes les opérations mathématiques et même les valeurs initiales pour les variables. Ce n’est qu’après que nous avons créé ce graphique, nous le transmettons ensuite à ce que Tensorflow appelle une session. Ceci est connu comme exécution différée. La session exécute le graphique en utilisant un code très efficace. Non seulement cela, mais bon nombre des opérations, telles que la multiplication de matrice, sont celles qui peuvent être effectuées sur une GPU prise en charge (unité de traitement graphique) et la session le fera pour vous. Aussi, tensorflow est bUilt pour pouvoir distribuer le traitement sur plusieurs machines et / ou GPU. Donner le graphique complet lui permet de le faire.
Créer le compteur binaire
Et voici le code de notre réseau de neurones binaires. Vous pouvez trouver le code source complet sur cette page GITUB. Notez qu’il y a un code supplémentaire dans celui-ci pour économiser des informations à utiliser avec Tensorboard.
Nous allons commencer par le code de la création du graphique des tenseurs et des ops.
importer tensorflow comme TF
sess = tf.interactiveession ()
Num_inputs = 3
Num_Check = 5
Num_outputts = 3
Nous importatons d’abord le module TensorFlow, créez une session à utiliser ultérieurement et, pour rendre notre code plus compréhensible, nous créons quelques variables contenant le nombre d’unités de notre réseau.
x = TF.PLacder (TF.FLOAT32, SHAPE = [NONE, NUM_Inputs], Nom = ‘x’)
Y_ = TF.PLacder (tf.float32, forme = [aucune, num_outputts], nom = ‘y_’)
Ensuite, nous créons des espaces réservés pour nos unités d’entrée et de sortie. Un espace réservé est un Tensorflow op pour des choses que nous fournirons des valeurs plus tard. X et Y_ sont maintenant des tenseurs dans un nouveau graphique et chacun a un espace de service associé à celui-ci.
Vous pouvez vous demander pourquoi nous définissons les formes comme [aucun, NUM_Inputs] et [Aucun, NUM_OutPUTS], deux listes dimensionnelles et pourquoi aucune pour la première dimension? Dans la vue d’ensemble des réseaux de neurones au-dessus, on dirait que nous lui donnerons une entrée à la fois et la former pour produire une sortie donnée. C’est plus efficace cependant, si nous lui donnons plusieurs paires d’entrée / sortie à la fois, ce qu’on appelle un lot. La première dimension concerne le nombre de paires d’entrée / sortie dans chaque lot. Nous ne saurons pas combien y a-t-il d’un lot jusqu’à ce que nous en donnions une plus tard. Et en fait, nous utilisons le même graphique pour la formation, les tests et pour l’utilisation réelle de sorte que la taille du lot ne soit pas toujours la même. Nous utilisons donc l’objet Python Placeholder Aucun pour la taille de la première dimension pour l’instant.
W_fc1 = tf.trunated_normal ([Num_Inputs, Num_Hésdités], moyenne = 0.5, stddev = 0,707)
W_fc1 = tf.variable (w_fc1, nom = ‘w_fc1’)
B_FC1 = TF.TRONCATED_NORMAL ([NUM_HÉDITS], moyenne = 0,5, STDDEV = 0.707)
B_FC1 = TF.VARIABLE (B_FC1, NOM = ‘B_FC1’)
h_fc1 = tf.nn.relu (tf.matmul (x, w_fc1) + b_fc1)
C’est suivi de la création d’une couche une couche du graphique de réseau neuronal: les poids w_fc1, les biais B_FC1 et les unités cachées H_FC1. Le “FC” est une convention signifiant “complètement connecté”, car les poids relient chaque unité d’entrée à chaque unité cachée.
TF.TRONCÉD_NORMAL résulte dans un certain nombre d’ops et de tenseurs qui assigneront plus tard des nombres aléatoires normalisés à tous les poids.
Les ops variables reçoivent une valeur d’initialisation avec des nombres aléatoires dans ce cas et de conserver leurs données sur plusieurs pistes. Ils sont également utiles pour sauver le réseau de neurones dans un fichier, quelque chose que vous voudrez faire une fois que cela est formé.
Vous pouvez voir où nous allons effectuer la multiplication de matrice en utilisant le MATMUL OP. Nous insérons également un ADD OP qui ajoutera sur les poids de biais. Le relu OP exécute ce que nous appelons une fonction d’activation. La multiplication de matrice et l’addition sont des opérations linéaires. Il y a un nombre très limité de choses qu’un réseau de neurones peut apprendre à utiliser uniquement des opérations linéaires. La fonction d’activation fournit une certaine non-linéarité. Dans le cas de la fonction d’activation relatives, il définit toutes les valeurs inférieures à zéro à zéro et toutes les autres valeurs sont laissées inchangées. Croyez-le ou non, faire cela ouvre un tout autre monde de choses qui peuvent être apprises.
W_fc2 = tf.trunated_ormal ([Num_Chorid, Num_outPutts], moyenne = 0.5, stddev = 0.707)
W_fc2 = tf.variable (w_fc2, nom = ‘w_fc2’)
b_fc2 = tf.trunated_normal ([Num_Outputts], moyenne = 0,5, stddev = 0,707)
B_FC2 = TF.VARIABLE (B_FC2, NOM = ‘B_FC2’)
y = tf.matmul (h_fc1, w_fc2) + b_fc2
Les poids et les biais pour la couche deux sont configurés de la même manière que pour la couche une mais la couche de sortie est différente. Nous ferons une fois une multiplication matricielle, cette fois multipliant les poids et les unités cachées, puis en ajoutant les poids de biais. Nous avons laissé la fonction d’activation pour le prochain bit de code.
Résultats = tf.sigmoid (y, nom = ‘Résultats’)
cross_entropy = tf.reduce_mean (
tf.nn.sigmoid_cross_tropy_with_logits (logits = y, étiquettes = y_))
Sigmoid est une autre fonction d’activation, comme le relu que nous avons rencontré ci-dessus, il faut fournir une non-linéarité. J’ai utilisé Sigmoid ici en partie parce que l’équation SIGMOID entraîne des valeurs comprises entre 0 et 1, idéal pour notre exemple binaire exemple. Je l’ai également utilisé car il est bon pour les sorties où plus d’une unité de sortie peut avoir une valeur importante. Dans notre cas, représenter le numéro binaire 111, toutes les unités de sortie peuvent avoir de grandes valeurs. Lorsque vous effectuez une classification de l’image, nous voudrions quelque chose de tout à fait différent, nous voudrions qu’une seule unité de sortie se déclenche avec une valeur importante. Par exemple, nous voudrions que l’unité de sortie représentant des girafes ait une valeur importante si une image contient une girafe. Quelque chose comme SoftMax serait un bon choix pour la classification de l’image.
En cas d’inspection étroite, il semble qu’il y a quelques duplications. Nous semblons insérer deux fois sigmoïde. Nous créons réellement deux différents, parallèlement ousput ici. Le tenseur Cross_entropy sera utilisé lors de la formation du réseau neutre. Le tenseur des résultats sera utilisé lorsque nous exécutons notre réseau de neurones entraînés ultérieurement pour un but créé, pour vous amuser dans notre cas. Je ne sais pas si c’est la meilleure façon de le faire, mais c’est comme ça que je suis venu.
Train_step = tf.train.rmspropoptimizer (0,25, Momentum = 0.5) .Minimize (cross_entropy)
La dernière pièce que nous ajoutons à notre graphique est la formation. C’est l’OP ou les OP qui ajusteront tous les poids en fonction des données de formation. N’oubliez pas que nous créons toujours un graphique ici. La formation réelle se produira plus tard lorsque nous exécutons le graphique.
Il y a quelques optimiseurs à choisir. J’ai choisi tf.train.rmspropoptimizer car, comme le sigmoïde, cela fonctionne bien pour les cas où toutes les valeurs de sortie peuvent être grandes. Pour classer les choses comme lors de la classification de l’image, tf.train.graientdescentoptimizer pourrait être mieux.
Formation et utilisation du compteur binaire
Après avoir créé le graphique, il est temps de faire la formation. Une fois que c’est formé, nous pouvons ensuite l’utiliser.
INPUTVALS = [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1] ,
[1, 1, 0], [1, 1, 1]]
Targevals = [[0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0] ,
[1, 1, 1], [0, 0, 0]]]
Premièrement, nous avons quelques données de formation: INTERVENVALS ET TARGEVALS. Les INTERVALS contiennent les entrées et pour chacun une valeur cible ciblée correspondante. Pour INTERVALES [0], nous avons [0, 0, 0] et la sortie attendue est des citadres [0], qui est [0, 0, 1], etc.
Si do_training == 1:
sess.run (tf.global_variables_initialiszer ())
Pour i à portée (10001):
Si je% 100 == 0:
Train_Error = cross_entropy.val (feed_dict = {x: INTERPORTVALS, Y_: Targevals})
Imprimer (“Étape% D, erreur de formation% g”% (i, train_error))
Si Train_Error <0,0005:
Pause
sess.run (train_step, feed_dict = {x: INTERPORTVALS, Y_: Targevals})
Si save_trained == 1:
Imprimer ("Sauver le réseau neural à% s. *"% (sauvegarde_file))
Saver = tf.train.saver ()
Saver.Save (sess, sauvegarde_file)
do_training and Save_trained peut être codé en couleur et modifié pour chaque utilisation, ou peut être défini à l'aide d'arguments de la ligne de commande.
Nous traversons d'abord toutes ces variables ops et avons-nous d'initialiser leurs tenseurs.
Ensuite, pour un maximum de 10001 fois, nous exécutons le graphique à partir du bas jusqu'à la tenseur Train_step, la dernière chose que nous avons ajoutée à notre graphique. Nous passons des entrées et des citadvales à Train_step's OP ou OPS, que nous avions ajouté à l'aide de RMSPropTimizer. C'est l'étape qui ajuste tous les poids tels que les entrées données entraînent quelque chose près des sorties cibles correspondantes. Si l'erreur entre les sorties cible et les sorties réelles devient suffisamment petite tôt, alors nous sortons de la boucle.
Si vous avez des milliers de paires d'entrée / sortie, vous pouvez lui donner un sous-ensemble à une époque, le lot que nous avons parlé plus tôt. Mais ici, nous n'avons que huit ans et nous les donnons donc à chaque fois.
Si nous voulons, nous pouvons également enregistrer le réseau à un fichier. Une fois que cela a bien entraîné, nous n'avons pas besoin de la former à nouveau.
Sinon: # Si nous ne nous entraînons pas, nous devons être en cours de chargement à partir de fichier
print("Loading neural network from %s"%(save_file))
saver = tf.train.Saver()
saver.restore(sess, save_file)
# Remarque: la restauration est à la fois chargée et initialise les variables
If we’re not training it then we instead load the trained network from a file. The file contains only the values for the tensors that have Variable ops. It doesn’t contain the structure of the graph. So even when running an already trained graph, we still need the code to create the graph. There is a way to save and load graphs from files using MetaGraphs but we’re not doing that here.
print('\nCounting starting with: 0 0 0')
res = sess.run(results, feed_dict={x: [[0, 0, 0]]})
print('%g %g %g'%(res[0][0], res[0][1], res[0][2]))