Trang này được dịch bởi Cloud Translation API.
Switch to English

Háo hức thực hiện

Xem trên TensorFlow.org Chạy trong Google Colab Xem nguồn trên GitHub Tải xuống sổ tay

Khả năng thực thi háo hức của TensorFlow là một môi trường lập trình bắt buộc đánh giá các hoạt động ngay lập tức mà không cần xây dựng đồ thị: các hoạt động trả về giá trị cụ thể thay vì xây dựng một biểu đồ tính toán để chạy sau đó. Điều này giúp bạn dễ dàng bắt đầu với TensorFlow và các mô hình gỡ lỗi, đồng thời nó cũng làm giảm quá trình soạn sẵn. Để làm theo hướng dẫn này, hãy chạy các mẫu mã bên dưới trong trình thông dịch python tương tác.

Thực thi háo hức là một nền tảng học máy linh hoạt để nghiên cứu và thử nghiệm, cung cấp:

  • Giao diện trực quan —Cấu trúc mã của bạn một cách tự nhiên và sử dụng cấu trúc dữ liệu Python. Lặp lại nhanh chóng trên các mô hình nhỏ và dữ liệu nhỏ.
  • Gỡ lỗi dễ dàng hơn —Gọi trực tiếp để kiểm tra các mô hình đang chạy và kiểm tra các thay đổi. Sử dụng các công cụ gỡ lỗi Python tiêu chuẩn để báo cáo lỗi ngay lập tức.
  • Luồng điều khiển tự nhiên —Sử dụng luồng điều khiển Python thay vì luồng điều khiển đồ thị, đơn giản hóa đặc điểm kỹ thuật của các mô hình động.

Thực thi háo hức hỗ trợ hầu hết các hoạt động TensorFlow và tăng tốc GPU.

Thiết lập và sử dụng cơ bản

import os

import tensorflow as tf

import cProfile

Trong Tensorflow 2.0, thực thi háo hức được bật theo mặc định.

tf.executing_eagerly()
True

Bây giờ bạn có thể chạy các hoạt động TensorFlow và kết quả sẽ trả về ngay lập tức:

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

Việc kích hoạt thực thi háo hức sẽ thay đổi cách hoạt động của các hoạt động TensorFlow — giờ đây, chúng ngay lập tức đánh giá và trả về giá trị của chúng cho Python. tf.Tensor đối tượng tf.Tensor tham chiếu các giá trị cụ thể thay vì xử lý tượng trưng cho các nút trong một đồ thị tính toán. Vì không có biểu đồ tính toán để xây dựng và chạy sau trong một phiên, nên thật dễ dàng để kiểm tra kết quả bằng cách sử dụng print() hoặc trình gỡ lỗi. Đánh giá, in và kiểm tra các giá trị tensor không phá vỡ luồng cho các gradient tính toán.

Thực thi háo hức hoạt động tốt với NumPy . Các phép toán NumPy chấp nhận các đối số tf.Tensor . Các hoạt động TensorFlow tf.math chuyển đổi các đối tượng Python và mảng NumPy thành các đối tượng tf.Tensor . Phương thức tf.Tensor.numpy trả về giá trị của đối tượng dưới dạng một 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]]

Dòng điều khiển động

Lợi ích chính của việc thực thi háo hức là tất cả các chức năng của ngôn ngữ máy chủ đều có sẵn trong khi mô hình của bạn đang thực thi. Vì vậy, chẳng hạn, có thể dễ dàng viết 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

Điều này có các điều kiện phụ thuộc vào giá trị tensor và nó in các giá trị này trong thời gian chạy.

Háo hức đào tạo

Tính toán gradient

Sự khác biệt tự động rất hữu ích cho việc triển khai các thuật toán học máy, chẳng hạn như backpropagation để đào tạo mạng nơ-ron. Trong quá trình thực thi háo hức, hãy sử dụng tf.GradientTape để theo dõi các hoạt động cho độ dốc tính toán sau này.

Bạn có thể sử dụng tf.GradientTape để đào tạo và / hoặc tính toán gradient một cách háo hức. Nó đặc biệt hữu ích cho các vòng huấn luyện phức tạp.

Vì các thao tác khác nhau có thể xảy ra trong mỗi cuộc gọi, nên tất cả các thao tác chuyển tiếp đều được ghi vào một "băng". Để tính toán độ dốc, phát đoạn băng về phía sau và sau đó loại bỏ. Một tf.GradientTape cụ thể chỉ có thể tính toán một gradient; các cuộc gọi tiếp theo gây ra lỗi thời gian chạy.

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)

Đào tạo người mẫu

Ví dụ sau đây tạo một mô hình nhiều lớp phân loại các chữ số viết tay MNIST tiêu chuẩn. Nó thể hiện trình tối ưu hóa và API lớp để xây dựng đồ thị có thể đào tạo trong một môi trường thực thi háo hức.

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

Ngay cả khi không được đào tạo, hãy gọi mô hình và kiểm tra đầu ra trong quá trình thực thi háo hức:

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[-0.04126375  0.03160043 -0.07807496 -0.10245611  0.02141886 -0.00049652
  -0.07772101  0.06026737  0.05762767 -0.10979556]]

Trong khi các mô hình keras có vòng lặp đào tạo nội trang (sử dụng phương pháp fit ), đôi khi bạn cần tùy chỉnh nhiều hơn. Đây là một ví dụ về vòng lặp đào tạo được triển khai với háo hức:

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

Các biến và trình tối ưu hóa

tf.Variable đối tượng tf.Variable lưu trữ các giá trị giống như tf.Tensor có thể thay đổi được truy cập trong quá trình đào tạo để giúp phân biệt tự động dễ dàng hơn.

