Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

Utilice modelos TF1.x en flujos de trabajo TF2

Ver en TensorFlow.org Ejecutar en Google Colab Ver en GitHub Descargar cuaderno

Esta guía proporciona una visión general y ejemplos de un calzo código de modelado que se puede emplear para utilizar sus modelos TF1.x existentes en TF2 flujos de trabajo, tales como la ejecución ansiosos, tf.function , y las estrategias de distribución con cambios mínimos en su código de modelado.

Alcance de uso

La calza descrita en esta guía está diseñada para los modelos TF1.x que se basan en:

  1. tf.compat.v1.get_variable y tf.compat.v1.variable_scope a la creación de variable de control y reutilización, y
  2. API basados Gráfico de recolección tales como tf.compat.v1.global_variables() , tf.compat.v1.trainable_variables , tf.compat.v1.losses.get_regularization_losses() , y tf.compat.v1.get_collection() para realizar un seguimiento de ponderaciones y pérdidas de regularización

Esto incluye la mayoría de los modelos construidos en la parte superior de tf.compat.v1.layer , tf.contrib.layers API y TensorFlow-Slim .

La cuña no es necesaria para los siguientes modelos TF1.x:

  1. Stand-solos modelos Keras que ya el seguimiento de todos sus pesos entrenables y pérdidas de regularización a través de model.trainable_weights y model.losses respectivamente.
  2. tf.Module s que ya realizar un seguimiento de todos sus pesos entrenables través module.trainable_variables , y sólo crean pesos si es que ya no se han creado.

Estos modelos son propensos a trabajar en TF2 con la ejecución ansiosos y tf.function s fuera de la caja.

Configuración

Importa TensorFlow y otras dependencias.

pip uninstall -y tensorflow_estimator tensorflow keras
pip install -U tf-nightly
# Note that the model mapping shim is available only in TF 2.7.
import tensorflow as tf
import tensorflow.compat.v1 as v1
import sys
import numpy as np

from unittest import mock
from contextlib import contextmanager

El track_tf1_style_variables decorador

La cuña clave descrito en este manual es tf.compat.v1.keras.utils.track_tf1_style_variables , un decorador que se puede utilizar dentro de los métodos pertenecientes a tf.keras.layers.Layer y tf.Module realizar el seguimiento de los pesos de estilo TF1.x y capturar pérdidas de regularización.

Decoración de un tf.keras.layers.Layer 'o s tf.Module métodos de llamadas' s con tf.compat.v1.keras.utils.track_tf1_style_variables permite la creación de variables y la reutilización a través de tf.compat.v1.get_variable (y, por extensión, tf.compat.v1.layers ) para trabajar correctamente en el interior del método de decoración en lugar de crear siempre una nueva variable en cada llamada. También hará que la capa o el módulo para el seguimiento de cualquier implícitamente pesos creados o se accede a través get_variable dentro del método decorado.

Además del seguimiento de los pesos a sí mismos bajo la norma layer.variable / module.variable / etc. propiedades, si el método pertenece a una tf.keras.layers.Layer , entonces cualquier pérdida de regularización especificados a través de la get_variable o tf.compat.v1.layers regularizador argumentos conseguirán rastreado por la capa bajo la norma layer.losses propiedad.

Este mecanismo de seguimiento permite el uso de grandes clases de estilo TF1.x código de paso modelo directo en el interior de las capas Keras o tf.Module s en TF2, incluso con comportamientos TF2 habilitadas.

Ejemplos de uso

Los ejemplos de uso de a continuación demuestran las cuñas de modelado utilizados para decorar tf.keras.layers.Layer métodos, pero salvo que interactúan específicamente con Keras características que son aplicables cuando la decoración de tf.Module métodos también.

Capa construida con tf.compat.v1.get_variable

Imagine que tiene una capa aplicado directamente sobre la parte superior de tf.compat.v1.get_variable de la siguiente manera:

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

