Ajuda a proteger a Grande Barreira de Corais com TensorFlow em Kaggle Junte Desafio

Use modelos TF1.x em fluxos de trabalho TF2

Ver no TensorFlow.org Executar no Google Colab Ver no GitHub Baixar caderno

Este guia fornece uma visão geral e exemplos de um calço código de modelagem que você pode empregar para usar seus modelos TF1.x existentes no TF2 fluxos de trabalho, tais como a execução ansioso, tf.function e estratégias de distribuição com mudanças mínimas para o seu código de modelagem.

Escopo de uso

O calço descrito neste guia é projetado para modelos TF1.x que dependem de:

  1. tf.compat.v1.get_variable e tf.compat.v1.variable_scope à criação e reutilização variável de controle, e
  2. APIs baseadas gráfico de recolha, tais como tf.compat.v1.global_variables() , tf.compat.v1.trainable_variables , tf.compat.v1.losses.get_regularization_losses() , e tf.compat.v1.get_collection() para manter o controle de pesos e perdas de regularização

Isto inclui a maioria dos modelos construídos em cima de tf.compat.v1.layer , tf.contrib.layers APIs e TensorFlow-Slim .

O calço não é necessário para os seguintes modelos TF1.x:

  1. Stand-alone modelos Keras que já rastreiam todos os seus pesos treináveis e perdas de regularização via model.trainable_weights e model.losses respectivamente.
  2. tf.Module s que já rastrear todos os seus pesos treináveis via module.trainable_variables e criar apenas pesos se eles já não foram criados.

Estes modelos são susceptíveis de trabalho em TF2 com a execução ansioso e tf.function s out-of-the-box.

Configurar

Importe TensorFlow e outras dependências.

pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is available only in
# Tensorflow 2.8

pip install -q tf-nightly
import tensorflow as tf
import tensorflow.compat.v1 as v1
import sys
import numpy as np

from contextlib import contextmanager

O track_tf1_style_variables decorador

O calço chave descrito neste guia é tf.compat.v1.keras.utils.track_tf1_style_variables , um decorador que você pode usar dentro de métodos que pertencem a tf.keras.layers.Layer e tf.Module para rastrear pesos TF1.x de estilo e capturar perdas de regularização.

Decorar um tf.keras.layers.Layer 's ou tf.Module métodos de chamada' s com tf.compat.v1.keras.utils.track_tf1_style_variables permite a criação variável e reutilização via tf.compat.v1.get_variable (e, por extensão tf.compat.v1.layers ) para funcionar corretamente dentro do método decorado ao invés de sempre criar uma nova variável em cada chamada. É também fará com que a camada ou módulo para implicitamente rastrear quaisquer pesos criados ou acedidos através get_variable dentro do método decorado.

Além de rastrear-se os pesos de acordo com a norma layer.variable / module.variable / etc. Propriedades, se o método pertence a uma tf.keras.layers.Layer , em seguida, quaisquer perdas de regularização especificados através da get_variable ou tf.compat.v1.layers regularizer argumentos vai ter rastreado pela camada de acordo com a norma layer.losses propriedade.

Este mecanismo de rastreamento permite a utilização de grandes classes de TF1.x de estilo de código-pass modelo para a frente dentro de camadas Keras ou tf.Module s em TF2 mesmo com comportamentos TF2 habilitado.

Exemplos de uso

Os exemplos de utilização abaixo demonstram os calços de modelização utilizadas para decorar tf.keras.layers.Layer métodos, mas, salvo se forem especificamente interagir com Keras características que são aplicáveis ao decorar tf.Module métodos bem.

Camada construída com tf.compat.v1.get_variable

