Introduction au *Machine Learning* – TensorFlow | Original, traduit par l'IA

Home 2021.03

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()

tf

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])

plt

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()

tf2

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])

cmap

Cette fois, nous recherchons pyplot cmap et trouvons quelques ressources.

plt.imshow(train_images[i], cmap=plt.cm.PiYG)

cmap1

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.

plot3

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()

plot_xticks

Remarquez que des éléments comme 0 25 sont appelés xticks. Lorsque nous zoomons ou dézoomons ce cadre, l’affichage change.

plot_scale

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()

pred

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()

pred1

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.


Back Donate