Lihat di TensorFlow.org | Jalankan di Google Colab | Lihat di GitHub | Unduh buku catatan |
Panduan ini memberikan gambaran umum dan contoh shim kode pemodelan yang dapat Anda terapkan untuk menggunakan model TF1.x yang ada dalam alur kerja TF2 seperti eksekusi bersemangat, tf.function
, dan strategi distribusi dengan sedikit perubahan pada kode pemodelan Anda.
Lingkup penggunaan
Shim yang dijelaskan dalam panduan ini dirancang untuk model TF1.x yang mengandalkan:
-
tf.compat.v1.get_variable
dantf.compat.v1.variable_scope
untuk mengontrol pembuatan dan penggunaan kembali variabel, dan - API berbasis koleksi grafik seperti
tf.compat.v1.global_variables()
,tf.compat.v1.trainable_variables
,tf.compat.v1.losses.get_regularization_losses()
, dantf.compat.v1.get_collection()
untuk melacak bobot dan kerugian regularisasi
Ini mencakup sebagian besar model yang dibuat di atas tf.compat.v1.layer
, tf.contrib.layers
API, dan TensorFlow-Slim .
Shim TIDAK diperlukan untuk model TF1.x berikut:
- Model Keras mandiri yang telah melacak semua bobot yang dapat dilatih dan kehilangan regularisasinya masing-masing melalui
model.trainable_weights
danmodel.losses
. -
tf.Module
s yang telah melacak semua bobot yang dapat dilatih melaluimodule.trainable_variables
, dan hanya membuat bobot jika belum dibuat.
Model-model ini cenderung bekerja di TF2 dengan eksekusi yang bersemangat dan tf.function
s out-of-the-box.
Mempersiapkan
Impor TensorFlow dan dependensi lainnya.
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
Dekorator track_tf1_style_variables
Shim kunci yang dijelaskan dalam panduan ini adalah tf.compat.v1.keras.utils.track_tf1_style_variables
, dekorator yang dapat Anda gunakan dalam metode milik tf.keras.layers.Layer
dan tf.Module
untuk melacak bobot gaya TF1.x dan menangkap kerugian regularisasi.
Mendekorasi metode panggilan tf.keras.layers.Layer
atau tf.Module
dengan tf.compat.v1.keras.utils.track_tf1_style_variables
memungkinkan pembuatan dan penggunaan kembali variabel melalui tf.compat.v1.get_variable
(dan dengan ekstensi tf.compat.v1.layers
) untuk bekerja dengan benar di dalam metode yang didekorasi daripada selalu membuat variabel baru pada setiap panggilan. Ini juga akan menyebabkan lapisan atau modul secara implisit melacak bobot yang dibuat atau diakses melalui get_variable
di dalam metode yang didekorasi.
Selain melacak bobot itu sendiri di bawah standar layer.variable
/ module.variable
/etc. properties, jika metode tersebut milik tf.keras.layers.Layer
, maka kehilangan regularisasi apa pun yang ditentukan melalui argumen pengatur get_variable
atau tf.compat.v1.layers
akan dilacak oleh lapisan di bawah properti layer.losses
standar.
Mekanisme pelacakan ini memungkinkan penggunaan kelas besar kode model-forward-pass gaya TF1.x di dalam lapisan Keras atau tf.Module
s di TF2 bahkan dengan perilaku TF2 diaktifkan.
Contoh penggunaan
Contoh penggunaan di bawah ini menunjukkan shim pemodelan yang digunakan untuk mendekorasi metode tf.keras.layers.Layer
, tetapi kecuali jika mereka secara khusus berinteraksi dengan fitur Keras, shim tersebut juga berlaku saat mendekorasi metode tf.Module
.
Lapisan dibangun dengan tf.compat.v1.get_variable
Bayangkan Anda memiliki lapisan yang diimplementasikan langsung di atas tf.compat.v1.get_variable
sebagai berikut:
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
Gunakan shim untuk mengubahnya menjadi layer dan menyebutnya pada input.
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)>
Akses variabel yang dilacak dan kehilangan regularisasi yang ditangkap seperti lapisan Keras standar.
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>]
Untuk melihat bahwa bobot digunakan kembali setiap kali Anda memanggil layer, atur semua bobot ke nol dan panggil layer lagi.
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)>
Anda juga dapat menggunakan lapisan yang dikonversi secara langsung dalam konstruksi model fungsional 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>]
Model dibuat dengan tf.compat.v1.layers
Bayangkan Anda memiliki lapisan atau model yang diimplementasikan langsung di atas tf.compat.v1.layers
sebagai berikut:
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
Gunakan shim untuk mengubahnya menjadi layer dan menyebutnya pada input.
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)>
Akses variabel yang dilacak dan kehilangan regularisasi yang ditangkap seperti lapisan Keras standar.
layer.trainable_variables
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03623246>, <tf.Tensor: shape=(), dtype=float32, numpy=0.14618248>]
Untuk melihat bahwa bobot digunakan kembali setiap kali Anda memanggil layer, atur semua bobot ke nol dan panggil layer lagi.
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)>
Anda juga dapat menggunakan lapisan yang dikonversi secara langsung dalam konstruksi model fungsional 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>]
Tangkap pembaruan normalisasi batch dan argumen training
model
Di TF1.x, Anda melakukan normalisasi batch seperti ini:
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])
Perhatikan bahwa:
- Pembaruan rata-rata bergerak normalisasi batch dilacak oleh
get_collection
yang dipanggil secara terpisah dari lapisan -
tf.compat.v1.layers.batch_normalization
memerlukan argumentraining
(umumnya disebutis_training
saat menggunakan lapisan normalisasi batch TF-Slim)
Di TF2, karena eksekusi yang bersemangat dan dependensi kontrol otomatis, pembaruan rata-rata bergerak normalisasi batch akan segera dieksekusi. Tidak perlu mengumpulkannya secara terpisah dari koleksi pembaruan dan menambahkannya sebagai dependensi kontrol eksplisit.
Selain itu, jika Anda memberikan argumen training
metode forward pass tf.keras.layers.Layer
Anda, Keras akan dapat melewati fase pelatihan saat ini dan semua lapisan bersarang ke sana seperti halnya untuk lapisan lainnya. Lihat dokumen API untuk tf.keras.Model
untuk informasi selengkapnya tentang cara Keras menangani argumen training
.
Jika Anda mendekorasi metode tf.Module
, Anda perlu memastikan untuk secara manual melewati semua argumen training
sesuai kebutuhan. Namun, pembaruan rata-rata bergerak normalisasi batch akan tetap diterapkan secara otomatis tanpa memerlukan dependensi kontrol eksplisit.
Cuplikan kode berikut menunjukkan cara menyematkan lapisan normalisasi batch di shim dan cara menggunakannya dalam model Keras bekerja (berlaku untuk 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)>}
Penggunaan kembali variabel berbasis cakupan variabel
Setiap pembuatan variabel di penerusan berdasarkan get_variable
akan mempertahankan penamaan variabel yang sama dan menggunakan kembali semantik yang dimiliki cakupan variabel di TF1.x. Ini benar selama Anda memiliki setidaknya satu cakupan luar yang tidak kosong untuk setiap tf.compat.v1.layers
dengan nama yang dibuat secara otomatis, seperti yang disebutkan di atas.
Eksekusi bersemangat & tf.function
Seperti yang terlihat di atas, metode yang didekorasi untuk tf.keras.layers.Layer
dan tf.Module
berjalan di dalam eksekusi yang bersemangat dan juga kompatibel dengan tf.function
. Ini berarti Anda dapat menggunakan pdb dan alat interaktif lainnya untuk melangkah melalui umpan maju Anda saat sedang berjalan.
Strategi distribusi
Panggilan ke get_variable
di dalam @track_tf1_style_variables
layer atau metode modul menggunakan pembuatan variabel tf.Variable
standar di bawah tenda. Ini berarti Anda dapat menggunakannya dengan berbagai strategi distribusi yang tersedia dengan tf.distribute
seperti MirroredStrategy
dan TPUStrategy
.
Bersarang tf.Variable
s, tf.Module
s, tf.keras.layers
& tf.keras.models
dalam panggilan yang didekorasi
Mendekorasi panggilan lapisan Anda di tf.compat.v1.keras.utils.track_tf1_style_variables
hanya akan menambahkan pelacakan implisit otomatis dari variabel yang dibuat (dan digunakan kembali) melalui tf.compat.v1.get_variable
. Itu tidak akan menangkap bobot yang dibuat secara langsung oleh panggilan tf.Variable
, seperti yang digunakan oleh lapisan Keras biasa dan sebagian besar tf.Module
s. Bagian ini menjelaskan cara menangani kasus bersarang ini.
(Penggunaan yang sudah ada sebelumnya) tf.keras.layers
dan tf.keras.models
Untuk penggunaan lapisan dan model Keras bersarang yang sudah ada sebelumnya, gunakan tf.compat.v1.keras.utils.get_or_create_layer
. Ini hanya disarankan untuk memudahkan migrasi penggunaan Keras bersarang TF1.x yang ada; kode baru harus menggunakan pengaturan atribut eksplisit seperti yang dijelaskan di bawah ini untuk tf.Variables dan tf.Modules.
Untuk menggunakan tf.compat.v1.keras.utils.get_or_create_layer
, bungkus kode yang menyusun model bersarang Anda ke dalam sebuah metode, dan teruskan ke dalam metode. Contoh:
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)>
Metode ini memastikan bahwa lapisan bersarang ini digunakan kembali dengan benar dan dilacak oleh tensorflow. Perhatikan bahwa dekorator @track_tf1_style_variables
masih diperlukan pada metode yang sesuai. Metode pembuat model yang diteruskan ke get_or_create_layer
(dalam hal ini, self.build_model
), tidak boleh menggunakan argumen.
Berat dilacak:
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)>]
Dan kerugian regularisasi juga:
tf.add_n(layer.losses)
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.5], dtype=float32)>
Migrasi tambahan: tf.Variables
dan tf.Modules
Jika Anda perlu menyematkan panggilan tf.Variable
atau tf.Module
s dalam metode yang didekorasi (misalnya, jika Anda mengikuti migrasi inkremental ke API TF2 non-legacy yang dijelaskan nanti dalam panduan ini), Anda masih perlu melacaknya secara eksplisit, dengan persyaratan sebagai berikut:
- Pastikan secara eksplisit bahwa variabel/modul/lapisan hanya dibuat sekali
- Lampirkan secara eksplisit sebagai atribut instan seperti yang Anda lakukan saat mendefinisikan modul atau lapisan biasa
- Gunakan kembali objek yang sudah dibuat secara eksplisit dalam panggilan lanjutan
Ini memastikan bahwa bobot tidak dibuat baru setiap panggilan dan digunakan kembali dengan benar. Selain itu, ini juga memastikan bahwa bobot yang ada dan kerugian regularisasi dapat dilacak.
Berikut adalah contoh bagaimana ini bisa terlihat:
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)>
Perhatikan bahwa pelacakan eksplisit dari modul bersarang diperlukan meskipun didekorasi dengan dekorator track_tf1_style_variables
. Ini karena setiap modul/lapisan dengan metode yang didekorasi memiliki penyimpanan variabel sendiri yang terkait dengannya.
Bobot dilacak dengan benar:
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)>]
Serta kehilangan regularisasi:
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.058749676>]
Perhatikan bahwa jika NestedLayer
adalah tf.Module
non-Keras, variabel akan tetap dilacak tetapi kehilangan regularisasi tidak akan dilacak secara otomatis, jadi Anda harus melacaknya secara eksplisit secara terpisah.
Panduan tentang nama variabel
Panggilan tf.Variable
eksplisit dan lapisan Keras menggunakan nama lapisan / mekanisme autogenerasi nama variabel yang berbeda dari yang biasa Anda gunakan dari kombinasi get_variable
dan variable_scopes
. Meskipun shim akan membuat nama variabel Anda cocok dengan variabel yang dibuat oleh get_variable
bahkan ketika beralih dari grafik TF1.x ke TF2 bersemangat eksekusi & tf.function
, itu tidak dapat menjamin hal yang sama untuk nama variabel yang dihasilkan untuk panggilan tf.Variable
dan lapisan Keras yang Anda menanamkan dalam dekorator metode Anda. Bahkan dimungkinkan untuk beberapa variabel untuk berbagi nama yang sama di TF2 bersemangat eksekusi dan tf.function
.
Anda harus berhati-hati dengan hal ini saat mengikuti bagian tentang validasi kebenaran dan pemetaan pos pemeriksaan TF1.x nanti dalam panduan ini.
Menggunakan tf.compat.v1.make_template
dalam metode yang didekorasi
Sangat disarankan Anda langsung menggunakan tf.compat.v1.keras.utils.track_tf1_style_variables
daripada menggunakan tf.compat.v1.make_template
, karena ini adalah lapisan yang lebih tipis di atas TF2 .
Ikuti panduan di bagian ini untuk kode TF1.x sebelumnya yang sudah mengandalkan tf.compat.v1.make_template
.
Karena tf.compat.v1.make_template
membungkus kode yang menggunakan get_variable
, dekorator track_tf1_style_variables
memungkinkan Anda untuk menggunakan template ini dalam panggilan lapisan dan berhasil melacak bobot dan kerugian regularisasi.
Namun, pastikan untuk memanggil make_template
hanya sekali dan kemudian menggunakan kembali template yang sama di setiap panggilan lapisan. Jika tidak, template baru akan dibuat setiap kali Anda memanggil layer bersama dengan set variabel baru.
Sebagai contoh,
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)
Migrasi tambahan ke TF2 Asli
Seperti disebutkan sebelumnya, track_tf1_style_variables
memungkinkan Anda untuk mencampur penggunaan tf.Variable / tf.keras.layers.Layer
/ tf.Module berorientasi objek gaya TF2 dengan tf.Variable
/ tf.Module
tf.compat.v1.get_variable
tf.compat.v1.layers
penggunaan di dalam modul/lapisan yang didekorasi sama.
Ini berarti bahwa setelah Anda membuat model TF1.x Anda sepenuhnya kompatibel dengan TF2, Anda dapat menulis semua komponen model baru dengan API TF2 asli (non tf.compat.v1
) dan membuatnya beroperasi dengan kode lama Anda.
Namun, jika Anda terus memodifikasi komponen model lama, Anda juga dapat memilih untuk secara bertahap mengalihkan penggunaan tf.compat.v1
gaya lama Anda ke API berorientasi objek murni asli yang direkomendasikan untuk kode TF2 yang baru ditulis.
Penggunaan tf.compat.v1.get_variable
dapat diganti dengan panggilan self.add_weight
jika Anda mendekorasi layer/model Keras, atau dengan panggilan tf.Variable
jika Anda mendekorasi objek Keras atau tf.Module
s.
Baik tf.compat.v1.layers
gaya fungsional dan berorientasi objek umumnya dapat diganti dengan lapisan tf.keras.layers
yang setara tanpa perubahan argumen yang diperlukan.
Anda juga dapat mempertimbangkan potongan bagian dari model atau pola umum Anda ke dalam lapisan/modul individual selama perpindahan inkremental Anda ke API asli murni, yang mungkin sendiri menggunakan track_tf1_style_variables
.
Catatan tentang Slim dan contrib.layers
Sejumlah besar kode TF 1.x lama menggunakan pustaka Slim , yang dikemas dengan TF 1.x sebagai tf.contrib.layers
. Mengonversi kode menggunakan Slim ke TF 2 asli lebih terlibat daripada mengonversi v1.layers
. Bahkan, mungkin masuk akal untuk mengonversi kode Slim Anda ke v1.layers
terlebih dahulu, lalu mengonversi ke Keras. Di bawah ini adalah beberapa panduan umum untuk mengonversi kode Slim.
- Pastikan semua argumen eksplisit. Hapus
arg_scopes
jika memungkinkan. Jika Anda masih perlu menggunakannya, pisahkannormalizer_fn
danactivation_fn
ke dalam lapisannya sendiri. - Lapisan konv yang dapat dipisahkan dipetakan ke satu atau lebih lapisan Keras yang berbeda (lapisan Keras yang mendalam, terarah, dan dapat dipisahkan).
- Slim dan
v1.layers
memiliki nama argumen dan nilai default yang berbeda. - Perhatikan bahwa beberapa argumen memiliki skala yang berbeda.
Migrasi ke TF2 Asli mengabaikan kompatibilitas pos pemeriksaan
Contoh kode berikut menunjukkan perpindahan bertahap model ke API asli murni tanpa mempertimbangkan kompatibilitas pos pemeriksaan.
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
Selanjutnya, ganti API compat.v1
dengan ekuivalen berorientasi objek asli secara bertahap. Mulailah dengan mengalihkan lapisan konvolusi ke objek Keras yang dibuat di konstruktor lapisan.
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
Gunakan kelas v1.keras.utils.DeterministicRandomTestTool
untuk memverifikasi bahwa perubahan inkremental ini meninggalkan model dengan perilaku yang sama seperti sebelumnya.
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())
Anda sekarang telah mengganti semua compat.v1.layers
individu dengan lapisan Keras asli.
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())
Terakhir, hapus penggunaan variable_scope
yang tersisa (tidak lagi diperlukan) dan dekorator track_tf1_style_variables
itu sendiri.
Sekarang Anda memiliki versi model yang sepenuhnya menggunakan API asli.
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())
Mempertahankan kompatibilitas pos pemeriksaan selama migrasi ke Native TF2
Proses migrasi di atas ke API TF2 asli mengubah nama variabel (karena Keras API menghasilkan nama bobot yang sangat berbeda), dan jalur berorientasi objek yang mengarah ke bobot berbeda dalam model. Dampak dari perubahan ini adalah bahwa mereka akan merusak pos pemeriksaan berbasis nama gaya TF1 yang ada atau pos pemeriksaan berorientasi objek gaya TF2.
Namun, dalam beberapa kasus, Anda mungkin dapat mengambil pos pemeriksaan berbasis nama asli Anda dan menemukan pemetaan variabel ke nama barunya dengan pendekatan seperti yang dirinci dalam panduan pos pemeriksaan Menggunakan Kembali TF1.x .
Beberapa tips untuk membuat ini layak adalah sebagai berikut:
- Semua variabel masih memiliki argumen
name
yang dapat Anda atur. - Model Keras juga mengambil argumen
name
yang mereka tetapkan sebagai awalan untuk variabel mereka. - Fungsi
v1.name_scope
dapat digunakan untuk mengatur awalan nama variabel. Ini sangat berbeda daritf.variable_scope
. Itu hanya memengaruhi nama, dan tidak melacak variabel dan menggunakan kembali.
Dengan mengingat petunjuk di atas, contoh kode berikut menunjukkan alur kerja yang dapat Anda sesuaikan dengan kode Anda untuk memperbarui bagian model secara bertahap sekaligus memperbarui pos pemeriksaan.
- Mulailah dengan mengalihkan gaya fungsional
tf.compat.v1.layers
ke versi berorientasi objeknya.
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']
- Selanjutnya, tetapkan objek compat.v1.layer dan variabel apa pun yang dibuat oleh
compat.v1.get_variable
sebagai properti objektf.keras.layers.Layer
/tf.Module
yang metodenya didekorasi dengantrack_tf1_style_variables
(perhatikan bahwa semua TF2 berorientasi objek pos pemeriksaan gaya sekarang akan menyimpan jalur dengan nama variabel dan jalur berorientasi objek baru).
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']
- Simpan pos pemeriksaan yang dimuat pada titik ini untuk menyimpan jalur baik dengan nama variabel (untuk compat.v1.layers), atau dengan grafik objek berorientasi objek.
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
- Anda sekarang dapat menukar
compat.v1.layers
berorientasi objek untuk lapisan Keras asli sambil tetap dapat memuat pos pemeriksaan yang baru saja disimpan. Pastikan Anda mempertahankan nama variabel untukcompat.v1.layers
yang tersisa dengan tetap merekamvariable_scopes
yang dibuat secara otomatis dari lapisan yang diganti. Lapisan/variabel yang dialihkan ini sekarang hanya akan menggunakan jalur atribut objek ke variabel di pos pemeriksaan alih-alih jalur nama variabel.
Secara umum, Anda dapat mengganti penggunaan compat.v1.get_variable
dalam variabel yang dilampirkan ke properti dengan:
- Mengalihkannya ke menggunakan
tf.Variable
, ATAU - Memperbarui mereka dengan menggunakan
tf.keras.layers.Layer.add_weight
. Perhatikan bahwa jika Anda tidak mengganti semua lapisan sekaligus, ini dapat mengubah penamaan lapisan/variabel yang dibuat secara otomatis untukcompat.v1.layers
yang tersisa yang tidak memiliki argumenname
. Jika demikian, Anda harus menjaga nama variabel untukcompat.v1.layers
yang tersisa tetap sama dengan membuka dan menutupvariable_scope
secara manual sesuai dengan nama lingkup yang dihasilkancompat.v1.layer
yang dihapus. Jika tidak, jalur dari pos pemeriksaan yang ada mungkin bertentangan dan pemuatan pos pemeriksaan akan berperilaku tidak benar.
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']
Menyimpan checkpoint pada langkah ini setelah membuat variabel akan membuatnya hanya berisi jalur objek yang tersedia saat ini.
Pastikan Anda mencatat cakupan compat.v1.layers
yang dihapus untuk mempertahankan nama bobot yang dibuat secara otomatis untuk compat.v1.layers
yang tersisa.
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
- Ulangi langkah di atas hingga Anda mengganti semua
compat.v1.layers
dancompat.v1.get_variable
s dalam model Anda dengan padanan yang sepenuhnya asli.
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']
Ingatlah untuk menguji untuk memastikan pos pemeriksaan yang baru diperbarui masih berfungsi seperti yang Anda harapkan. Terapkan teknik yang dijelaskan dalam panduan kebenaran numerik validasi pada setiap langkah tambahan dari proses ini untuk memastikan kode yang dimigrasikan berjalan dengan benar.
Menangani perubahan perilaku TF1.x ke TF2 yang tidak tercakup oleh shim pemodelan
Shim pemodelan yang dijelaskan dalam panduan ini dapat memastikan bahwa variabel, lapisan, dan kerugian regularisasi yang dibuat dengan get_variable
, tf.compat.v1.layers
, dan variable_scope
semantik terus bekerja seperti sebelumnya saat menggunakan eksekusi bersemangat dan tf.function
, tanpa harus mengandalkan koleksi.
Ini tidak mencakup semua semantik khusus TF1.x yang dapat diandalkan oleh model forward pass Anda. Dalam beberapa kasus, shim mungkin tidak cukup untuk menjalankan model forward pass Anda di TF2 sendiri. Baca panduan perilaku TF1.x vs TF2 untuk mempelajari lebih lanjut tentang perbedaan perilaku antara TF1.x dan TF2.