Bases de la personnalisation : tenseurs et opérations

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Il s'agit d'un didacticiel d'introduction à TensorFlow qui montre comment :

  • Importer le package requis
  • Créer et utiliser des tenseurs
  • Utiliser l'accélération GPU
  • Démontrer tf.data.Dataset

Importer TensorFlow

Pour commencer, importez le module tensorflow . À partir de TensorFlow 2, l'exécution hâtive est activée par défaut. Cela permet une interface plus interactive pour TensorFlow, dont nous discuterons des détails beaucoup plus tard.

import tensorflow as tf

Tenseurs

Un tenseur est un tableau multidimensionnel. Semblables aux objets NumPy ndarray , les objets tf.Tensor ont un type de données et une forme. De plus, tf.Tensor s peut résider dans la mémoire de l'accélérateur (comme un GPU). TensorFlow offre une riche bibliothèque d'opérations ( tf.add , tf.matmul , tf.linalg.inv etc.) qui consomment et produisent des tf.Tensor s. Ces opérations convertissent automatiquement les types Python natifs, par exemple :

print(tf.add(1, 2))
print(tf.add([1, 2], [3, 4]))
print(tf.square(5))
print(tf.reduce_sum([1, 2, 3]))

# Operator overloading is also supported
print(tf.square(2) + tf.square(3))
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(13, shape=(), dtype=int32)

Chaque tf.Tensor a une forme et un type de données :

x = tf.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
tf.Tensor([[2 3]], shape=(1, 2), dtype=int32)
(1, 2)
<dtype: 'int32'>

Les différences les plus évidentes entre les tableaux NumPy et les tf.Tensor sont :

  1. Les tenseurs peuvent être soutenus par une mémoire d'accélérateur (comme GPU, TPU).
  2. Les tenseurs sont immuables.

Compatibilité NumPy

La conversion entre un TensorFlow tf.Tensor s et un NumPy ndarray est simple :

  • Les opérations TensorFlow convertissent automatiquement les ndarrays NumPy en Tensors.
  • Les opérations NumPy convertissent automatiquement les Tensors en ndarrays NumPy.

Les tenseurs sont explicitement convertis en ndarrays NumPy à l'aide de leur méthode .numpy() . Ces conversions sont généralement bon marché puisque le tableau et tf.Tensor partagent la représentation mémoire sous-jacente, si possible. Cependant, le partage de la représentation sous-jacente n'est pas toujours possible car le tf.Tensor peut être hébergé dans la mémoire GPU tandis que les tableaux NumPy sont toujours sauvegardés par la mémoire hôte, et la conversion implique une copie du GPU vers la mémoire hôte.

import numpy as np

ndarray = np.ones([3, 3])

print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.multiply(ndarray, 42)
print(tensor)


print("And NumPy operations convert Tensors to numpy arrays automatically")
print(np.add(tensor, 1))

print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor(
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to numpy arrays automatically
[[43. 43. 43.]
 [43. 43. 43.]
 [43. 43. 43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]]

Accélération GPU

De nombreuses opérations TensorFlow sont accélérées à l'aide du GPU pour le calcul. Sans aucune annotation, TensorFlow décide automatiquement d'utiliser le GPU ou le CPU pour une opération, en copiant le tenseur entre la mémoire CPU et GPU, si nécessaire. Les tenseurs produits par une opération sont généralement sauvegardés par la mémoire de l'appareil sur lequel l'opération est exécutée, par exemple :

x = tf.random.uniform([3, 3])

print("Is there a GPU available: "),
print(tf.config.list_physical_devices("GPU"))

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))
Is there a GPU available: 
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
Is the Tensor on GPU #0:  
True

Noms de périphérique

La propriété Tensor.device fournit un nom de chaîne complet du périphérique hébergeant le contenu du tenseur. Ce nom encode de nombreux détails, tels qu'un identifiant de l'adresse réseau de l'hôte sur lequel ce programme s'exécute et le périphérique au sein de cet hôte. Ceci est nécessaire pour l'exécution distribuée d'un programme TensorFlow. La chaîne se termine par GPU:<N> si le tenseur est placé sur le N -ième GPU sur l'hôte.

Placement explicite de l'appareil

Dans TensorFlow, le placement fait référence à la façon dont les opérations individuelles sont attribuées (placées sur) un appareil pour exécution. Comme mentionné, lorsqu'aucune instruction explicite n'est fournie, TensorFlow décide automatiquement quel appareil exécuter une opération et copie les tenseurs sur cet appareil, si nécessaire. Cependant, les opérations TensorFlow peuvent être explicitement placées sur des appareils spécifiques à l'aide du gestionnaire de contexte tf.device , par exemple :

import time

def time_matmul(x):
  start = time.time()
  for loop in range(10):
    tf.matmul(x, x)

  result = time.time()-start

  print("10 loops: {:0.2f}ms".format(1000*result))

# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
  x = tf.random.uniform([1000, 1000])
  assert x.device.endswith("CPU:0")
  time_matmul(x)

# Force execution on GPU #0 if available
if tf.config.list_physical_devices("GPU"):
  print("On GPU:")
  with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
    x = tf.random.uniform([1000, 1000])
    assert x.device.endswith("GPU:0")
    time_matmul(x)
On CPU:
10 loops: 91.47ms
On GPU:
10 loops: 388.16ms

Jeux de données

Cette section utilise l' API tf.data.Dataset pour créer un pipeline permettant d'alimenter en données votre modèle. L'API tf.data.Dataset est utilisée pour créer des pipelines d'entrée complexes et performants à partir de pièces simples et réutilisables qui alimenteront les boucles d'entraînement ou d'évaluation de votre modèle.

Créer un jeu de Dataset source

Créez un jeu de données source à l'aide de l'une des fonctions d'usine telles que Dataset.from_tensors , Dataset.from_tensor_slices ou à l'aide d'objets qui lisent à partir de fichiers tels que TextLineDataset ou TFRecordDataset . Consultez le guide de l'ensemble de données TensorFlow pour plus d'informations.

ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp()

with open(filename, 'w') as f:
  f.write("""Line 1
Line 2
Line 3
  """)

ds_file = tf.data.TextLineDataset(filename)

Appliquer des transformations

Utilisez les fonctions de transformation telles que map , batch et shuffle pour appliquer des transformations aux enregistrements de l'ensemble de données.

ds_tensors = ds_tensors.map(tf.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

Répéter

Les objets tf.data.Dataset prennent en charge l'itération pour parcourir les enregistrements :

print('Elements of ds_tensors:')
for x in ds_tensors:
  print(x)

print('\nElements in ds_file:')
for x in ds_file:
  print(x)
Elements of ds_tensors:
tf.Tensor([1 9], shape=(2,), dtype=int32)
tf.Tensor([16  4], shape=(2,), dtype=int32)
tf.Tensor([25 36], shape=(2,), dtype=int32)

Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)