Dzień Społeczności ML jest 9 listopada! Dołącz do nas na aktualizacje z TensorFlow Jax i więcej Dowiedz się więcej

Używaj modeli TF1.x w przepływach pracy TF2

Zobacz na TensorFlow.org Uruchom w Google Colab Zobacz na GitHub Pobierz notatnik

Ten przewodnik zawiera przegląd i przykłady podkładki kodu modelowanie , że można zatrudnić do korzystania z istniejących modeli TF1.x w TF2 przepływy pracy, takich jak chętny wykonania, tf.function i strategii dystrybucji z minimalnymi zmianami w kodzie modelowania.

Zakres użytkowania

Podkładka opisana w tym przewodniku jest przeznaczona dla modeli TF1.x, które opierają się na:

  1. tf.compat.v1.get_variable i tf.compat.v1.variable_scope do tworzenia zmiennej kontrola i ponownego wykorzystania, a
  2. Graph-kolekcja API oparte takich jak tf.compat.v1.global_variables() , tf.compat.v1.trainable_variables , tf.compat.v1.losses.get_regularization_losses() i tf.compat.v1.get_collection() , aby śledzić wag i ubytków regularyzacyjnych

Dotyczy to większości modeli zbudowanych na szczycie tf.compat.v1.layer , tf.contrib.layers API i TensorFlow-Slim .

Podkładka nie jest konieczne dla następujących modeli TF1.x:

  1. Jednostkowe modele Keras że już śledzić wszystkie ich wyszkolić wag i strat legalizacji poprzez model.trainable_weights i model.losses odpowiednio.
  2. tf.Module s, które już śledzić wszystkie ich wyszkolić ciężarów poprzez module.trainable_variables , a jedynie stworzyć ciężary, jeśli nie zostały już utworzone.

Modele te mogą pracować w TF2 z upragnieniem wykonania i tf.function s out-of-the-box.

Ustawiać

Importuj TensorFlow i inne zależności.

pip uninstall -y -q tensorflow
# Install tf-nightly as the model mapping shim is available only in
# TensorFlow 2.7
pip install -q tf-nightly
import tensorflow as tf
import tensorflow.compat.v1 as v1
import sys
import numpy as np

from unittest import mock
from contextlib import contextmanager

track_tf1_style_variables dekorator

Kluczem podkładka Opisane w tej instrukcji jest tf.compat.v1.keras.utils.track_tf1_style_variables , dekorator, które można wykorzystać w ciągu metod należących do tf.keras.layers.Layer i tf.Module śledzić ciężarów TF1.x stylu i wychwytywanie strat związanych z regularyzacją.

Dekorowanie tf.keras.layers.Layer „s lub tf.Module metod połączeń” sz tf.compat.v1.keras.utils.track_tf1_style_variables umożliwia tworzenie i ponownego wykorzystania zmiennej poprzez tf.compat.v1.get_variable (a co za tym idzie tf.compat.v1.layers ), aby działać poprawnie wewnątrz zdobione metodą aniżeli zawsze tworzenie nowej zmiennej na każdym połączeniu. Będzie on również powodować warstwę lub moduł niejawnie śledzić wszelkie ciężary utworzone lub dostępu poprzez get_variable wewnątrz zdobione metodą.

Oprócz śledzenia wagi się pod standardowym layer.variable / module.variable / etc. Właściwości, jeżeli sposób należy do tf.keras.layers.Layer , a wszelkie pozostałości regularyzacji określana za pośrednictwem get_variable lub tf.compat.v1.layers regularizer argumenty będą się śledzone przez warstwę na podstawie standardowych layer.losses własności.

Ten mechanizm umożliwia śledzenie przy użyciu dużych klas TF1.x stylu kodu modelu przód-pass wewnętrznej warstwy Keras lub tf.Module s w TF2 nawet z włączonym zachowania TF2.

Przykłady użycia

Poniższe przykłady użycia wykazać podkładek modelowania wykorzystywane do dekoracji tf.keras.layers.Layer metod, ale wyjątkiem sytuacji, gdy są one specjalnie interakcji z Keras wyposażony mają one zastosowanie przy projektowaniu tf.Module metod, jak również.

Warstwa zbudowana za pomocą tf.compat.v1.get_variable