Tập hợp các biến có thể được đóng gói thành các lớp hoặc mô hình, cùng với các phương thức hoạt động trên chúng. Xem các lớp và mô hình Keras tùy chỉnh để biết thêm chi tiết. Sự khác biệt chính giữa các lớp và mô hình là các mô hình thêm các phương thức như Model.fit , Model.evaluateModel.save .

Ví dụ, ví dụ về phân biệt tự động ở trên có thể được viết lại:

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

Kế tiếp:

  1. Tạo mô hình.
  2. Các phái sinh của một hàm tổn thất đối với các tham số mô hình.
  3. Một chiến lược để cập nhật các biến dựa trên các dẫn xuất.
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.274
Loss at step 000: 65.640
Loss at step 020: 30.091
Loss at step 040: 14.106
Loss at step 060: 6.914
Loss at step 080: 3.677
Loss at step 100: 2.218
Loss at step 120: 1.561
Loss at step 140: 1.264
Loss at step 160: 1.130
Loss at step 180: 1.070
Loss at step 200: 1.043
Loss at step 220: 1.030
Loss at step 240: 1.025
Loss at step 260: 1.022
Loss at step 280: 1.021

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

print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.997738838195801, B = 2.018033742904663

Tiết kiệm dựa trên đối tượng

Một tf.keras.Model bao gồm một phương thức save_weights cho phép bạn dễ dàng tạo một điểm kiểm tra:

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

Sử dụng tf.train.Checkpoint bạn có thể kiểm soát toàn bộ quá trình này.

Phần này là phiên bản viết tắt của hướng dẫn về các điểm kiểm tra đào tạo .

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>

Để lưu và tải mô hình, tf.train.Checkpoint lưu trữ trạng thái bên trong của các đối tượng mà không yêu cầu các biến ẩn. Để ghi lại trạng thái của một model , một trình optimizer và một bước toàn cục, hãy chuyển chúng tới một 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 0x7f88ef2e99e8>

Các chỉ số hướng đối tượng

tf.keras.metrics được lưu trữ dưới dạng đối tượng. Cập nhật một số liệu bằng cách chuyển dữ liệu mới đến tệp có thể gọi và truy xuất kết quả bằng phương thức tf.keras.metrics.result , ví dụ:

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>

Summaries và TensorBoard

TensorBoard là một công cụ trực quan hóa để hiểu, gỡ lỗi và tối ưu hóa quá trình đào tạo mô hình. Nó sử dụng các sự kiện tóm tắt được viết trong khi thực hiện chương trình.

Bạn có thể sử dụng tf.summary để ghi lại tóm tắt của biến trong quá trình thực thi mong muốn. Ví dụ: để ghi tóm tắt loss một lần sau mỗi 100 bước huấn luyện:

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.1599701382.kokoro-gcp-ubuntu-prod-2031910853.25648.619697.v2

Chủ đề phân biệt tự động nâng cao

Mô hình động

tf.GradientTape cũng có thể được sử dụng trong các mô hình động. Ví dụ này cho thuật toán tìm kiếm theo dòng backtracking trông giống như mã NumPy bình thường, ngoại trừ có các độ dốc và có thể phân biệt được, mặc dù quy trình điều khiển phức tạp:

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

Gradient tùy chỉnh

Gradient tùy chỉnh là một cách dễ dàng để ghi đè gradient. Trong hàm chuyển tiếp, xác định gradient liên quan đến đầu vào, đầu ra hoặc kết quả trung gian. Ví dụ: đây là một cách dễ dàng để cắt tiêu chuẩn của gradient trong đường chuyền lùi:

@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

Gradient tùy chỉnh thường được sử dụng để cung cấp một gradient ổn định về số lượng cho một chuỗi hoạt động:

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

Ở đây, hàm log1pexp có thể được đơn giản hóa về mặt phân tích với một gradient tùy chỉnh. Việc triển khai bên dưới sử dụng lại giá trị cho tf.exp(x) được tính toán trong quá trình chuyển tiếp — làm cho nó hiệu quả hơn bằng cách loại bỏ các phép tính thừa:

@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

Hiệu suất

Tính toán tự động được tải xuống GPU trong quá trình thực thi háo hức. Nếu bạn muốn kiểm soát nơi tính toán chạy, bạn có thể đặt nó trong một tf.device('/gpu:0') (hoặc CPU tương đương):

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.9814188480377197 secs
GPU: 0.0416111946105957 secs

Một đối tượng tf.Tensor có thể được sao chép sang một thiết bị khác để thực hiện các hoạt động của nó:

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.

Điểm chuẩn

Đối với các mô hình máy tính nặng, chẳng hạn như đào tạo ResNet50 trên GPU, hiệu suất thực thi mong muốn có thể so sánh với thực thi chức năng tf.function . Nhưng khoảng cách này ngày càng lớn đối với các mô hình có ít tính toán hơn và còn nhiều việc phải làm để tối ưu hóa các đường dẫn mã nóng cho các mô hình có nhiều thao tác nhỏ.

Làm việc với các chức năng

Trong khi thực thi háo hức làm cho việc phát triển và gỡ lỗi tương tác hơn, thực thi đồ thị kiểu TensorFlow 1.x có lợi thế cho đào tạo phân tán, tối ưu hóa hiệu suất và triển khai sản xuất. Để thu hẹp khoảng cách này, TensorFlow 2.0 giới thiệu các function s thông qua API tf.function . tf.function . Để biết thêm thông tin, hãy xem hướng dẫn chức năng tf .