Imagine que você tem uma camada implementado diretamente em cima de tf.compat.v1.get_variable da seguinte forma:

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 o shim para transformá-lo em uma camada e chamá-lo nas 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_27038/795621215.py:7: The name tf.keras.utils.track_tf1_style_variables is deprecated. Please use tf.compat.v1.keras.utils.track_tf1_style_variables instead.
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[-0.51018804, -0.58145535,  0.25050664, -0.09880018,  0.71741414,
        -0.08512568,  0.33404148,  0.50894034,  0.19362557,  0.03945067],
       [-0.66160053,  0.43442816, -0.6187523 ,  0.00753711,  1.3946855 ,
         0.22528797,  0.55661404, -1.6155301 ,  1.5854199 , -0.4165327 ],
       [ 0.15855707,  0.43848652,  0.04762229,  0.22020248,  0.88300526,
         0.31525093, -0.10912375,  0.03332198,  1.3462385 , -0.37986106],
       [ 0.02546233, -0.01084138,  0.0417656 ,  1.1082407 ,  0.926408  ,
         0.46938205,  1.0183189 ,  1.2039868 , -0.09619217, -0.50863194],
       [-1.6222394 ,  0.17156005, -0.07482994,  0.646423  ,  1.0284312 ,
         2.3619173 ,  0.6322627 ,  0.5350776 , -2.2700598 , -0.8211552 ],
       [-1.1044651 ,  0.7303245 ,  1.0183476 ,  1.2858934 ,  0.4575533 ,
         0.93400717,  0.5323913 , -0.01242167,  0.8308919 ,  0.03202473],
       [ 0.3880633 , -1.2345276 ,  0.7713047 , -0.33720714,  1.0418141 ,
        -1.055242  , -1.6942265 ,  1.705035  ,  0.8671215 ,  0.8162696 ],
       [ 0.02216246, -0.5235669 ,  0.01065174, -1.1682817 ,  0.44079733,
         0.25890222, -1.0779501 ,  0.37716752, -0.27636313, -0.6359312 ]],
      dtype=float32)>

Acesse as variáveis ​​rastreadas e as perdas de regularização capturadas como uma camada Keras padrão.

layer.trainable_variables
layer.losses
2021-12-04 02:24:42.941890: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
[<tf.Tensor: shape=(), dtype=float32, numpy=0.10789324>]

Para ver se os pesos são reutilizados cada vez que você chama a camada, defina todos os pesos como zero e chame a camada novamente.

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

Você também pode usar a camada convertida diretamente na construção do modelo funcional Keras.

inputs = tf.keras.Input(shape=(20))
outputs = DenseLayer(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 20))
model(x)

# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.1345337>]

Modelo construído com tf.compat.v1.layers

Imagine que você tem uma camada ou modelo implementado diretamente em cima de tf.compat.v1.layers da seguinte forma:

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 o shim para transformá-lo em uma camada e chamá-lo nas 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([[ 2.4439096 , -0.2912227 ,  1.5531251 ,  1.284059  ,  0.10077369,
        -0.4231838 ,  1.0458903 , -0.01530766,  0.07358164, -0.6108157 ],
       [-0.4576063 ,  0.34942552,  2.3044965 ,  1.1483003 , -1.2211238 ,
         0.5634397 ,  0.73821646, -0.07581732,  0.5747937 , -0.66470885],
       [-2.2948585 , -2.709268  ,  1.7494816 , -0.9808065 , -2.9099958 ,
         0.5067346 , -1.011502  ,  2.559535  , -3.0888772 ,  0.3522656 ],
       [ 1.7788265 ,  0.8846102 ,  0.45562026,  0.01498583, -0.12482446,
        -0.32868862, -0.7743829 ,  2.3106992 , -0.0997327 , -0.7715093 ],
       [ 0.40295708,  0.04771695, -0.21336336, -0.13069987,  2.279875  ,
         2.7284563 ,  0.6444641 , -1.1919906 ,  0.96321577,  1.0182515 ],
       [ 0.47900966,  0.04906505,  1.1335449 ,  0.2907704 ,  0.7732022 ,
         0.68217   ,  0.51932573, -0.45156685,  2.081223  ,  1.068861  ],
       [ 0.10084352,  1.6456002 ,  0.63820475,  1.5959243 ,  0.22463399,
         0.07713126,  0.7467398 , -1.5435244 ,  1.2494736 , -0.07683721],
       [ 2.1396816 ,  1.5613532 , -1.1726325 , -0.88917583,  1.6447946 ,
        -1.0071977 , -1.8496083 ,  1.1887017 ,  2.1971662 ,  2.1175954 ]],
      dtype=float32)>