Use la calza para convertirlo en una capa y llamarlo en las entradas.

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_11242/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([[ 2.1375508 , -1.7944846 ,  0.565429  ,  2.217993  ,  1.0197983 ,
         1.1995478 ,  0.76082695,  1.2525213 , -1.1448774 , -1.5099244 ],
       [-1.8368615 ,  0.929764  , -0.68088764, -3.7934241 , -0.873991  ,
         1.1868672 ,  1.5348943 , -2.8576217 , -1.8646189 , -1.4464494 ],
       [ 1.4563093 ,  1.9133099 ,  0.2668215 , -0.47504902,  1.3939316 ,
        -2.4648583 ,  0.67149144,  0.8774765 ,  1.9594793 , -0.9630938 ],
       [ 0.63517594,  1.2447351 ,  0.57714343, -1.8551574 ,  1.2194395 ,
        -1.3226352 , -1.534353  , -1.571831  , -1.3915701 , -0.4385677 ],
       [-1.1224217 , -1.8950897 ,  1.9080337 ,  1.5483713 ,  0.3007682 ,
        -0.11733571,  1.4215202 ,  1.0951209 , -0.40666753,  1.3011668 ],
       [-1.6115788 , -0.36258316,  0.279747  , -3.3505366 ,  0.9046302 ,
        -0.0449394 , -0.25892067, -3.1661186 , -1.825649  ,  0.34308952],
       [ 0.57928437, -0.41061705, -0.18791246,  0.43806618, -1.1424513 ,
        -0.8472259 , -0.18853194,  1.1114476 , -1.1165383 , -2.1490216 ],
       [-1.425385  , -0.64927876, -0.28559908, -0.95958436, -0.5622783 ,
        -0.223617  , -1.5422437 ,  1.429243  ,  0.19077098, -0.97339046]],
      dtype=float32)>

Acceda a las variables rastreadas y las pérdidas de regularización capturadas como una capa estándar de Keras.

layer.trainable_variables
layer.losses
2021-11-23 02:29:53.768499: 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.15060465>]

Para ver que los pesos se reutilizan cada vez que llama a la capa, establezca todos los pesos en cero y vuelva a llamar a la capa.

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

También puede utilizar la capa convertida directamente en la construcción del modelo funcional de 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.12031876>]

Modelo construido con tf.compat.v1.layers

Imagine que tiene una capa o modelo implementado directamente encima de tf.compat.v1.layers de la siguiente manera:

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

Use la calza para convertirlo en una capa y llamarlo en las entradas.

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([[ 0.37805164,  1.8133228 ,  0.86462975, -1.4787364 ,  0.02895362,
         0.8421986 ,  0.15317512,  1.1292509 , -0.2179926 ,  1.4042507 ],
       [-1.0554819 , -0.14058013, -1.3772738 ,  2.1067414 , -0.887224  ,
         0.20268968,  0.05371363,  2.3933268 ,  0.47980696,  0.07456923],
       [-0.05067754,  0.04003759, -1.1708652 ,  0.50643575,  0.43419954,
         0.49038708,  1.4956386 ,  0.52199614, -0.98080426,  0.22641146],
       [-1.4830599 ,  1.5334661 , -0.24063748, -1.5365379 , -1.323379  ,
         2.311288  ,  0.50101113,  1.661559  , -0.24971324, -0.42585582],
       [ 0.31571257, -0.5366141 , -0.38673356,  1.3282443 , -1.3107554 ,
         0.63491017, -0.9445646 ,  0.44513133,  0.8641659 ,  0.4294421 ],
       [ 0.30027592,  0.188151  ,  0.39278126,  0.9219465 ,  1.8363616 ,
        -0.18119514,  0.17797446, -0.2636444 , -1.6716032 , -1.0964239 ],
       [-0.557606  , -2.302523  , -0.82658786, -0.6043796 ,  0.4406705 ,
         0.25789356,  2.9949172 , -0.76322764,  1.8916178 , -2.500245  ],
       [-0.8927715 , -1.5578954 , -0.05657649, -1.8374336 , -0.8938144 ,
         0.8692418 , -1.4616051 ,  0.9205449 ,  2.6908588 , -2.20056   ]],
      dtype=float32)>

Acceda a las variables rastreadas y las pérdidas de regularización capturadas como una capa estándar de Keras.

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

Para ver que los pesos se reutilizan cada vez que llama a la capa, establezca todos los pesos en cero y vuelva a llamar a la capa.

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