Wyobraź sobie, że masz warstwę realizowane bezpośrednio na szczycie tf.compat.v1.get_variable następująco:

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

Użyj podkładki, aby przekształcić ją w warstwę i wywołać na wejściach.

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_8081/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([[ 1.7597902 , -0.12526923, -0.734049  ,  2.5817192 , -0.01271561,
        -0.25088227, -1.2578905 , -0.40534267, -0.7229135 ,  1.0163841 ],
       [-0.55586016,  0.42092317,  0.42841718,  0.5004029 , -1.0160432 ,
        -0.85993516, -0.42043334, -0.5913943 , -0.99035263, -0.57529175],
       [-0.43051845,  1.7361227 , -0.21349846, -0.43727797,  1.1395434 ,
        -0.9180088 ,  0.1007064 ,  0.187071  ,  1.2680445 , -2.4286427 ],
       [ 1.3920264 , -1.166398  ,  0.02597153,  0.6020498 ,  0.9661896 ,
         2.3711524 ,  0.60498756,  1.7055467 ,  0.9859872 , -1.2211678 ],
       [-0.99510145, -1.7450962 , -0.91934776,  0.21399808, -1.2053561 ,
        -1.3233564 , -0.31193715,  0.34772244,  0.17815316,  0.8217619 ],
       [-0.32171404, -1.314636  ,  1.4708065 ,  0.40499133, -1.0266875 ,
         0.19609049,  0.06033951,  1.5589962 , -0.1522339 , -0.20177484],
       [ 1.0114921 ,  0.27357772,  0.06933609,  0.81041557, -2.623424  ,
        -0.7116536 ,  0.5435144 , -0.27573258, -1.5256566 ,  1.6624123 ],
       [ 1.2698063 , -1.5160124 , -1.0788453 ,  1.8094345 , -0.13966891,
         0.06064254, -0.737417  , -0.00817302, -1.293212  ,  0.08209532]],
      dtype=float32)>

Uzyskaj dostęp do śledzonych zmiennych i przechwyconych strat regularyzacji jak do standardowej warstwy Keras.

layer.trainable_variables
layer.losses
2021-09-23 01:23:28.399131: 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.13249503>]

Aby zobaczyć, że wagi są ponownie używane za każdym razem, gdy wywołujesz warstwę, ustaw wszystkie wagi na zero i ponownie wywołaj warstwę.

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)>

Przekonwertowanej warstwy można użyć również bezpośrednio w konstrukcji modelu funkcjonalnego 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.12129142>]

Model zbudowany z tf.compat.v1.layers

Wyobraź sobie, że warstwa lub modelu realizowane bezpośrednio na szczycie tf.compat.v1.layers następująco:

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

Użyj podkładki, aby przekształcić ją w warstwę i wywołać na wejściach.

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)
/home/kbuilder/.local/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:563: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/home/kbuilder/.local/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:523: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/home/kbuilder/.local/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:255: 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([[-0.40776828,  2.3573866 ,  1.6894324 ,  0.22241476,  0.18800357,
         0.697348  , -1.3395607 ,  0.05975401,  0.39043084, -0.86733705],
       [ 0.83767503, -0.99410766, -1.4979119 , -1.8434849 , -0.10467762,
         2.2965403 ,  1.7911294 , -0.09771984, -1.5293416 , -0.11446023],
       [ 0.6498386 ,  1.3734608 , -0.31780475, -0.82371867,  0.5639928 ,
        -0.31449968, -0.02882274,  0.54086614,  0.01044557, -0.5772825 ],
       [-0.27125332, -0.23233527, -1.2216266 ,  1.3790796 ,  0.04667859,
        -1.7748597 ,  3.1854274 ,  0.5146454 ,  0.16350481,  0.9344469 ],
       [ 1.100132  ,  0.44006342,  0.91936946,  0.20134284,  0.09150642,
        -0.4153509 , -0.5515176 , -0.4722049 , -0.70342726, -0.3094808 ],
       [ 0.13144666,  0.6824104 ,  1.4116762 , -1.0161233 , -0.28532824,
         1.2188898 , -3.9369202 ,  1.2268828 , -1.0280368 , -2.517522  ],
       [-4.027055  , -1.0911764 , -0.3793312 , -0.92047167, -3.8340063 ,
        -0.9912698 ,  4.76791   , -1.041395  ,  1.012804  ,  3.040803  ],
       [ 2.1164694 ,  0.75651765,  0.7104589 , -0.6455864 ,  0.9304292 ,
        -0.6130173 ,  0.44713086, -0.04708579, -0.30096936,  1.8738902 ]],
      dtype=float32)>

