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 penting yang mengevaluasi operasi dengan segera, tanpa membuat grafik: operasi mengembalikan nilai konkret alih-alih membuat grafik komputasi untuk dijalankan nanti. Hal ini memudahkan untuk memulai TensorFlow dan model debug, dan juga mengurangi boilerplate. Untuk mengikuti panduan ini, jalankan contoh kode di bawah ini dalam interpreter python interaktif.

Eksekusi bersemangat adalah platform pembelajaran mesin yang fleksibel untuk penelitian dan eksperimen, menyediakan:

  • Antarmuka yang intuitif —Struktur kode Anda secara alami dan gunakan struktur data Python. Lakukan iterasi dengan cepat pada model kecil dan data kecil.
  • Proses debug yang lebih mudah —Panggil operasi secara langsung untuk memeriksa model yang sedang berjalan dan menguji perubahan. Gunakan alat debugging Python standar untuk pelaporan kesalahan langsung.
  • Aliran kendali alami —Gunakan aliran kendali Python alih-alih aliran kendali grafik, yang menyederhanakan spesifikasi model dinamis.

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

Penyiapan dan penggunaan dasar

import os

import tensorflow as tf

import cProfile
.dll

Di Tensorflow 2.0, eager execution diaktifkan secara default.

tf.executing_eagerly()
True

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

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

Mengaktifkan eager execution mengubah perilaku operasi TensorFlow — sekarang operasi tersebut segera mengevaluasi dan mengembalikan nilainya ke Python. tf.Tensor Objek tf.Tensor mereferensikan nilai konkret alih-alih tuas simbolik ke node dalam grafik komputasi. Karena tidak ada grafik komputasi untuk dibuat dan dijalankan nanti dalam sesi, mudah untuk memeriksa hasil menggunakan print() atau debugger. Mengevaluasi, mencetak, dan memeriksa nilai tensor tidak memutus aliran untuk menghitung gradien.

Eksekusi bersemangat bekerja dengan baik dengan NumPy . Operasi NumPy menerima argumen tf.Tensor . Operasi TensorFlow tf.math mengonversi 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 eager execution adalah bahwa semua fungsionalitas bahasa host tersedia saat model Anda dijalankan. Jadi, misalnya, menulis fizzbuzz dengan mudah:

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 kondisional yang bergantung pada nilai tensor dan mencetak nilai ini pada waktu proses.

Pelatihan yang bersemangat

Menghitung gradien

Diferensiasi otomatis berguna untuk mengimplementasikan algoritme pembelajaran mesin seperti propagasi mundur untuk melatih jaringan saraf. Selama eager execution, gunakantf.GradientTape untuk melacak operasi komputasi gradien nanti.

Anda dapat menggunakantf.GradientTape untuk melatih dan / atau menghitung gradien dengan bersemangat. Ini sangat berguna untuk loop pelatihan yang rumit.

Karena operasi yang berbeda dapat terjadi selama setiap panggilan, semua operasi forward-pass direkam ke sebuah "tape". Untuk menghitung gradien, putar kaset ke belakang dan kemudian buang. Sebuahtf.GradientTape tertentu hanya dapat menghitung satu gradien; panggilan berikutnya memunculkan kesalahan waktu proses.

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 MNIST standar. Ini mendemonstrasikan pengoptimal dan API lapisan untuk membuat grafik yang dapat dilatih dalam 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 keluarannya dalam eksekusi cepat:

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[ 0.06289896 -0.03877686 -0.07346137 -0.03169462  0.02922358 -0.02436475
  -0.00588411  0.03256026  0.01715117 -0.02714448]]

Meskipun model keras memiliki loop pelatihan bawaan (menggunakan metode fit ), terkadang Anda memerlukan lebih banyak penyesuaian. Berikut adalah contoh training loop yang diimplementasikan dengan eager:

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 Objek tf.Variable menyimpan nilai seperti tf.Tensor dapat berubah yang diakses selama pelatihan untuk membuat diferensiasi otomatis lebih mudah.

Kumpulan variabel dapat dienkapsulasi menjadi lapisan atau model, bersama dengan metode yang mengoperasikannya. Lihat model dan lapisan Keras Kustom 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 modelnya.
  2. Derivatif dari fungsi kerugian yang terkait 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.602
Loss at step 000: 65.948
Loss at step 020: 30.156
Loss at step 040: 14.091
Loss at step 060: 6.878
Loss at step 080: 3.637
Loss at step 100: 2.180
Loss at step 120: 1.525
Loss at step 140: 1.231
Loss at step 160: 1.098
Loss at step 180: 1.038
Loss at step 200: 1.011
Loss at step 220: 0.999
Loss at step 240: 0.994
Loss at step 260: 0.991
Loss at step 280: 0.990

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

print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 3.001922369003296, B = 2.0047335624694824

Penghematan berbasis objek

Sebuah tf.keras.Model menyertakan metode save_weights yang memudahkan Anda membuat pos pemeriksaan:

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

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

Bagian ini adalah versi singkat dari panduan untuk pos pemeriksaan pelatihan .

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 status internal objek, tanpa memerlukan variabel tersembunyi. Untuk merekam status model , optimizer , dan langkah global, teruskan 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 0x7f9abd45f1d0>

Metrik berorientasi objek

tf.keras.metrics disimpan sebagai objek. Perbarui metrik dengan meneruskan data baru ke callable, dan mengambil 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 TensorBoard

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

Anda dapat menggunakan tf.summary untuk merekam ringkasan variabel dalam eksekusi yang bersemangat. Misalnya, untuk mencatat ringkasan loss sekali 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.1602033841.kokoro-gcp-ubuntu-prod-892356553.1670.619697.v2

Topik diferensiasi otomatis lanjutan

Model dinamis

tf.GradientTape juga dapat digunakan dalam model dinamis. Contoh algoritme penelusuran garis mundur ini terlihat seperti kode NumPy normal, kecuali terdapat gradien dan dapat dibedakan, terlepas dari aliran kontrol yang rumit:

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 kustom

Gradien kustom adalah cara mudah untuk mengganti gradien. Dalam fungsi maju, tentukan gradien sehubungan dengan masukan, keluaran, atau hasil antara. Misalnya, berikut ini cara mudah untuk memotong norma gradien di backward pass:

@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 kustom biasanya digunakan untuk memberikan gradien yang stabil secara numerik untuk rangkaian 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 — membuatnya lebih efisien dengan menghilangkan penghitungan 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 cepat. Jika Anda ingin mengontrol di mana komputasi dijalankan, Anda dapat memasukkannya ke dalam 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.9788374900817871 secs
GPU: 0.04241943359375 secs

Objek tf.Tensor dapat disalin ke perangkat lain 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-1-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-1-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-berat, seperti pelatihan ResNet50 pada GPU, kinerja eksekusi yang bersemangat sebanding dengan eksekusi tf.function . Namun kesenjangan ini semakin besar untuk model dengan komputasi yang lebih sedikit dan ada pekerjaan yang harus diselesaikan untuk mengoptimalkan jalur kode panas untuk model dengan banyak operasi kecil.

Bekerja dengan fungsi

Meskipun eager execution membuat pengembangan dan debugging menjadi lebih interaktif, eksekusi grafik gaya TensorFlow 1.x memiliki kelebihan untuk pelatihan terdistribusi, pengoptimalan performa, dan penerapan produksi. Untuk menjembatani kesenjangan ini, TensorFlow 2.0 memperkenalkan function melalui tf.function API. Untuk informasi lebih lanjut, lihat panduan fungsi tf .