Introduction au *Machine Learning* – TensorFlow | Original, traduit par l'IA
Ce post a été initialement écrit en chinois. Il a été traduit en anglais pour faciliter les traductions dans d’autres langues.
Puisque nous apprenons Python
, nous devons absolument parler d’apprentissage automatique. Beaucoup de ses bibliothèques sont écrites en Python. Commençons par les installer et les essayer.
TensorFlow
Installons-le.
$ pip install tensorflow
ERROR: Could not find a version that satisfies the requirement tensorflow
ERROR: No matching distribution found for tensorflow
$ type python
python est un alias pour `/usr/local/Cellar/python@3.9/3.9.1_6/bin/python3'
Cependant, TensorFlow 2
ne supporte que Python 3.5–3.8
. Nous utilisons la version 3.9
.
% type python3
python3 est /usr/bin/python3
% python3 -V
Python 3.8.2
Remarquez que le python3
de mon système est la version 3.8.2
. Où le pip
correspondant à cette version de Python installe-t-il les paquets ?
% python3 -m pip -V
pip 21.0.1 from /Users/lzw/Library/Python/3.8/lib/python/site-packages/pip (python 3.8)
Le pip
correspondant se trouve ici. Je vais donc modifier le fichier .zprofile
. Récemment, j’ai changé mon shell
, et .zprofile
est équivalent à l’ancien .bash_profile
. Ajoutez une ligne :
alias pip3=/Users/lzw/Library/Python/3.8/bin/pip3
Ainsi, nous pouvons utiliser python3
et pip3
pour travailler avec TensorFlow
.
% pip3 install tensorflow
...
Successfully installed absl-py-0.12.0 astunparse-1.6.3 cachetools-4.2.1 certifi-2020.12.5 chardet-4.0.0 flatbuffers-1.12 gast-0.3.3 google-auth-1.27.1 google-auth-oauthlib-0.4.3 google-pasta-0.2.0 grpcio-1.32.0 h5py-2.10.0 idna-2.10 keras-preprocessing-1.1.2 markdown-3.3.4 numpy-1.19.5 oauthlib-3.1.0 opt-einsum-3.3.0 protobuf-3.15.6 pyasn1-0.4.8 pyasn1-modules-0.2.8 requests-2.25.1 requests-oauthlib-1.3.0 rsa-4.7.2 tensorboard-2.4.1 tensorboard-plugin-wit-1.8.0 tensorflow-2.4.1 tensorflow-estimator-2.4.0 termcolor-1.1.0 typing-extensions-3.7.4.3 urllib3-1.26.3 werkzeug-1.0.1 wheel-0.36.2 wrapt-1.12.1
De nombreuses bibliothèques ont été installées. Utilisons un exemple du site officiel.
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10)
])
predictions = model(x_train[:1]).numpy()
print(predictions)
Exécutons-le.
$ /usr/bin/python3 tf.py
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 10s 1us/step
[[ 0.15477428 -0.3877643 0.0994779 0.07474922 -0.26219758 -0.03550266
0.32226565 -0.37141111 0.10925996 -0.0115255 ]]
Comme vous pouvez le voir, le jeu de données a été téléchargé et les résultats ont été affichés.
Ensuite, regardons un exemple de classification d’images.
# TensorFlow et tf.keras
import tensorflow as tf
# Bibliothèques auxiliaires
import numpy as np
import matplotlib.pyplot as plt
print(tf.__version__)
Une erreur s’est produite.
ModuleNotFoundError: No module named 'matplotlib'
Installons-le.
% pip3 install matplotlib
Maintenant, c’est correct.
$ /usr/bin/python3 image.py
2.4.1
Copions et collons le code de l’exemple.
# TensorFlow et tf.keras
import tensorflow as tf
# Bibliothèques auxiliaires
import numpy as np
import matplotlib.pyplot as plt
fashion_mnist = tf.keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
class_names = ['T-shirt/haut', 'Pantalon', 'Pull', 'Robe', 'Manteau',
'Sandale', 'Chemise', 'Basket', 'Sac', 'Bottine']
print(train_images.shape)
print(len(train_labels))
Les résultats sont affichés. Remarquez que nous avons train_images
, train_labels
, test_images
et test_labels
. Ceux-ci sont divisés en ensembles de données d’entraînement et de test.
(60000, 28, 28)
60000
Ensuite, essayons d’afficher une image.
print(train_images[0])
Voyons le résultat.
[[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 13 73 0
0 1 4 0 0 0 0 1 1 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 3 0 36 136 127 62
54 0 0 0 1 3 4 0 0 3]
[ 0 0 0 0 0 0 0 0 0 0 0 0 6 0 102 204 176 134
144 123 23 0 0 0 0 12 10 0]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 236 207 178
107 156 161 109 64 23 77 130 72 15]
....
Ici, une partie du résultat est extraite.
print(len(train_images[0][0]))
Affiche 28
. Il est donc clair que c’est une matrice de largeur 28. Continuons à afficher.
print(len(train_images[0][0][0]))
TypeError: object of type 'numpy.uint8' has no len()
Donc, c’est clair. Chaque image est un tableau 28*28
. La dernière dimension stocke les valeurs RVB. Cependant, nous pourrions nous tromper sur ce point.
print(train_images[0][1][20])
0
print(train_images[0][1])
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
Cela montre que chaque image est un tableau 28*28
. Après quelques ajustements, nous avons finalement compris le secret.
Commençons par regarder l’image de sortie.
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()
Voyez-vous la barre de couleur à droite ? De 0
à 250
. Il s’avère que c’est un dégradé entre deux couleurs. Mais comment sait-il quelles sont ces deux couleurs ? Où avons-nous spécifié cela ?
Ensuite, affichons également la deuxième image.
plt.imshow(train_images[1])
Très intéressant. Est-ce le paramètre par défaut de la bibliothèque pyplot
? Continuons à exécuter le code fourni par le site officiel.
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()
Remarquez que les images et leurs classifications sont affichées ici. Enfin, nous comprenons le paramètre cmap
. Si cmap
n’est pas spécifié, il utilisera par défaut le schéma de couleurs que nous avons vu précédemment. En effet.
plt.imshow(train_images[i])
Cette fois, nous recherchons pyplot cmap
et trouvons quelques ressources.
plt.imshow(train_images[i], cmap=plt.cm.PiYG)
Modifions le code.
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(2,5,i+1) ## Ligne modifiée
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.Blues)
plt.xlabel(class_names[train_labels[i]])
plt.show()
Cependant, une erreur s’est produite.
ValueError: num must be 1 <= num <= 10, not 11
Que signifie ceci ? Que signifie exactement le 5,5,i+1
précédent ? Pourquoi cela ne fonctionne-t-il pas lorsqu’il est changé en 2
? Bien que nous comprenions intuitivement qu’il pourrait signifier 5 lignes et 5 colonnes, pourquoi cette erreur se produit-elle ? Comment le 11
est-il calculé ? Que signifie num
? Que signifie 10
? Remarquez que 2*5=10
. Donc, peut-être que l’erreur se produit lorsque i=11
. Lorsque nous changeons en for i in range(10):
, nous obtenons le résultat suivant.
Cette fois, après avoir brièvement consulté la documentation, nous apprenons à propos de subplot(nrows, ncols, index, **kwargs)
. D’accord, maintenant nous comprenons.
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
# plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.Blues)
plt.xlabel(class_names[train_labels[i]])
plt.show()
Remarquez que des éléments comme 0 25
sont appelés xticks
. Lorsque nous zoomons ou dézoomons ce cadre, l’affichage change.
Remarquez que lors du zoom avant ou arrière, xticks
et xlabels
s’affichent différemment.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=10)
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print('\nTest accuracy:', test_acc)
Remarquez la manière dont le modèle est défini ici, en utilisant la classe Sequential
. Faites attention à ces paramètres : 28,28
, 128
, relu
, 10
. Remarquez que vous devez compile
et fit
. fit
signifie ajustement. Remarquez que 28,28
correspond à la taille de l’image.
Epoch 1/10
1875/1875 [==============================] - 2s 928us/step - loss: 0.6331 - accuracy: 0.7769
Epoch 2/10
1875/1875 [==============================] - 2s 961us/step - loss: 0.3860 - accuracy: 0.8615
Epoch 3/10
1875/1875 [==============================] - 2s 930us/step - loss: 0.3395 - accuracy: 0.8755
Epoch 4/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.3071 - accuracy: 0.8890
Epoch 5/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.2964 - accuracy: 0.8927
Epoch 6/10
1875/1875 [==============================] - 2s 985us/step - loss: 0.2764 - accuracy: 0.8955
Epoch 7/10
1875/1875 [==============================] - 2s 961us/step - loss: 0.2653 - accuracy: 0.8996
Epoch 8/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.2549 - accuracy: 0.9052
Epoch 9/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.2416 - accuracy: 0.9090
Epoch 10/10
1875/1875 [==============================] - 2s 1ms/step - loss: 0.2372 - accuracy: 0.9086
313/313 - 0s - loss: 0.3422 - accuracy: 0.8798
Test accuracy: 0.879800021648407
Le modèle a été entraîné. Modifions les paramètres.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(28, activation='relu'), # 128 -> 28
tf.keras.layers.Dense(10)
])
Modifions le premier paramètre de Dense
.
Epoch 1/10
1875/1875 [==============================] - 2s 714us/step - loss: 6.9774 - accuracy: 0.3294
Epoch 2/10
1875/1875 [==============================] - 1s 715us/step - loss: 1.3038 - accuracy: 0.4831
Epoch 3/10
1875/1875 [==============================] - 1s 747us/step - loss: 1.0160 - accuracy: 0.6197
Epoch 4/10
1875/1875 [==============================] - 1s 800us/step - loss: 0.7963 - accuracy: 0.6939
Epoch 5/10
1875/1875 [==============================] - 2s 893us/step - loss: 0.7006 - accuracy: 0.7183
Epoch 6/10
1875/1875 [==============================] - 1s 747us/step - loss: 0.6675 - accuracy: 0.7299
Epoch 7/10
1875/1875 [==============================] - 1s 694us/step - loss: 0.6681 - accuracy: 0.7330
Epoch 8/10
1875/1875 [==============================] - 1s 702us/step - loss: 0.6675 - accuracy: 0.7356
Epoch 9/10
1875/1875 [==============================] - 1s 778us/step - loss: 0.6508 - accuracy: 0.7363
Epoch 10/10
1875/1875 [==============================] - 1s 732us/step - loss: 0.6532 - accuracy: 0.7350
313/313 - 0s - loss: 0.6816 - accuracy: 0.7230
Test accuracy: 0.7229999899864197
Remarquez le changement de Test accuracy
avant et après. Les journaux Epoch
sont produits par la fonction fit
. Remarquez qu’avec 128
, accuracy
passe de 0.7769
à 0.9086
. Avec 28
, accuracy
passe de 0.3294
à 0.7350
. Cette fois, nous voyons que nous utilisons d’abord l’ensemble d’entraînement pour optimiser loss
et accuracy
, puis nous utilisons l’ensemble de test pour évaluer. Regardons train_labels
.
print(train_labels)
[9 0 0 ... 3 0 5]
print(len(train_labels))
60000
Cela signifie que les nombres 0 à 9
représentent ces catégories. Par coïncidence, class_names
compte également 10 éléments.
class_names = ['T-shirt/haut', 'Pantalon', 'Pull', 'Robe', 'Manteau',
'Sandale', 'Chemise', 'Basket', 'Sac', 'Bottine']
Apportons une autre modification.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(28, activation='relu'),
tf.keras.layers.Dense(5) # 10 -> 5
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=10)
Une erreur s’est produite.
tensorflow.python.framework.errors_impl.InvalidArgumentError: Received a label value of 9 which is outside the valid range of [0, 5). Label values: 4 3 2 9 4 1 6 0 7 9 1 6 5 2 3 8 6 3 8 0 3 5 6 1 2 6 3 6 8 4 8 4
[[node sparse_categorical_crossentropy/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits (defined at /curiosity-courses/ml/tf/image.py:53) ]] [Op:__inference_train_function_538]
Function call stack:
train_function
Changer le troisième paramètre de Sequential
, Dense
, en 15
résout le problème. Les résultats ne sont pas très différents. Essayons de changer Epoch
.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(28, activation='relu'),
tf.keras.layers.Dense(15)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=15) # 10 -> 15
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print('\nTest accuracy:', test_acc)
Epoch 1/15
1875/1875 [==============================] - 2s 892us/step - loss: 6.5778 - accuracy: 0.3771
Epoch 2/15
1875/1875 [==============================] - 2s 872us/step - loss: 1.3121 - accuracy: 0.4910
Epoch 3/15
1875/1875 [==============================] - 2s 909us/step - loss: 1.0900 - accuracy: 0.5389
Epoch 4/15
1875/1875 [==============================] - 1s 730us/step - loss: 1.0422 - accuracy: 0.5577
Epoch 5/15
1875/1875 [==============================] - 1s 709us/step - loss: 0.9529 - accuracy: 0.5952
Epoch 6/15
1875/1875 [==============================] - 1s 714us/step - loss: 0.9888 - accuracy: 0.5950
Epoch 7/15
1875/1875 [==============================] - 1s 767us/step - loss: 0.8678 - accuracy: 0.6355
Epoch 8/15
1875/1875 [==============================] - 1s 715us/step - loss: 0.8247 - accuracy: 0.6611
Epoch 9/15
1875/1875 [==============================] - 1s 721us/step - loss: 0.8011 - accuracy: 0.6626
Epoch 10/15
1875/1875 [==============================] - 1s 711us/step - loss: 0.8024 - accuracy: 0.6622
Epoch 11/15
1875/1875 [==============================] - 1s 781us/step - loss: 0.7777 - accuracy: 0.6696
Epoch 12/15
1875/1875 [==============================] - 1s 724us/step - loss: 0.7764 - accuracy: 0.6728
Epoch 13/15
1875/1875 [==============================] - 1s 731us/step - loss: 0.7688 - accuracy: 0.6767
Epoch 14/15
1875/1875 [==============================] - 1s 715us/step - loss: 0.7592 - accuracy: 0.6793
Epoch 15/15
1875/1875 [==============================] - 1s 786us/step - loss: 0.7526 - accuracy: 0.6792
313/313 - 0s - loss: 0.8555 - accuracy: 0.6418
Test accuracy: 0.6417999863624573
Remarquez que le changement à 15 ne fait pas une grande différence. tf.keras.layers.Dense(88, activation='relu')
est important. En essayant de changer 128 en 88, nous avons obtenu Test accuracy: 0.824999988079071
. Avec 128, c’était 0.879800021648407
. Avec 28, c’était 0.7229999899864197
. Une valeur plus grande signifie-t-elle de meilleurs résultats ? Cependant, lorsque nous l’avons changé en 256
, nous avons obtenu Test accuracy: 0.8409000039100647
. Cela nous amène à réfléchir sur la signification de loss
et accuracy
.
probability_model = tf.keras.Sequential([model,
tf.keras.layers.Softmax()])
Ensuite, faisons une prédiction. Remarquez que Sequential
est le même que ci-dessus. Faites attention aux paramètres model
et tf.keras.layers.Softmax()
.
probability_model = tf.keras.Sequential([model,
tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)
def plot_image(i, predictions_array, true_label, img):
true_label, img = true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
true_label = true_label[i]
plt.grid(False)
plt.xticks(range(10))
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i], test_labels)
plt.show()
Cela indique que cette image a 99 % de chances d’être une Bottine
. Remarquez que plot_image
affiche le graphique de gauche et plot_value_array
produit le graphique de droite.
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()
Remarquez que cela affiche simplement plus de résultats de test. Nous comprenons donc grossièrement le flux d’utilisation. Nous ne savons toujours pas comment les calculs fonctionnent en interne, mais nous savons comment les utiliser. Derrière tout cela se trouve le calcul infinitésimal. Comment comprenons-nous le calcul infinitésimal ?
Par exemple, il y a un nombre entre 1 et 100 que vous devez deviner. Chaque fois que vous devinez, je vous dis si c’est trop bas ou trop haut. Vous devinez 50. Je dis trop bas. Vous devinez 80. Je dis trop haut. Vous devinez 65. Je dis trop haut. Vous devinez 55. Je dis trop bas. Vous devinez 58. Je dis oui, vous l’avez trouvé.
L’apprentissage automatique simule un processus similaire en interne, simplement plus complexe. Il pourrait impliquer de nombreuses plages comme 1 à 100
, en devinant plusieurs nombres à la fois. Chaque supposition implique beaucoup de calculs, et déterminer si c’est trop haut ou trop bas nécessite également de nombreux calculs.