Uzyskaj dostęp do śledzonych zmiennych i przechwycone straty regularyzacji, jak w przypadku standardowej warstwy Keras.

layer.trainable_variables
layer.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03748229>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.14483754>]

Aby zobaczyć, że wagi są ponownie używane za każdym razem, gdy wywołujesz warstwę, ustaw wszystkie wagi na zero i ponownie wywołaj warstwę.

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>]
/home/kbuilder/.local/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] == '':
/home/kbuilder/.local/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]
/home/kbuilder/.local/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)>

Przekonwertowanej warstwy można użyć również bezpośrednio w konstrukcji modelu funkcjonalnego 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)
/home/kbuilder/.local/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)
/home/kbuilder/.local/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]
/home/kbuilder/.local/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([[ 1.7254884 , -2.9545083 ,  0.36877984, -1.3624213 , -0.5710023 ,
        -0.49868777,  1.9663497 , -0.9770504 ,  0.85530245,  0.26259243],
       [ 0.77756464,  0.8888914 , -1.7472007 ,  0.21576326, -1.2464366 ,
         0.95418   , -0.54376763, -0.08816621,  1.1474992 , -2.2782483 ],
       [ 1.372475  , -0.20368464, -0.3307865 ,  0.7593809 ,  1.1833515 ,
        -0.5684725 ,  0.46004218, -0.9633938 ,  0.7036123 , -1.1437936 ],
       [-0.8412093 ,  0.90696293, -2.8927922 ,  0.5110863 , -0.0651812 ,
        -0.25058645, -2.5217125 , -3.0134842 ,  2.4276328 , -0.005849  ],
       [-0.6436453 , -2.4422355 ,  3.6500096 , -0.7153996 ,  1.015534  ,
         1.2260826 ,  0.70473236,  1.7375998 , -1.0351129 , -1.5901128 ],
       [-1.144584  ,  2.3042653 , -1.0492066 ,  0.7169852 , -0.02998945,
         0.9399648 , -0.29914314,  0.999437  ,  2.3420253 , -1.0753604 ],
       [-1.3222666 , -0.02447131, -2.0274506 ,  1.1783165 , -0.01704457,
         0.08102873, -0.06982261, -0.9558692 , -0.6824415 , -0.17403287],
       [ 1.5070809 ,  0.63156915, -0.6576477 , -0.69560015, -0.07243534,
         0.3713924 ,  0.7633158 ,  0.6799017 , -0.06758842, -0.22009295]],
      dtype=float32)>
# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.035233162>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.13585311>]

Przechwytywanie aktualizacje normalizacja partii i model training args

W TF1.x wykonujesz normalizację wsadową w następujący sposób:

  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])

Zwróć uwagę, że:

  1. Normalizacja partia średniej ruchomej aktualizacje są śledzone przez get_collection która została wywołana oddzielnie od warstwy
  2. tf.compat.v1.layers.batch_normalization wymaga training argument (ogólnie zwanego is_training przy użyciu TF cienki warstwy normalizacji partii)

W TF2, z powodu chętny wykonanie i zależnościami automatycznych kontroli, normalizacja partii średniej ruchomej aktualizacje będą realizowane od razu. Nie ma potrzeby oddzielnego zbierania ich z kolekcji aktualizacji i dodawania ich jako jawnych zależności kontrolnych.

Dodatkowo, jeśli dasz swoją tf.keras.layers.Layer naprzód metoda Pass „s do training argument Keras będzie mógł przekazać aktualną fazę treningu i żadnych zagnieżdżonych warstw do niego tak jak to robi dla każdej innej warstwie. Zobacz docs API dla tf.keras.Model uzyskać więcej informacji na temat Keras obsługuje training argument.

Jeśli zdobienia tf.Module metody, trzeba upewnić się, aby ręcznie przejść wszystkie training argumentów, ile potrzeba. Jednak aktualizacje średniej ruchomej normalizacji partii będą nadal stosowane automatycznie, bez konieczności jawnych zależności kontroli.