Acesse as variáveis ​​rastreadas e as perdas de regularização capturadas como uma camada Keras padrão.

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

Para ver se os pesos são reutilizados cada vez que você chama a camada, defina todos os pesos como zero e chame a camada novamente.

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

Você também pode usar a camada convertida diretamente na construção do modelo funcional Keras.

inputs = tf.keras.Input(shape=(5, 5, 5))
outputs = CompatV1LayerModel(10)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

x = tf.random.normal(shape=(8, 5, 5, 5))
model(x)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/base.py:573: UserWarning: `layer.updates` will be removed in a future version. This property should not be used in TensorFlow 2.0, as `updates` are applied automatically.
  _add_elements_to_collection(self.updates, tf.compat.v1.GraphKeys.UPDATE_OPS)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()
<tf.Tensor: shape=(8, 10), dtype=float32, numpy=
array([[ 0.19487001,  0.54727787,  1.1044168 , -0.6613899 , -0.26437742,
        -1.1580509 , -0.24707682,  0.97752655,  0.59436107,  0.13125825],
       [ 0.48974586, -1.3510125 ,  0.7186962 , -0.8996632 , -0.60448873,
         0.06332532,  0.31494308,  0.23021704, -1.9166642 ,  0.3890404 ],
       [-0.06499191, -0.21485235,  0.01158494,  1.4407377 , -0.0488929 ,
        -0.37594396, -0.4386894 , -0.08751169,  1.0905663 , -1.5450519 ],
       [-2.2749739 , -2.4603422 , -1.3834419 , -2.8800466 ,  0.8954872 ,
        -3.0429187 , -0.7885461 ,  1.6037437 , -3.1845028 , -1.0725503 ],
       [ 0.98735195, -0.45159122,  0.892656  ,  0.477053  ,  0.31193537,
        -0.44723228, -0.01815075, -0.47465172, -1.665448  , -2.105824  ],
       [-2.5408387 , -1.7552321 , -1.924145  , -0.6395873 ,  0.4081779 ,
        -0.48731515, -3.2637763 , -1.4409767 , -2.032539  ,  0.10204412],
       [ 2.1583526 ,  0.78955674, -0.07266375,  0.06652926,  2.1300716 ,
        -1.6256162 ,  0.56154627, -0.76179224,  2.2985756 , -1.5504618 ],
       [ 2.062847  ,  0.971378  , -1.0830508 ,  1.8224751 , -0.3542943 ,
         0.74113446, -0.6204865 ,  1.4503044 , -0.4979878 , -0.4383126 ]],
      dtype=float32)>
# Access the model variables and regularization losses
model.weights
model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=0.03079858>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.12991619>]

Captura de atualizações de normalização lote e modelo training args

No TF1.x, você executa a normalização em lote 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])

Observe que:

  1. A normalização lote movendo atualizações médias são rastreados pelo get_collection que foi chamado separadamente da camada
  2. tf.compat.v1.layers.batch_normalization exige uma training argumento (geralmente chamado de is_training ao usar TF-Magro camadas de normalização lote)

Em TF2, devido à execução ansioso e dependências de controle automático, a normalização lote movendo atualizações média será executada imediatamente. Não há necessidade de coletá-los separadamente da coleção de atualizações e adicioná-los como dependências de controle explícitas.

Além disso, se você dá o seu tf.keras.layers.Layer método de passe para frente de um training argumento, Keras vai ser capaz de passar a fase de treinamento atual e quaisquer camadas aninhadas a ela, assim como ele faz para qualquer outra camada. Consulte a documentação da API para tf.keras.Model para mais informações sobre como Keras lida com a training argumento.