También puede utilizar la capa convertida directamente en la construcción del modelo funcional de 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([[ 1.4855937e+00, -2.7656064e+00,  1.3545771e+00,  1.8412153e+00,
         2.6830747e+00,  1.5520985e+00,  1.6604857e+00, -1.5574534e+00,
         4.8879254e-01, -9.3593240e-01],
       [-3.5260645e-01, -8.5253775e-01,  2.9307604e-03,  2.5392106e+00,
        -1.0028646e+00, -1.3632554e+00,  1.3462807e+00, -9.8628730e-01,
         8.0417931e-01, -5.2788424e-01],
       [-1.1495411e+00,  3.4236248e+00,  1.4656919e+00,  8.5768580e-01,
         1.3331357e+00, -8.4157258e-01,  9.8651722e-02,  1.0235069e+00,
         1.2864964e+00,  1.7336640e-01],
       [ 1.3583817e+00, -1.2720991e+00,  2.7617774e+00, -1.6359773e+00,
        -9.3302876e-03,  2.1517355e+00,  1.4786386e-01, -2.2064322e-01,
        -7.9553246e-01,  1.3321551e+00],
       [-6.7520809e-01, -2.7840310e-01, -5.4193705e-01,  8.4345484e-01,
         4.9731803e-01, -6.1475182e-01,  1.9032955e+00, -1.2340800e+00,
        -1.0945371e-01, -1.4558470e-01],
       [-1.4447448e+00, -2.1551886e+00, -1.6724775e+00,  2.7837777e+00,
         7.7755189e-01, -4.4531783e-01,  2.2827234e+00, -1.1688620e-02,
         3.0173159e-01, -2.1856803e-01],
       [ 1.3978167e+00, -7.4688423e-01,  3.1681514e-01, -1.1488553e+00,
        -2.5831108e+00,  1.5824573e-01, -1.3887520e+00,  8.8456994e-01,
         6.5672320e-01, -5.1850575e-01],
       [-2.9664264e+00, -6.5011466e-01, -1.6712356e+00, -7.9054677e-01,
        -4.6599650e+00, -2.5024600e+00,  1.4304999e+00,  2.7220290e+00,
         7.2737026e-01,  5.9418190e-01]], dtype=float32)>
# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.042700935>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.13701487>]

Actualizaciones por lotes de normalización de captura y modelo training args

En TF1.x, realiza una normalización por lotes como esta:

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

Tenga en cuenta que:

  1. La normalización lote mover actualizaciones promedio son rastreados por get_collection que fue llamada por separado de la capa de
  2. tf.compat.v1.layers.batch_normalization requiere una training argumento (generalmente llamada is_training cuando se utilizan capas de lotes de normalización TF-Slim)

En TF2, debido a la ejecución ansiosos y dependencias de control automático, la normalización de lotes en movimiento actualizaciones promedio será ejecutado de inmediato. No es necesario recopilarlos por separado de la colección de actualizaciones y agregarlos como dependencias de control explícitas.

Además, si usted da su tf.keras.layers.Layer método de pase hacia adelante 's una training argumento, Keras será capaz de pasar a la fase de entrenamiento actual y las capas anidadas para que al igual que lo hace con cualquier otra capa. Consulte la documentación de la API para tf.keras.Model para obtener más información sobre cómo Keras se encarga de la training argumento.

Si usted está adornando tf.Module métodos, es necesario asegurarse de que pasar manualmente todas training argumentos, según sea necesario. Sin embargo, las actualizaciones de promedio móvil de normalización por lotes se seguirán aplicando automáticamente sin necesidad de dependencias de control explícitas.

Los siguientes fragmentos de código muestran cómo capas lote de normalización embed de la cuña y cómo se utiliza en un modelo funciona Keras (aplicables a 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([ 1.1385456e-03, -2.3051118e-04, -2.1241283e-05,  1.3993075e-03,
       -4.8623187e-04], dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.9989541, 0.9992638, 0.9984195, 0.9991469, 1.000844 ],
      dtype=float32)>}

Reutilización de variables basadas en alcance variable

