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:
-
tf.compat.v1.get_variable
vàtf.compat.v1.variable_scope
để kiểm soát việc tạo và sử dụng lại biến, và - 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()
và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.layers
và TensorFlow-Slim .
Miếng đệm lót KHÔNG cần thiết cho các kiểu TF1.x sau:
- 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_weights
vàmodel.losses
tương ứng. -
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 quamodule.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.Layer
và tf.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:
- 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 -
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.Layer
và tf.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ư MirroredStrategy
và TPUStrategy
.
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.layers
và tf.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.Variables
và tf.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_variable
và variable_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 chianormalizer_fn
vàactivation_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ớitf.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.
- 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']
- 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ượngtf.keras.layers.Layer
/tf.Module
có phương thức được trang trí bằngtrack_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']
- 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
- 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áccompat.v1.layers
còn lại bằng cách vẫn ghi lại cácvariable_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ớpcompat.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áccompat.v1.layers
còn lại bằng cách mở và đóng thủ công mộtvariable_scope
tương ứng với tên phạm vi được tạo củacompat.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
- Lặp lại các bước trên cho đến khi bạn đã thay thế tất cả các
compat.v1.layers
vàcompat.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.