Se você está decorando tf.Module métodos, você precisa ter certeza de passar manualmente todos training argumentos conforme necessário. No entanto, as atualizações da média móvel da normalização em lote ainda serão aplicadas automaticamente, sem a necessidade de dependências de controle explícitas.

Os seguintes fragmentos de código demonstram como camadas de normalização em lotes em incorporar o calço e como utilizar num modelo Keras obras (aplicáveis 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([-0.00177554, -0.00036542, -0.00099426, -0.00112544,  0.0008541 ],
      dtype=float32)>, 'batch_norm_layer/batch_normalization/moving_variance:0': <tf.Tensor: shape=(5,), dtype=float32, numpy=
array([1.0005339, 1.0003369, 0.9976748, 1.0001523, 1.0009514],
      dtype=float32)>}

Reutilização de variável baseada em escopo variável

Quaisquer criações variáveis no passe para frente com base em get_variable vai manter as mesmas variáveis de nomeação e reutilização semântica que escopos de variável tem em TF1.x. Isto é verdade, desde que você tem pelo menos um escopo externo não vazio por quaisquer tf.compat.v1.layers com nomes gerados automaticamente, como mencionado acima.

Execução ansioso & tf.function

Como visto acima, métodos para decorado tf.keras.layers.Layer e tf.Module executado dentro da execução ansioso e também são compatíveis com tf.function . Isto significa que você pode usar APO e outras ferramentas interativas para percorrer o seu passe para frente como ele está sendo executado.

Estratégias de distribuição

Chamadas para get_variable dentro de @track_tf1_style_variables camada ou módulo métodos -decorated usar padrão tf.Variable criações variáveis sob o capô. Isto significa que você pode usá-los com as diversas estratégias de distribuição disponíveis com tf.distribute como MirroredStrategy e TPUStrategy .

Nidificação tf.Variable s, tf.Module s, tf.keras.layers & tf.keras.models em chamadas decorados

Decorar a sua chamada camada na tf.compat.v1.keras.utils.track_tf1_style_variables só irá adicionar rastreamento implícita automática de variáveis criadas (e reutilizados) via tf.compat.v1.get_variable . Não vai pesos captura diretamente criado por tf.Variable chamadas, tais como aqueles usados por camadas típicas Keras e mais tf.Module s. Esta seção descreve como lidar com esses casos aninhados.

(Usos pré-existente) tf.keras.layers e tf.keras.models

Para usos de camadas e modelos Keras aninhadas, o uso pré-existente tf.compat.v1.keras.utils.get_or_create_layer . Isso é recomendado apenas para facilitar a migração de usos Keras aninhados TF1.x existentes; o novo código deve usar a configuração de atributo explícita, conforme descrito abaixo para tf.Variables e tf.Modules.

Para usar tf.compat.v1.keras.utils.get_or_create_layer , envolva o código que constrói o seu modelo aninhado em um método, e passá-lo para o método. Exemplo:

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 garante que essas camadas aninhadas sejam corretamente reutilizadas e rastreadas pelo tensorflow. Note-se que o @track_tf1_style_variables decorador ainda é necessário no método apropriado. O método Model Builder passou para get_or_create_layer (neste caso, self.build_model ), deve tomar sem argumentos.

Pesos são rastreados:

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

E perda de regularização também:

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

De migração: tf.Variables e tf.Modules

Se você precisa incorporar tf.Variable chamadas ou tf.Module s em seus métodos decorados (por exemplo, se você está seguindo a migração incremental para APIs TF2 não legados descrito posteriormente neste guia), você ainda precisa controlar explicitamente estes, com os seguintes requisitos:

  • Certifique-se explicitamente de que a variável / módulo / camada é criada apenas uma vez
  • Explicitamente anexá-los como atributos exemplo tal como faria ao definir um módulo típico ou camada
  • Reutilize explicitamente o objeto já criado em chamadas subsequentes

Isso garante que os pesos não sejam criados a cada chamada e sejam reutilizados corretamente. Além disso, isso também garante que os pesos existentes e as perdas de regularização sejam rastreados.