Cualquier creaciones variables en el pase hacia adelante sobre la base de get_variable mantendrán los mismos nombres y reutilización semántica variables que tienen en ámbitos de variable TF1.x. Esto es cierto siempre y cuando tenga al menos un ámbito exterior no vacía para cualquier tf.compat.v1.layers con nombres generados automáticamente, como se mencionó anteriormente.

Ejecución y ansiosos tf.function

Como se ha visto anteriormente, los métodos para decorada tf.keras.layers.Layer y tf.Module carrera dentro de la ejecución ansiosos y también son compatibles con tf.function . Esto significa que puede utilizar el AP y otras herramientas interactivas para el paso a través de su pase hacia adelante, ya que se está ejecutando.

Estrategias de distribución

Las llamadas a get_variable interior de @track_tf1_style_variables métodos de capa o módulo -decorated uso estándar tf.Variable creaciones variables bajo el capó. Esto significa que los puede utilizar con las distintas estrategias de distribución disponibles con tf.distribute como MirroredStrategy y TPUStrategy .

Anidación tf.Variable s, tf.Module s, tf.keras.layers y tf.keras.models en llamadas decoradas

La decoración de su llamada capa de tf.compat.v1.keras.utils.track_tf1_style_variables sólo se sumará seguimiento implícita automática de variables creadas (y reutilizados) a través de tf.compat.v1.get_variable . No va a pesos de captura directamente creado por tf.Variable llamadas, tales como los utilizados por capas típicas Keras y más tf.Module s. Esta sección describe cómo manejar estos casos anidados.

(Usos preexistentes) tf.keras.layers y tf.keras.models

Para usos de capas y modelos Keras anidados, el uso pre-existente tf.compat.v1.keras.utils.get_or_create_layer . Esto solo se recomienda para facilitar la migración de usos de Keras anidados TF1.x existentes; el nuevo código debe usar una configuración de atributo explícita como se describe a continuación para tf.Variables y tf.Modules.

Para utilizar tf.compat.v1.keras.utils.get_or_create_layer , envolver el código que construye su modelo anidado en un método, y pasarlo en el método. Ejemplo:

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

Este método garantiza que estas capas anidadas se reutilicen y rastreen correctamente mediante tensorflow. Tenga en cuenta que el @track_tf1_style_variables decorador todavía se requiere en el método apropiado. El método de generador de modelos pasado a get_or_create_layer (en este caso, self.build_model ), no debe tomar argumentos.

Se realiza un seguimiento de los pesos:

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

Y pérdida de regularización también:

tf.add_n(layer.losses)
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([0.5], dtype=float32)>

Incrementales de migración: tf.Variables y tf.Modules

Si necesita integrar tf.Variable llamadas o tf.Module s en sus métodos decoradas (por ejemplo, si usted está siguiendo la migración gradual a las API de TF2 no heredados se describe más adelante en esta guía), todavía se necesita para realizar un seguimiento de forma explícita estos, con los siguientes requisitos:

  • Asegúrese explícitamente de que la variable / módulo / capa solo se cree una vez
  • Explícitamente adjuntar como atributos de instancia del mismo modo que cuando se define un módulo o capa típica
  • Reutilice explícitamente el objeto ya creado en llamadas de seguimiento

Esto garantiza que no se creen nuevos pesos en cada llamada y que se reutilicen correctamente. Además, esto también asegura que se rastreen los pesos existentes y las pérdidas de regularización.

Aquí hay un ejemplo de cómo podría verse esto:

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.87398976,  1.2405497 ,  0.6845182 ,  0.4866921 , -0.6569822 ,
         1.0673944 , -1.3701987 ,  0.4779834 , -0.18968081,  1.5541892 ],
       [ 0.87398976,  1.2405497 ,  0.6845182 ,  0.4866921 , -0.6569822 ,
         1.0673944 , -1.3701987 ,  0.4779834 , -0.18968081,  1.5541892 ],
       [ 0.87398976,  1.2405497 ,  0.6845182 ,  0.4866921 , -0.6569822 ,
         1.0673944 , -1.3701987 ,  0.4779834 , -0.18968081,  1.5541892 ],
       [ 0.87398976,  1.2405497 ,  0.6845182 ,  0.4866921 , -0.6569822 ,
         1.0673944 , -1.3701987 ,  0.4779834 , -0.18968081,  1.5541892 ],
       [ 0.87398976,  1.2405497 ,  0.6845182 ,  0.4866921 , -0.6569822 ,
         1.0673944 , -1.3701987 ,  0.4779834 , -0.18968081,  1.5541892 ]],
      dtype=float32)>

