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

Hiệu quả TensorFlow 2

Có nhiều thay đổi trong TensorFlow 2.0 để giúp người dùng TensorFlow làm việc hiệu quả hơn. TensorFlow 2.0 loại bỏ các API dư thừa , làm cho các API nhất quán hơn ( RNN hợp nhất , Trình tối ưu hóa hợp nhất ) và tích hợp tốt hơn với thời gian chạy Python với thực thi Eager .

Nhiều RFC đã giải thích những thay đổi đã tạo nên TensorFlow 2.0. Hướng dẫn này trình bày tầm nhìn về sự phát triển trong TensorFlow 2.0 sẽ như thế nào. Giả sử bạn đã quen thuộc với TensorFlow 1.x.

Tóm tắt ngắn gọn về những thay đổi chính

Dọn dẹp API

Nhiều API đã biến mất hoặc được di chuyển trong TF 2.0. Một số thay đổi chính bao gồm xóa tf.app , tf.flagstf.logging để ủng hộ absl-py mã nguồn mở hiện nay, chỉnh sửa lại các dự án tồn tại trong tf.contrib và dọn dẹp không gian tên tf.* bằng cách chuyển các hàm ít được sử dụng hơn vào các gói con như tf.math . Một số API đã được thay thế bằng các API tương đương của chúng - tf.summary , tf.keras.metricstf.keras.optimizers . Cách dễ nhất để tự động áp dụng những tên đổi này là sử dụng tập lệnh nâng cấp v2 .

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

TensorFlow 1.X yêu cầu người dùng ghép thủ công một cây cú pháp trừu tượng (biểu đồ) bằng cách thực hiện các lệnh gọi API tf.* . Sau đó, nó yêu cầu người dùng biên dịch cây cú pháp trừu tượng theo cách thủ công bằng cách chuyển một tập hợp các tensor đầu ra và tensors đầu vào cho một cuộc gọi session.run() . TensorFlow 2.0 thực thi một cách háo hức (giống như Python thường làm) và trong 2.0, đồ thị và phiên sẽ giống như chi tiết triển khai.

Một sản phẩm phụ đáng chú ý của việc thực thi háo hức là tf.control_dependencies() không còn được yêu cầu nữa, vì tất cả các dòng mã đều thực thi theo thứ tự (trong một tf.function ., mã có tác dụng phụ sẽ thực thi theo thứ tự đã viết).

Không còn hình cầu

TensorFlow 1.X chủ yếu dựa vào các không gian tên toàn cầu ngầm. Khi bạn gọi tf.Variable() , nó sẽ được đưa vào đồ thị mặc định và nó sẽ vẫn ở đó, ngay cả khi bạn mất dấu biến Python trỏ đến nó. Sau đó, bạn có thể khôi phục tf.Variable đó, nhưng chỉ khi bạn biết tên mà nó đã được tạo. Điều này khó thực hiện nếu bạn không kiểm soát được việc tạo biến. Do đó, tất cả các loại cơ chế đã phát triển để cố gắng giúp người dùng tìm lại các biến của họ và các khuôn khổ để tìm các biến do người dùng tạo: Phạm vi biến, tập hợp toàn cục, các phương thức trợ giúp như tf.get_global_step() , tf.global_variables_initializer() , trình tối ưu hóa tính toán ngầm định các độ dốc trên tất cả các biến có thể đào tạo, v.v. TensorFlow 2.0 loại bỏ tất cả các cơ chế này ( Biến 2.0 RFC ) để có lợi cho cơ chế mặc định: Theo dõi các biến của bạn! Nếu bạn mất dấu tf.Variable , nó sẽ được thu gom rác.

Yêu cầu theo dõi các biến tạo ra một số công việc bổ sung cho người dùng, nhưng với các đối tượng Keras (xem bên dưới), gánh nặng được giảm thiểu.

Chức năng, không phải phiên

session.run() gọi session.run() gần giống như một lệnh gọi hàm: Bạn chỉ định các đầu vào và hàm sẽ được gọi, và bạn nhận lại một tập hợp các đầu ra. Trong TensorFlow 2.0, bạn có thể trang trí một hàm Python bằng cách sử dụng tf.function() để đánh dấu nó cho quá trình biên dịch JIT để TensorFlow chạy nó dưới dạng một biểu đồ duy nhất ( Functions 2.0 RFC ). Cơ chế này cho phép TensorFlow 2.0 đạt được tất cả các lợi ích của chế độ biểu đồ:

  • Hiệu suất: Chức năng có thể được tối ưu hóa (cắt bỏ nút, hợp nhất nhân, v.v.)
  • Tính di động: Chức năng có thể được xuất / nhập lại ( SavedModel 2.0 RFC ), cho phép người dùng sử dụng lại và chia sẻ các chức năng TensorFlow mô-đun.
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TensorFlow 2.0
outputs = f(input)