Aqui está um exemplo de como isso poderia ser:

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

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

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def __call__(self, inputs):
    out = inputs
    with tf.compat.v1.variable_scope("inner_dense"):
      # The weights are created with a `regularizer`,
      # so the layer should track their regularization losses
      kernel = tf.compat.v1.get_variable(
          shape=[out.shape[-1], self.units],
          regularizer=tf.keras.regularizers.L2(),
          initializer=tf.compat.v1.initializers.glorot_normal,
          name="kernel")
      bias = tf.compat.v1.get_variable(
          shape=[self.units,],
          initializer=tf.compat.v1.initializers.zeros,
          name="bias")
      out = tf.linalg.matmul(out, kernel)
      out = tf.compat.v1.nn.bias_add(out, bias)
    return out

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

  def __init__(self, units, **kwargs):
    super().__init__(**kwargs)
    self.units = units
    # Only create the nested tf.variable/module/layer/model
    # once, and then reuse it each time!
    self._dense_layer = NestedLayer(self.units)

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('outer'):
      outputs = tf.compat.v1.layers.dense(inputs, 3)
      outputs = tf.compat.v1.layers.dense(inputs, 4)
      return self._dense_layer(outputs)

layer = WrappedDenseLayer(10)

layer(tf.ones(shape=(5, 5)))
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:38: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:39: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
<tf.Tensor: shape=(5, 10), dtype=float32, numpy=
array([[-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731],
       [-0.4987283 ,  0.06630042, -0.09875254,  0.20954818,  0.03599668,
         0.3980474 ,  0.11181635,  0.6891558 , -0.33903462,  0.15674731]],
      dtype=float32)>

Observe que o rastreamento explícita do módulo aninhada é necessário ainda que é decorado com o track_tf1_style_variables decorador. Isso ocorre porque cada módulo / camada com métodos decorados tem seu próprio armazenamento de variável associado a ele.

Os pesos são rastreados corretamente:

assert len(layer.weights) == 6
weights = {x.name: x for x in layer.variables}

assert set(weights.keys()) == {"outer/inner_dense/bias:0",
                               "outer/inner_dense/kernel:0",
                               "outer/dense/bias:0",
                               "outer/dense/kernel:0",
                               "outer/dense_1/bias:0",
                               "outer/dense_1/kernel:0"}

layer.trainable_weights
[<tf.Variable 'outer/inner_dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/inner_dense/kernel:0' shape=(4, 10) dtype=float32, numpy=
 array([[-0.20786692,  0.14702448, -0.2577947 ,  0.1885891 ,  0.28935957,
          0.02086618, -0.20579144, -0.7509229 , -0.23490003,  0.00370591],
        [ 0.09247629, -0.37428686, -0.6002815 , -0.2702465 ,  0.20350575,
          0.34964404, -0.32633537,  0.50722903, -0.0419833 , -0.61815673],
        [ 0.24821116,  0.15504731, -0.12409697, -0.2506969 ,  0.22316858,
         -0.44847375, -0.08295754, -0.8262154 ,  0.7674222 , -0.40613693],
        [-0.7447006 ,  0.2992331 , -0.45639235,  0.0669547 ,  0.39443025,
          0.3182467 ,  0.10884362,  0.5395837 ,  0.32210502, -0.30076835]],
       dtype=float32)>,
 <tf.Variable 'outer/dense/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense/kernel:0' shape=(5, 3) dtype=float32, numpy=
 array([[ 0.6283595 , -0.80413634, -0.5471641 ],
        [ 0.25296038, -0.7657203 ,  0.5884425 ],
        [-0.7180575 , -0.29509914,  0.44014376],
        [ 0.81024987,  0.39888996,  0.80002993],
        [-0.32921118, -0.7010279 ,  0.820375  ]], dtype=float32)>,
 <tf.Variable 'outer/dense_1/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>,
 <tf.Variable 'outer/dense_1/kernel:0' shape=(5, 4) dtype=float32, numpy=
 array([[ 0.7941524 , -0.58552563,  0.46828055, -0.44095916],
        [-0.16019303,  0.27973688, -0.60373306, -0.20117629],
        [ 0.6345844 ,  0.30732214,  0.18921828,  0.37930095],
        [-0.50815696, -0.2471816 , -0.10282421,  0.21441567],
        [-0.71987414,  0.18304104, -0.5701992 ,  0.4926386 ]],
       dtype=float32)>]