Tenga en cuenta que se necesita que el seguimiento explícito del módulo de anidado a pesar de que está decorado con la track_tf1_style_variables decorador. Esto se debe a que cada módulo / capa con métodos decorados tiene su propio almacén de variables asociado.

Los pesos se controlan correctamente:

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.7106493 ,  0.03652234, -0.5641838 ,  0.44038984,  0.26725787,
         -0.8249933 ,  0.79204524, -0.38647223, -0.68761927, -0.10278723],
        [-0.19713117, -0.61713815,  0.00494798, -0.8592477 ,  0.03517161,
         -0.41172737,  0.34112948,  0.08910135,  0.5520702 , -0.7381817 ],
        [ 0.07412005, -0.29660687, -0.23315382,  0.5994434 ,  0.40819865,
          0.35701373,  0.14988966, -0.3089575 , -0.11347155, -0.2857559 ],
        [ 0.13573293,  0.11401974, -0.24189845,  0.26831126, -0.13960141,
          0.03242165,  0.2838935 ,  0.53873944,  0.5168897 ,  0.36707175]],
       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.865285  , -0.5579717 , -0.22214234],
        [ 0.10053962, -0.10505754,  0.49894482],
        [ 0.16439968,  0.08750641,  0.35952443],
        [-0.6860548 , -0.76112765,  0.38850957],
        [ 0.19568652,  0.5770381 , -0.505653  ]], 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.47451308, -0.29268932, -0.31780362,  0.679634  ],
        [-0.7615033 , -0.7985905 , -0.54569066,  0.2096864 ],
        [-0.37253472, -0.70463765,  0.22033823, -0.7091312 ],
        [ 0.45600712, -0.34825963,  0.08295816, -0.01225257],
        [ 0.28514922,  0.5162982 , -0.33372337, -0.14636421]],
       dtype=float32)>]

Además de la pérdida de regularización:

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

Tenga en cuenta que si el NestedLayer eran un no-Keras tf.Module lugar, las variables serían todavía ser rastreados pero las pérdidas de regularización no serían rastreados de forma automática, por lo que tendría que realizar un seguimiento de forma explícita por separado.

Orientación sobre nombres de variables

Explícitas tf.Variable llamadas y capas Keras utilizan un mecanismo diferente nombre autogeneración nombre de la capa / variables de lo que usted puede ser utilizado a partir de la combinación de get_variable y variable_scopes . Aunque la cuña hará que sus nombres de las variables se ajustan para las variables creadas por get_variable incluso cuando se pasa de gráficos TF1.x a TF2 ejecución ansiosos y tf.function , no se puede garantizar el mismo para los nombres de las variables generadas por tf.Variable llamadas y capas que Keras incrustar dentro de los decoradores de su método. Incluso es posible que los múltiples variables que comparten el mismo nombre en TF2 ejecución ansiosos y tf.function .

Debe tener especial cuidado con esto cuando siga las secciones sobre validación de corrección y mapeo de puntos de control TF1.x más adelante en esta guía.

Usando tf.compat.v1.make_template en el método de decoración

Es muy recomendable que utilice directamente tf.compat.v1.keras.utils.track_tf1_style_variables en lugar de utilizar tf.compat.v1.make_template , ya que es una capa delgada en la parte superior de TF2.

Siga las instrucciones de esta sección para el código TF1.x antes de que ya contaba con tf.compat.v1.make_template .

Debido tf.compat.v1.make_template envuelve el código que utiliza get_variable , la track_tf1_style_variables decorador le permite utilizar estas plantillas en las llamadas capas y con éxito un seguimiento de los pesos y las pérdidas de regularización.

Sin embargo, asegúrese de llamar make_template sola vez y luego volver a utilizar la misma plantilla en cada llamada capa. De lo contrario, se creará una nueva plantilla cada vez que llame a la capa junto con un nuevo conjunto de variables.

