Gỡ lỗi đường ống đào tạo đã di chuyển TF2

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

Sổ tay này trình bày cách gỡ lỗi đường dẫn đào tạo khi di chuyển sang TF2. Nó bao gồm các thành phần sau:

  1. Các bước được đề xuất và các mẫu mã để gỡ lỗi quy trình đào tạo
  2. Công cụ gỡ lỗi
  3. Các nguồn liên quan khác

Một giả định là bạn có mã TF1.x và các mô hình được đào tạo để so sánh và bạn muốn xây dựng mô hình TF2 đạt được độ chính xác xác thực tương tự.

Máy tính xách tay này KHÔNG đề cập đến việc gỡ lỗi các vấn đề về hiệu suất đối với tốc độ đào tạo / suy luận hoặc sử dụng bộ nhớ.

Gỡ lỗi quy trình làm việc

Dưới đây là quy trình chung để gỡ lỗi các đường dẫn đào tạo TF2 của bạn. Lưu ý rằng bạn không cần phải làm theo các bước sau theo thứ tự. Bạn cũng có thể sử dụng cách tiếp cận tìm kiếm nhị phân trong đó bạn kiểm tra mô hình ở bước trung gian và thu hẹp phạm vi gỡ lỗi.

  1. Sửa lỗi biên dịch và thời gian chạy

  2. Xác thực chuyển tiếp một lần (trong một hướng dẫn riêng)

    Một. Trên một thiết bị CPU

    • Xác minh các biến chỉ được tạo một lần
    • Kiểm tra số lượng biến, tên và hình dạng phù hợp
    • Đặt lại tất cả các biến, kiểm tra sự tương đương về số với tất cả tính ngẫu nhiên bị tắt
    • Căn chỉnh việc tạo số ngẫu nhiên, kiểm tra sự tương đương của số trong suy luận
    • (Tùy chọn) Các điểm kiểm tra được tải đúng cách và các mô hình TF1.x / TF2 tạo ra đầu ra đồng nhất

    b. Trên thiết bị GPU / TPU đơn

    C. Với chiến lược đa thiết bị

  3. Xác thực tương đương số đào tạo mô hình trong một vài bước (các mẫu mã có sẵn bên dưới)

    Một. Xác thực bước đào tạo duy nhất bằng cách sử dụng dữ liệu nhỏ và cố định trên thiết bị CPU đơn. Cụ thể, hãy kiểm tra sự tương đương về số cho các thành phần sau

    • tính toán tổn thất
    • số liệu
    • tỷ lệ học
    • tính toán và cập nhật gradient

    b. Kiểm tra thống kê sau khi đào tạo 3 bước trở lên để xác minh các hành vi của trình tối ưu hóa như động lượng, vẫn với dữ liệu cố định trên thiết bị CPU đơn

    C. Trên thiết bị GPU / TPU đơn

    d. Với các chiến lược đa thiết bị (xem phần giới thiệu về MultiProcessRunner ở dưới cùng)

  4. Thử nghiệm bao trùm từ đầu đến cuối trên tập dữ liệu thực

    Một. Kiểm tra hành vi đào tạo với TensorBoard

    • sử dụng các trình tối ưu hóa đơn giản, ví dụ như SGD và các chiến lược phân phối đơn giản, ví dụ như tf.distribute.OneDeviceStrategy trước
    • số liệu đào tạo
    • số liệu đánh giá
    • tìm ra dung sai hợp lý cho tính ngẫu nhiên vốn có là bao nhiêu

    b. Kiểm tra tính tương đương với trình tối ưu hóa nâng cao / công cụ lập lịch biểu / phân phối tốc độ học nâng cao

    C. Kiểm tra tính tương đương khi sử dụng độ chính xác hỗn hợp

  5. Tiêu chuẩn sản phẩm bổ sung

Thành lập

pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is only available in
# Tensorflow 2.8
pip install -q tf-nightly

Xác thực một lần chuyển tiếp

Xác thực chuyển tiếp một lần, bao gồm cả tải điểm kiểm tra, được đề cập trong một chuyên mục khác.

import sys
import unittest
import numpy as np

