Sử dụng mô hình TF1.x trong quy trình làm việc TF2

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

Hướng dẫn này cung cấp tổng quan và các ví dụ về một miếng đệm mã mô hình mà bạn có thể sử dụng để sử dụng các mô hình TF1.x hiện có của mình trong quy trình công việc TF2, chẳng hạn như thực thi háo hức, tf.function và các chiến lược phân phối với những thay đổi tối thiểu đối với mã mô hình của bạn.

Phạm vi sử dụng

Miếng đệm được mô tả trong hướng dẫn này được thiết kế cho các mẫu TF1.x dựa trên:

  1. tf.compat.v1.get_variabletf.compat.v1.variable_scope để kiểm soát việc tạo và sử dụng lại biến, và
  2. Các API dựa trên thu thập đồ thị như tf.compat.v1.global_variables() , tf.compat.v1.trainable_variables , tf.compat.v1.losses.get_regularization_losses()tf.compat.v1.get_collection() để theo dõi trọng số và tổn thất quy định

Điều này bao gồm hầu hết các mô hình được xây dựng trên API tf.compat.v1.layer , tf.contrib.layersTensorFlow-Slim .

Miếng đệm lót KHÔNG cần thiết cho các kiểu TF1.x sau:

  1. Các mô hình Keras độc lập đã theo dõi tất cả các trọng lượng có thể huấn luyện và tổn thất chính quy thông qua model.trainable_weightsmodel.losses tương ứng.
  2. tf.Module s đã theo dõi tất cả các trọng số có thể đào tạo của chúng thông qua module.trainable_variables và chỉ tạo các trọng số nếu chúng chưa được tạo.

Các mô hình này có khả năng hoạt động trong TF2 với khả năng thực thi nhanh chóng và tf.function -out-of-the-box.

Thành lập

Nhập TensorFlow và các phụ thuộc khác.

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

pip install -q tf-nightly
import tensorflow as tf
import tensorflow.compat.v1 as v1
import sys
import numpy as np

from contextlib import contextmanager

Trình trang trí track_tf1_style_variables

Chêm khóa được mô tả trong hướng dẫn này là tf.compat.v1.keras.utils.track_tf1_style_variables , một trình trang trí mà bạn có thể sử dụng trong các phương thức thuộc tf.keras.layers.Layertf.Module để theo dõi trọng số kiểu TF1.x và nắm bắt các tổn thất về quy định.

Việc trang trí các phương thức gọi của tf.keras.layers.Layer hoặc tf.Module với tf.compat.v1.keras.utils.track_tf1_style_variables cho phép tạo và sử dụng lại biến thông qua tf.compat.v1.get_variable (và bởi phần mở rộng tf.compat.v1.layers ) để hoạt động chính xác bên trong phương thức được trang trí thay vì luôn tạo một biến mới trên mỗi lần gọi. Nó cũng sẽ khiến lớp hoặc mô-đun theo dõi ngầm bất kỳ trọng số nào được tạo hoặc truy cập thông qua get_variable bên trong phương thức được trang trí.

Ngoài việc tự theo dõi trọng lượng trong lớp tiêu layer.variable / module.variable / etc. thuộc tính, nếu phương thức thuộc về tf.keras.layers.Layer , thì bất kỳ tổn thất chính quy nào được chỉ định qua đối số get_variable hoặc tf.compat.v1.layers sẽ được theo dõi bởi lớp bên dưới thuộc tính layer.losses tiêu chuẩn.

Cơ chế theo dõi này cho phép sử dụng các lớp lớn mã chuyển tiếp mô hình kiểu TF1.x bên trong các lớp Keras hoặc tf.Module s trong TF2 ngay cả khi các hành vi TF2 được kích hoạt.

Các ví dụ sử dụng

Các ví dụ sử dụng bên dưới minh họa các miếng chêm mô hình được sử dụng để trang trí các phương thức tf.keras.layers.Layer , nhưng ngoại trừ trường hợp chúng tương tác cụ thể với các tính năng của Keras, chúng cũng có thể áp dụng khi trang trí các phương thức tf.Module .

Lớp được xây dựng bằng tf.compat.v1.get_variable

Hãy tưởng tượng bạn có một lớp được triển khai trực tiếp trên đầu tf.compat.v1.get_variable như sau:

def dense(self, inputs, units):
  out = inputs
  with tf.compat.v1.variable_scope("dense"):
    # The weights are created with a `regularizer`,
    kernel = tf.compat.v1.get_variable(
        shape=[out.shape[-1], units],
        regularizer=tf.keras.regularizers.L2(),
        initializer=tf.compat.v1.initializers.glorot_normal,
        name="kernel")
    bias = tf.compat.v1.get_variable(
        shape=[units,],
        initializer=tf.compat.v1.initializers.zeros,
        name="bias")
    out = tf.linalg.matmul(out, kernel)
    out = tf.compat.v1.nn.bias_add(out, bias)
  return out

Sử dụng miếng đệm để biến nó thành một lớp và gọi nó trên các đầu vào.