Với khả năng tự do xen kẽ mã Python và TensorFlow, người dùng có thể tận dụng khả năng diễn đạt của Python. Nhưng TensorFlow di động thực thi trong các ngữ cảnh không có trình thông dịch Python, chẳng hạn như di động, C ++ và JavaScript. Để giúp người dùng tránh phải viết lại mã của họ khi thêm @tf.function , AutoGraph chuyển đổi một tập hợp con các cấu trúc Python thành các cấu trúc tương đương TensorFlow của họ:

  • for / while -> tf.while_loop ( breakcontinue được hỗ trợ)
  • if -> tf.cond
  • for _ in dataset -> dataset.reduce

AutoGraph hỗ trợ lồng tùy ý luồng điều khiển, giúp bạn có thể triển khai một cách chính xác và rõ ràng nhiều chương trình ML phức tạp như mô hình tuần tự, học củng cố, vòng huấn luyện tùy chỉnh, v.v.

Đề xuất cho TensorFlow 2.0 thành ngữ

Cấu trúc lại mã của bạn thành các chức năng nhỏ hơn

Một mô hình sử dụng phổ biến trong TensorFlow 1.X là chiến lược "bồn rửa trong nhà bếp", trong đó sự kết hợp của tất cả các phép tính có thể được đặt ra trước và sau đó các tensor đã chọn được đánh giá thông qua session.run() . Trong TensorFlow 2.0, người dùng nên cấu trúc lại mã của họ thành các hàm nhỏ hơn được gọi khi cần thiết. Nói chung, không cần thiết phải trang trí từng chức năng nhỏ hơn này với tf.function . tf.function ; chỉ sử dụng tf.function để trang trí các tính toán cấp cao - ví dụ: một bước đào tạo hoặc chuyển tiếp mô hình của bạn.

Sử dụng các lớp và mô hình Keras để quản lý các biến

Các mô hình và lớp Keras cung cấp các variables thuận tiện và thuộc tính trainable_variables , các thuộc tính này thu thập một cách đệ quy tất cả các biến phụ thuộc. Điều này giúp dễ dàng quản lý các biến cục bộ tại nơi chúng đang được sử dụng.

Tương phản:

def dense(x, W, b):
  return tf.nn.sigmoid(tf.matmul(x, W) + b)

@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
  x = dense(x, w0, b0)
  x = dense(x, w1, b1)
  x = dense(x, w2, b2)
  ...

# You still have to manage w_i and b_i, and their shapes are defined far away from the code.

với phiên bản Keras:

# Each layer can be called, with a signature equivalent to linear(x)
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)

# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]

Các lớp / mô hình tf.train.Checkpointable kế thừa từ tf.train.Checkpointable và được tích hợp với @tf.function , giúp bạn có thể trực tiếp kiểm tra hoặc xuất SavedModels từ các đối tượng Keras. Bạn không nhất thiết phải sử dụng API .fit() của .fit() để tận dụng các tích hợp này.

Dưới đây là một ví dụ học chuyển đổi thể hiện cách Keras giúp dễ dàng thu thập một tập hợp con các biến có liên quan. Giả sử bạn đang đào tạo một mô hình nhiều đầu với một thân chia sẻ:

trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])

path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])

# Train on primary dataset
for x, y in main_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path1(x, training=True)
    loss = loss_fn_head1(prediction, y)
  # Simultaneously optimize trunk and head1 weights.
  gradients = tape.gradient(loss, path1.trainable_variables)
  optimizer.apply_gradients(zip(gradients, path1.trainable_variables))

# Fine-tune second head, reusing the trunk
for x, y in small_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path2(x, training=True)
    loss = loss_fn_head2(prediction, y)
  # Only optimize head2 weights, not trunk weights
  gradients = tape.gradient(loss, head2.trainable_variables)
  optimizer.apply_gradients(zip(gradients, head2.trainable_variables))

# You can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)

Kết hợp tf.data.Datasets và @ tf. Chức năng

Khi lặp qua dữ liệu đào tạo phù hợp với bộ nhớ, hãy sử dụng lặp lại Python thông thường. Nếu không,tf.data.Dataset là cách tốt nhất để truyền dữ liệu đào tạo từ đĩa. Tập dữ liệu là các tệp lặp (không phải trình vòng lặp) và hoạt động giống như các tệp lặp Python khác ở chế độ Eager. Bạn có thể sử dụng đầy đủ các tính năng tìm nạp / phát trực tuyến không đồng bộ tập dữ liệu bằng cách gói mã của bạn trong tf.function() , thay thế lặp lại Python bằng các hoạt động biểu đồ tương đương bằng cách sử dụng AutoGraph.

@tf.function
def train(model, dataset, optimizer):
  for x, y in dataset:
    with tf.GradientTape() as tape:
      # training=True is only needed if there are layers with different
      # behavior during training versus inference (e.g. Dropout).
      prediction = model(x, training=True)
      loss = loss_fn(prediction, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Nếu bạn sử dụng API Keras .fit() , bạn sẽ không phải lo lắng về việc lặp lại tập dữ liệu.

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)