import tensorflow as tf
import tensorflow.compat.v1 as v1

Đào tạo mô hình xác nhận tương đương số trong một vài bước

Thiết lập cấu hình mô hình và chuẩn bị một tập dữ liệu giả.

params = {
    'input_size': 3,
    'num_classes': 3,
    'layer_1_size': 2,
    'layer_2_size': 2,
    'num_train_steps': 100,
    'init_lr': 1e-3,
    'end_lr': 0.0,
    'decay_steps': 1000,
    'lr_power': 1.0,
}

# make a small fixed dataset
fake_x = np.ones((2, params['input_size']), dtype=np.float32)
fake_y = np.zeros((2, params['num_classes']), dtype=np.int32)
fake_y[0][0] = 1
fake_y[1][1] = 1

step_num = 3

Xác định mô hình TF1.x.

# Assume there is an existing TF1.x model using estimator API
# Wrap the model_fn to log necessary tensors for result comparison
class SimpleModelWrapper():
  def __init__(self):
    self.logged_ops = {}
    self.logs = {
        'step': [],
        'lr': [],
        'loss': [],
        'grads_and_vars': [],
        'layer_out': []}

  def model_fn(self, features, labels, mode, params):
      out_1 = tf.compat.v1.layers.dense(features, units=params['layer_1_size'])
      out_2 = tf.compat.v1.layers.dense(out_1, units=params['layer_2_size'])
      logits = tf.compat.v1.layers.dense(out_2, units=params['num_classes'])
      loss = tf.compat.v1.losses.softmax_cross_entropy(labels, logits)

      # skip EstimatorSpec details for prediction and evaluation 
      if mode == tf.estimator.ModeKeys.PREDICT:
          pass
      if mode == tf.estimator.ModeKeys.EVAL:
          pass
      assert mode == tf.estimator.ModeKeys.TRAIN

      global_step = tf.compat.v1.train.get_or_create_global_step()
      lr = tf.compat.v1.train.polynomial_decay(
        learning_rate=params['init_lr'],
        global_step=global_step,
        decay_steps=params['decay_steps'],
        end_learning_rate=params['end_lr'],
        power=params['lr_power'])

      optmizer = tf.compat.v1.train.GradientDescentOptimizer(lr)
      grads_and_vars = optmizer.compute_gradients(
          loss=loss,
          var_list=graph.get_collection(
              tf.compat.v1.GraphKeys.TRAINABLE_VARIABLES))
      train_op = optmizer.apply_gradients(
          grads_and_vars,
          global_step=global_step)

      # log tensors
      self.logged_ops['step'] = global_step
      self.logged_ops['lr'] = lr
      self.logged_ops['loss'] = loss
      self.logged_ops['grads_and_vars'] = grads_and_vars
      self.logged_ops['layer_out'] = {
          'layer_1': out_1,
          'layer_2': out_2,
          'logits': logits}

      return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

  def update_logs(self, logs):
    for key in logs.keys():
      model_tf1.logs[key].append(logs[key])

Lớp v1.keras.utils.DeterministicRandomTestTool sau đây cung cấp scope() có thể thực hiện các hoạt động ngẫu nhiên có trạng thái sử dụng cùng một hạt giống trên cả biểu đồ / phiên TF1 và thực thi háo hức,

Công cụ này cung cấp hai chế độ kiểm tra:

  1. constant sử dụng cùng một hạt giống cho mọi hoạt động bất kể nó đã được gọi bao nhiêu lần và,
  2. num_random_ops sử dụng số lượng các hoạt động ngẫu nhiên có trạng thái đã quan sát trước đó làm hạt giống hoạt động.

Điều này áp dụng cho cả các phép toán ngẫu nhiên có trạng thái được sử dụng để tạo và khởi tạo các biến và các phép toán ngẫu nhiên có trạng thái được sử dụng trong tính toán (chẳng hạn như cho các lớp bỏ học).

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
WARNING:tensorflow:From /tmp/ipykernel_26769/2689227634.py:1: The name tf.keras.utils.DeterministicRandomTestTool is deprecated. Please use tf.compat.v1.keras.utils.DeterministicRandomTestTool instead.