class DenseLayer(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    out = inputs
    with tf.compat.v1.variable_scope("dense"):
      # The weights are created with a `regularizer`,
      # so the layer should track their regularization losses
      kernel = tf.compat.v1.get_variable(
          shape=[out.shape[-1], self.units],
          regularizer=tf.keras.regularizers.L2(),
          initializer=tf.compat.v1.initializers.glorot_normal,
          name="kernel")
      bias = tf.compat.v1.get_variable(
          shape=[self.units,],
          initializer=tf.compat.v1.initializers.zeros,
          name="bias")
      out = tf.linalg.matmul(out, kernel)
      out = tf.compat.v1.nn.bias_add(out, bias)
    return out

layer = DenseLayer(10)
x = tf.random.normal(shape=(8, 20))
layer(x)
WARNING:tensorflow:From /tmp/ipykernel_27038/795621215.py:7: The name tf.keras.utils.track_tf1_style_variables is deprecated. Please use tf.compat.v1.keras.utils.track_tf1_style_variables instead.
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[-0.51018804, -0.58145535,  0.25050664, -0.09880018,  0.71741414,
        -0.08512568,  0.33404148,  0.50894034,  0.19362557,  0.03945067],
       [-0.66160053,  0.43442816, -0.6187523 ,  0.00753711,  1.3946855 ,
         0.22528797,  0.55661404, -1.6155301 ,  1.5854199 , -0.4165327 ],
       [ 0.15855707,  0.43848652,  0.04762229,  0.22020248,  0.88300526,
         0.31525093, -0.10912375,  0.03332198,  1.3462385 , -0.37986106],
       [ 0.02546233, -0.01084138,  0.0417656 ,  1.1082407 ,  0.926408  ,
         0.46938205,  1.0183189 ,  1.2039868 , -0.09619217, -0.50863194],
       [-1.6222394 ,  0.17156005, -0.07482994,  0.646423  ,  1.0284312 ,
         2.3619173 ,  0.6322627 ,  0.5350776 , -2.2700598 , -0.8211552 ],
       [-1.1044651 ,  0.7303245 ,  1.0183476 ,  1.2858934 ,  0.4575533 ,
         0.93400717,  0.5323913 , -0.01242167,  0.8308919 ,  0.03202473],
       [ 0.3880633 , -1.2345276 ,  0.7713047 , -0.33720714,  1.0418141 ,
        -1.055242  , -1.6942265 ,  1.705035  ,  0.8671215 ,  0.8162696 ],
       [ 0.02216246, -0.5235669 ,  0.01065174, -1.1682817 ,  0.44079733,
         0.25890222, -1.0779501 ,  0.37716752, -0.27636313, -0.6359312 ]],
      dtype=float32)>

Truy cập các biến được theo dõi và các tổn thất chính quy được thu thập giống như một lớp Keras tiêu chuẩn.

layer.trainable_variables
layer.losses
2021-12-04 02:24:42.941890: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
[<tf.Tensor: shape=(), dtype=float32, numpy=0.10789324>]

Để thấy rằng các trọng số được sử dụng lại mỗi khi bạn gọi lớp, hãy đặt tất cả các trọng số bằng 0 và gọi lại lớp.

print("Resetting variables to zero:", [var.name for var in layer.trainable_variables])

for var in layer.trainable_variables:
  var.assign(var * 0.0)

# Note: layer.losses is not a live view and
# will get reset only at each layer call
print("layer.losses:", layer.losses)
print("calling layer again.")
out = layer(x)
print("layer.losses: ", layer.losses)
out
Resetting variables to zero: ['dense/bias:0', 'dense/kernel:0']
layer.losses: [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
calling layer again.
layer.losses:  [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>

Bạn cũng có thể sử dụng lớp đã chuyển đổi trực tiếp trong xây dựng mô hình chức năng Keras.

inputs = tf.keras.Input(shape=(20))
outputs = DenseLayer(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 20))
model(x)

# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.1345337>]

Mô hình được xây dựng bằng tf.compat.v1.layers

Hãy tưởng tượng bạn có một lớp hoặc mô hình được triển khai trực tiếp trên đầu tf.compat.v1.layers như sau:

def model(self, inputs, units):
  with tf.compat.v1.variable_scope('model'):
    out = tf.compat.v1.layers.conv2d(
        inputs, 3, 3,
        kernel_regularizer="l2")
    out = tf.compat.v1.layers.flatten(out)
    out = tf.compat.v1.layers.dense(
        out, units,
        kernel_regularizer="l2")
    return out

Sử dụng miếng đệm để biến nó thành một lớp và gọi nó trên các đầu vào.

class CompatV1LayerModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

layer = CompatV1LayerModel(10)
x = tf.random.normal(shape=(8, 5, 5, 5))
layer(x)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/convolutional.py:575: 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:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:541: 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: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()
/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)
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[ 2.4439096 , -0.2912227 ,  1.5531251 ,  1.284059  ,  0.10077369,
        -0.4231838 ,  1.0458903 , -0.01530766,  0.07358164, -0.6108157 ],
       [-0.4576063 ,  0.34942552,  2.3044965 ,  1.1483003 , -1.2211238 ,
         0.5634397 ,  0.73821646, -0.07581732,  0.5747937 , -0.66470885],
       [-2.2948585 , -2.709268  ,  1.7494816 , -0.9808065 , -2.9099958 ,
         0.5067346 , -1.011502  ,  2.559535  , -3.0888772 ,  0.3522656 ],
       [ 1.7788265 ,  0.8846102 ,  0.45562026,  0.01498583, -0.12482446,
        -0.32868862, -0.7743829 ,  2.3106992 , -0.0997327 , -0.7715093 ],
       [ 0.40295708,  0.04771695, -0.21336336, -0.13069987,  2.279875  ,
         2.7284563 ,  0.6444641 , -1.1919906 ,  0.96321577,  1.0182515 ],
       [ 0.47900966,  0.04906505,  1.1335449 ,  0.2907704 ,  0.7732022 ,
         0.68217   ,  0.51932573, -0.45156685,  2.081223  ,  1.068861  ],
       [ 0.10084352,  1.6456002 ,  0.63820475,  1.5959243 ,  0.22463399,
         0.07713126,  0.7467398 , -1.5435244 ,  1.2494736 , -0.07683721],
       [ 2.1396816 ,  1.5613532 , -1.1726325 , -0.88917583,  1.6447946 ,
        -1.0071977 , -1.8496083 ,  1.1887017 ,  2.1971662 ,  2.1175954 ]],
      dtype=float32)>

Truy cập các biến được theo dõi và nắm bắt các tổn thất chính quy giống như một lớp Keras tiêu chuẩn.

