השתמש במודלים של TF1.x בזרימות עבודה של TF2

הצג באתר TensorFlow.org הפעל בגוגל קולאב הצג ב-GitHub הורד מחברת

מדריך זה מספק סקירה כללית ודוגמאות של תבנית קוד מידול שתוכל להשתמש במודלים הקיימים של TF1.x בזרימות עבודה של TF2 כגון ביצוע נלהב, tf.function ואסטרטגיות הפצה עם שינויים מינימליים בקוד המידול שלך.

היקף השימוש

ה-shim המתואר במדריך זה מיועד לדגמי TF1.x המסתמכים על:

  1. tf.compat.v1.get_variable ו- tf.compat.v1.variable_scope כדי לשלוט ביצירת משתנים ושימוש חוזר, וכן
  2. ממשקי 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 הבאים:

  1. דגמי Keras עצמאיים שכבר עוקבים אחר כל המשקולות הניתנות לאימון והפסדי הרגולציה באמצעות model.trainable_weights ו- model.losses בהתאמה.
  2. 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])

ציין זאת:

  1. עדכוני הממוצע הנע של אצווה עוקבים על ידי get_collection שנקרא בנפרד מהשכבה
  2. 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 . זה משפיע רק על שמות, ואינו עוקב אחר משתנים ושימוש חוזר.

מתוך מחשבה על המצביעים שלעיל, דוגמאות הקוד הבאות מדגימות זרימת עבודה שתוכל להתאים לקוד שלך כדי לעדכן בהדרגה חלק מהמודל ובו זמנית לעדכן נקודות ביקורת.

  1. התחל על ידי החלפת 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']
  1. לאחר מכן, הקצה את האובייקטים 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']
  1. שמור מחדש נקודת ביקורת נטענת בנקודה זו כדי לחסוך נתיבים הן לפי שם המשתנה (עבור 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
  1. כעת אתה יכול להחליף את השכבות 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
  1. חזור על השלבים שלעיל עד שתחליף את כל 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.