Poniższe fragmenty kodu wykazać jak umieścić warstw normalizacji partia w podkładki i jak go używać w modelu Keras prac (zastosowanie do 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})
/home/kbuilder/.local/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:455: 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.00013645, -0.00088516, -0.00016109, -0.00042606,  0.00032286],
      dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.9992796 , 0.9995561 , 1.002134  , 0.9999655 , 0.99899757],
      dtype=float32)>}

Ponowne wykorzystanie zmiennych o zmiennym zakresie

Wszelkie wytwory zmienne w piłkę z przodu oparte na get_variable będzie utrzymać te same zmienne nazewnictwa i ponowne semantykę że zmienne zakresy mają w TF1.x. To prawda, tak długo, jak masz co najmniej jeden niepusty zewnętrzną zakres wszelkich tf.compat.v1.layers o nazwach generowanych automatycznie, jak wspomniano powyżej.

Marzą wykonanie i tf.function

Jak widać powyżej, zdobione metody tf.keras.layers.Layer i tf.Module run wewnątrz chętny wykonania, a także są kompatybilne z tf.function . W ten sposób można korzystać z WPB i innych interaktywnych narzędzi do kroku za pośrednictwem podaniu jak to działa.

Strategie dystrybucji

Rozmowy do get_variable wnętrza @track_tf1_style_variables -decorated metody warstwa lub moduł używać standardowych tf.Variable projekty zmienne pod maską. Oznacza to, że można z nich korzystać z różnych strategii dystrybucji dostępnych z tf.distribute takich jak MirroredStrategy i TPUStrategy .

Gniazdowania tf.Variable s, tf.Module s, tf.keras.layers & tf.keras.models zdobione zaproszenia

Dekorowanie połączenie warstw w tf.compat.v1.keras.utils.track_tf1_style_variables doda automatycznego niejawny śledzenie zmiennych utworzonych (i ponownego wykorzystania) wyłącznie za pośrednictwem tf.compat.v1.get_variable . To nie będzie ciężary przechwytywania utworzony bezpośrednio przez tf.Variable połączeń, takich jak te używane przez typowych warstw Keras i najbardziej tf.Module s. Trzeba jeszcze wyraźnie śledzić je w taki sam sposób, jak dla każdej innej warstwy Keras lub tf.Module .

Jeśli musisz umieścić tf.Variable połączeń, warstw Keras / modeli lub tf.Module w twoich dekoratorów (albo dlatego, że są następujące przyrostowe migracji do Native TF2 opisane w dalszej części tego przewodnika, albo dlatego, że kod TF1.x częściowo składały modułów Keras):

  • Jawnie upewnij się, że zmienna/moduł/warstwa jest tworzona tylko raz
  • Jawnie dołączyć je jako instancja atrybuty tak samo jak podczas definiowania typowego modułu / warstwę
  • Jawne ponowne użycie już utworzonego obiektu w kolejnych wywołaniach

Gwarantuje to, że odważniki nie są tworzone nowe i są prawidłowo wykorzystywane. Dodatkowo zapewnia to również śledzenie istniejących wag i strat związanych z regularyzacją.

Oto przykład, jak to może wyglądać:

class WrappedDenseLayer(tf.keras.layers.Layer):

  def __init__(self, units, **kwargs):
    super().__init__(**kwargs)
    self.units = units
    self._dense_model = None

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    # Create the nested tf.variable/module/layer/model
    # only if it has not been created already
    if not self._dense_model:
      inp = tf.keras.Input(shape=inputs.shape)
      dense_layer = tf.keras.layers.Dense(
          self.units, name="dense",
          kernel_regularizer="l2")
      self._dense_model = tf.keras.Model(
          inputs=inp, outputs=dense_layer(inp))
    return self._dense_model(inputs)

layer = WrappedDenseLayer(10)

