הצג באתר TensorFlow.org | הפעל בגוגל קולאב | הצג ב-GitHub | הורד מחברת |
מדריך זה מספק סקירה כללית ודוגמאות של תבנית קוד מידול שתוכל להשתמש במודלים הקיימים של TF1.x בזרימות עבודה של TF2 כגון ביצוע נלהב, tf.function
ואסטרטגיות הפצה עם שינויים מינימליים בקוד המידול שלך.
היקף השימוש
ה-shim המתואר במדריך זה מיועד לדגמי 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()
כדי לעקוב אחר של משקלים ואיבודי סדירות
זה כולל את רוב הדגמים שנבנו על גבי ממשקי API של tf.compat.v1.layer
, tf.contrib.layers
ו- TensorFlow-Slim .
ה-shim אינו הכרחי עבור דגמי TF1.x הבאים:
- דגמי Keras עצמאיים שכבר עוקבים אחר כל המשקולות הניתנות לאימון והפסדי הרגולציה באמצעות
model.trainable_weights
ו-model.losses
בהתאמה. -
tf.Module
s שכבר עוקבים אחר כל המשקלים הניתנים לאימון שלהם באמצעות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
בתוך השיטה המעוטרת.
בנוסף למעקב אחר המשקולות עצמן תחת השכבה הסטנדרטית. module.variable
layer.variable
etc. מאפיינים, אם השיטה שייכת tf.keras.layers.Layer
, אז כל הפסדי רגוליזציה שצוינו דרך get_variable
או tf.compat.v1.layers
regularizer יעברו מעקב על ידי השכבה שמתחת למאפיין layer.losses
הסטנדרטי.
מנגנון מעקב זה מאפשר שימוש במחלקות גדולות של קוד מודל-forward-pass בסגנון TF1.x בתוך שכבות Keras או tf.Module
s ב-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
השתמש ב-shim כדי להפוך אותו לשכבה ולקרוא לו בכניסות.
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
השתמש ב-shim כדי להפוך אותו לשכבה ולקרוא לו בכניסות.
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
מודלים
ב-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
לפי הצורך. עם זאת, עדכוני הממוצע הנע של אצווה עדיין יוחלו אוטומטית ללא צורך בתלות בקרה מפורשת.
קטעי הקוד הבאים מדגימים כיצד להטמיע שכבות נורמליזציה של אצווה ב-shim וכיצד עובד השימוש בו במודל 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
שכבה או מודול מעוטרות משתמשות ביצירת משתנים סטנדרטיים 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
s. סעיף זה מתאר כיצד לטפל במקרים מקוננים אלה.
(שימושים קיימים) 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)>
הגירה מצטברת: tf.Variables
ו- tf.Modules
אם אתה צריך להטמיע קריאות tf.Variable
או tf.Module
s בשיטות המעוטרות שלך (לדוגמה, אם אתה עוקב אחר ההגירה המצטברת לממשקי API של TF2 שאינם מדור קודם המתוארים בהמשך מדריך זה), אתה עדיין צריך לעקוב אחר אלה באופן מפורש, עם הדרישות הבאות:
- ודא במפורש שהמשתנה/מודול/שכבה נוצר רק פעם אחת
- צרף אותם במפורש כמאפייני מופע בדיוק כפי שהיית מצרף בעת הגדרת מודול או שכבה טיפוסית
- השתמש מחדש במפורש באובייקט שכבר נוצר בשיחות המשך
זה מבטיח שמשקולות לא ייווצרו חדשות בכל שיחה ושנעשה בהן שימוש חוזר כראוי. בנוסף, זה גם מבטיח שעוקבים אחר המשקלים הקיימים ואיבודי ההסדרה.
הנה דוגמה איך זה יכול להיראות:
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
decorator. הסיבה לכך היא שלכל מודול/שכבה עם שיטות מעוטרות יש חנות משתנה משלה הקשורה אליו.
המשקולות נמצאות במעקב נכון:
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>]
שים לב שאם ה- NestedLayer
היה במקום זאת tf.Module שאינו של tf.Module
, המשתנים עדיין היו במעקב, אך הפסדי רגוליזציה לא יעברו מעקב אוטומטי, כך שתצטרך לעקוב אחריהם באופן מפורש בנפרד.
הדרכה לגבי שמות משתנים
קריאות tf.Variable
מפורשות ושכבות Keras משתמשות במנגנון יצירה אוטומטי של שם שכבה/משתנה שונה ממה שאתה עשוי להתרגל אליו מהשילוב של get_variable
ו- variable_scopes
. למרות שה-shim יגרום לשמות המשתנים שלך להתאים למשתנים שנוצרו על ידי get_variable
גם כאשר עוברים מגרפים TF1.x ל-TF2 eager execution & tf.function
, הוא לא יכול להבטיח את אותו הדבר עבור שמות המשתנים שנוצרו עבור קריאות tf.Variable
ושכבות Keras ש אתה מטמיע בתוך השיטה שלך מעצבים. זה אפילו אפשרי עבור משתנים מרובים לחלוק את אותו השם ב-TF2 eager execution ו- 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)
העברה מצטברת ל-Native TF2
כפי שהוזכר קודם לכן, track_tf1_style_variables
מאפשר לך לערבב tf.Variable
/ tf.keras.layers.Layer
/ tf.Module
מונחה עצמים בסגנון TF2 עם ישן tf.compat.v1.get_variable
/ tf.compat.v1.layers
שימוש בתוך אותו מודול/שכבה מעוטרים.
משמעות הדבר היא שאחרי שהפכת את דגם ה-TF1.x שלך לתואם לחלוטין ל-TF2, תוכל לכתוב את כל רכיבי הדגם החדשים עם ממשקי API מקוריים (שאינם tf.compat.v1
) TF2 ולגרום להם לפעול יחד עם הקוד הישן יותר.
עם זאת, אם תמשיך לשנות את רכיבי הדגם הישנים שלך, תוכל גם לבחור להעביר בהדרגה את השימוש שלך ב- tf.compat.v1
בסגנון מדור קודם לממשקי ה-API המונחה עצמים מקוריים בלבד, המומלצים עבור קוד TF2 שנכתב לאחרונה.
ניתן להחליף את השימוש ב- tf.compat.v1.get_variable
בקריאות self.add_weight
אם אתה מקשט שכבה/דגם של Keras, או בקריאות tf.Variable
אם אתה מקשט חפצי Keras או tf.Module
s.
בדרך כלל ניתן להחליף שכבות tf.keras.layers
tf.compat.v1.layers
ללא צורך בשינויי ארגומנטים.
אתה יכול גם לשקול חלקים של חלקים מהמודל שלך או דפוסים נפוצים לשכבות/מודולים בודדים במהלך המעבר המצטבר שלך לממשקי API מקוריים בלבד, שעשויים בעצמם להשתמש ב- track_tf1_style_variables
.
הערה על Slim ו-contrib.layers
כמות גדולה של קוד TF 1.x ישן יותר משתמשת בספריית Slim , שנארזה עם TF 1.x כ- tf.contrib.layers
. המרת קוד באמצעות Slim ל-TF 2 מקורית היא מעורבת יותר מהמרת v1.layers
. למעשה, אולי הגיוני להמיר את קוד ה-Slim שלך ל- v1.layers
תחילה, ואז להמיר ל-Keras. להלן כמה הנחיות כלליות להמרת קוד Slim.
- ודא שכל הטיעונים מפורשים. הסר
arg_scopes
אם אפשר. אם אתה עדיין צריך להשתמש בהם, פצל אתnormalizer_fn
ואתactivation_fn
לשכבות משלהם. - שכבות ההמרה הניתנות להפרדה ממפות לשכבת 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
לאחר מכן, החלף את ממשקי ה-API של compat.v1
עם המקבילים המקוריים שלהם מונחה עצמים בצורה חלקית. התחל על ידי החלפת שכבת הקונבולציה לאובייקט 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
decorator עצמו.
כעת נשארת עם גרסה של המודל שמשתמשת בממשקי 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 מייצרים שמות משקל שונים מאוד), והן את הנתיבים מונחה עצמים המצביעים על משקלים שונים במודל. ההשפעה של השינויים הללו היא שהם ישברו הן את כל נקודות המחסום הקיימות מבוססות שמות בסגנון 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']
- שמור מחדש נקודת ביקורת נטענת בנקודה זו כדי לחסוך נתיבים הן לפי שם המשתנה (עבור 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. מונחה עצמים בשכבות מקוריות של
compat.v1.layers
תוך כדי יכולת לטעון את נקודת הבידוק שנשמרה לאחרונה. ודא שאתה משמר שמות משתנים עבור השכבות הנותרות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
המתאים לשם ה-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
בדגם שלך עם מקבילות מקוריות לחלוטין.
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 שאינם מכוסים על ידי תבניות הדוגמנות
תבניות הדוגמנות המתוארות במדריך זה יכולות לוודא שמשתנים, שכבות והפסדי רגוליזציה שנוצרו עם get_variable
, tf.compat.v1.layers
וסמנטיקה variable_scope
ימשיכו לעבוד כבעבר בעת שימוש בביצוע נלהב וב- tf.function
, ללא צורך להסתמך על אוספים.
זה לא מכסה את כל הסמנטיקה הספציפית ל-TF1.x שעליה עשוי המודל שלך להסתמך קדימה. במקרים מסוימים, יתכן שה-shims לא מספיקים כדי להפעיל את הדגם קדימה ב-TF2 בעצמם. קרא את מדריך ההתנהגויות TF1.x לעומת TF2 כדי ללמוד עוד על ההבדלים ההתנהגותיים בין TF1.x ו-TF2.