Por ejemplo,

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)

Migración incremental a Native TF2

Como se mencionó anteriormente, track_tf1_style_variables le permite mezclar orientado a objetos de estilo TF2 tf.Variable / tf.keras.layers.Layer / tf.Module uso con el legado tf.compat.v1.get_variable / tf.compat.v1.layers al estilo uso dentro del mismo módulo / capa decorada.

Esto significa que después de haber hecho totalmente compatible TF2-TF1.x su modelo, se puede escribir todos los nuevos componentes del modelo con nativo (no tf.compat.v1 ) TF2 API y tienen que interoperar con su código más viejos.

Sin embargo, si continúa a modificar los componentes del modelo de mayor edad, también puede optar por cambiar su estilo de forma incremental legado tf.compat.v1 uso a las API orientado a objetos puramente nativos que se recomiendan para TF2 código recién escrito.

tf.compat.v1.get_variable uso se puede sustituir por self.add_weight llamadas si está decorando una capa / modelo Keras, o con tf.Variable llamadas si va a decorar objetos Keras o tf.Module s.

Tanto de estilo funcional y orientado a objetos tf.compat.v1.layers generalmente pueden ser reemplazados con el equivalente tf.keras.layers capa sin cambios argumento necesario.

También puede considerar trozos partes de su modelo o modelos comunes en capas / módulos individuales durante su desplazamiento incremental a las API puramente nativos, que pueden a su vez utilizar track_tf1_style_variables .

Una nota sobre Slim y contrib.layers

Una gran cantidad de código mayores TF 1.x utiliza el delgado de la biblioteca, que fue empaquetado con 1.x TF como tf.contrib.layers . La conversión de código usando Delgado a TF 2 nativa es más complicado que la conversión v1.layers . De hecho, puede tener sentido para convertir su código Delgado a v1.layers en primer lugar, a continuación, convertir a Keras. A continuación se muestran algunas pautas generales para convertir código Slim.

  • Asegúrese de que todos los argumentos sean explícitos. Retire arg_scopes si es posible. Si aún necesita a ellos, utilice dividida normalizer_fn y activation_fn en sus propias capas.
  • Las capas de conv separables se asignan a una o más capas de Keras diferentes (capas de Keras en profundidad, puntuales y separables).
  • Slim y v1.layers tienen diferentes nombres de argumentos y valores por defecto.
  • Tenga en cuenta que algunos argumentos tienen diferentes escalas.

Migración a Native TF2 ignorando la compatibilidad del punto de control

El siguiente ejemplo de código demuestra un movimiento incremental de un modelo a API puramente nativas sin considerar la compatibilidad de puntos de control.

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

A continuación, reemplazar los compat.v1 API por sus equivalentes nativos orientados a objetos de una manera a trozos. Comience cambiando la capa de convolución a un objeto Keras creado en el constructor de capas.

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

Utilice la herramienta de prueba de generación de números deterministas para verificar que este cambio incremental deja el modelo con el mismo comportamiento que antes.

# 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)
/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 = 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)
/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())

Ahora ha reemplazado todos los individuales compat.v1.layers con capas Keras nativos.

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

Finalmente, eliminar tanto cualquier restante (que ya no necesaria) variable_scope uso y los track_tf1_style_variables decorador sí mismo.

Ahora te queda una versión del modelo que utiliza API completamente nativas.

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

Mantener la compatibilidad del punto de control durante la migración a Native TF2

El proceso de migración anterior a las API TF2 nativas cambió tanto los nombres de las variables (ya que las API de Keras producen nombres de peso muy diferentes) como las rutas orientadas a objetos que apuntan a diferentes pesos en el modelo. El impacto de estos cambios es que habrán roto tanto los puntos de control basados ​​en nombres de estilo TF1 existentes como los puntos de control orientados a objetos de estilo TF2.

Sin embargo, en algunos casos, es posible que pueda tomar su puesto de control basada en el nombre original y encontrar un mapeo de las variables a sus nuevos nombres con los enfoques como el que se detalla en la guía de los puestos de control Reutilización TF1.x .

