Cela fait un mois que TensorFlow est sorti, et je me sens déjà en retard, mais je l'ai d'abord traduit pour essayer le tutoriel pour débutants "MNIST For ML Beginners". Cependant, soyez prudent lorsque vous y faites référence car il y a de fortes chances que la traduction soit incorrecte. Je vous serais reconnaissant de bien vouloir signaler toute erreur.
Traduit par: MNIST For ML Beginners
Ce didacticiel est destiné aux lecteurs qui découvrent à la fois l'apprentissage automatique et TensorFlow. Si vous savez déjà ce qu'est MNIST et ce qu'est la régression softmax (logistique multi-termes), vous devriez faire un autre tutoriel.
Lorsque vous apprenez à programmer, la première chose que vous faites généralement est d'imprimer «Hello World». L'apprentissage automatique a MNIST, tout comme la programmation a Hello World.
MNIST est un simple jeu de données de vision par ordinateur. L'ensemble de données se compose des images numériques manuscrites suivantes.
(Figure)
De plus, chaque image contient une étiquette dont il s'agit. Par exemple, l'étiquette de l'image ci-dessus est 5, 0, 4, 1.
Dans ce didacticiel, nous entraînons un modèle qui inspecte les images et prédit leurs nombres. Notre objectif n'est pas vraiment de former des modèles complexes pour obtenir des performances de pointe (mais nous vous fournirons ce code plus tard!), Mais plutôt d'essayer TensorFlow. Ainsi, nous commençons avec un modèle très simple appelé régression Softmax.
Le code réel de ce tutoriel est très court et toutes les choses intéressantes se produisent en seulement trois lignes. Cependant, il est très important de comprendre l'idée derrière cela. C'est à la fois le fonctionnement de TensorFlow et le cœur du concept d'apprentissage automatique. Pour cette raison, nous sommes très prudents et utiles tout au long du code.
Les données MNIST sont fournies sur le site Web de Yann LeCun. Pour votre commodité, nous avons inclus du code Python qui télécharge et installe automatiquement les données. Vous pouvez télécharger ce code et l'importer comme suit, ou simplement Vous pouvez copier et coller dans. (Remarque: copier et coller signifie que vous pouvez coller et utiliser dans le même fichier sans télécharger input_data.py lié ci-dessus et l'importer dans un fichier séparé.)
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
Ces données téléchargées sont divisées en deux parties: 60 000 données d'entraînement (mnist.train) et 10 000 données de test (mnist.test). Cette division est très importante. Les données divisées que nous n'apprenons pas sont essentielles dans l'apprentissage automatique afin que nous puissions voir ce que nous avons réellement appris en général! (Remarque: la traduction est suspecte ici. Peut-être que je veux dire qu'en plus des données d'entraînement utilisées pour l'entraînement, les données de test non utilisées pour l'entraînement sont indispensables ...)
Comme mentionné au début, chaque point de données MNIST comprend deux parties, une image numérique manuscrite et une étiquette associée. Nous appellerons l'image "xs" et l'étiquette "ys". Les ensembles d'entraînement et les ensembles de tests (note: probablement mnist.train et mnist.test) incluent xs et ys. Par exemple, les images des données d'entraînement sont mnist.train.images et les étiquettes des données d'entraînement sont mnist.train.labels.
Chaque image fait 28x28 pixels. Nous pouvons interpréter cela comme un tableau de grands nombres.
(Figure)
Nous pouvons étendre cette séquence à un vecteur de nombres 28x28 = 784. Peu importe la façon dont nous étirons la séquence si nous sommes cohérents entre les images. De ce point de vue, l'image MNIST n'est qu'une structure très riche (Attention: visualisation informatique intensive ) Est un grand nombre de points dans l'espace vectoriel à 784 dimensions.
L'étirement des données jette des informations sur la structure bidimensionnelle de l'image. Est-ce une mauvaise chose? C'est la meilleure méthode de vision par ordinateur pour tirer parti de cette structure dans les didacticiels suivants. (Remarque: la traduction est suspecte.) Mais la méthode simple que nous utilisons ici est la régression softmax, pas elle.
Le résultat de mnist.train.images est un tenseur (tableau à n dimensions) de la forme [60000, 784]. La première dimension (60000) représente l'image et la seconde dimension (784) représente les pixels de chaque image. Chaque élément du tenseur a une intensité de pixel comprise entre 0 et 1 et est un pixel particulier dans une image particulière.
(Figure)
L'étiquette correspondante dans MNIST est décrite comme un nombre donné à l'image, qui est un nombre de 0 à 9. Pour les besoins de ce didacticiel, nous voulons que notre étiquette soit "un vecteur chaud". Un vecteur chaud est un vecteur de 0 dans plusieurs dimensions et de 1 dans une dimension. (Remarque: il n'y a qu'un seul 1 dans le vecteur décrit plus loin.) Dans ce cas, le nième nombre est représenté comme un vecteur à n dimensions. Par exemple, 3 est [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]. Par conséquent, mnist.train.labels est une séquence de type float [60000, 10]. (Remarque: il y a 60000 28x28 = 784 images entraînées, qui sont représentées par [60000, 784] dans mnist.train.images, et ces images sont numérotées de 0 à 9, donc mnist.train.labels est Il est représenté par [60000, 10].)
(Figure)
Nous sommes maintenant prêts à fabriquer notre modèle!
Nous savons que toutes les images dans MNIST sont des nombres, 0 ou 9. Nous voulons trouver l'image et donner une probabilité de son nombre. Par exemple, notre modèle recherche une image de 9, et nous sommes sûrs que c'est 9 sur 80%, mais cela nous donne 5% de chances d'être 8 (à cause de la boucle supérieure), et certainement Parce que ce n'est pas le cas, cela donne une petite chance de devenir un autre.
C'est le cas classique où la régression Softmax est un modèle naturel et simple. Si vous souhaitez attribuer des probabilités à l'une des différentes choses, Softmax est fait pour cela. Plus tard, alors que nous formons des modèles plus sophistiqués, la dernière étape sera la couche Softmax.
La régression Softmax comporte deux étapes. Premièrement, nous augmentons la preuve de notre entrée, qui est une classe solide, et nous transformons la preuve en probabilités.
La somme des preuves données dans l'image est dans une classe particulière (Note: les nombres 0-9) et nous pondérons la somme des intensités de pixels. Le poids est négatif si l'image de la classe a un pixel de haute intensité qui est la preuve opposée, et positif si c'est la preuve de soutien.
La figure ci-dessous montre le poids d'un modèle formé pour chaque classe. Le rouge représente un poids négatif et le bleu un poids positif.
(Figure)
Nous ajoutons également des preuves supplémentaires appelées biais. Fondamentalement, nous voulons pouvoir dire que quelque chose n'a rien à voir avec l'entrée. La preuve pour la classe $ i $ est le résultat donné à l'entrée $ x $.
evidence_i = \sum_{j} W_{i,j} x_j + b_i
$ W_i $ est le poids, $ b_i $ est le biais pour la classe $ i $, et $ j $ est l'indice du nombre total de pixels dans l'image d'entrée $ x $. Nous utilisons ensuite la fonction Softmax pour convertir notre probabilité prédite $ y $ à partir de la somme des preuves.
y = softmax(evidence)
Ce softmax sert de "fonction d'activation" ou de "fonction de liaison", façonnant la sortie de notre fonction linéaire dans la forme que nous voulons. Dans ce cas, il s'agit d'une distribution de probabilité sur 10 cas. Vous pouvez considérer cela comme la conversion de la somme des preuves en probabilité de notre entrée pour chaque classe. Il est défini comme suit.
softmax(x) = normalize(exp(x))
Si vous étendez cette formule, vous obtenez:
softmax(x)_i = \frac {exp(x_i)} {\sum_{j} exp(x_j)}
Mais cela aide souvent à penser à la première méthode, Softmax. Il s'agit de multiplier l'entrée puis de la normaliser. Powering signifie une autre unité de preuve qui amplifie et augmente le poids donné à une hypothèse. Et d'un autre côté, la réduction d'une unité de preuve signifie que l'hypothèse prend rapidement du poids. Aucune des hypothèses n'a de poids nul ou négatif. Softmax normalise ensuite ces poids, les additionnant en un seul, le transformant en une distribution de probabilité valide. (Pour obtenir une connaissance plus intuitive des fonctions softmax, consultez la section du livre de Michael Nieslen avec visualisation bidirectionnelle. Simplement fais-le.
Vous pouvez considérer la régression Softmax comme quelque chose comme ça, malgré le grand montant de $ x $. Pour chaque sortie, nous calculons une somme pondérée de $ x $, la biaisons, puis appliquons Softmax.
(Figure)
Si nous l'écrivons sous forme de formule, nous obtenons:
\begin{bmatrix}
y_1 \\
y_2 \\
y_3 \\
\end{bmatrix} = softmax
\begin{pmatrix}
W_{1,1} x_1 + W_{1,2} x_2 + W_{1,3} x_3 + b_1 \\
W_{2,1} x_1 + W_{2,2} x_2 + W_{2,3} x_3 + b_2\\
W_{3,1} x_1 + W_{3,2} x_2 + W_{3,3} x_3 + b_3
\end{pmatrix}
Nous pouvons "montrer cette procédure comme un vecteur" et la transformer en multiplication matricielle et addition de vecteur. Ceci est utile pour l'efficacité du calcul. (C'est aussi une manière utile de penser)
\begin{bmatrix}
y_1 \\
y_2 \\
y_3 \\
\end{bmatrix} = softmax
\begin{pmatrix}
\begin{bmatrix}
W_{1,1} & W_{1,2} & W_{1,3} \\
W_{2,1} & W_{2,2} & W_{2,3} \\
W_{3,1} & W_{3,2} & W_{3,3}
\end{bmatrix}
\cdot
\begin{bmatrix}
x_1 \\
x_2 \\
x_3
\end{bmatrix}
+
\begin{bmatrix}
b_1 \\
b_2\\
b_3
\end{bmatrix}
\end{pmatrix}
Pour le rendre plus compact, nous pouvons simplement écrire:
y = softmax(W_x + b)
Pour effectuer des calculs numériques efficaces avec Python, nous utilisons généralement du code très efficace implémenté dans d'autres langages, tels que NumPy, qui effectue des opérations coûteuses comme la multiplication de matrice en dehors de Python. Utilisez la bibliothèque. Malheureusement, il semble encore y avoir beaucoup de surcharge pour passer à Python pour chaque opération. Cette surcharge est particulièrement mauvaise si vous souhaitez exécuter des calculs sur des GPU ou de manière distribuée, où les coûts de transfert des données seront élevés.
TensorFlow fait également un gros travail en dehors de Python, mais franchit une étape supplémentaire pour éviter cette surcharge. Au lieu d'exécuter un processus coûteux indépendamment de Python, TensorFlow nous permet de dessiner un graphique des processus d'interaction qui s'exécutent complètement en dehors de Python. (Une telle approche peut être trouvée dans certaines bibliothèques d'apprentissage automatique.)
Pour utiliser TensorFlow, nous devons l'implémenter.
import tensorflow as tf
Nous décrivons ces processus en interaction par des variables symboliques qui les manipulent. Faisons un.
x = tf.placeholder(tf.float32, [None, 784])
$ x $ n'est pas une valeur spéciale. Il s'agit d'un espace réservé, la valeur que nous saisissons lorsque nous demandons à TensorFlow d'exécuter le calcul. Nous voulons pouvoir saisir chaque nombre dans l'image MNIST, chacun parallèle à 784 dimensions. Nous exprimons cela comme un tenseur 2-D avec un certain nombre de points parallèles, avec la forme [None, 784]. (Ce Aucun signifie une dimension qui peut être de n'importe quelle longueur.)
Nous avons également besoin de pondérations et de biais pour notre modèle. Nous pouvons imaginer les traiter comme des entrées supplémentaires, mais TensorFlow a une meilleure façon de les traiter. C'est variable. Variavle est un tenseur mutable qui vit dans le graphe TensorFlow du traitement d'interaction. Il peut être utilisé et modifié par calcul. Pour les applications d'apprentissage automatique, les paramètres du modèle sont généralement variables.
W = tf.Variable(tf.zeros([784, 10))
b = tf.Variable(tf.zeros([10]))
Nous créons ces variables en leur donnant tf.Variable comme valeur initiale des variables. Dans ce cas, nous initialisons à la fois $ W $ et $ b $ comme un tenseur de tous les zéros. Ils sont très problématiques jusqu'à ce que nous formions $ W $ et $ b $.
Notez que $ W $ a la forme [784, 10], car nous voulons multiplier le vecteur d'une image à 784 dimensions par elle pour produire un vecteur de preuves à 10 dimensions pour différentes classes. $ b $ a la forme [10] et nous pouvons l'ajouter à la sortie.
Nous pouvons maintenant implémenter notre modèle. Ce n'est qu'une ligne!
y = tf.nn.softmax(tf.matmul(x, W) + b)
Tout d'abord, nous multiplions $ x $ et $ W $ par la représentation de tf.matmul ($ x $, $ W $). Ceci est inversé lors de leur multiplication dans notre formule avec $ W_x $ comme une petite astuce pour gérer x qui est un tenseur 2D avec beaucoup d'entrées. Nous ajoutons ensuite $ b $ et appliquons finalement tf.nn.softmax.
C'est tout. Il suffit d'une ligne après une paire de courtes lignes de configuration pour définir notre modèle. Ce n'est pas parce que TensorFlow est conçu pour rendre la régression softmax particulièrement facile. C'est juste un moyen très flexible de représenter de nombreux types de calculs numériques à partir de modèles d'apprentissage automatique pour la simulation physique. Et une fois clair, notre modèle peut fonctionner sur différents appareils. Le processeur, le GPU de votre ordinateur ou même votre téléphone portable!
Afin de former notre modèle, nous devons définir ce que signifie être bon pour le modèle. En pratique, dans l'apprentissage automatique, nous définissons généralement ce qui est censé être mauvais pour le modèle, ce que l'on appelle le coût ou la perte, et comment réduire les mauvais. Essayer. Mais les deux sont équivalents.
Une fonction de coût très ordinaire et très bonne est "l'entropie croisée". Étonnamment, l'entropie croisée découle de la réflexion sur les codes de compression de l'information de la théorie de l'information, mais elle finit par être une idée importante dans de nombreux domaines et découle du jeu d'apprentissage automatique. Il est défini comme:
H_{y^{'}}(y) = -\sum_i y^{'}_i \log(y_i)
$ y $ est la distribution de probabilité que nous avons prédit et $ y_ {'} $ est la vraie distribution de probabilité (un vecteur chaud que nous entrons). Dans une sorte de sensibilité, l'entropie croisée évalue à quel point nos prédictions sont inefficaces pour la vérité. Plus de détails sur l'entropie croisée sortent du cadre de ce didacticiel, mais Understanding en vaut la peine.
Pour implémenter l'entropie croisée, nous devons d'abord ajouter l'entrée de réponse correcte à l'espace réservé.
y_ = tf.placeholder(tf.float32, [None, 10])
Ensuite, nous pouvons implémenter l'entropie croisée, $ - \ sum_i y ^ {'} _i \ log (y_i) $.
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
Premièrement, tf.log
calcule le logarithme de chaque élément y
.
Ensuite, nous multiplions chaque élément y_
par l'élément correspondant tf.log (y)
.
Enfin, tf.reduce_sum
ajoute les tenseurs de tous les éléments.
(À noter, ce n'est pas seulement la véritable entropie croisée dans une prédiction, mais la somme des entropies croisées des 100 images que nous avons recherchées. Quelle est la qualité des 100 données? Seulement mieux décrit comment notre modèle est meilleur qu'un seul élément de données.)
Maintenant que nous savons ce que nous voulons que notre modèle fasse, TensorFlow est très facile à faire. Étant donné que TensorFlow connaît l'ensemble du graphique de votre calcul, il identifie automatiquement [erreur inverse] comment vos variables affectent le coût que vous souhaitez minimiser. L'algorithme de propagation](http://colah.github.io/posts/2015-08-Backprop/) peut être utilisé. Vous pouvez ensuite modifier les variables et appliquer l'algorithme d'optimisation de votre choix pour réduire les coûts.
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
Dans ce cas, nous voulons que TensorFlow minimise cross_entropy
en utilisant la méthode de descente de gradient avec un coefficient d'apprentissage de 0,01.
La descente de gradient est une procédure simple et TensorFlow modifie simplement chaque variable en un petit peu dans le sens des économies de coûts.
Mais TensorFlow fournit également de nombreux autres algorithmes d'optimisation.
En utilisant quelque chose d'aussi simple que d'ajuster une ligne.
Ce que TensorFlow est vraiment ici, dans les coulisses, est d'ajouter un nouveau traitement à votre graphique qui implémente la propagation des erreurs et la descente de gradient. Ensuite, une fois exécuté, il est donné un pas en arrière dans la réduction de l'entraînement sur la pente et l'ajustement des variables pour réduire légèrement les coûts.
Nous avons maintenant mis en place un modèle de formation. La dernière chose avant de faire cela est que nous devons ajouter un traitement à l'initialisation des variables que nous avons créées.
init = tf.initialize_all_variables()
Nous pouvons maintenant exécuter le modèle dans Session
et lancer le processus d'initialisation des variables.
sess = tf.Session()
sess.run(init)
Entraînons-nous. Nous effectuons 1000 étapes de formation!
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_:batch_ys})
À chaque étape de la boucle, nous obtenons un «lot» de 100 points de données aléatoires de l'ensemble d'apprentissage.
Nous effectuons un train_step
qui récupère les données de lots pour échanger les espaces réservés et autres.
L'utilisation d'un petit lot de données aléatoires est appelée entraînement stochastique, dans ce cas une descente de gradient stochastique. Idéalement, nous voulons utiliser toutes les données à chaque étape de la formation, mais cela coûte cher car cela nous donne une bonne idée de ce que nous devrions faire. Au lieu de cela, nous utilisons un sous-ensemble différent à chaque fois. Faire cela est bon marché et présente les mêmes avantages.
Quelle est la qualité de notre modèle?
Eh bien d'abord, connaissons l'étiquette correcte que nous avons prédit.
tf.argmax
est une fonction très utile qui donne l'indice de l'entrée la plus élevée dans un tenseur le long d'un axe.
Par exemple, tf.argmax (y, 1)
est l'étiquette de notre modèle le plus probable pour chaque entrée, tandis que tf.argmax (y_, 1)
est l'étiquette correcte.
Nous pouvons utiliser tf.equal
pour voir si nos prédictions sont vraies.
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
Cela nous donne une liste de booléens. Pour déterminer si la fonction est correcte, nous la convertissons en virgule flottante, puis prenons la valeur moyenne. Par exemple, [True, False, True, True] devient [1,0,1,1] et (Note: valeur moyenne) devient 0,75.
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
Enfin, nous exigeons la précision des données de test.
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
Cela devrait être d'environ 91%.
Est-ce bien? Pas vraiment. En fait, c'est un peu mauvais. C'est parce que j'ai utilisé un modèle très simple. Avec un petit changement, nous pouvons obtenir 97%. Le meilleur modèle peut obtenir une précision de plus de 99,7%! (Voir cette Liste des résultats pour plus d'informations.)
Le problème est que nous avons appris de ce modèle. Néanmoins, si vous n'aimez pas ces résultats, il est facile d'apprendre à créer un modèle plus sophistiqué avec TensorFlow [Tutoriel suivant](https: //www.tensorflow. Vérifiez org / versions / master / tutorials / mnist / pros / index.html)!
Ce qui précède est la traduction de MNIST For ML Beginners.
Il y a des traductions suspectes et subtiles à certains endroits, mais maintenant je sais ce que je veux faire. Il y a des formules, mais ce que je fais, c'est simplement multiplier et ajouter des matrices, et je ne fais pas cela difficile. TensorFlow est idéal pour la régression softmax difficile et la descente de gradient. Eh bien, je pense que c'est la chose même qui comprend ici.
Je pense que ce qui suit est un bref résumé.
Ensuite, je voudrais réellement composer un code et exécuter s'il peut reconnaître des caractères.
Recommended Posts