Chạy mô hình TF1.x ở chế độ đồ thị. Thu thập số liệu thống kê cho 3 bước đào tạo đầu tiên để so sánh số tương đương.

with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    model_tf1 = SimpleModelWrapper()
    # build the model
    inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
    labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
    spec = model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
    train_op = spec.train_op

    sess.run(tf.compat.v1.global_variables_initializer())
    for step in range(step_num):
      # log everything and update the model for one step
      logs, _ = sess.run(
          [model_tf1.logged_ops, train_op],
          feed_dict={inputs: fake_x, labels: fake_y})
      model_tf1.update_logs(logs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:261: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  from ipykernel import kernelapp as app
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()

Xác định mô hình TF2.

class SimpleModel(tf.keras.Model):
  def __init__(self, params, *args, **kwargs):
    super(SimpleModel, self).__init__(*args, **kwargs)
    # define the model
    self.dense_1 = tf.keras.layers.Dense(params['layer_1_size'])
    self.dense_2 = tf.keras.layers.Dense(params['layer_2_size'])
    self.out = tf.keras.layers.Dense(params['num_classes'])
    learning_rate_fn = tf.keras.optimizers.schedules.PolynomialDecay(
      initial_learning_rate=params['init_lr'],
      decay_steps=params['decay_steps'],
      end_learning_rate=params['end_lr'],
      power=params['lr_power'])  
    self.optimizer = tf.keras.optimizers.SGD(learning_rate_fn)
    self.compiled_loss = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
    self.logs = {
        'lr': [],
        'loss': [],
        'grads': [],
        'weights': [],
        'layer_out': []}

  def call(self, inputs):
    out_1 = self.dense_1(inputs)
    out_2 = self.dense_2(out_1)
    logits = self.out(out_2)
    # log output features for every layer for comparison
    layer_wise_out = {
        'layer_1': out_1,
        'layer_2': out_2,
        'logits': logits}
    self.logs['layer_out'].append(layer_wise_out)
    return logits

  def train_step(self, data):
    x, y = data
    with tf.GradientTape() as tape:
      logits = self(x)
      loss = self.compiled_loss(y, logits)
    grads = tape.gradient(loss, self.trainable_weights)
    # log training statistics
    step = self.optimizer.iterations.numpy()
    self.logs['lr'].append(self.optimizer.learning_rate(step).numpy())
    self.logs['loss'].append(loss.numpy())
    self.logs['grads'].append(grads)
    self.logs['weights'].append(self.trainable_weights)
    # update model
    self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
    return

Chạy mô hình TF2 ở chế độ háo hức. Thu thập số liệu thống kê cho 3 bước đào tạo đầu tiên để so sánh số tương đương.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  model_tf2 = SimpleModel(params)
  for step in range(step_num):
    model_tf2.train_step([fake_x, fake_y])

So sánh sự tương đương về số cho một vài bước đào tạo đầu tiên.

Bạn cũng có thể kiểm tra sổ tay xác thực tính đúng đắn và tương đương số để có lời khuyên bổ sung cho tính tương đương số.

np.testing.assert_allclose(model_tf1.logs['lr'], model_tf2.logs['lr'])
np.testing.assert_allclose(model_tf1.logs['loss'], model_tf2.logs['loss'])
for step in range(step_num):
  for name in model_tf1.logs['layer_out'][step]:
    np.testing.assert_allclose(
        model_tf1.logs['layer_out'][step][name],
        model_tf2.logs['layer_out'][step][name])

Bài kiểm tra đơn vị

Có một số loại kiểm thử đơn vị có thể giúp gỡ lỗi mã di chuyển của bạn.

  1. Xác thực một lần chuyển tiếp
  2. Đào tạo mô hình xác nhận tương đương số trong một vài bước
  3. Hiệu suất suy luận điểm chuẩn
  4. Mô hình được đào tạo đưa ra dự đoán chính xác trên các điểm dữ liệu cố định và đơn giản

Bạn có thể sử dụng @parameterized.parameters để kiểm tra các mô hình có cấu hình khác nhau. Chi tiết với mẫu mã .

Lưu ý rằng có thể chạy các API phiên và thực thi háo hức trong cùng một trường hợp thử nghiệm. Các đoạn mã dưới đây cho biết cách thực hiện.

import unittest

class TestNumericalEquivalence(unittest.TestCase):

  # copied from code samples above
  def setup(self):
    # record statistics for 100 training steps
    step_num = 100

    # setup TF 1 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      # run TF1.x code in graph mode with context management
      graph = tf.Graph()
      with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
        self.model_tf1 = SimpleModelWrapper()
        # build the model
        inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
        labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
        spec = self.model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
        train_op = spec.train_op

        sess.run(tf.compat.v1.global_variables_initializer())
        for step in range(step_num):
          # log everything and update the model for one step
          logs, _ = sess.run(
              [self.model_tf1.logged_ops, train_op],
              feed_dict={inputs: fake_x, labels: fake_y})
          self.model_tf1.update_logs(logs)

    # setup TF2 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      self.model_tf2 = SimpleModel(params)
      for step in range(step_num):
        self.model_tf2.train_step([fake_x, fake_y])

  def test_learning_rate(self):
    np.testing.assert_allclose(
        self.model_tf1.logs['lr'],
        self.model_tf2.logs['lr'])

  def test_training_loss(self):
    # adopt different tolerance strategies before and after 10 steps
    first_n_step = 10

    # abosolute difference is limited below 1e-5
    # set `equal_nan` to be False to detect potential NaN loss issues
    abosolute_tolerance = 1e-5
    np.testing.assert_allclose(
        actual=self.model_tf1.logs['loss'][:first_n_step],
        desired=self.model_tf2.logs['loss'][:first_n_step],
        atol=abosolute_tolerance,
        equal_nan=False)

    # relative difference is limited below 5%
    relative_tolerance = 0.05
    np.testing.assert_allclose(self.model_tf1.logs['loss'][first_n_step:],
                               self.model_tf2.logs['loss'][first_n_step:],
                               rtol=relative_tolerance,
                               equal_nan=False)

Công cụ gỡ lỗi

tf.print

tf.print so với print / logging.info

  • Với các đối số có thể định cấu hình, tf.print có thể hiển thị một cách đệ quy một số phần tử đầu tiên và cuối cùng của mỗi kích thước cho các tensors được in. Kiểm tra tài liệu API để biết chi tiết.
  • Để thực thi nhanh chóng, cả printtf.print in giá trị của tensor. Tuy nhiên, quá trình print có thể liên quan đến việc sao chép từ thiết bị đến máy chủ, điều này có thể làm chậm mã của bạn.
  • Đối với chế độ biểu đồ bao gồm việc sử dụng bên trong tf.function , bạn cần sử dụng tf.print để in giá trị tensor thực tế. tf.print được biên dịch thành một op trong biểu đồ, trong khi printlogging.info chỉ ghi nhật ký tại thời điểm theo dõi, điều này thường không như bạn muốn.
  • tf.print cũng hỗ trợ in các bộ căng tổng hợp như tf.RaggedTensortf.sparse.SparseTensor .
  • Bạn cũng có thể sử dụng lệnh gọi lại để theo dõi các chỉ số và biến. Vui lòng kiểm tra cách sử dụng lệnh gọi lại tùy chỉnh với thuộc tính logself.model .

tf.print so với in bên trong tf. Chức năng

# `print` prints info of tensor object
# `tf.print` prints the tensor value
@tf.function
def dummy_func(num):
  num += 1
  print(num)
  tf.print(num)
  return num

_ = dummy_func(tf.constant([1.0]))

# Output:
# Tensor("add:0", shape=(1,), dtype=float32)
# [2]
Tensor("add:0", shape=(1,), dtype=float32)
[2]

tf.distribute.Strategy

  • Nếu hàm tf.function chứa tf.print được thực thi trên worker, chẳng hạn như khi sử dụng TPUStrategy hoặc ParameterServerStrategy , bạn cần kiểm tra nhật ký máy chủ worker / tham số để tìm các giá trị được in.
  • Đối với print hoặc logging.info , nhật ký sẽ được in trên bộ điều phối khi sử dụng ParameterServerStrategy và nhật ký sẽ được in trên STDOUT trên worker0 khi sử dụng TPU.

tf.keras.Model

  • Khi sử dụng mô hình API tuần tự và chức năng, nếu bạn muốn in các giá trị, ví dụ: đầu vào mô hình hoặc tính năng trung gian sau một số lớp, bạn có các tùy chọn sau.
    1. Viết một lớp tùy chỉnh tf.print . In các đầu vào.
    2. Bao gồm các đầu ra trung gian mà bạn muốn kiểm tra trong các đầu ra của mô hình.
  • Các lớp tf.keras.layers.Lambda có (de) giới hạn tuần tự hóa. Để tránh các vấn đề về tải điểm kiểm tra, hãy viết một lớp phân lớp tùy chỉnh thay thế. Kiểm tra tài liệu API để biết thêm chi tiết.
  • Bạn không thể tf.print kết quả đầu ra trung gian trong tf.keras.callbacks.LambdaCallback nếu bạn không có quyền truy cập vào các giá trị thực mà thay vào đó chỉ đến các đối tượng tensor Keras tượng trưng.

Tùy chọn 1: viết một lớp tùy chỉnh

class PrintLayer(tf.keras.layers.Layer):
  def call(self, inputs):
    tf.print(inputs)
    return inputs

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # use custom layer to tf.print intermediate features
  out_3 = PrintLayer()(out_2)
  model = tf.keras.Model(inputs=inputs, outputs=out_3)
  return model

model = get_model()
model.compile(optimizer="adam", loss="mse")
model.fit([1, 2, 3], [0.0, 0.0, 1.0])
[[-0.327884018]
 [-0.109294668]
 [-0.218589336]]
1/1 [==============================] - 0s 280ms/step - loss: 0.6077
<keras.callbacks.History at 0x7f63d46bf190>

Tùy chọn 2: bao gồm các đầu ra trung gian mà bạn muốn kiểm tra trong các đầu ra của mô hình.

Lưu ý rằng trong trường hợp đó, bạn có thể cần một số tùy chỉnh để sử dụng Model.fit .

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # include intermediate values in model outputs
  model = tf.keras.Model(
      inputs=inputs,
      outputs={
          'inputs': inputs,
          'out_1': out_1,
          'out_2': out_2})
  return model

pdb

Bạn có thể sử dụng pdb cả trong terminal và Colab để kiểm tra các giá trị trung gian để gỡ lỗi.

Trực quan hóa đồ thị với TensorBoard

Bạn có thể kiểm tra đồ thị TensorFlow với TensorBoard . TensorBoard cũng được hỗ trợ trên colab . TensorBoard là một công cụ tuyệt vời để trực quan hóa các bản tóm tắt. Bạn có thể sử dụng nó để so sánh tốc độ học tập, trọng số mô hình, thang độ dốc, số liệu đào tạo / xác thực hoặc thậm chí mô hình kết quả trung gian giữa mô hình TF1.x và mô hình TF2 đã di chuyển thông qua quá trình đào tạo và xem các giá trị có giống như mong đợi hay không.

TensorFlow Profiler

TensorFlow Profiler có thể giúp bạn hình dung tiến trình thực thi trên GPU / TPU. Bạn có thể xem Colab Demo này để biết cách sử dụng cơ bản của nó.

MultiProcessRunner

MultiProcessRunner là một công cụ hữu ích khi gỡ lỗi với MultiWorkerMirroredStrategy và ParameterServerStrategy. Bạn có thể xem ví dụ cụ thể này để biết cách sử dụng của nó.

Cụ thể đối với các trường hợp của hai chiến lược này, bạn nên 1) không chỉ có các bài kiểm tra đơn vị để bao quát luồng của chúng, 2) mà còn cố gắng tạo lại các lỗi bằng cách sử dụng nó trong bài kiểm tra đơn vị để tránh khởi chạy công việc được phân phối thực sự mỗi khi họ cố gắng một sửa chữa.