Algunos consejos para hacer esto factible son los siguientes:

  • Las variables siguen todos tienen un name argumento se puede establecer.
  • Modelos Keras también toman un name argumento como el que establecen como prefijo para sus variables.
  • El v1.name_scope función puede ser utilizada para establecer los prefijos de nombre de variable. Esto es muy diferente de tf.variable_scope . Solo afecta a los nombres y no realiza un seguimiento de las variables ni la reutilización.

Con los indicadores anteriores en mente, los siguientes ejemplos de código demuestran un flujo de trabajo que puede adaptar a su código para actualizar gradualmente parte de un modelo y al mismo tiempo actualizar los puntos de control.

  1. Comience por conmutación de estilo funcional tf.compat.v1.layers a sus versiones orientados a objetos.
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. A continuación, asignar los objetos compat.v1.layer y cualesquiera variables creadas por compat.v1.get_variable como propiedades del tf.keras.layers.Layer / tf.Module objeto cuyo método está decorado con track_tf1_style_variables (nota que cualquier TF2 orientado a objetos los puntos de control de estilo ahora guardarán tanto una ruta por nombre de variable como la nueva ruta orientada a objetos).
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. Vuelva a guardar un punto de control cargado en este punto para guardar rutas tanto por el nombre de la variable (para compat.v1.layers) como por el gráfico de objetos orientado a objetos.
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. Ahora puede intercambiar los orientados a objetos compat.v1.layers para las capas Keras nativas sin dejar de ser capaz de cargar el punto de control guardado recientemente. Asegúrese de conservar los nombres de variables para los restantes compat.v1.layers por la grabación de fotografías de los generados automáticamente variable_scopes de las capas reemplazados. Estas capas / variables cambiadas ahora solo usarán la ruta del atributo del objeto a las variables en el punto de control en lugar de la ruta del nombre de la variable.

En general, se puede reemplazar el uso de compat.v1.get_variable en las variables unidas a las propiedades de:

  • Conmutación a usar tf.Variable , OR
  • Su actualización mediante el uso de tf.keras.layers.Layer.add_weight . Tenga en cuenta que si no está cambiando todas las capas de una sola vez esto puede cambiar de capa / variable de nombres generada automáticamente para el resto de compat.v1.layers cuales les falta un name argumento. Si ese es el caso, usted debe tener los nombres de las variables para permanecer compat.v1.layers la misma mediante la apertura manual y el cierre de una variable_scope correspondiente al eliminado compat.v1.layer 'S generada a nombre de ámbito. De lo contrario, las rutas desde los puntos de control existentes pueden entrar en conflicto y la carga del punto de control se comportará incorrectamente.
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']

Guardar un puesto de control a cabo en este paso después de la construcción de las variables hará que sea sólo contienen las trayectorias de objetos disponibles en la actualidad.

Asegúrese de grabar los alcances de las retiradas compat.v1.layers para preservar los nombres de peso generados automáticamente para el resto de 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. Repita los pasos anteriores hasta que haya sustituido a todos los compat.v1.layers y compat.v1.get_variable s en su modelo con los equivalentes completamente nativas.
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']

Recuerde realizar una prueba para asegurarse de que el punto de control recién actualizado aún se comporte como espera. Aplicar las técnicas descritas en la validación guía corrección numérica a cada paso gradual de este proceso para asegurar que sus carreras de código migrados correctamente.

Manejo de cambios de comportamiento de TF1.xa TF2 no cubiertos por las calzas de modelado

Las cuñas de modelado descritos en esta guía pueden asegurarse de que las variables, las capas y las pérdidas de regularización creados con get_variable , tf.compat.v1.layers y variable_scope semántica siguen funcionando como antes cuando se utiliza la ejecución ansiosos y tf.function , sin tener que confiar en las colecciones.

Esto no cubre todos semántica TF1.x específicos que su modelo pasa hacia adelante puede depender. En algunos casos, las calzas pueden ser insuficientes para que su modelo se ejecute en TF2 por sí solo. Lea la TF1.x vs TF2 comportamientos de guía para aprender más acerca de las diferencias de comportamiento entre TF1.x y TF2.