Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Eksekusi yang bersemangat

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Eksekusi bersemangat TensorFlow adalah lingkungan pemrograman imperatif yang mengevaluasi operasi segera, tanpa membangun grafik: operasi mengembalikan nilai konkret alih-alih membangun grafik komputasi untuk menjalankan nanti. Ini membuatnya mudah untuk memulai dengan TensorFlow dan model debug, dan itu juga mengurangi boilerplate. Untuk mengikuti panduan ini, jalankan contoh kode di bawah ini dalam juru bahasa python interaktif.

Eksekusi yang cepat adalah platform pembelajaran mesin yang fleksibel untuk penelitian dan eksperimen, memberikan:

  • Antarmuka yang intuitif —Struktur kode Anda secara alami dan gunakan struktur data Python. Ulangi dengan cepat pada model kecil dan data kecil.
  • Debugging lebih mudah - Panggilan ops langsung untuk memeriksa model yang sedang berjalan dan menguji perubahan. Gunakan alat debugging Python standar untuk pelaporan kesalahan segera.
  • Aliran kontrol alami - Gunakan aliran kontrol Python alih-alih aliran kontrol grafik, sederhanakan spesifikasi model dinamis.

Eksekusi yang cepat mendukung sebagian besar operasi TensorFlow dan akselerasi GPU.

Pengaturan dan penggunaan dasar

 import os

import tensorflow as tf

import cProfile
 

Di Tensorflow 2.0, eksekusi yang cepat diaktifkan secara default.

 tf.executing_eagerly()
 
True

Sekarang Anda dapat menjalankan operasi TensorFlow dan hasilnya akan segera kembali:

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

Mengaktifkan eksekusi yang cepat mengubah perilaku operasi TensorFlow — sekarang mereka segera mengevaluasi dan mengembalikan nilainya ke Python. tf.Tensor mereferensikan nilai konkret alih-alih pegangan simbolik ke node dalam grafik komputasi. Karena tidak ada grafik komputasi untuk dibangun dan dijalankan kemudian dalam suatu sesi, mudah untuk memeriksa hasil menggunakan print() atau debugger. Mengevaluasi, mencetak, dan memeriksa nilai tensor tidak mematahkan aliran komputasi gradien.

Eksekusi yang bersemangat bekerja dengan baik dengan NumPy . Operasi NumPy menerima argumen tf.Tensor . Operasi TensorFlow tf.math mengubah objek Python dan array NumPy menjadi objek tf.Tensor . Metode tf.Tensor.numpy mengembalikan nilai objek sebagai ndarray NumPy.

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

Aliran kontrol dinamis

Manfaat utama dari eksekusi yang cepat adalah bahwa semua fungsi bahasa host tersedia saat model Anda dieksekusi. Jadi, misalnya, mudah untuk menulis 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

Ini memiliki persyaratan yang bergantung pada nilai tensor dan mencetak nilai-nilai ini saat runtime.

Pelatihan yang bersemangat

Komputasi gradien

Diferensiasi otomatis berguna untuk mengimplementasikan algoritma pembelajaran mesin seperti backpropagation untuk pelatihan jaringan saraf. Selama eksekusi penuh semangat, gunakan tf.GradientTape untuk melacak operasi untuk menghitung gradien nanti.

Anda dapat menggunakan tf.GradientTape untuk melatih dan / atau menghitung gradien dengan penuh semangat. Ini sangat berguna untuk loop pelatihan yang rumit.

Karena operasi yang berbeda dapat terjadi selama setiap panggilan, semua operasi forward-pass direkam ke "tape". Untuk menghitung gradien, putar kaset ke belakang lalu abaikan. tf.GradientTape tertentu hanya dapat menghitung satu gradien; panggilan selanjutnya menimbulkan kesalahan runtime.

 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)

Latih model

Contoh berikut membuat model multi-layer yang mengklasifikasikan digit tulisan tangan standar MNIST. Ini menunjukkan optimizer dan layer API untuk membangun grafik yang dapat dilatih di lingkungan eksekusi yang bersemangat.

 # 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)
 
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step

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

Bahkan tanpa pelatihan, panggil model dan periksa output dalam pelaksanaan bersemangat:

 for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
 
Logits:  [[-0.04290903  0.05850095 -0.09306249  0.01919096 -0.04339378  0.09877204
  -0.16061416  0.03829113 -0.04268045 -0.01678811]]

Sementara model keras memiliki loop pelatihan bawaan (menggunakan metode fit ), kadang-kadang Anda perlu lebih banyak penyesuaian. Berikut ini contoh, dari loop pelatihan yang diterapkan dengan bersemangat:

 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

Variabel dan pengoptimal

tf.Variable menyimpan nilai yang dapat berubah tf.Tensor - seperti diakses selama pelatihan untuk membuat diferensiasi otomatis lebih mudah.

Koleksi variabel dapat diringkas ke dalam lapisan atau model, bersama dengan metode yang beroperasi pada mereka. Lihat lapisan dan model Kustom Keras untuk detailnya. Perbedaan utama antara lapisan dan model adalah bahwa model menambahkan metode seperti Model.fit , Model.evaluate , dan Model.save .