layer(tf.ones(shape=(5, 5)))
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[-1.311166  , -0.56161934,  0.06100595, -2.0354538 ,  0.43949485,
         0.79418707, -0.33393025, -0.23065254, -1.4712268 , -0.5599899 ],
       [-1.311166  , -0.56161934,  0.06100595, -2.0354538 ,  0.43949485,
         0.79418707, -0.33393025, -0.23065254, -1.4712268 , -0.5599899 ],
       [-1.311166  , -0.56161934,  0.06100595, -2.0354538 ,  0.43949485,
         0.79418707, -0.33393025, -0.23065254, -1.4712268 , -0.5599899 ],
       [-1.311166  , -0.56161934,  0.06100595, -2.0354538 ,  0.43949485,
         0.79418707, -0.33393025, -0.23065254, -1.4712268 , -0.5599899 ],
       [-1.311166  , -0.56161934,  0.06100595, -2.0354538 ,  0.43949485,
         0.79418707, -0.33393025, -0.23065254, -1.4712268 , -0.5599899 ]],
      dtype=float32)>

Wagi są prawidłowo śledzone:

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([[-0.4260246 ,  0.63220686, -0.25491676, -0.4732077 , -0.22389129,
          0.14093792,  0.23929453, -0.3063315 , -0.4763435 ,  0.17360973],
        [-0.3149459 , -0.56472075, -0.37183157, -0.43579376,  0.3173498 ,
          0.12601191, -0.40831637,  0.0440948 , -0.01100564, -0.57002085],
        [-0.6098382 , -0.30805996,  0.13013041, -0.50657886, -0.14245549,
          0.62366086,  0.5047323 ,  0.025406  , -0.32095137,  0.6075271 ],
        [ 0.36144507, -0.3933347 , -0.06775016, -0.34555444,  0.05576169,
          0.41973764, -0.15750635,  0.19361281, -0.3617522 , -0.2969904 ],
        [-0.32180244,  0.07228923,  0.625374  , -0.27431908,  0.43273014,
         -0.5161612 , -0.5121344 , -0.18743467, -0.30117404, -0.47411546]],
       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)>]

Podobnie jak utrata regularyzacji (jeśli występuje):

regularization_loss = tf.add_n(layer.losses)
regularization_loss
<tf.Tensor: shape=(), dtype=float32, numpy=0.0709362>

Wskazówki dotyczące nazw zmiennych

Jawne tf.Variable rozmowy i warstw Keras użyć innej nazwy / zmienna warstwa mechanizm nazwa autogeneration niż może być używany do z połączenia get_variable i variable_scopes . Choć podkładka sprawi, że nazwy zmiennych dopasować do zmiennych tworzonych przez get_variable nawet gdy dzieje z wykresami TF1.x do TF2 chętny wykonanie & tf.function , nie może zagwarantować takie same dla nazw zmiennych generowanych przez tf.Variable połączeń i warstw Keras że osadzasz w swoich dekoratorach metod. Możliwe jest nawet dla wielu zmiennych dzielić tę samą nazwę w TF2 chętny wykonania i tf.function .

Należy zachować szczególną ostrożność podczas wykonywania sekcji dotyczących sprawdzania poprawności i mapowania punktów kontrolnych TF1.x w dalszej części tego przewodnika.

Gniazdowania Warstwy / modułów mechanicznych @track_tf1_style_variables

Jeśli jesteś jedną warstwę gniazdowania, który używa @track_tf1_style_variables dekorator wnętrze inny, należy go traktować tak samo byś traktować każdą warstwę Keras lub tf.Module że nie skorzystaliśmy get_variable tworzyć swoje zmienne.

Na przykład,

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("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)))

# Recursively track weights and regularization losses
layer.trainable_weights
layer.losses
/home/kbuilder/.local/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.
/home/kbuilder/.local/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=(), dtype=float32, numpy=0.05660137>]

Zauważ, że variable_scope s zestaw w warstwie zewnętrznej może mieć wpływ na nazewnictwo zmiennych określonych w zagnieżdżonej warstwie, ale get_variable nie będzie udostępniać zmienne wg nazwy drugiej warstwy zewnętrznej podkładki na bazie i zagnieżdżonego warstwie podkładki oparte nawet jeśli mają taką samą nazwę , ponieważ warstwa zagnieżdżona i zewnętrzna wykorzystują różne wewnętrzne magazyny zmiennych.

Jak wspomniano wcześniej, jeśli używasz podkładkę dekorowany tf.Module nie ma losses nieruchomość do rekurencyjnie i automatycznie śledzić utratę uregulowania swojej zagnieżdżonego warstwie, i trzeba będzie go śledzić oddzielnie.