Bem como perda de regularização:

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

Note-se que se o NestedLayer foram um não-Keras tf.Module vez, as variáveis ainda seria rastreado mas as perdas de regularização não seria automaticamente rastreadas, então você teria que acompanhá-los explicitamente separadamente.

Orientação sobre nomes de variáveis

Explícitas tf.Variable chamadas camadas e utilizar um Keras / mecanismo nome autogeneration variável diferente nome da camada que pode ser utilizado para a partir da combinação de get_variable e variable_scopes . Embora o calço fará com que seus nomes de variáveis corresponder para as variáveis criadas por get_variable mesmo quando indo de gráficos TF1.x para TF2 execução ansioso & tf.function , não podemos garantir o mesmo para os nomes de variáveis geradas para tf.Variable chamadas e camadas Keras que você incorpora em seus decoradores de método. É mesmo possível para múltiplas variáveis para compartilhar o mesmo nome em execução ansioso TF2 e tf.function .

Você deve ter cuidado especial com isso ao seguir as seções sobre validação de correção e mapeamento de pontos de verificação TF1.x posteriormente neste guia.

Usando tf.compat.v1.make_template no método decorado

É altamente recomendável que você usar diretamente tf.compat.v1.keras.utils.track_tf1_style_variables em vez de usar tf.compat.v1.make_template , pois é uma camada mais fina no topo do TF2.

Siga as orientações nesta seção para código de TF1.x antes que já estava contando com tf.compat.v1.make_template .

Porque tf.compat.v1.make_template envolve o código que usa get_variable , o track_tf1_style_variables decorador permite que você use esses modelos em chamadas camadas e com sucesso controlar os pesos e as perdas de regularização.

No entanto, não se esqueça de chamada make_template apenas uma vez e, em seguida, reutilizar o mesmo modelo em cada chamada camada. Caso contrário, um novo modelo será criado cada vez que você chamar a camada junto com um novo conjunto de variáveis.

Por exemplo,

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)

Migração incremental para TF2 nativo

Como mencionado anteriormente, track_tf1_style_variables permite misturar TF2 de estilo orientado a objetos tf.Variable / tf.keras.layers.Layer / tf.Module uso com o legado tf.compat.v1.get_variable / tf.compat.v1.layers de estilo uso dentro do mesmo módulo / camada decorado.

Isto significa que depois de ter feito o seu modelo TF1.x totalmente TF2-compatível, você pode escrever todos os novos componentes do modelo com (não nativa tf.compat.v1 ) TF2 APIs e tê-los interagir com o seu código antigo.

No entanto, se você continuar a modificar seus componentes modelo mais antigo, você pode também optar por incrementalmente mudar o seu estilo legado tf.compat.v1 uso sobre as APIs orientadas a objetos puramente nativos que são recomendados para o código TF2 recém-escrito.

tf.compat.v1.get_variable uso pode ser substituído por self.add_weight chamadas se você está decorando uma camada / modelo Keras ou com tf.Variable chamadas se você está decorando Keras objetos ou tf.Module s.

Ambos-estilo funcional e orientada para objectos tf.compat.v1.layers pode, geralmente, ser substituídas com o equivalentes tf.keras.layers camada com nenhuma alteração argumento necessário.

Você também pode considerar pedaços partes do seu modelo ou padrões comuns em camadas / módulos individuais durante seu movimento incremental para APIs puramente nativos, o que pode-se usar track_tf1_style_variables .

Uma observação sobre Slim e contrib.layers