Misalnya, contoh diferensiasi otomatis di atas dapat ditulis ulang:

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

Lanjut:

  1. Buat model.
  2. Derivatif fungsi kerugian sehubungan dengan parameter model.
  3. Strategi untuk memperbarui variabel berdasarkan turunannya.
 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: 68.574
Loss at step 000: 65.927
Loss at step 020: 30.202
Loss at step 040: 14.151
Loss at step 060: 6.936
Loss at step 080: 3.692
Loss at step 100: 2.233
Loss at step 120: 1.576
Loss at step 140: 1.281
Loss at step 160: 1.148
Loss at step 180: 1.088
Loss at step 200: 1.061
Loss at step 220: 1.049
Loss at step 240: 1.043
Loss at step 260: 1.041
Loss at step 280: 1.040

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

 print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
 
W = 2.988429069519043, B = 2.008305311203003

Penghematan berbasis objek

Model tf.keras.Model menyertakan metode save_weights yang save_weights memungkinkan Anda membuat pos pemeriksaan dengan mudah:

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

Menggunakan tf.train.Checkpoint Anda dapat mengambil kendali penuh atas proses ini.

Bagian ini adalah versi singkat panduan untuk melatih pos-pos pemeriksaan .

 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('./ckpt/')
 
'./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>

Untuk menyimpan dan memuat model, tf.train.Checkpoint menyimpan keadaan internal objek, tanpa memerlukan variabel tersembunyi. Untuk merekam keadaan model , optimizer , dan langkah global, berikan mereka ke 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 0x7f9dcc8be588>

Metrik berorientasi objek

tf.keras.metrics disimpan sebagai objek. Perbarui metrik dengan meneruskan data baru ke yang dapat dipanggil, dan ambil hasilnya menggunakan metode tf.keras.metrics.result , misalnya:

 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>

Ringkasan dan Papan Tensor

TensorBoard adalah alat visualisasi untuk memahami, men -debug dan mengoptimalkan proses pelatihan model. Menggunakan ringkasan acara yang ditulis saat menjalankan program.

Anda dapat menggunakan tf.summary untuk merekam ringkasan variabel dalam eksekusi yang tf.summary . Misalnya, untuk mencatat ringkasan loss setiap 100 langkah pelatihan:

 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.1595467632.kokoro-gcp-ubuntu-prod-341901152.10415.619671.v2

Topik diferensiasi otomatis tingkat lanjut

Model yang dinamis

tf.GradientTape juga dapat digunakan dalam model dinamis. Contoh ini untuk algoritma pencarian garis lacak mundur terlihat seperti kode NumPy normal, kecuali ada gradien dan dapat dibedakan, meskipun ada aliran kontrol yang kompleks:

 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
 

Gradien khusus

Gradien khusus adalah cara mudah untuk menimpa gradien. Dalam fungsi penerusan, tentukan gradien sehubungan dengan input, output, atau hasil antara. Sebagai contoh, inilah cara mudah untuk memotong norma gradien pada pass mundur:

 @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
 

Gradien khusus biasanya digunakan untuk memberikan gradien yang stabil secara numerik untuk urutan operasi:

 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

Di sini, fungsi log1pexp dapat disederhanakan secara analitik dengan gradien khusus. Implementasi di bawah ini menggunakan kembali nilai untuk tf.exp(x) yang dihitung selama forward pass — menjadikannya lebih efisien dengan menghilangkan perhitungan yang berlebihan:

 @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

Performa

Komputasi secara otomatis diturunkan ke GPU selama eksekusi yang diinginkan. Jika Anda ingin mengontrol di mana komputasi berjalan Anda dapat melampirkannya di tf.device('/gpu:0') (atau yang setara dengan 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.experimental.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: 0.9854905605316162 secs
GPU: 0.0423429012298584 secs

Objek tf.Tensor dapat disalin ke perangkat yang berbeda untuk menjalankan operasinya:

 if tf.config.experimental.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 <ipython-input-43-876293b5769c>: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 <ipython-input-43-876293b5769c>: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.

Tolak ukur

Untuk model komputasi yang berat, seperti pelatihan ResNet50 tentang GPU, kinerja eksekusi yang cepat sebanding dengan eksekusi tf.function . Tetapi celah ini tumbuh lebih besar untuk model dengan perhitungan yang lebih sedikit dan ada pekerjaan yang harus dilakukan untuk mengoptimalkan jalur kode panas untuk model dengan banyak operasi kecil.

Bekerja dengan fungsi

Sementara eksekusi yang bersemangat membuat pengembangan dan debugging menjadi lebih interaktif, eksekusi grafik gaya 1.x TensorFlow memiliki kelebihan untuk pelatihan terdistribusi, optimalisasi kinerja, dan penyebaran produksi. Untuk menjembatani kesenjangan ini, TensorFlow 2.0 memperkenalkan function s melalui API tf.function . Untuk informasi lebih lanjut, lihat panduan fungsi tf .