Korzystanie tf.compat.v1.make_template w zdobione metodą

Jest wysoce zalecane korzystać bezpośrednio tf.compat.v1.keras.utils.track_tf1_style_variables zamiast korzystania tf.compat.v1.make_template , ponieważ jest cieńsza warstwa na górze TF2.

Postępuj zgodnie z instrukcjami w tej sekcji uprzedniej kodu TF1.x który został już polegającego na tf.compat.v1.make_template .

Ponieważ tf.compat.v1.make_template owija kod, który używa get_variable The track_tf1_style_variables dekorator pozwala korzystać z tych szablonów w warstwie połączeń i skutecznie śledzić ciężary i straty legalizacji.

Jednakże, to upewnij się, aby zadzwonić make_template tylko raz, a następnie używać tego samego szablonu w każdym wywołaniu warstwy. W przeciwnym razie za każdym razem, gdy wywołasz warstwę, zostanie utworzony nowy szablon wraz z nowym zestawem zmiennych.

Na przykład,

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)

Przyrostowa migracja do Native TF2

Jak wspomniano wcześniej, track_tf1_style_variables pozwala mieszać TF2 stylu obiektowego tf.Variable / tf.keras.layers.Layer / tf.Module użycia ze starszymi tf.compat.v1.get_variable / tf.compat.v1.layers -Style zastosowanie wewnątrz tego samego dekorowanego modułu/warstwy.

Oznacza to, że po dokonaniu model TF1.x pełni kompatybilny TF2, można napisać wszystkie nowe elementy modelu z natywnym (nie tf.compat.v1 ) TF2 API i ich współdziałanie ze swoim starszym kodzie.

Jednakże, jeśli w dalszym ciągu zmieniać swoich starszych składników modelu, można również zdecydować się stopniowo przełączyć dziedzictwo stylu tf.compat.v1 wykorzystanie nad do czysto rodzimej obiektowe API, które są zalecane do nowo napisany kod TF2.

tf.compat.v1.get_variable użycie może być zastąpione albo self.add_weight połączeń jeśli zdobienia Keras / warstwa modelu, lub z tf.Variable nazywa jeśli zdobienia Keras obiektów lub tf.Module s.

Zarówno funkcjonalny styl i obiektowe tf.compat.v1.layers można generalnie zastąpione równoważnymi tf.keras.layers warstwy bez zmian wymaganych argumentów.

Można również rozważyć Kawałki części modelu lub wspólnych wzorców w poszczególnych warstwach / modułów w trakcie przeprowadzki do przyrostowego czysto-natywnych API, które same mogą wykorzystać track_tf1_style_variables .

Uwaga na temat Slim i contrib.layers

Duża ilość starszego kodu TF 1.x wykorzystuje Slim biblioteki, które zostało dostarczone wraz z TF 1.x jako tf.contrib.layers . Konwersja kodu przy użyciu Slim z natywnym TF 2 jest bardziej zaangażowany niż konwersja v1.layers . W rzeczywistości może to sens do konwersji kodu Slim do v1.layers pierwszy, a następnie przekonwertować do Keras. Poniżej znajdują się ogólne wskazówki dotyczące konwersji kodu Slim.

  • Upewnij się, że wszystkie argumenty są jawne. Usuń arg_scopes jeśli to możliwe. Jeśli trzeba jeszcze z nich korzystać, Split normalizer_fn i activation_fn do własnych warstw.
  • Oddzielne warstwy konw. są mapowane na jedną lub więcej różnych warstw Keras (warstwy wgłębne, punktowe i rozdzielne Keras).
  • Slim i v1.layers mają różne nazwy argumentów i wartości domyślnych.
  • Zauważ, że niektóre argumenty mają różne skale.

Migracja do Native TF2 z pominięciem zgodności punktów kontrolnych

Poniższy przykładowy kod demonstruje przyrostowe przenoszenie modelu do czysto natywnych interfejsów API bez uwzględniania zgodności punktu kontrolnego.

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

Następnie wymień compat.v1 API z ich rodzimych odpowiedników obiektowych w sposób odcinkowo. Zacznij od przełączenia warstwy splotu na obiekt Keras utworzony w konstruktorze warstwy.

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