Uma grande quantidade de mais velho código TF 1.x usa o Magro biblioteca, que foi embalada com TF 1.x como tf.contrib.layers . Convertendo código usando Slim TF nativo 2 é mais envolvido do que converter v1.layers . Na verdade, pode fazer sentido para converter seu código Slim v1.layers primeiro, em seguida, converter para Keras. Abaixo estão algumas orientações gerais para a conversão de código Slim.

  • Certifique-se de que todos os argumentos são explícitos. Remover arg_scopes se possível. Se você ainda precisa usá-los, dividir normalizer_fn e activation_fn em suas próprias camadas.
  • Camadas conv separáveis ​​são mapeadas para uma ou mais camadas Keras diferentes (camadas Keras profundas, pontuais e separáveis).
  • Slim e v1.layers ter diferentes nomes de argumentos e valores padrão.
  • Observe que alguns argumentos têm escalas diferentes.

Migração para TF2 nativo ignorando a compatibilidade do ponto de verificação

O exemplo de código a seguir demonstra uma movimentação incremental de um modelo para APIs puramente nativas sem considerar a compatibilidade do ponto de verificação.

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

Em seguida, substituir os compat.v1 APIs com os seus equivalentes orientada para objectos nativas de uma forma descontínua. Comece mudando a camada de convolução para um objeto Keras criado no construtor de camada.

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

Use o v1.keras.utils.DeterministicRandomTestTool classe para verificar que isso deixa de mudanças incrementais o modelo com o mesmo comportamento de antes.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = CompatModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  original_output = layer(inputs)

  # Grab the regularization loss as well
  original_regularization_loss = tf.math.add_n(layer.losses)