Tận dụng AutoGraph với luồng điều khiển Python

AutoGraph cung cấp một cách để chuyển đổi luồng điều khiển phụ thuộc vào dữ liệu thành các chế độ tương đương ở chế độ đồ thị như tf.condtf.while_loop .

Một nơi phổ biến mà luồng điều khiển phụ thuộc vào dữ liệu xuất hiện là trong các mô hình tuần tự. tf.keras.layers.RNN bao bọc một ô RNN, cho phép bạn tf.keras.layers.RNN cuộn lặp lại một cách tĩnh hoặc động. Vì lợi ích của cuộc trình diễn, bạn có thể thực hiện lại việc hủy cuộn động như sau:

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell

  def call(self, input_data):
    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    outputs = tf.TensorArray(tf.float32, input_data.shape[0])
    state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
    for i in tf.range(input_data.shape[0]):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state

Để biết tổng quan chi tiết hơn về các tính năng của AutoGraph, hãy xem hướng dẫn .

tf.metrics tổng hợp dữ liệu và tf.summary ghi lại chúng

Để ghi tóm tắt, hãy sử dụng tf.summary.(scalar|histogram|...) và chuyển hướng nó đến một người viết bằng trình quản lý ngữ cảnh. (Nếu bạn bỏ qua trình quản lý ngữ cảnh, không có gì xảy ra.) Không giống như TF 1.x, các bản tóm tắt được gửi trực tiếp cho người viết; không có op "hợp nhất" riêng biệt và không có lệnh gọi add_summary() riêng biệt, có nghĩa là giá trị step phải được cung cấp tại trang web gọi.

summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)

Để tổng hợp dữ liệu trước khi ghi chúng dưới dạng tóm tắt, hãy sử dụng tf.metrics . Các chỉ số có trạng thái: Chúng tích lũy các giá trị và trả về kết quả tích lũy khi bạn gọi .result() . Xóa các giá trị đã tích lũy bằng .reset_states() .

def train(model, optimizer, dataset, log_freq=10):
  avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
  for images, labels in dataset:
    loss = train_step(model, optimizer, images, labels)
    avg_loss.update_state(loss)
    if tf.equal(optimizer.iterations % log_freq, 0):
      tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
      avg_loss.reset_states()

def test(model, test_x, test_y, step_num):
  # training=False is only needed if there are layers with different
  # behavior during training versus inference (e.g. Dropout).
  loss = loss_fn(model(test_x, training=False), test_y)
  tf.summary.scalar('loss', loss, step=step_num)

train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')

with train_summary_writer.as_default():
  train(model, optimizer, dataset)

with test_summary_writer.as_default():
  test(model, test_x, test_y, optimizer.iterations)

Trực quan hóa các bản tóm tắt đã tạo bằng cách trỏ TensorBoard vào thư mục nhật ký tóm tắt:

tensorboard --logdir /tmp/summaries

Sử dụng tf.config.experimental_run_functions_eagerly () khi gỡ lỗi

Trong TensorFlow 2.0, việc thực thi Eager cho phép bạn chạy mã từng bước để kiểm tra hình dạng, kiểu dữ liệu và giá trị. Một số API nhất định, như tf.function , tf.keras , v.v. được thiết kế để sử dụng thực thi Đồ thị, cho hiệu suất và tính di động. Khi gỡ lỗi, hãy sử dụng tf.config.experimental_run_functions_eagerly(True) để sử dụng thực thi Eager bên trong mã này.

Ví dụ:

@tf.function
def f(x):
  if x > 0:
    import pdb
    pdb.set_trace()
    x = x + 1
  return x

tf.config.experimental_run_functions_eagerly(True)
f(tf.constant(1))
>>> f()
-> x = x + 1
(Pdb) l
  6     @tf.function
  7     def f(x):
  8       if x > 0:
  9         import pdb
 10         pdb.set_trace()
 11  ->     x = x + 1
 12       return x
 13
 14     tf.config.experimental_run_functions_eagerly(True)
 15     f(tf.constant(1))
[EOF]

Điều này cũng hoạt động bên trong các mô hình Keras và các API khác hỗ trợ thực thi Eager:

class CustomModel(tf.keras.models.Model):

  @tf.function
  def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
      return input_data
    else:
      import pdb
      pdb.set_trace()
      return input_data // 2


tf.config.experimental_run_functions_eagerly(True)
model = CustomModel()
model(tf.constant([-2, -4]))
>>> call()
-> return input_data // 2
(Pdb) l
 10         if tf.reduce_mean(input_data) > 0:
 11           return input_data
 12         else:
 13           import pdb
 14           pdb.set_trace()
 15  ->       return input_data // 2
 16
 17
 18     tf.config.experimental_run_functions_eagerly(True)
 19     model = CustomModel()
 20     model(tf.constant([-2, -4]))