Użyj narzędzia do testowania deterministycznego generowania liczb, aby sprawdzić, czy ta przyrostowa zmiana pozostawia model z takim samym zachowaniem jak poprzednio.

# import tensorflow.python.framework.random_seed as random_seed
seed_implementation = sys.modules[tf.compat.v1.get_seed.__module__]

class DeterministicTestTool(object):
  def __init__(self, seed: int = 42, mode='constant'):
    """Set mode to 'constant' or 'num_random_ops'. Defaults to 'constant'."""
    if mode not in {'constant', 'num_random_ops'}:
      raise ValueError("Mode arg must be 'constant' or 'num_random_ops'. " +
                       "Got: {}".format(mode))

    self._mode = mode
    self._seed = seed
    self.operation_seed = 0
    self._observed_seeds = set()

  def scope(self):
    tf.random.set_seed(self._seed)

    def _get_seed(_):
      """Wraps TF get_seed to make deterministic random generation easier.

      This makes a variable's initialization (and calls that involve random
      number generation) depend only on how many random number generations
      were used in the scope so far, rather than on how many unrelated
      operations the graph contains.

      Returns:
        Random seed tuple.
      """
      op_seed = self.operation_seed
      if self._mode == "constant":
        tf.random.set_seed(op_seed)
      else:
        if op_seed in self._observed_seeds:
          raise ValueError(
              'This `DeterministicTestTool` object is trying to re-use the ' +
              'already-used operation seed {}. '.format(op_seed) +
              'It cannot guarantee random numbers will match between eager ' +
              'and sessions when an operation seed is reused. ' +
              'You most likely set ' +
              '`operation_seed` explicitly but used a value that caused the ' +
              'naturally-incrementing operation seed sequences to overlap ' +
              'with an already-used seed.')

        self._observed_seeds.add(op_seed)
        self.operation_seed += 1

      return (self._seed, op_seed)

    # mock.patch internal symbols to modify the behavior of TF APIs relying on them

    return mock.patch.object(seed_implementation, 'get_seed', wraps=_get_seed)
random_tool = DeterministicTestTool(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)
/home/kbuilder/.local/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] == '':
/home/kbuilder/.local/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]
/home/kbuilder/.local/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:401: 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)
/home/kbuilder/.local/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 = DeterministicTestTool(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)
/home/kbuilder/.local/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.
  
/home/kbuilder/.local/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
/home/kbuilder/.local/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())

Masz teraz wymienić wszystkich poszczególnych compat.v1.layers z native warstw 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 = DeterministicTestTool(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())

Wreszcie usunąć zarówno wszelkie pozostałe (nie-już potrzebne) variable_scope Wykorzystanie i track_tf1_style_variables dekorator się.

Masz teraz wersję modelu, która wykorzystuje całkowicie natywne interfejsy 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 = DeterministicTestTool(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())

Utrzymanie zgodności punktów kontrolnych podczas migracji do Native TF2

Powyższy proces migracji do natywnych interfejsów API TF2 zmienił zarówno nazwy zmiennych (ponieważ interfejsy API Keras generują bardzo różne nazwy wag), jak i ścieżki zorientowane obiektowo, które wskazują różne wagi w modelu. Wpływ tych zmian polega na tym, że zniszczą zarówno istniejące punkty kontrolne oparte na nazwach w stylu TF1, jak i punkty kontrolne zorientowane obiektowo w stylu TF2.

Jednak w niektórych przypadkach, może być w stanie wziąć swoje nazwisko na bazie oryginalnego punktu kontrolnego i znaleźć odwzorowanie zmiennych do nowych nazw z podejść jak ten szczegółowo w Ponowne TF1.x punktów kontrolnych przewodnika .

Oto kilka wskazówek, jak to zrobić:

  • Zmienne nadal wszyscy mają name argumentu można ustawić.
  • Modele Keras wziąć również name argumentu za którą ustawiony jako przedrostek dla swoich zmiennych.
  • v1.name_scope funkcja może być używany do ustawiania zmiennych przedrostki nazw. Jest to bardzo różni się od tf.variable_scope . Wpływa tylko na nazwy i nie śledzi zmiennych ani ponownego użycia.