print(original_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:12: UserWarning: `tf.layers.conv2d` is deprecated and will be removed in a future version. Please Use `tf.keras.layers.Conv2D` instead.
  if sys.path[0] == '':
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:13: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  del sys.path[0]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:413: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs, training=training)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:17: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = PartiallyMigratedModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dropout` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dropout` instead.
  from ipykernel import kernelapp as app
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:18: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Você já substituiu todos os individuais compat.v1.layers com camadas nativas Keras.

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

  def __init__(self, units, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.units = units
    self.conv_layer = tf.keras.layers.Conv2D(
      3, 3,
      kernel_regularizer="l2")
    self.flatten_layer = tf.keras.layers.Flatten()
    self.dense_layer = tf.keras.layers.Dense(
      self.units,
      kernel_regularizer="l2")

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    with tf.compat.v1.variable_scope('model'):
      out = self.conv_layer(inputs)
      out = self.flatten_layer(out)
      out = self.dense_layer(out)
      return out
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = NearlyFullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Finalmente, tanto remover qualquer (que não são mais necessários) restante variable_scope uso e os track_tf1_style_variables decorador si.

Agora você fica com uma versão do modelo que usa APIs totalmente 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 = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  layer = FullyNativeModel(10)

  inputs = tf.random.normal(shape=(10, 5, 5, 5))
  migrated_output = layer(inputs)

  # Grab the regularization loss as well
  migrated_regularization_loss = tf.math.add_n(layer.losses)

print(migrated_regularization_loss)
tf.Tensor(0.17953834, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
np.testing.assert_allclose(original_regularization_loss.numpy(), migrated_regularization_loss.numpy())
np.testing.assert_allclose(original_output.numpy(), migrated_output.numpy())

Manter a compatibilidade do ponto de verificação durante a migração para o TF2 nativo

O processo de migração acima para APIs TF2 nativas mudou tanto os nomes de variáveis ​​(como Keras APIs produzem nomes de pesos muito diferentes) e os caminhos orientados a objetos que apontam para pesos diferentes no modelo. O impacto dessas mudanças é que elas terão quebrado tanto os pontos de verificação baseados em nomes no estilo TF1 existentes quanto os pontos de verificação orientados a objetos no estilo TF2.

No entanto, em alguns casos, você pode ser capaz de tomar o seu posto de controle baseados em nome original e encontrar um mapeamento das variáveis para seus novos nomes com abordagens como o detalhado no guia checkpoints Reutilizando TF1.x .

Algumas dicas para tornar isso viável são as seguintes:

  • Variáveis ainda têm um name argumento que você pode definir.
  • Modelos Keras também ter um name argumento como o que eles definido como o prefixo para as suas variáveis.
  • O v1.name_scope função pode ser usada para definir prefixos nome da variável. Isto é muito diferente de tf.variable_scope . Afeta apenas nomes e não rastreia variáveis ​​e reutiliza.

Com as dicas acima em mente, os exemplos de código a seguir demonstram um fluxo de trabalho que você pode adaptar ao seu código para atualizar de forma incremental parte de um modelo enquanto atualiza simultaneamente os pontos de verificação.

  1. Comece mudando de estilo funcional tf.compat.v1.layers para suas versões orientadas 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. Em seguida, atribuir os objectos compat.v1.layer e quaisquer variáveis criadas por compat.v1.get_variable como propriedades do tf.keras.layers.Layer / tf.Module objecto cujo método é decorada com track_tf1_style_variables (nota que qualquer TF2 orientada a objectos os pontos de verificação de estilo agora salvarão um caminho por nome de variável e o novo caminho orientado a objeto).
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. Salve novamente um ponto de verificação carregado neste ponto para salvar os caminhos pelo nome da variável (para compat.v1.layers) ou pelo gráfico de objeto 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. Agora você pode trocar as orientadas a objetos compat.v1.layers para camadas nativas Keras enquanto ainda está sendo capaz de carregar o ponto de verificação recém-salvos. Certifique-se de preservar os nomes de variáveis para os restantes compat.v1.layers por ainda gravar as geradas automaticamente variable_scopes das camadas substituídos. Essas camadas / variáveis ​​trocadas agora usarão apenas o caminho do atributo do objeto para as variáveis ​​no ponto de verificação, em vez do caminho do nome da variável.

Em geral, você pode substituir o uso de compat.v1.get_variable em variáveis ligadas a propriedades por:

  • Trocando-os a usar tf.Variable , OR
  • Atualizá-los usando tf.keras.layers.Layer.add_weight . Note que se você não está trocando todas as camadas de uma só vez isso pode mudar camada de nomenclatura auto-gerado / variável para os restantes compat.v1.layers que estão faltando um name argumento. Se for esse o caso, você deve manter os nomes das variáveis para o restante compat.v1.layers o mesmo por abertura manualmente e fechar uma variable_scope correspondente à removido compat.v1.layer é gerado nome do escopo. Caso contrário, os caminhos dos pontos de verificação existentes podem entrar em conflito e o carregamento do ponto de verificação se comportará incorretamente.
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']

Salvando um posto de controle fora neste passo após a construção das variáveis tornará conter apenas os caminhos de objetos atualmente disponíveis.

Certifique-se de gravar os âmbitos das removidos compat.v1.layers para preservar os nomes de peso gerados automaticamente para os restantes 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 os passos acima até que você tenha substituído todos os compat.v1.layers e compat.v1.get_variable s no seu modelo com equivalentes totalmente 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']

Lembre-se de testar para garantir que o ponto de verificação recém-atualizado ainda se comporte conforme o esperado. Aplicar as técnicas descritas no guia de correção de validação numérica a cada passo incremental de este processo para garantir suas corridas de código migrados corretamente.

Manipulação de mudanças de comportamento de TF1.x para TF2 não abrangidas pelos calços de modelagem

Os calços de modelagem descritas neste guia pode ter certeza de que variáveis, camadas e perdas de regularização criados com get_variable , tf.compat.v1.layers e variable_scope semântica continuar a trabalhar como antes, quando usando execução ansioso e tf.function , sem ter que dependem de coleções.

Isso não cobrir todas as semânticas específicas-TF1.x que o modelo passa a frente pode estar contando com. Em alguns casos, os calços podem ser insuficientes para que seu passe de avanço do modelo execute no TF2 por conta própria. Leia o TF1.x vs TF2 comportamentos guiar para saber mais sobre as diferenças comportamentais entre TF1.x e TF2.