Aide à protéger la Grande barrière de corail avec tensorflow sur Kaggle Rejoignez Défi

Exécution impatiente

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

L'exécution rapide de TensorFlow est un environnement de programmation impératif qui évalue les opérations immédiatement, sans créer de graphiques : les opérations renvoient des valeurs concrètes au lieu de construire un graphique de calcul à exécuter plus tard. Cela facilite la mise en route avec TensorFlow et les modèles de débogage, et réduit également le passe-partout. Pour suivre ce guide, exécutez les exemples de code ci - dessous dans un environnement interactif python interprète.

Eager execution est une plate-forme flexible d'apprentissage automatique pour la recherche et l'expérimentation, offrant :

  • Une interface intuitive -Structure votre code naturellement et utiliser des structures de données Python. Itérer rapidement sur de petits modèles et de petites données.
  • Débogage plus facile ops -CALL directement pour inspecter les modèles en cours d' exécution et les changements de test. Utilisez les outils de débogage Python standard pour un rapport d'erreur immédiat.
  • Contrôle de flux naturel flux de contrôle -Utiliser Python au lieu de flux de contrôle graphique, ce qui simplifie la spécification des modèles dynamiques.

L'exécution impatiente prend en charge la plupart des opérations TensorFlow et l'accélération GPU.

Configuration et utilisation de base

import os

import tensorflow as tf

import cProfile

Dans Tensorflow 2.0, l'exécution rapide est activée par défaut.

tf.executing_eagerly()
True

Vous pouvez maintenant exécuter des opérations TensorFlow et les résultats seront immédiatement renvoyés :

x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))
hello, [[4.]]

L'activation de l'exécution rapide modifie le comportement des opérations TensorFlow. Désormais, elles évaluent et renvoient immédiatement leurs valeurs à Python. tf.Tensor objets de valeurs concrètes de référence au lieu de poignées symboliques à des noeuds dans un graphe de calcul. Comme il n'y a pas un graphe de calcul pour construire et exécuter plus tard dans une session, il est facile d'inspecter à l' aide des résultats d' print() ou un débogueur. L'évaluation, l'impression et la vérification des valeurs de tenseur n'interrompent pas le calcul des gradients.

Exécution Désireuse fonctionne bien avec NumPy . Opérations numpy acceptent tf.Tensor arguments. Les tensorflow tf.math opérations convertir des objets Python et tableaux numpy à tf.Tensor objets. La tf.Tensor.numpy méthode retourne la valeur de l'objet en tant que NumPy ndarray .

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)
tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32)
# Broadcasting support
b = tf.add(a, 1)
print(b)
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32)
# Operator overloading is supported
print(a * b)
tf.Tensor(
[[ 2  6]
 [12 20]], shape=(2, 2), dtype=int32)
# Use NumPy values
import numpy as np

c = np.multiply(a, b)
print(c)
[[ 2  6]
 [12 20]]
# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]
[[1 2]
 [3 4]]

Flux de contrôle dynamique

L'un des principaux avantages d'une exécution rapide est que toutes les fonctionnalités du langage hôte sont disponibles pendant l'exécution de votre modèle. Ainsi, par exemple, il est facile d'écrire FizzBuzz :

def fizzbuzz(max_num):
  counter = tf.constant(0)
  max_num = tf.convert_to_tensor(max_num)
  for num in range(1, max_num.numpy()+1):
    num = tf.constant(num)
    if int(num % 3) == 0 and int(num % 5) == 0:
      print('FizzBuzz')
    elif int(num % 3) == 0:
      print('Fizz')
    elif int(num % 5) == 0:
      print('Buzz')
    else:
      print(num.numpy())
    counter += 1
fizzbuzz(15)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

Cela a des conditions qui dépendent des valeurs du tenseur et il imprime ces valeurs au moment de l'exécution.

Avide de formation

Calcul des gradients

La différenciation automatique est utile pour la mise en œuvre des algorithmes d' apprentissage machine , telles que rétropropagation pour la formation de réseaux de neurones. Pendant l' exécution avide, utilisez tf.GradientTape pour tracer les opérations de calcul des gradients plus tard.

Vous pouvez utiliser tf.GradientTape pour former et / ou les gradients de calcul en hâte. Il est particulièrement utile pour les boucles d'entraînement compliquées.

Étant donné que différentes opérations peuvent se produire au cours de chaque appel, toutes les opérations de transmission directe sont enregistrées sur une "bande". Pour calculer le gradient, lisez la bande à l'envers, puis jetez-la. Un particulier tf.GradientTape ne peut calculer une pente; les appels suivants génèrent une erreur d'exécution.

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

Former un modèle

L'exemple suivant crée un modèle multicouche qui classe les chiffres manuscrits MNIST standard. Il montre l'optimiseur et les API de couche pour créer des graphiques pouvant être entraînés dans un environnement d'exécution dynamique.

# Fetch and format the mnist data
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
   tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
# Build the model
mnist_model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu',
                         input_shape=(None, None, 1)),
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])