Mając na uwadze powyższe wskaźniki, poniższe przykłady kodu demonstrują przepływ pracy, który można dostosować do kodu, aby przyrostowo aktualizować część modelu, jednocześnie aktualizując punkty kontrolne.

  1. Rozpocznij przełączając funkcjonalnym stylu tf.compat.v1.layers ich wersjach obiektowych.
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]
/home/kbuilder/.local/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.
  
/home/kbuilder/.local/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()
/home/kbuilder/.local/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. Następnie przypisać obiekty compat.v1.layer i wszelkie zmienne utworzone przez compat.v1.get_variable jako właściwości tf.keras.layers.Layer / tf.Module obiektu, którego metoda jest ozdobiony track_tf1_style_variables (zauważ, że każdy obiektowego TF2 punkty kontrolne stylu będą teraz zapisywać zarówno ścieżkę według nazwy zmiennej, jak i nową ścieżkę zorientowaną obiektowo).
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]
/home/kbuilder/.local/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. Ponownie zapisz załadowany punkt kontrolny w tym momencie, aby zapisać ścieżki zarówno przez nazwę zmiennej (dla compat.v1.layers), jak i przez obiektowy graf obiektowy.
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. Teraz możesz zamienić się z obiektowych compat.v1.layers dla rodzimych warstw Keras a jednocześnie jest w stanie załadować ostatnio zapisanego punktu kontrolnego. Upewnij się, że zachowanie nazwy zmiennych dla pozostałych compat.v1.layers przez nadal nagrywania automatycznie wygenerowane variable_scopes zastąpionego warstwach. Te przełączane warstwy/zmienne będą teraz używać tylko ścieżki atrybutu obiektu do zmiennych w punkcie kontrolnym zamiast ścieżki nazwy zmiennej.

Ogólnie rzecz biorąc, można zastąpić użycie compat.v1.get_variable w zmiennych przyłączonych do właściwości poprzez:

  • Włączanie ich do korzystania tf.Variable , OR
  • Aktualizacja je za pomocą tf.keras.layers.Layer.add_weight . Należy pamiętać, że jeśli nie wszystkie warstwy przełączania w jednym iść to może się zmienić automatycznie wygenerowane warstwy / zmienna nazewnictwa dla pozostałych compat.v1.layers że brakuje name argumentu. Jeśli tak jest, należy zachować nazwy zmiennych dla pozostałych compat.v1.layers samo przez otwieranie i zamykanie ręcznie variable_scope odpowiadający usuniętej compat.v1.layer „s generowanej nazwy zakresu. W przeciwnym razie ścieżki z istniejących punktów kontrolnych mogą kolidować i ładowanie punktów kontrolnych będzie zachowywać się niepoprawnie.
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]
/home/kbuilder/.local/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']

Zapisywanie kontrolny się na tym etapie po skonstruowaniu zmiennych pozwoli zawierać tylko aktualnie dostępnych ścieżek obiektu.

Upewnij się rejestrować zakresów usuniętych compat.v1.layers zachować nazwy generowane automatycznie waga dla pozostałych 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. Powtórz powyższe kroki, dopóki nie zastępuje wszystkie compat.v1.layers i compat.v1.get_variable S w modelu z pełni rodzimych odpowiedników.
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']

Pamiętaj, aby przetestować, aby upewnić się, że nowo zaktualizowany punkt kontrolny nadal zachowuje się zgodnie z oczekiwaniami. Zastosuj techniki opisane w validate liczbowej przewodnika dokładność na każdym kroku przyrostowego tego procesu w celu zapewnienia zmigrowanych uruchamia kod poprawnie.

Obsługa zmian zachowania TF1.x do TF2 nieobjętych podkładkami modelującymi

Podkładki modelowania opisane w tej instrukcji może upewnić się, że zmienne, warstwy, i straty powstałe z regularyzacji get_variable , tf.compat.v1.layers i variable_scope semantyki nadal działać jak poprzednio przy użyciu chętny wykonanie i tf.function , bez konieczności polegać na kolekcjach.

To nie obejmuje wszystkich TF1.x specyficzne semantykę że model przechodzi do przodu może być powołując się na. W niektórych przypadkach podkładki mogą być niewystarczające do samodzielnego uruchomienia modelu w TF2. Przeczytać TF1.x vs TF2 zachowań kierować , aby dowiedzieć się więcej na temat różnic między TF1.x behawioralnych i TF2.