layer.trainable_variables
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03623246>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.14618248>]

Để thấy rằng các trọng số được sử dụng lại mỗi khi bạn gọi lớp, hãy đặt tất cả các trọng số bằng 0 và gọi lại lớp.

print("Resetting variables to zero:", [var.name for var in layer.trainable_variables])

for var in layer.trainable_variables:
  var.assign(var * 0.0)

out = layer(x)
print("layer.losses: ", layer.losses)
out
Resetting variables to zero: ['model/conv2d/bias:0', 'model/conv2d/kernel:0', 'model/dense/bias:0', 'model/dense/kernel:0']
layer.losses:  [<tf.Tensor: shape=(), dtype=float32, numpy=0.0>, <tf.Tensor: shape=(), dtype=float32, numpy=0.0>]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/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()
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>

Bạn cũng có thể sử dụng lớp đã chuyển đổi trực tiếp trong xây dựng mô hình chức năng Keras.

inputs = tf.keras.Input(shape=(5, 5, 5))
outputs = CompatV1LayerModel(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 5, 5, 5))
model(x)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/base.py:573: UserWarning: `layer.updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.
  _add_elements_to_collection(self.updates, tf.compat.v1.GraphKeys.UPDATE_OPS)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/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()
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[ 0.19487001,  0.54727787,  1.1044168 , -0.6613899 , -0.26437742,
        -1.1580509 , -0.24707682,  0.97752655,  0.59436107,  0.13125825],
       [ 0.48974586, -1.3510125 ,  0.7186962 , -0.8996632 , -0.60448873,
         0.06332532,  0.31494308,  0.23021704, -1.9166642 ,  0.3890404 ],
       [-0.06499191, -0.21485235,  0.01158494,  1.4407377 , -0.0488929 ,
        -0.37594396, -0.4386894 , -0.08751169,  1.0905663 , -1.5450519 ],
       [-2.2749739 , -2.4603422 , -1.3834419 , -2.8800466 ,  0.8954872 ,
        -3.0429187 , -0.7885461 ,  1.6037437 , -3.1845028 , -1.0725503 ],
       [ 0.98735195, -0.45159122,  0.892656  ,  0.477053  ,  0.31193537,
        -0.44723228, -0.01815075, -0.47465172, -1.665448  , -2.105824  ],
       [-2.5408387 , -1.7552321 , -1.924145  , -0.6395873 ,  0.4081779 ,
        -0.48731515, -3.2637763 , -1.4409767 , -2.032539  ,  0.10204412],
       [ 2.1583526 ,  0.78955674, -0.07266375,  0.06652926,  2.1300716 ,
        -1.6256162 ,  0.56154627, -0.76179224,  2.2985756 , -1.5504618 ],
       [ 2.062847  ,  0.971378  , -1.0830508 ,  1.8224751 , -0.3542943 ,
         0.74113446, -0.6204865 ,  1.4503044 , -0.4979878 , -0.4383126 ]],
      dtype=float32)>
# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03079858>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.12991619>]

Nắm bắt các bản cập nhật chuẩn hóa hàng loạt và các vòng training mô hình

Trong TF1.x, bạn thực hiện chuẩn hóa hàng loạt như sau:

  x_norm = tf.compat.v1.layers.batch_normalization(x, training=training)

  # ...

  update_ops = tf.compat.v1.get_collection(tf.GraphKeys.UPDATE_OPS)
  train_op = optimizer.minimize(loss)
  train_op = tf.group([train_op, update_ops])

Lưu ý rằng:

  1. Các bản cập nhật trung bình động chuẩn hóa hàng loạt được theo dõi bởi get_collection , được gọi riêng biệt với lớp
  2. tf.compat.v1.layers.batch_normalization yêu cầu đối số training (thường được gọi là is_training khi sử dụng các lớp chuẩn hóa hàng loạt TF-Slim)

Trong TF2, do các phụ thuộc điều khiển tự động và thực thi háo hức , các cập nhật đường trung bình động chuẩn hóa hàng loạt sẽ được thực thi ngay lập tức. Không cần phải thu thập riêng chúng từ bộ sưu tập cập nhật và thêm chúng dưới dạng phụ thuộc kiểm soát rõ ràng.

Ngoài ra, nếu bạn cung cấp cho phương thức chuyển tiếp của tf.keras.layers.Layer một đối số training , Keras sẽ có thể vượt qua giai đoạn huấn luyện hiện tại và bất kỳ lớp nào được lồng vào nó giống như đối với bất kỳ lớp nào khác. Xem tài liệu API cho tf.keras.Model để biết thêm thông tin về cách Keras xử lý đối số training .

Nếu bạn đang trang trí các phương thức tf.Module , bạn cần đảm bảo chuyển tất cả các đối số training theo cách thủ công nếu cần. Tuy nhiên, các bản cập nhật trung bình động chuẩn hóa hàng loạt sẽ vẫn được áp dụng tự động mà không cần phụ thuộc kiểm soát rõ ràng.

Các đoạn mã sau đây trình bày cách nhúng các lớp chuẩn hóa hàng loạt vào miếng đệm và cách sử dụng nó trong mô hình Keras hoạt động (áp dụng cho tf.keras.layers.Layer ).

class CompatV1BatchNorm(tf.keras.layers.Layer):

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    print("Forward pass called with `training` =", training)
    with v1.variable_scope('batch_norm_layer'):
      return v1.layers.batch_normalization(x, training=training)
print("Constructing model")
inputs = tf.keras.Input(shape=(5, 5, 5))
outputs = CompatV1BatchNorm()(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

print("Calling model in inference mode")
x = tf.random.normal(shape=(8, 5, 5, 5))
model(x, training=False)

print("Moving average variables before training: ",
      {var.name: var.read_value() for var in model.non_trainable_variables})

# Notice that when running TF2 and eager execution, the batchnorm layer directly
# updates the moving averages while training without needing any extra control
# dependencies
print("calling model in training mode")
model(x, training=True)

print("Moving average variables after training: ",
      {var.name: var.read_value() for var in model.non_trainable_variables})
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:7: UserWarning: `tf.layers.batch_normalization` is deprecated and will be removed in a future version. Please use `tf.keras.layers.BatchNormalization` instead. In particular, `tf.control_dependencies(tf.GraphKeys.UPDATE_OPS)` should not be used (consult the `tf.keras.layers.BatchNormalization` documentation).
  import sys
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/normalization.py:463: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs, training=training)
Constructing model
Forward pass called with `training` = None
Calling model in inference mode
Forward pass called with `training` = False
Moving average variables before training:  {'batch_norm_layer/batch_normalization/moving_mean:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=array([0., 0., 0., 0., 0.], dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=array([1., 1., 1., 1., 1.], dtype=float32)>}
calling model in training mode
Forward pass called with `training` = True
Moving average variables after training:  {'batch_norm_layer/batch_normalization/moving_mean:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([-0.00177554, -0.00036542, -0.00099426, -0.00112544,  0.0008541 ],
      dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([1.0005339, 1.0003369, 0.9976748, 1.0001523, 1.0009514],
      dtype=float32)>}

Tái sử dụng biến dựa trên phạm vi biến

Bất kỳ sáng tạo biến nào trong chuyển tiếp dựa trên get_variable sẽ duy trì cách đặt tên biến giống nhau và sử dụng lại ngữ nghĩa mà phạm vi biến có trong TF1.x. Điều này đúng với điều kiện là bạn có ít nhất một phạm vi bên ngoài không trống cho bất kỳ tf.compat.v1.layers nào có tên được tạo tự động, như đã đề cập ở trên.

Háo hức thực hiện & tf.function

Như đã thấy ở trên, các phương thức được trang trí cho tf.keras.layers.Layertf.Module chạy bên trong việc thực thi háo hức và cũng tương thích với chức năng tf.function . Điều này có nghĩa là bạn có thể sử dụng pdb và các công cụ tương tác khác để vượt qua thẻ chuyển tiếp của bạn khi nó đang chạy.

Các chiến lược phân phối

Các lệnh gọi đến get_variable bên trong @track_tf1_style_variables -các phương thức lớp hoặc mô-đun được trang trí sử dụng các sáng tạo biến tf.Variable tiêu chuẩn bên dưới. Điều này có nghĩa là bạn có thể sử dụng chúng với các chiến lược phân phối khác nhau có sẵn với tf.distribute như MirroredStrategyTPUStrategy .

Lồng các tf.Variable s, tf.Module s, tf.keras.layers & tf.keras.models trong các lệnh gọi được trang trí

Việc trang trí lệnh gọi lớp của bạn trong tf.compat.v1.keras.utils.track_tf1_style_variables sẽ chỉ thêm theo dõi ngầm tự động các biến được tạo (và được sử dụng lại) qua tf.compat.v1.get_variable . Nó sẽ không nắm bắt các trọng số được tạo trực tiếp bởi các lệnh gọi tf.Variable , chẳng hạn như các trọng số được sử dụng bởi các lớp Keras điển hình và hầu hết các tf.Module . Phần này mô tả cách xử lý các trường hợp lồng nhau này.

(Các tập quán đã có từ trước) tf.keras.layerstf.keras.models

Đối với cách sử dụng đã có từ trước của các lớp và mô hình Keras lồng nhau, hãy sử dụng tf.compat.v1.keras.utils.get_or_create_layer . Điều này chỉ được khuyến nghị để giảm bớt việc di chuyển các cách sử dụng Keras lồng nhau TF1.x hiện có; mã mới nên sử dụng cài đặt thuộc tính rõ ràng như được mô tả bên dưới cho tf.Variables và tf.Modules.

Để sử dụng tf.compat.v1.keras.utils.get_or_create_layer , hãy bọc mã xây dựng mô hình lồng nhau của bạn vào một phương thức và chuyển nó vào phương thức. Thí dụ:

class NestedModel(tf.keras.Model):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  def build_model(self):
    inp = tf.keras.Input(shape=(5, 5))
    dense_layer = tf.keras.layers.Dense(
        10, name="dense", kernel_regularizer="l2",
        kernel_initializer=tf.compat.v1.ones_initializer())
    model = tf.keras.Model(inputs=inp, outputs=dense_layer(inp))
    return model

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    # Get or create a nested model without assigning it as an explicit property
    model = tf.compat.v1.keras.utils.get_or_create_layer(
        "dense_model", self.build_model)
    return model(inputs)

layer = NestedModel(10)
layer(tf.ones(shape=(5,5)))
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
       [5., 5., 5., 5., 5., 5., 5., 5., 5., 5.]], dtype=float32)>

Phương pháp này đảm bảo rằng các lớp lồng nhau này được sử dụng lại và theo dõi một cách chính xác bởi dòng chảy căng thẳng. Lưu ý rằng trình trang trí @track_tf1_style_variables vẫn được yêu cầu đối với phương thức thích hợp. Phương thức trình tạo mô hình được truyền vào get_or_create_layer (trong trường hợp này self.build_model ), sẽ không có đối số.

Cân nặng được theo dõi:

assert len(layer.weights) == 2
weights = {x.name: x for x in layer.variables}

assert set(weights.keys()) == {"dense/bias:0", "dense/kernel:0"}

layer.weights
[<tf.Variable 'dense/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]], dtype=float32)>,
 <tf.Variable 'dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]

Và mất quy định cũng như:

tf.add_n(layer.losses)
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.5], dtype=float32)>

Di chuyển tăng dần: tf.Variablestf.Modules

Nếu bạn cần nhúng các lệnh gọi tf.Variable hoặc tf.Module vào các phương thức được trang trí của mình (ví dụ: nếu bạn đang theo dõi quá trình di chuyển tăng dần sang các API TF2 không kế thừa được mô tả sau trong hướng dẫn này), bạn vẫn cần theo dõi rõ ràng những điều này, với các yêu cầu sau:

  • Đảm bảo rõ ràng rằng biến / mô-đun / lớp chỉ được tạo một lần
  • Đính kèm rõ ràng chúng dưới dạng thuộc tính phiên bản giống như bạn làm khi xác định một mô-đun hoặc lớp điển hình
  • Sử dụng lại rõ ràng đối tượng đã được tạo trong các lệnh gọi tiếp theo

Điều này đảm bảo rằng các trọng số không được tạo mới mỗi cuộc gọi và được sử dụng lại một cách chính xác. Ngoài ra, điều này cũng đảm bảo rằng các trọng số hiện có và tổn thất quy định được theo dõi.

Đây là một ví dụ về cách nó có thể trông như thế nào:

class NestedLayer(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def __call__(self, inputs):
    out = inputs
    with tf.compat.v1.variable_scope("inner_dense"):
      # The weights are created with a `regularizer`,
      # so the layer should track their regularization losses
      kernel = tf.compat.v1.get_variable(
          shape=[out.shape[-1], self.units],
          regularizer=tf.keras.regularizers.L2(),
          initializer=tf.compat.v1.initializers.glorot_normal,
          name="kernel")
      bias = tf.compat.v1.get_variable(
          shape=[self.units,],
          initializer=tf.compat.v1.initializers.zeros,
          name="bias")
      out = tf.linalg.matmul(out, kernel)
      out = tf.compat.v1.nn.bias_add(out, bias)
    return out

class WrappedDenseLayer(tf.keras.layers.Layer):

  def __init__(self, units, **kwargs):
    super().__init__(**kwargs)
    self.units = units
    # Only create the nested tf.variable/module/layer/model
    # once, and then reuse it each time!
    self._dense_layer = NestedLayer(self.units)

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('outer'):
      outputs = tf.compat.v1.layers.dense(inputs, 3)
      outputs = tf.compat.v1.layers.dense(inputs, 4)
      return self._dense_layer(outputs)

layer = WrappedDenseLayer(10)

layer(tf.ones(shape=(5, 5)))
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:38: 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/ipykernel_launcher.py:39: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731]],
      dtype=float32)>

Lưu ý rằng cần theo dõi rõ ràng mô-đun lồng nhau mặc dù nó được trang trí bằng trình trang trí track_tf1_style_variables . Điều này là do mỗi mô-đun / lớp với các phương thức được trang trí có một kho biến riêng được liên kết với nó.

Trọng lượng được theo dõi chính xác:

assert len(layer.weights) == 6
weights = {x.name: x for x in layer.variables}

assert set(weights.keys()) == {"outer/inner_dense/bias:0",
                               "outer/inner_dense/kernel:0",
                               "outer/dense/bias:0",
                               "outer/dense/kernel:0",
                               "outer/dense_1/bias:0",
                               "outer/dense_1/kernel:0"}

layer.trainable_weights
[<tf.Variable 'outer/inner_dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/inner_dense/kernel:0' shape=(4, 10) dtype=float32, numpy=
 array([[-0.20786692,  0.14702448, -0.2577947 ,  0.1885891 ,  0.28935957,
          0.02086618, -0.20579144, -0.7509229 , -0.23490003,  0.00370591],
        [ 0.09247629, -0.37428686, -0.6002815 , -0.2702465 ,  0.20350575,
          0.34964404, -0.32633537,  0.50722903, -0.0419833 , -0.61815673],
        [ 0.24821116,  0.15504731, -0.12409697, -0.2506969 ,  0.22316858,
         -0.44847375, -0.08295754, -0.8262154 ,  0.7674222 , -0.40613693],
        [-0.7447006 ,  0.2992331 , -0.45639235,  0.0669547 ,  0.39443025,
          0.3182467 ,  0.10884362,  0.5395837 ,  0.32210502, -0.30076835]],
       dtype=float32)>,
 <tf.Variable 'outer/dense/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense/kernel:0' shape=(5, 3) dtype=float32, numpy=
 array([[ 0.6283595 , -0.80413634, -0.5471641 ],
        [ 0.25296038, -0.7657203 ,  0.5884425 ],
        [-0.7180575 , -0.29509914,  0.44014376],
        [ 0.81024987,  0.39888996,  0.80002993],
        [-0.32921118, -0.7010279 ,  0.820375  ]], dtype=float32)>,
 <tf.Variable 'outer/dense_1/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense_1/kernel:0' shape=(5, 4) dtype=float32, numpy=
 array([[ 0.7941524 , -0.58552563,  0.46828055, -0.44095916],
        [-0.16019303,  0.27973688, -0.60373306, -0.20117629],
        [ 0.6345844 ,  0.30732214,  0.18921828,  0.37930095],
        [-0.50815696, -0.2471816 , -0.10282421,  0.21441567],
        [-0.71987414,  0.18304104, -0.5701992 ,  0.4926386 ]],
       dtype=float32)>]

Cũng như mất chính quy:

layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.058749676>]

Lưu ý rằng nếu NestedLayer không phải là Keras tf.Module thay vào đó, các biến sẽ vẫn được theo dõi nhưng tổn thất về quy định sẽ không được theo dõi tự động, vì vậy bạn sẽ phải theo dõi chúng một cách rõ ràng.

Hướng dẫn về tên biến

Lệnh gọi tf.Variable rõ ràng và các lớp Keras sử dụng cơ chế tự động tạo tên lớp / tên biến khác với cơ chế bạn có thể quen làm từ sự kết hợp của get_variablevariable_scopes . Mặc dù miếng đệm sẽ làm cho tên biến của bạn khớp với các biến được tạo bởi get_variable ngay cả khi đi từ đồ thị TF1.x sang TF2 háo hức thực thi & tf.function ., nhưng nó không thể đảm bảo giống nhau cho các tên biến được tạo cho các lệnh gọi tf.Variable . Biến và lớp Keras mà bạn nhúng bên trong trình trang trí phương pháp của bạn. Thậm chí, nhiều biến có thể dùng chung tên trong thực thi háo hức TF2 và tf.function .

Bạn nên đặc biệt lưu ý điều này khi làm theo các phần về xác thực tính đúng đắn và ánh xạ các điểm kiểm tra TF1.x ở phần sau trong hướng dẫn này.

Sử dụng tf.compat.v1.make_template trong phương thức được trang trí

Chúng tôi thực sự khuyên bạn nên sử dụng trực tiếp tf.compat.v1.keras.utils.track_tf1_style_variables thay vì sử dụng tf.compat.v1.make_template , vì nó là một lớp mỏng hơn trên TF2 .

Làm theo hướng dẫn trong phần này để biết mã TF1.x trước đó đã dựa trên tf.compat.v1.make_template .

Bởi vì tf.compat.v1.make_template kết thúc mã sử dụng get_variable , trình trang trí track_tf1_style_variables cho phép bạn sử dụng các mẫu này trong các lệnh gọi lớp và theo dõi thành công trọng số và tổn thất chính quy.

Tuy nhiên, hãy đảm bảo chỉ gọi make_template một lần và sau đó sử dụng lại cùng một mẫu trong mỗi lần gọi lớp. Nếu không, một mẫu mới sẽ được tạo mỗi khi bạn gọi lớp cùng với một tập hợp các biến mới.

Ví dụ,

class CompatV1TemplateScaleByY(tf.keras.layers.Layer):

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    def my_op(x, scalar_name):
      var1 = tf.compat.v1.get_variable(scalar_name,
                            shape=[],
                            regularizer=tf.compat.v1.keras.regularizers.L2(),
                            initializer=tf.compat.v1.constant_initializer(1.5))
      return x * var1
    self.scale_by_y = tf.compat.v1.make_template('scale_by_y', my_op, scalar_name='y')

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('layer'):
      # Using a scope ensures the `scale_by_y` name will not be incremented
      # for each instantiation of the layer.
      return self.scale_by_y(inputs)

layer = CompatV1TemplateScaleByY()

out = layer(tf.ones(shape=(2, 3)))
print("weights:", layer.weights)
print("regularization loss:", layer.losses)
print("output:", out)
weights: [<tf.Variable 'layer/scale_by_y/y:0' shape=() dtype=float32, numpy=1.5>]
regularization loss: [<tf.Tensor: shape=(), dtype=float32, numpy=0.022499999>]
output: tf.Tensor(
[[1.5 1.5 1.5]
 [1.5 1.5 1.5]], shape=(2, 3), dtype=float32)

Di chuyển tăng dần sang TF2 Gốc

Như đã đề cập trước đó, track_tf1_style_variables cho phép bạn kết hợp tf.Variable / tf.keras.layers.Layer / tf.Module sử dụng với tf.compat.v1.get_variable / tf.compat.v1.layers -style kế thừa sử dụng bên trong của cùng một mô-đun / lớp được trang trí.

Điều này có nghĩa là sau khi bạn đã làm cho mô hình TF1.x của mình tương thích hoàn toàn với TF2, bạn có thể viết tất cả các thành phần mô hình mới với các API TF2 gốc ( tf.compat.v1 ) và để chúng tương thích với mã cũ hơn của bạn.

Tuy nhiên, nếu bạn tiếp tục sửa đổi các thành phần mô hình cũ hơn của mình, bạn cũng có thể chọn chuyển dần cách sử dụng tf.compat.v1 theo kiểu kế thừa của mình sang các API hướng đối tượng thuần túy gốc được khuyến nghị cho mã TF2 mới được viết.

Việc sử dụng tf.compat.v1.get_variable có thể được thay thế bằng lệnh gọi self.add_weight nếu bạn đang trang trí một lớp / mô hình Keras hoặc bằng lệnh gọi tf.Variable nếu bạn đang trang trí các đối tượng Keras hoặc tf.Module .

Cả hai lớp tf.compat.v1.layers kiểu chức năng và hướng đối tượng thường có thể được thay thế bằng lớp tf.keras.layers tương đương mà không cần thay đổi đối số.

Bạn cũng có thể xem xét các phần của mô hình hoặc các mẫu chung của mình thành các lớp / mô-đun riêng lẻ trong quá trình chuyển dần sang các API thuần túy gốc, bản thân các API này có thể sử dụng track_tf1_style_variables .

Một lưu ý trên Slim và Contrib.layers

Một lượng lớn mã TF 1.x cũ hơn sử dụng thư viện Slim , được đóng gói với TF 1.x dưới dạng tf.contrib.layers . Việc chuyển đổi mã sử dụng Slim sang TF 2 gốc có nhiều liên quan hơn là chuyển đổi v1.layers . Trên thực tế, có thể hợp lý khi chuyển đổi mã Slim của bạn thành v1.layers trước, sau đó chuyển đổi sang Keras. Dưới đây là một số hướng dẫn chung để chuyển đổi mã Slim.

  • Đảm bảo tất cả các đối số là rõ ràng. Loại bỏ arg_scopes nếu có thể. Nếu bạn vẫn cần sử dụng chúng, hãy chia normalizer_fnactivation_fn thành các lớp riêng của chúng.
  • Các lớp chuyển đổi riêng biệt ánh xạ tới một hoặc nhiều lớp Keras khác nhau (theo chiều sâu, theo chiều kim và các lớp Keras có thể phân tách).
  • Slim và v1.layers có tên đối số và giá trị mặc định khác nhau.
  • Lưu ý rằng một số đối số có tỷ lệ khác nhau.

Di chuyển sang Native TF2 bỏ qua khả năng tương thích của trạm kiểm soát

Mẫu mã sau đây cho thấy sự chuyển đổi gia tăng của một mô hình sang các API thuần túy nguyên gốc mà không xem xét khả năng tương thích của trạm kiểm soát.

class CompatModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dropout(out, training=training)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

Tiếp theo, thay thế các API compat.v1 bằng các API hướng đối tượng gốc của chúng theo cách thức từng phần. Bắt đầu bằng cách chuyển lớp tích chập thành một đối tượng Keras được tạo trong phương thức khởi tạo lớp.

class PartiallyMigratedModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_layer(inputs)
      out = tf.compat.v1.layers.flatten(out)
      out = tf.compat.v1.layers.dropout(out, training=training)
      out = tf.compat.v1.layers.dense(
          out, self.units,
          kernel_regularizer="l2")
      return out

Sử dụng lớp v1.keras.utils.DeterministicRandomTestTool để xác minh rằng sự thay đổi gia tăng này khiến mô hình có cùng hành vi như trước đây.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = CompatModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  original_output = layer(inputs)

  # Grab the regularization loss as well
  original_regularization_loss = tf.math.add_n(layer.losses)

print(original_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:413: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs, training=training)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:17: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = PartiallyMigratedModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  from ipykernel import kernelapp as app
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:18: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Bây giờ bạn đã thay thế tất cả các lớp compat.v1.layers riêng lẻ bằng các lớp Keras gốc.

class NearlyFullyNativeModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")
    self.flatten_layer = tf.keras.layers.Flatten()
    self.dense_layer = tf.keras.layers.Dense(
      self.units,
      kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_layer(inputs)
      out = self.flatten_layer(out)
      out = self.dense_layer(out)
      return out
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = NearlyFullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Cuối cùng, hãy xóa cả việc sử dụng variable_scope còn lại (không còn cần thiết) và chính trình trang trí track_tf1_style_variables .

Bây giờ bạn còn lại với một phiên bản của mô hình sử dụng các API hoàn toàn tự nhiên.

class FullyNativeModel(tf.keras.layers.Layer):

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")
    self.flatten_layer = tf.keras.layers.Flatten()
    self.dense_layer = tf.keras.layers.Dense(
      self.units,
      kernel_regularizer="l2")

  def call(self, inputs):
    out = self.conv_layer(inputs)
    out = self.flatten_layer(out)
    out = self.dense_layer(out)
    return out
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = FullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Duy trì khả năng tương thích của trạm kiểm soát trong quá trình di chuyển sang Native TF2

Quá trình di chuyển ở trên sang các API TF2 gốc đã thay đổi cả tên biến (vì API Keras tạo ra các tên trọng số rất khác nhau) và các đường dẫn hướng đối tượng trỏ đến các trọng số khác nhau trong mô hình. Tác động của những thay đổi này là chúng sẽ phá vỡ mọi điểm kiểm tra dựa trên tên kiểu TF1 hiện có hoặc điểm kiểm tra hướng đối tượng kiểu TF2.

Tuy nhiên, trong một số trường hợp, bạn có thể sử dụng điểm kiểm tra dựa trên tên ban đầu của mình và tìm ánh xạ các biến thành tên mới của chúng bằng các cách tiếp cận như cách tiếp cận được nêu chi tiết trong hướng dẫn Sử dụng lại các điểm kiểm tra TF1.x.

Một số mẹo để làm cho điều này khả thi như sau:

  • Tất cả các biến vẫn có một đối số name mà bạn có thể đặt.
  • Các mô hình Keras cũng lấy một đối số name mà chúng đặt làm tiền tố cho các biến của chúng.
  • Hàm v1.name_scope có thể được sử dụng để đặt tiền tố tên biến. Điều này rất khác với tf.variable_scope . Nó chỉ ảnh hưởng đến tên và không theo dõi các biến và sử dụng lại.

Với những lưu ý ở trên, các mẫu mã sau đây thể hiện quy trình làm việc mà bạn có thể thích ứng với mã của mình để cập nhật từng bước một phần của mô hình trong khi cập nhật đồng thời các điểm kiểm tra.

  1. Bắt đầu bằng cách chuyển các tf.compat.v1.layers kiểu chức năng sang các phiên bản hướng đối tượng của chúng.
class FunctionalStyleCompatModel(tf.keras.layers.Layer):

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = tf.compat.v1.layers.conv2d(
          inputs, 3, 3,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.conv2d(
          out, 4, 4,
          kernel_regularizer="l2")
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = FunctionalStyleCompatModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:8: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  # This is added back by InteractiveShellApp.init_path()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['model/conv2d/bias:0',
 'model/conv2d/kernel:0',
 'model/conv2d_1/bias:0',
 'model/conv2d_1/kernel:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']
  1. Tiếp theo, gán các đối tượng compat.v1.layer và bất kỳ biến nào được tạo bởi compat.v1.get_variable làm thuộc tính của đối tượng tf.keras.layers.Layer / tf.Module có phương thức được trang trí bằng track_tf1_style_variables (lưu ý rằng bất kỳ TF2 hướng đối tượng nào các điểm kiểm tra kiểu bây giờ sẽ lưu ra cả đường dẫn theo tên biến và đường dẫn hướng đối tượng mới).
class OOStyleCompatModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.compat.v1.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.compat.v1.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      out = self.conv_2(out)
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = OOStyleCompatModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:19: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['model/conv2d/kernel:0',
 'model/conv2d/bias:0',
 'model/conv2d_1/kernel:0',
 'model/conv2d_1/bias:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']
  1. Lưu lại một điểm kiểm tra đã tải tại thời điểm này để lưu các đường dẫn theo cả tên biến (đối với compat.v1.layers) hoặc bằng biểu đồ đối tượng hướng đối tượng.
weights = {v.name: v for v in layer.weights}
assert weights['model/conv2d/kernel:0'] is layer.conv_1.kernel
assert weights['model/conv2d_1/bias:0'] is layer.conv_2.bias
  1. Bây giờ bạn có thể hoán đổi lớp compat.v1.layers hướng đối tượng cho các lớp Keras gốc trong khi vẫn có thể tải điểm kiểm tra đã lưu gần đây. Đảm bảo rằng bạn giữ nguyên các tên biến cho các compat.v1.layers còn lại bằng cách vẫn ghi lại các variable_scopes được tạo tự động của các lớp được thay thế. Các lớp / biến được chuyển đổi này giờ sẽ chỉ sử dụng đường dẫn thuộc tính đối tượng đến các biến trong trạm kiểm soát thay vì đường dẫn tên biến.

Nói chung, bạn có thể thay thế việc sử dụng compat.v1.get_variable trong các biến được đính kèm với thuộc tính bằng cách:

  • Chuyển chúng sang sử dụng tf.Variable , HOẶC
  • Cập nhật chúng bằng cách sử dụng tf.keras.layers.Layer.add_weight . Lưu ý rằng nếu bạn không chuyển đổi tất cả các lớp cùng một lúc, điều này có thể thay đổi cách đặt tên lớp / biến được tạo tự động cho các lớp compat.v1.layers còn lại thiếu đối số name . Nếu đúng như vậy, bạn phải giữ nguyên tên biến cho các compat.v1.layers còn lại bằng cách mở và đóng thủ công một variable_scope tương ứng với tên phạm vi được tạo của compat.v1.layer đã bị loại bỏ. Nếu không, các đường dẫn từ các trạm kiểm soát hiện có có thể xung đột và tải điểm kiểm tra sẽ hoạt động không chính xác.
def record_scope(scope_name):
  """Record a variable_scope to make sure future ones get incremented."""
  with tf.compat.v1.variable_scope(scope_name):
    pass

class PartiallyNativeKerasLayersModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.keras.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.keras.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      record_scope('conv2d') # Only needed if follow-on compat.v1.layers do not pass a `name` arg
      out = self.conv_2(out)
      record_scope('conv2d_1') # Only needed if follow-on compat.v1.layers do not pass a `name` arg
      out = tf.compat.v1.layers.conv2d(
          out, 5, 5,
          kernel_regularizer="l2")
      return out

layer = PartiallyNativeKerasLayersModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:26: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
['partially_native_keras_layers_model/model/conv2d_13/kernel:0',
 'partially_native_keras_layers_model/model/conv2d_13/bias:0',
 'partially_native_keras_layers_model/model/conv2d_14/kernel:0',
 'partially_native_keras_layers_model/model/conv2d_14/bias:0',
 'model/conv2d_2/bias:0',
 'model/conv2d_2/kernel:0']

Lưu một điểm kiểm tra ở bước này sau khi xây dựng các biến sẽ làm cho nó chỉ chứa các đường dẫn đối tượng hiện có sẵn.

Đảm bảo bạn ghi lại các phạm vi của compat.v1.layers đã loại bỏ để giữ lại tên trọng số được tạo tự động cho các compat.v1.layers còn lại.

weights = set(v.name for v in layer.weights)
assert 'model/conv2d_2/kernel:0' in weights
assert 'model/conv2d_2/bias:0' in weights
  1. Lặp lại các bước trên cho đến khi bạn đã thay thế tất cả các compat.v1.layerscompat.v1.get_variable trong mô hình của mình bằng các tệp tương đương hoàn toàn gốc.
class FullyNativeKerasLayersModel(tf.keras.layers.Layer):

  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.conv_1 = tf.keras.layers.Conv2D(
          3, 3,
          kernel_regularizer="l2")
    self.conv_2 = tf.keras.layers.Conv2D(
          4, 4,
          kernel_regularizer="l2")
    self.conv_3 = tf.keras.layers.Conv2D(
          5, 5,
          kernel_regularizer="l2")


  def call(self, inputs, training=None):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_1(inputs)
      out = self.conv_2(out)
      out = self.conv_3(out)
      return out

layer = FullyNativeKerasLayersModel()
layer(tf.ones(shape=(10, 10, 10, 10)))
[v.name for v in layer.weights]
['fully_native_keras_layers_model/model/conv2d_16/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_16/bias:0',
 'fully_native_keras_layers_model/model/conv2d_17/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_17/bias:0',
 'fully_native_keras_layers_model/model/conv2d_18/kernel:0',
 'fully_native_keras_layers_model/model/conv2d_18/bias:0']

Hãy nhớ kiểm tra để đảm bảo rằng điểm kiểm tra mới được cập nhật vẫn hoạt động như bạn mong đợi. Áp dụng các kỹ thuật được mô tả trong hướng dẫn xác thực tính đúng số ở mỗi bước gia tăng của quy trình này để đảm bảo mã đã di chuyển của bạn chạy chính xác.

Xử lý các thay đổi hành vi từ TF1.x sang TF2 không có trong miếng chêm mô hình

Các miếng chêm mô hình được mô tả trong hướng dẫn này có thể đảm bảo rằng các biến, lớp và tổn thất chính quy được tạo bằng get_variable , tf.compat.v1.layers và ngữ nghĩa variable_scope tiếp tục hoạt động như trước khi sử dụng hàm thực thi háo hức và tf.function . function mà không cần phải dựa vào các bộ sưu tập.

Điều này không bao gồm tất cả các ngữ nghĩa cụ thể của TF1.x mà mô hình của bạn chuyển tiếp có thể dựa vào. Trong một số trường hợp, miếng chêm có thể không đủ để khiến mô hình của bạn tự chạy trong TF2. Đọc hướng dẫn về hành vi TF1.x và TF2 để tìm hiểu thêm về sự khác biệt về hành vi giữa TF1.x và TF2.