Même sans formation, appelez le modèle et inspectez la sortie dans une exécution rapide :

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[-0.01775933 -0.01194787 -0.08372174 -0.06535977  0.00338565 -0.01974326
  -0.04763228  0.00904049 -0.00144051 -0.01944664]]

Alors que les modèles de KERAS ont une boucle de formation de builtin ( en utilisant la fit méthode), parfois vous avez besoin de plus de personnalisation. Voici un exemple, d'une boucle d'entraînement implémentée avec désir :

optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

loss_history = []
def train_step(images, labels):
  with tf.GradientTape() as tape:
    logits = mnist_model(images, training=True)

    # Add asserts to check the shape of the output.
    tf.debugging.assert_equal(logits.shape, (32, 10))

    loss_value = loss_object(labels, logits)

  loss_history.append(loss_value.numpy().mean())
  grads = tape.gradient(loss_value, mnist_model.trainable_variables)
  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
def train(epochs):
  for epoch in range(epochs):
    for (batch, (images, labels)) in enumerate(dataset):
      train_step(images, labels)
    print ('Epoch {} finished'.format(epoch))
train(epochs = 3)
Epoch 0 finished
Epoch 1 finished
Epoch 2 finished
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
Text(0, 0.5, 'Loss [entropy]')

png

Variables et optimiseurs

tf.Variable objets mutable stocker tf.Tensor -comme valeurs accessibles lors de l' entraînement pour rendre la différenciation automatique plus facile.

Les collections de variables peuvent être encapsulées dans des couches ou des modèles, ainsi que des méthodes qui les exploitent. Voir couches et modèles personnalisés KERAS pour plus de détails. La principale différence entre les couches et les modèles que les modèles ajoutent des méthodes telles que Model.fit , Model.evaluate et Model.save .

Par exemple, l'exemple de différenciation automatique ci-dessus peut être réécrit :

class Linear(tf.keras.Model):
  def __init__(self):
    super(Linear, self).__init__()
    self.W = tf.Variable(5., name='weight')
    self.B = tf.Variable(10., name='bias')
  def call(self, inputs):
    return inputs * self.W + self.B
# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# The loss function to be optimized
def loss(model, inputs, targets):
  error = model(inputs) - targets
  return tf.reduce_mean(tf.square(error))

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return tape.gradient(loss_value, [model.W, model.B])

Prochain:

  1. Créez le modèle.
  2. Les dérivés d'une fonction de perte par rapport aux paramètres du modèle.
  3. Une stratégie de mise à jour des variables basée sur les dérivées.
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

steps = 300
for i in range(steps):
  grads = grad(model, training_inputs, training_outputs)
  optimizer.apply_gradients(zip(grads, [model.W, model.B]))
  if i % 20 == 0:
    print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))
Initial loss: 69.909
Loss at step 000: 67.145
Loss at step 020: 30.170
Loss at step 040: 13.859
Loss at step 060: 6.659
Loss at step 080: 3.479
Loss at step 100: 2.074
Loss at step 120: 1.453
Loss at step 140: 1.178
Loss at step 160: 1.056
Loss at step 180: 1.003
Loss at step 200: 0.979
Loss at step 220: 0.968
Loss at step 240: 0.963
Loss at step 260: 0.961
Loss at step 280: 0.960
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.960
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.9515867233276367, B = 2.0210201740264893

Enregistrement basé sur les objets

Un tf.keras.Model comprend une pratique save_weights méthode vous permettant de créer facilement un point de contrôle:

model.save_weights('weights')
status = model.load_weights('weights')

L' utilisation tf.train.Checkpoint vous pouvez prendre le contrôle total sur ce processus.

Cette section est une version abrégée du guide pour les postes de contrôle de formation .

x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
x.assign(2.)   # Assign a new value to the variables and save.
checkpoint_path = './ckpt/'
checkpoint.save(checkpoint_path)
'./ckpt/-1'
x.assign(11.)  # Change the variable after saving.

# Restore values from the checkpoint
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))

print(x)  # => 2.0
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>

Pour enregistrer et modèles de charge, tf.train.Checkpoint stocke l'état interne des objets, sans nécessiter des variables cachées. Pour enregistrer l'état d'un model , un optimizer , et une démarche globale, les passer à un tf.train.Checkpoint :

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = 'path/to/model_dir'
if not os.path.exists(checkpoint_dir):
  os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
                           model=model)

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f4ba0648310>

Métriques orientées objet

tf.keras.metrics sont stockés comme des objets. Mettre à jour une métrique en passant les nouvelles données à l'appelables et récupérer le résultat en utilisant la tf.keras.metrics.result méthode, par exemple:

m = tf.keras.metrics.Mean("loss")
m(0)
m(5)
m.result()  # => 2.5
m([8, 9])
m.result()  # => 5.5
<tf.Tensor: shape=(), dtype=float32, numpy=5.5>

Résumés et TensorBoard

TensorBoard est un outil de visualisation pour la compréhension, le débogage et l' optimisation du processus de formation du modèle. Il utilise des événements récapitulatifs qui sont écrits lors de l'exécution du programme.

Vous pouvez utiliser tf.summary à des résumés record de variables dans l' exécution avide. Par exemple, pour enregistrer les résumés des loss une fois tous les 100 étapes de formation:

logdir = "./tb/"
writer = tf.summary.create_file_writer(logdir)

steps = 1000
with writer.as_default():  # or call writer.set_as_default() before the loop.
  for i in range(steps):
    step = i + 1
    # Calculate loss with your real train function.
    loss = 1 - 0.001 * step
    if step % 100 == 0:
      tf.summary.scalar('loss', loss, step=step)
ls tb/
events.out.tfevents.1632342765.kokoro-gcp-ubuntu-prod-230753280.22287.0.v2

Sujets avancés de différenciation automatique

Modèles dynamiques

tf.GradientTape peut également être utilisé dans les modèles dynamiques. Cet exemple pour une recherche en ligne de retours en arrière algorithme ressemble à un code NumPy normale, sauf qu'il ya des gradients et différentiables, malgré le flux de contrôle complexe:

def line_search_step(fn, init_x, rate=1.0):
  with tf.GradientTape() as tape:
    # Variables are automatically tracked.
    # But to calculate a gradient from a tensor, you must `watch` it.
    tape.watch(init_x)
    value = fn(init_x)
  grad = tape.gradient(value, init_x)
  grad_norm = tf.reduce_sum(grad * grad)
  init_value = value
  while value > init_value - rate * grad_norm:
    x = init_x - rate * grad
    value = fn(x)
    rate /= 2.0
  return x, value

Dégradés personnalisés

Les dégradés personnalisés sont un moyen facile de remplacer les dégradés. Dans la fonction forward, définissez le gradient par rapport aux entrées, sorties ou résultats intermédiaires. Par exemple, voici un moyen simple de découper la norme des dégradés dans la passe arrière :

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
  y = tf.identity(x)
  def grad_fn(dresult):
    return [tf.clip_by_norm(dresult, norm), None]
  return y, grad_fn

Les dégradés personnalisés sont couramment utilisés pour fournir un dégradé numériquement stable pour une séquence d'opérations :

def log1pexp(x):
  return tf.math.log(1 + tf.exp(x))

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# The gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# However, x = 100 fails because of numerical instability.
grad_log1pexp(tf.constant(100.)).numpy()
nan

Ici, la log1pexp fonction peut être analytiquement simplifiée avec un dégradé personnalisé. La mise en œuvre ci - dessous réutilisations la valeur pour tf.exp(x) qui est calculée au cours de la passe-faire avancer plus efficace en éliminant les calculs redondants:

@tf.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.math.log(1 + e), grad

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# As before, the gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# And the gradient computation also works at x = 100.
grad_log1pexp(tf.constant(100.)).numpy()
1.0

Performance

Le calcul est automatiquement déchargé sur les GPU lors d'une exécution rapide. Si vous voulez contrôler où un calcul vous court pouvez l' enfermer dans un tf.device('/gpu:0') bloc (ou l'équivalent CPU):

import time

def measure(x, steps):
  # TensorFlow initializes a GPU the first time it's used, exclude from timing.
  tf.matmul(x, x)
  start = time.time()
  for i in range(steps):
    x = tf.matmul(x, x)
  # tf.matmul can return before completing the matrix multiplication
  # (e.g., can return after enqueing the operation on a CUDA stream).
  # The x.numpy() call below will ensure that all enqueued operations
  # have completed (and will also copy the result to host memory,
  # so we're including a little more than just the matmul operation
  # time).
  _ = x.numpy()
  end = time.time()
  return end - start

shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: {} secs".format(measure(tf.random.normal(shape), steps)))

# Run on GPU, if available:
if tf.config.list_physical_devices("GPU"):
  with tf.device("/gpu:0"):
    print("GPU: {} secs".format(measure(tf.random.normal(shape), steps)))
else:
  print("GPU: not found")
Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 1.007401466369629 secs
GPU: 0.04124784469604492 secs

Un tf.Tensor objet peut être copié sur un autre appareil pour exécuter ses opérations:

if tf.config.list_physical_devices("GPU"):
  x = tf.random.normal([10, 10])

  x_gpu0 = x.gpu()
  x_cpu = x.cpu()

  _ = tf.matmul(x_cpu, x_cpu)    # Runs on CPU
  _ = tf.matmul(x_gpu0, x_gpu0)  # Runs on GPU:0
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:4: _EagerTensorBase.gpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:5: _EagerTensorBase.cpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.

Repères

Pour les modèles de calcul lourds, tels que ResNet50 formation sur un GPU, les performances d'exécution désireux est comparable à tf.function exécution. Mais cet écart s'agrandit pour les modèles avec moins de calculs et il y a du travail à faire pour optimiser les chemins de code chaud pour les modèles avec beaucoup de petites opérations.

Travailler avec des fonctions

Alors que l'exécution rapide rend le développement et le débogage plus interactifs, l'exécution graphique de style TensorFlow 1.x présente des avantages pour la formation distribuée, l'optimisation des performances et le déploiement en production. Pour combler cette lacune, tensorflow 2.0 introduit function s par l'intermédiaire du tf.function API. Pour plus d' informations, consultez le tf.function guide.