ดูบน TensorFlow.org | ทำงานใน Google Colab | ดูบน GitHub | ดาวน์โหลดโน๊ตบุ๊ค |
คู่มือนี้ให้ภาพรวมและตัวอย่าง โค้ดชิมของรหัสโมเดล ที่คุณสามารถใช้เพื่อใช้โมเดล TF1.x ที่มีอยู่ในเวิร์กโฟลว์ TF2 เช่น การดำเนินการอย่างกระตือรือร้น tf.function
และกลยุทธ์การแจกจ่ายโดยมีการเปลี่ยนแปลงเล็กน้อยในโค้ดการสร้างแบบจำลองของคุณ
ขอบเขตการใช้งาน
แผ่นชิมที่อธิบายในคู่มือนี้ออกแบบมาสำหรับรุ่น TF1.x ที่ต้องพึ่งพา:
-
tf.compat.v1.get_variable
และtf.compat.v1.variable_scope
เพื่อควบคุมการสร้างตัวแปรและการนำกลับมาใช้ใหม่ และ - API ที่ใช้การรวบรวมกราฟ เช่น
tf.compat.v1.global_variables()
,tf.compat.v1.trainable_variables
,tf.compat.v1.losses.get_regularization_losses()
และtf.compat.v1.get_collection()
เพื่อติดตาม ของน้ำหนักและการสูญเสียการทำให้เป็นมาตรฐาน
ซึ่งรวมถึงโมเดลส่วนใหญ่ที่สร้างขึ้นบน tf.compat.v1.layer
, tf.contrib.layers
API และ TensorFlow-Slim
แผ่นชิม ไม่ จำเป็นสำหรับรุ่น TF1.x ต่อไปนี้:
- โมเดล Keras แบบสแตนด์อโลนที่ติดตามน้ำหนักที่ฝึกได้และการสูญเสียการทำให้เป็นมาตรฐานผ่าน
model.trainable_weights
และmodel.losses
ตามลำดับ -
tf.Module
ที่ติดตามน้ำหนักที่ฝึกได้ทั้งหมดผ่านทางmodule.trainable_variables
และสร้างเฉพาะน้ำหนักหากยังไม่ได้สร้าง
โมเดลเหล่านี้มีแนวโน้มที่จะทำงานใน TF2 ด้วยการดำเนินการที่กระตือรือร้นและ tf.function
ที่พร้อมใช้งานทันที
ติดตั้ง
นำเข้า TensorFlow และการพึ่งพาอื่น ๆ
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
track_tf1_style_variables
มัณฑนากร
คีย์ชิมที่อธิบายในคู่มือนี้คือ tf.compat.v1.keras.utils.track_tf1_style_variables
ซึ่งเป็นมัณฑนากรที่คุณใช้ภายในเมธอดที่เป็นของ tf.keras.layers.Layer
และ tf.Module
เพื่อติดตามตุ้มน้ำหนักแบบ TF1.x และ จับการสูญเสียการทำให้เป็นมาตรฐาน
การตกแต่งเมธอดการโทรของ tf.keras.layers.Layer
หรือ tf.Module
ด้วย tf.compat.v1.keras.utils.track_tf1_style_variables
อนุญาตให้สร้างตัวแปรและนำกลับมาใช้ใหม่ผ่าน tf.compat.v1.get_variable
(และตามส่วนขยาย tf.compat.v1.layers
) เพื่อให้ทำงานอย่างถูกต้องภายในเมธอดที่ตกแต่ง แทนที่จะสร้างตัวแปรใหม่ทุกครั้งที่เรียก นอกจากนี้ยังจะทำให้เลเยอร์หรือโมดูลติดตามน้ำหนักที่สร้างหรือเข้าถึงโดยปริยายผ่าน get_variable
ภายในวิธีที่ตกแต่ง
นอกเหนือจากการติดตามตุ้มน้ำหนักด้วยตนเองภายใต้ layer.variable
มาตรฐาน / module.variable
/etc คุณสมบัติ ถ้าวิธีการเป็นของ tf.keras.layers.Layer
การสูญเสียการทำให้เป็นมาตรฐานใด ๆ ที่ระบุผ่านอาร์กิวเมนต์ตัวกำหนด get_variable
หรือ tf.compat.v1.layers
จะถูกติดตามโดยเลเยอร์ภายใต้คุณสมบัติ layer.losses
มาตรฐาน
กลไกการติดตามนี้เปิดใช้งานการใช้คลาสขนาดใหญ่ของรหัสส่งต่อโมเดลรูปแบบ TF1.x ภายในเลเยอร์ Keras หรือ tf.Module
ใน TF2 แม้จะเปิดใช้งานพฤติกรรม TF2
ตัวอย่างการใช้งาน
ตัวอย่างการใช้งานด้านล่างแสดงให้เห็นแบบจำลองชิมเมอร์ที่ใช้ในการตกแต่ง tf.keras.layers.Layer
แต่ยกเว้นในกรณีที่มีการโต้ตอบกับฟีเจอร์ของ Keras โดยเฉพาะ จะนำไปใช้เมื่อตกแต่งวิธี tf.Module
เช่นกัน
เลเยอร์ที่สร้างด้วย tf.compat.v1.get_variable
ลองนึกภาพว่าคุณมีเลเยอร์ที่ใช้งานโดยตรงบน tf.compat.v1.get_variable
ดังนี้:
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
ใช้แผ่นชิมเพื่อเปลี่ยนเป็นเลเยอร์และเรียกใช้อินพุต
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)>
เข้าถึงตัวแปรที่ติดตามและการสูญเสียการทำให้เป็นมาตรฐานที่บันทึกไว้เช่นเลเยอร์ Keras มาตรฐาน
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>]
หากต้องการดูว่าน้ำหนักถูกนำมาใช้ซ้ำทุกครั้งที่คุณเรียกใช้เลเยอร์ ให้ตั้งค่าน้ำหนักทั้งหมดเป็นศูนย์และเรียกเลเยอร์นั้นอีกครั้ง
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)>
คุณสามารถใช้เลเยอร์ที่แปลงแล้วโดยตรงในการสร้างแบบจำลองการทำงานของ 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>]
โมเดลที่สร้างด้วย tf.compat.v1.layers
ลองนึกภาพว่าคุณมีเลเยอร์หรือโมเดลที่ใช้งานโดยตรงบน tf.compat.v1.layers
ดังนี้:
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
ใช้แผ่นชิมเพื่อเปลี่ยนเป็นเลเยอร์และเรียกใช้อินพุต
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)>
เข้าถึงตัวแปรที่ติดตามและการสูญเสียการทำให้เป็นมาตรฐานที่บันทึกไว้เช่นเลเยอร์ Keras มาตรฐาน
layer.trainable_variables
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03623246>, <tf.Tensor: shape=(), dtype=float32, numpy=0.14618248>]
หากต้องการดูว่าน้ำหนักถูกนำมาใช้ซ้ำทุกครั้งที่คุณเรียกใช้เลเยอร์ ให้ตั้งค่าน้ำหนักทั้งหมดเป็นศูนย์และเรียกเลเยอร์นั้นอีกครั้ง
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)>
คุณสามารถใช้เลเยอร์ที่แปลงแล้วโดยตรงในการสร้างแบบจำลองการทำงานของ 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>]
จับภาพการอัปเดตการทำให้เป็นมาตรฐานของแบทช์และ training
โมเดล args
ใน TF1.x คุณทำการทำให้เป็นมาตรฐานของแบทช์ดังนี้:
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])
โปรดทราบว่า:
- การอัปเดตค่าเฉลี่ยเคลื่อนที่ของแบทช์ทำให้เป็นมาตรฐานถูกติดตามโดย
get_collection
ซึ่งถูกเรียกแยกจากเลเยอร์ -
tf.compat.v1.layers.batch_normalization
ต้องการอาร์กิวเมนต์training
(โดยทั่วไปเรียกว่าis_training
เมื่อใช้เลเยอร์การทำให้เป็นมาตรฐานของแบทช์ TF-Slim)
ใน TF2 เนื่องจาก การดำเนินการที่กระตือรือร้น และการพึ่งพาการควบคุมอัตโนมัติ การอัปเดตค่าเฉลี่ยเคลื่อนที่ของแบทช์จะเป็นมาตรฐานจะดำเนินการทันที ไม่จำเป็นต้องรวบรวมแยกจากคอลเลกชันอัพเดต และเพิ่มเป็นการพึ่งพาการควบคุมอย่างชัดเจน
นอกจากนี้ หากคุณให้อาร์กิวเมนต์การส่งต่อของ tf.keras.layers.Layer
เป็นอาร์กิวเมนต์ training
Keras จะสามารถส่งผ่านเฟสการฝึกปัจจุบันและเลเยอร์ที่ซ้อนอยู่ได้เช่นเดียวกับเลเยอร์อื่นๆ ดูเอกสาร API สำหรับ tf.keras.Model
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ Keras จัดการกับอาร์กิวเมนต์ training
หากคุณกำลังตกแต่งวิธี tf.Module
คุณต้องแน่ใจว่าได้ส่งอาร์กิวเมนต์ training
ทั้งหมดตามความจำเป็นด้วยตนเอง อย่างไรก็ตาม การอัปเดตค่าเฉลี่ยเคลื่อนที่ของการทำให้เป็นมาตรฐานของแบตช์จะยังคงใช้โดยอัตโนมัติโดยไม่จำเป็นต้องพึ่งพาการควบคุมอย่างชัดเจน
ข้อมูลโค้ดต่อไปนี้สาธิตวิธีการฝังเลเยอร์การทำให้เป็นมาตรฐานของแบตช์ในชิมและวิธีใช้งานในแบบจำลอง Keras (ใช้ได้กับ 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)>}
การใช้ซ้ำตัวแปรตามขอบเขตตัวแปร
การสร้างตัวแปรใดๆ ในการส่งต่อโดยอิงตาม get_variable
จะคงไว้ซึ่งการตั้งชื่อตัวแปรแบบเดียวกันและนำความหมายมาใช้ใหม่ซึ่งขอบเขตของตัวแปรมีใน TF1.x สิ่งนี้เป็นจริงตราบใดที่คุณมีขอบเขตภายนอกที่ไม่ว่างเปล่าอย่างน้อยหนึ่งขอบเขตสำหรับ tf.compat.v1.layers
ใดๆ ที่มีชื่อที่สร้างขึ้นโดยอัตโนมัติตามที่กล่าวไว้ข้างต้น
การดำเนินการอย่างกระตือรือร้น & tf.function
ตามที่เห็นด้านบน วิธีการตกแต่งสำหรับ tf.keras.layers.Layer
และ tf.Module
จะทำงานภายในการดำเนินการที่กระตือรือร้นและยังเข้ากันได้กับ tf.function
ซึ่งหมายความว่าคุณสามารถใช้ pdb และเครื่องมือแบบโต้ตอบอื่นๆ เพื่อดำเนินการส่งต่อในขณะที่ทำงาน
กลยุทธ์การจัดจำหน่าย
การเรียก get_variable
ภายใน @track_tf1_style_variables
-decorated วิธีการเลเยอร์หรือโมดูลใช้การสร้างตัวแปร tf.Variable
มาตรฐานภายใต้ประทุน ซึ่งหมายความว่าคุณสามารถใช้กับกลยุทธ์การกระจายต่างๆ ที่มีอยู่กับ tf.distribute
เช่น MirroredStrategy
และ TPUStrategy
ซ้อน tf.Variable
s, tf.Module
s, tf.keras.layers
& tf.keras.models
ในการโทรตกแต่ง
การตกแต่งการเรียกเลเยอร์ของคุณใน tf.compat.v1.keras.utils.track_tf1_style_variables
จะเพิ่มเฉพาะการติดตามโดยปริยายของตัวแปรที่สร้างขึ้น (และนำกลับมาใช้ใหม่) ผ่าน tf.compat.v1.get_variable
เท่านั้น จะไม่บันทึกน้ำหนักที่สร้างขึ้นโดยตรงโดยการเรียก tf.Variable
เช่นที่ใช้โดยเลเยอร์ Keras ทั่วไปและ tf.Module
ส่วนใหญ่ ส่วนนี้อธิบายวิธีจัดการกับกรณีและปัญหาที่ซ้อนกันเหล่านี้
(ประเพณีที่มีอยู่แล้ว) tf.keras.layers
และ tf.keras.models
สำหรับการใช้งานเลเยอร์และโมเดล Keras ที่ซ้อนกันอยู่แล้ว ให้ใช้ tf.compat.v1.keras.utils.get_or_create_layer
แนะนำเฉพาะสำหรับการทำให้การย้ายข้อมูลของ Keras ที่ซ้อนกัน TF1.x ที่มีอยู่ง่ายขึ้นเท่านั้น รหัสใหม่ควรใช้การตั้งค่าแอตทริบิวต์ที่ชัดเจนตามที่อธิบายไว้ด้านล่างสำหรับ tf.Variables และ tf.Modules
ในการใช้ tf.compat.v1.keras.utils.get_or_create_layer
ให้ห่อโค้ดที่สร้างโมเดลที่ซ้อนกันเป็นเมธอด แล้วส่งต่อไปยังเมธอด ตัวอย่าง:
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)>
วิธีนี้ช่วยให้แน่ใจว่าเลเยอร์ที่ซ้อนกันเหล่านี้ถูกนำมาใช้ซ้ำอย่างถูกต้องและติดตามโดยเทนเซอร์โฟลว์ โปรดทราบว่ายังคงต้องใช้ตัวตกแต่ง @track_tf1_style_variables
ในวิธีการที่เหมาะสม วิธีการสร้างแบบจำลองที่ส่งผ่านไปยัง get_or_create_layer
(ในกรณีนี้คือ self.build_model
) ไม่ควรมีข้อโต้แย้งใดๆ
มีการติดตามน้ำหนัก:
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)>]
และการสูญเสียการทำให้เป็นมาตรฐานเช่นกัน:
tf.add_n(layer.losses)
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.5], dtype=float32)>ตัวยึดตำแหน่ง33
การย้ายข้อมูลส่วนเพิ่ม: tf.Variables
และ tf.Modules
หากคุณต้องการฝังการเรียก tf.Variable
หรือ tf.Module
ไว้ในวิธีที่ตกแต่งแล้ว (เช่น หากคุณกำลังติดตามการย้ายข้อมูลส่วนเพิ่มไปยัง TF2 API ที่ไม่ใช่แบบเดิมที่อธิบายไว้ในคู่มือนี้) คุณยังต้องติดตามสิ่งเหล่านี้อย่างชัดเจน โดยมีข้อกำหนดดังต่อไปนี้
- ตรวจสอบให้แน่ใจอย่างชัดเจนว่าตัวแปร/โมดูล/เลเยอร์ถูกสร้างขึ้นเพียงครั้งเดียว
- แนบไว้อย่างชัดเจนเป็นแอตทริบิวต์ของอินสแตนซ์ เช่นเดียวกับที่คุณทำเมื่อกำหนด โมดูลหรือเลเยอร์ทั่วไป
- นำออบเจ็กต์ที่สร้างไว้แล้วมาใช้ใหม่อย่างชัดเจนในการเรียกที่ตามมา
เพื่อให้แน่ใจว่าไม่มีการสร้างน้ำหนักขึ้นใหม่ในการโทรแต่ละครั้งและนำกลับมาใช้ใหม่อย่างถูกต้อง นอกจากนี้ สิ่งนี้ยังช่วยให้แน่ใจว่าน้ำหนักที่มีอยู่และการสูญเสียการทำให้เป็นมาตรฐานได้รับการติดตาม
นี่คือตัวอย่างลักษณะของสิ่งนี้:
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)>
โปรดทราบว่าจำเป็นต้องมีการติดตามโมดูลที่ซ้อนกันอย่างชัดเจน แม้ว่าจะมีการตกแต่งด้วยมัณฑนากร track_tf1_style_variables
เนื่องจากแต่ละโมดูล/เลเยอร์ที่มีเมธอดที่ตกแต่งแล้วจะมีที่เก็บตัวแปรที่เกี่ยวข้องกัน
มีการติดตามน้ำหนักอย่างถูกต้อง:
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)>]
เช่นเดียวกับการสูญเสียการทำให้เป็นมาตรฐาน:
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.058749676>]ตัวยึดตำแหน่ง39
โปรดทราบว่าหาก NestedLayer
ไม่ใช่ Keras tf.Module
แทน ตัวแปรจะยังคงถูกติดตาม แต่การสูญเสียการทำให้เป็นมาตรฐานจะไม่ถูกติดตามโดยอัตโนมัติ ดังนั้น คุณจะต้องติดตามแยกกันอย่างชัดเจน
คำแนะนำเกี่ยวกับชื่อตัวแปร
การเรียก tf.Variable
และเลเยอร์ Keras อย่างชัดเจนใช้ชื่อเลเยอร์ / กลไกการสร้างชื่อตัวแปรอัตโนมัติที่แตกต่างจากที่คุณอาจเคยใช้จากการรวมกันของ get_variable
และ variable_scopes
แม้ว่าชิมจะทำให้ชื่อตัวแปรของคุณตรงกันสำหรับตัวแปรที่สร้างโดย get_variable
แม้ว่าจะเปลี่ยนจากกราฟ TF1.x ไปเป็น TF2 ความกระตือรือร้นในการดำเนินการ & tf.function
แต่ก็ไม่สามารถรับประกันได้เหมือนกันสำหรับชื่อตัวแปรที่สร้างขึ้นสำหรับการเรียก tf.Variable
และเลเยอร์ Keras ที่ คุณฝังอยู่ภายในวิธีการของคุณมัณฑนากร เป็นไปได้ด้วยซ้ำที่ตัวแปรหลายตัวจะใช้ชื่อเดียวกันในการดำเนินการที่กระตือรือร้นของ TF2 และ tf.function
คุณควรใช้ความระมัดระวังเป็นพิเศษกับสิ่งนี้เมื่อปฏิบัติตามหัวข้อเกี่ยวกับการตรวจสอบความถูกต้องและการทำแผนที่จุดตรวจ TF1.x ในภายหลังในคู่มือนี้
ใช้ tf.compat.v1.make_template
ในเมธอดการตกแต่ง
ขอแนะนำให้คุณใช้โดยตรง tf.compat.v1.keras.utils.track_tf1_style_variables
แทนการใช้ tf.compat.v1.make_template
เนื่องจากเป็นเลเยอร์ที่บางกว่าที่ด้านบนของ TF2
ทำตามคำแนะนำในส่วนนี้สำหรับโค้ด TF1.x ก่อนหน้าซึ่งใช้ tf.compat.v1.make_template
แล้ว
เนื่องจาก tf.compat.v1.make_template
ล้อมโค้ดที่ใช้ get_variable
มัณฑนากร track_tf1_style_variables
ช่วยให้คุณใช้เทมเพลตเหล่านี้ในการเรียกเลเยอร์และติดตามน้ำหนักและการสูญเสียการทำให้เป็นมาตรฐานได้สำเร็จ
อย่างไรก็ตาม อย่าลืมเรียก make_template
เพียงครั้งเดียว แล้วใช้เทมเพลตเดิมซ้ำในการเรียกแต่ละเลเยอร์ มิฉะนั้น เทมเพลตใหม่จะถูกสร้างขึ้นทุกครั้งที่คุณเรียกเลเยอร์พร้อมกับตัวแปรชุดใหม่
ตัวอย่างเช่น,
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)ตัวยึดตำแหน่ง41
การย้ายข้อมูลส่วนเพิ่มไปยัง Native TF2
ดังที่กล่าวไว้ก่อนหน้านี้ track_tf1_style_variables
ช่วยให้คุณสามารถผสม tf.Variable
เชิงวัตถุสไตล์ TF2 / tf.keras.layers.Layer
/ tf.Module
กับ tf.compat.v1.get_variable
แบบเดิม / tf.compat.v1.layers
การใช้งานภายในโมดูล/เลเยอร์ที่ตกแต่งเดียวกัน
ซึ่งหมายความว่าหลังจากที่คุณสร้างโมเดล TF1.x ที่เข้ากันได้กับ TF2 อย่างสมบูรณ์แล้ว คุณสามารถเขียนส่วนประกอบโมเดลใหม่ทั้งหมดด้วย TF2 API ดั้งเดิม (ไม่ใช่ tf.compat.v1
) และให้ทำงานร่วมกันกับโค้ดเก่าของคุณ
อย่างไรก็ตาม หากคุณยังคงแก้ไขส่วนประกอบรุ่นเก่าของคุณ คุณอาจเลือกที่จะสลับการใช้งาน tf.compat.v1
สไตล์ดั้งเดิมของคุณแบบค่อยเป็นค่อยไปไปเป็น API เชิงวัตถุแบบเนทีฟล้วนๆ ที่แนะนำสำหรับโค้ด TF2 ที่เขียนใหม่
การใช้งาน tf.compat.v1.get_variable
สามารถแทนที่ด้วยการโทร self.add_weight
หากคุณกำลังตกแต่งเลเยอร์/โมเดล Keras หรือการเรียก tf.Variable
หากคุณกำลังตกแต่งวัตถุ Keras หรือ tf.Module
s
tf.compat.v1.layers
เชิงฟังก์ชันและเชิงวัตถุโดยทั่วไปสามารถแทนที่ด้วยเลเยอร์ tf.keras.layers
ที่เทียบเท่ากันโดยไม่ต้องเปลี่ยนแปลงอาร์กิวเมนต์
คุณอาจพิจารณาชิ้นส่วนต่างๆ ของโมเดลหรือรูปแบบทั่วไปลงในแต่ละเลเยอร์/โมดูลระหว่างการย้ายส่วนเพิ่มไปยัง API ดั้งเดิม ซึ่งอาจใช้ track_tf1_style_variables
หมายเหตุเกี่ยวกับ Slim และ contrib.layers
โค้ด TF 1.x รุ่นเก่าจำนวนมากใช้ไลบรารี Slim ซึ่งบรรจุด้วย TF 1.x เป็น tf.contrib.layers
การแปลงโค้ดโดยใช้ Slim เป็น Native TF 2 นั้นมีความเกี่ยวข้องมากกว่าการแปลง v1.layers
อันที่จริง การแปลงโค้ด Slim ของคุณเป็น v1.layers
ก่อนนั้นอาจสมเหตุสมผล แล้วจึงแปลงเป็น Keras ด้านล่างนี้คือคำแนะนำทั่วไปสำหรับการแปลงโค้ด Slim
- ตรวจสอบให้แน่ใจว่าอาร์กิวเมนต์ทั้งหมดมีความชัดเจน ลบ
arg_scopes
ถ้าเป็นไปได้ หากคุณยังต้องการใช้ ให้แบ่งnormalizer_fn
และactivation_fn
เป็นเลเยอร์ของตัวเอง - เลเยอร์ Conv. แบบแยกได้จะจับคู่กับเลเยอร์ Keras ที่แตกต่างกันอย่างน้อยหนึ่งเลเยอร์ (เลเยอร์ Keras ในเชิงลึก เชิงลึก และแบบแยกได้)
- Slim และ
v1.layers
มีชื่ออาร์กิวเมนต์และค่าเริ่มต้นต่างกัน - โปรดทราบว่าอาร์กิวเมนต์บางข้อมีมาตราส่วนต่างกัน
การโยกย้ายไปยัง Native TF2 โดยไม่สนใจความเข้ากันได้ของจุดตรวจ
ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็นถึงการย้ายโมเดลที่เพิ่มขึ้นไปยัง API ดั้งเดิมโดยไม่พิจารณาความเข้ากันได้ของจุดตรวจสอบ
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
ถัดไป แทนที่ compat.v1
API ด้วยสิ่งที่เทียบเท่าเชิงวัตถุดั้งเดิมในลักษณะทีละส่วน เริ่มต้นด้วยการเปลี่ยนเลเยอร์ Convolution เป็นวัตถุ Keras ที่สร้างขึ้นในตัวสร้างเลเยอร์
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
ใช้คลาส v1.keras.utils.DeterministicRandomTestTool
เพื่อตรวจสอบว่าการเปลี่ยนแปลงที่เพิ่มขึ้นนี้ทำให้โมเดลมีลักษณะการทำงานเหมือนเดิมหรือไม่
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())
ตอนนี้คุณได้แทนที่ compat.v1.layers
แต่ละรายการด้วยเลเยอร์ Keras ดั้งเดิมแล้ว
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())
สุดท้าย ให้ลบการใช้งาน variable_scope
ที่เหลือ (ไม่จำเป็น) และตัวตกแต่ง track_tf1_style_variables
เอง
ตอนนี้คุณเหลือรุ่นของโมเดลที่ใช้ API ดั้งเดิมทั้งหมด
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())
การรักษาความเข้ากันได้ของจุดตรวจระหว่างการโยกย้ายไปยัง Native TF2
กระบวนการย้ายด้านบนไปเป็น TF2 API ดั้งเดิมได้เปลี่ยนทั้งชื่อตัวแปร (เนื่องจาก Keras APIs สร้างชื่อน้ำหนักที่แตกต่างกันมาก) และเส้นทางเชิงวัตถุที่ชี้ไปที่น้ำหนักที่แตกต่างกันในโมเดล ผลกระทบของการเปลี่ยนแปลงเหล่านี้คือ การเปลี่ยนแปลงเหล่านี้จะทำลายจุดตรวจตามชื่อสไตล์ TF1 ที่มีอยู่หรือจุดตรวจสอบเชิงวัตถุสไตล์ TF2
อย่างไรก็ตาม ในบางกรณี คุณอาจใช้จุดตรวจตามชื่อเดิมของคุณและค้นหาการแมปของตัวแปรกับชื่อใหม่ได้โดยใช้แนวทางเช่นเดียวกับที่มีรายละเอียดใน คู่มือการใช้จุดตรวจ TF1.x ซ้ำ
เคล็ดลับบางประการในการทำให้สิ่งนี้เป็นไปได้มีดังนี้:
- ตัวแปรทั้งหมดยังมีอาร์กิวเมนต์
name
ที่คุณสามารถตั้งค่าได้ - โมเดล Keras ยังใช้อาร์กิวเมนต์
name
ตามที่ตั้งค่าเป็นคำนำหน้าสำหรับตัวแปร - ฟังก์ชัน
v1.name_scope
สามารถใช้เพื่อตั้งค่าคำนำหน้าชื่อตัวแปรได้ ซึ่งแตกต่างจากtf.variable_scope
มาก มีผลกับชื่อเท่านั้น ไม่ติดตามตัวแปรและการนำกลับมาใช้ใหม่
เมื่อคำนึงถึงตัวชี้ด้านบนแล้ว ตัวอย่างโค้ดต่อไปนี้จะสาธิตเวิร์กโฟลว์ที่คุณสามารถปรับให้เข้ากับโค้ดของคุณเพื่ออัปเดตส่วนต่างๆ ของโมเดลในขณะที่อัปเดตจุดตรวจพร้อมกัน
- เริ่มต้นด้วยการเปลี่ยน
tf.compat.v1.layers
สไตล์การทำงานไปเป็นเวอร์ชันเชิงวัตถุ
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']
- ถัดไป กำหนดอ็อบเจ็กต์ compat.v1.layer และตัวแปรใดๆ ที่สร้างโดย
compat.v1.get_variable
เป็นคุณสมบัติของtf.keras.layers.Layer
/tf.Module
ที่เมธอดตกแต่งด้วยtrack_tf1_style_variables
(โปรดทราบว่า TF2 เชิงวัตถุใดๆ จุดตรวจสอบลักษณะจะบันทึกทั้งเส้นทางตามชื่อตัวแปรและเส้นทางเชิงวัตถุใหม่)
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']ตัวยึดตำแหน่ง60
- บันทึกจุดตรวจสอบที่โหลดใหม่ ณ จุดนี้เพื่อบันทึกเส้นทางทั้งโดยชื่อตัวแปร (สำหรับ compat.v1.layers) หรือโดยกราฟวัตถุเชิงวัตถุ
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
- ตอนนี้คุณสามารถสลับ
compat.v1.layers
เชิงวัตถุสำหรับเลเยอร์ Keras ดั้งเดิมในขณะที่ยังสามารถโหลดจุดตรวจสอบที่บันทึกไว้ล่าสุด ตรวจสอบให้แน่ใจว่าคุณรักษาชื่อตัวแปรไว้สำหรับcompat.v1.layers
ที่เหลือ โดยยังคงบันทึกvariable_scopes
สร้างขึ้นโดยอัตโนมัติของเลเยอร์ที่ถูกแทนที่ เลเยอร์/ตัวแปรที่สับเปลี่ยนเหล่านี้จะใช้เฉพาะเส้นทางแอตทริบิวต์ของวัตถุไปยังตัวแปรในจุดตรวจสอบแทนเส้นทางชื่อตัวแปร
โดยทั่วไป คุณสามารถแทนที่การใช้ compat.v1.get_variable
ในตัวแปรที่แนบมากับคุณสมบัติโดย:
- เปลี่ยนเป็นใช้
tf.Variable
, OR - อัปเดตโดยใช้
tf.keras.layers.Layer.add_weight
โปรดทราบว่าหากคุณไม่ได้สลับเลเยอร์ทั้งหมดในคราวเดียว การทำเช่นนี้อาจเปลี่ยนการตั้งชื่อเลเยอร์/ตัวแปรที่สร้างขึ้นโดยอัตโนมัติสำหรับcompat.v1.layers
ที่เหลือซึ่งไม่มีอาร์กิวเมนต์name
หากเป็นกรณีนี้ คุณต้องรักษาชื่อตัวแปรสำหรับcompat.v1.layers
ที่เหลืออยู่โดยเปิดและปิดvariable_scope
ด้วยตนเองซึ่งสอดคล้องกับชื่อขอบเขตที่สร้างขึ้นของcompat.v1.layer
ที่ถูกลบ มิฉะนั้น เส้นทางจากจุดตรวจที่มีอยู่อาจขัดแย้งกัน และการโหลดจุดตรวจจะทำงานไม่ถูกต้อง
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']
การบันทึกจุดตรวจสอบในขั้นตอนนี้หลังจากสร้างตัวแปรจะทำให้มี เฉพาะ เส้นทางของวัตถุที่มีอยู่ในปัจจุบันเท่านั้น
ตรวจสอบให้แน่ใจว่าคุณได้บันทึกขอบเขตของ compat.v1.layers
ที่ถูกลบออกเพื่อรักษาชื่อน้ำหนักที่สร้างขึ้นโดยอัตโนมัติสำหรับ compat.v1.layers
ที่เหลือ
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
- ทำซ้ำขั้นตอนข้างต้นจนกว่าคุณจะแทนที่
compat.v1.layers
และcompat.v1.get_variable
s ทั้งหมดในแบบจำลองของคุณด้วยค่าเทียบเท่าเนทีฟทั้งหมด
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']
อย่าลืมทดสอบเพื่อให้แน่ใจว่าจุดตรวจที่อัปเดตใหม่ยังคงทำงานตามที่คุณคาดหวัง ใช้เทคนิคที่อธิบายไว้ในคู่มือการ ตรวจสอบความถูกต้องของตัวเลข ในทุกขั้นตอนที่เพิ่มขึ้นของกระบวนการนี้ เพื่อให้แน่ใจว่าโค้ดที่โอนย้ายของคุณทำงานอย่างถูกต้อง
การจัดการการเปลี่ยนแปลงพฤติกรรมของ TF1.x เป็น TF2 ที่ไม่ครอบคลุมโดยการจำลองแบบจำลอง shims
ชิมแบบจำลองที่อธิบายในคู่มือนี้ทำให้แน่ใจได้ว่าตัวแปร เลเยอร์ และการสูญเสียการทำให้เป็นมาตรฐานที่สร้างด้วย get_variable
, tf.compat.v1.layers
และ ความหมาย variable_scope
จะยังคงทำงานเหมือนเดิมเมื่อใช้การเรียกใช้งานแบบกระตือรือร้นและ tf.function
โดยไม่ต้อง พึ่งพาคอลเลกชัน
ข้อมูลนี้ไม่ครอบคลุมความหมายเฉพาะของ TF1.x ทั้งหมด ที่โมเดล Forward Pass ของคุณอาจใช้ ในบางกรณี แผ่นชิมอาจไม่เพียงพอที่จะทำให้โมเดลของคุณส่งต่อการส่งผ่านใน TF2 ได้ด้วยตัวเอง อ่าน คู่มือพฤติกรรม TF1.x เทียบกับ TF2 เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับความแตกต่างทางพฤติกรรมระหว่าง TF1.x และ TF2