Doğruluğu ve sayısal denkliği doğrulama

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın GitHub'da görüntüle Not defterini indir

TensorFlow kodunuzu TF1.x'ten TF2'ye taşırken, taşınan kodunuzun TF2'de TF1.x'te olduğu gibi davranmasını sağlamak iyi bir uygulamadır.

Bu kılavuz, tf.keras.layers.Layer yöntemlerine uygulanan tf.compat.v1.keras.utils.track_tf1_style_variables modelleme altlığı ile geçiş kodu örneklerini kapsar. TF2 modelleme şimleri hakkında daha fazla bilgi edinmek için model eşleme kılavuzunu okuyun.

Bu kılavuz, aşağıdakiler için kullanabileceğiniz yaklaşımların ayrıntılarını verir:

  • Taşınan kodu kullanarak eğitim modellerinden elde edilen sonuçların doğruluğunu doğrulama
  • TensorFlow sürümlerinde kodunuzun sayısal denkliğini doğrulayın

Kurmak

pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is available only in
# Tensorflow 2.8
pip install -q tf-nightly
pip install -q tf_slim
import tensorflow as tf
import tensorflow.compat.v1 as v1

import numpy as np
import tf_slim as slim
import sys


from contextlib import contextmanager
!git clone --depth=1 https://github.com/tensorflow/models.git
import models.research.slim.nets.inception_resnet_v2 as inception
Cloning into 'models'...
remote: Enumerating objects: 3192, done.[K
remote: Counting objects: 100% (3192/3192), done.[K
remote: Compressing objects: 100% (2696/2696), done.[K
remote: Total 3192 (delta 848), reused 1381 (delta 453), pack-reused 0[K
Receiving objects: 100% (3192/3192), 33.39 MiB | 12.89 MiB/s, done.
Resolving deltas: 100% (848/848), done.

Şime önemsiz olmayan bir ileri geçiş kodu öbeği koyuyorsanız, bunun TF1.x'te olduğu gibi davrandığını bilmek istersiniz. Örneğin, tüm bir TF-Slim Inception-Resnet-v2 modelini altlığa şu şekilde yerleştirmeyi düşünün:

# TF1 Inception resnet v2 forward pass based on slim layers
def inception_resnet_v2(inputs, num_classes, is_training):
  with slim.arg_scope(
    inception.inception_resnet_v2_arg_scope(batch_norm_scale=True)):
    return inception.inception_resnet_v2(inputs, num_classes, is_training=is_training)
class InceptionResnetV2(tf.keras.layers.Layer):
  """Slim InceptionResnetV2 forward pass as a Keras layer"""

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

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs, training=None):
    is_training = training or False 

    # Slim does not accept `None` as a value for is_training,
    # Keras will still pass `None` to layers to construct functional models
    # without forcing the layer to always be in training or in inference.
    # However, `None` is generally considered to run layers in inference.

    with slim.arg_scope(
        inception.inception_resnet_v2_arg_scope(batch_norm_scale=True)):
      return inception.inception_resnet_v2(
          inputs, self.num_classes, is_training=is_training)
-yer tutucu8 l10n-yer
WARNING:tensorflow:From /tmp/ipykernel_27382/2131234657.py:8: The name tf.keras.utils.track_tf1_style_variables is deprecated. Please use tf.compat.v1.keras.utils.track_tf1_style_variables instead.

Olduğu gibi, bu katman aslında kutunun dışında mükemmel bir şekilde çalışıyor (doğru düzenlileştirme kaybı takibi ile tamamlandı).

Ancak, bu hafife almak isteyeceğiniz bir şey değil. Gerçekten TF1.x'te olduğu gibi davrandığını doğrulamak için aşağıdaki adımları izleyin ve mükemmel sayısal denkliği gözlemleyin. Bu adımlar ayrıca ileri geçişin hangi bölümünün TF1.x'ten sapmaya neden olduğunu belirlemenize yardımcı olabilir (farklılığın, modelin farklı bir parçasının aksine model ileri geçişinde ortaya çıkıp çıkmadığını belirleyin).

Adım 1: Değişkenlerin yalnızca bir kez oluşturulduğunu doğrulayın

Doğrulamanız gereken ilk şey, modeli, her seferinde yanlışlıkla yeni değişkenler oluşturup kullanmak yerine, her çağrıda değişkenleri yeniden kullanacak şekilde doğru bir şekilde oluşturduğunuzdur. Örneğin, modeliniz yeni bir Keras katmanı oluşturuyorsa veya her ileri geçiş çağrısında tf.Variable çağırıyorsa, büyük olasılıkla değişkenleri yakalamakta başarısız olur ve her seferinde yenilerini oluşturur.

Aşağıda, modelinizin ne zaman yeni değişkenler oluşturduğunu tespit etmek ve modelin hangi bölümünün bunu yaptığını hata ayıklamak için kullanabileceğiniz iki bağlam yöneticisi kapsamı verilmiştir.

@contextmanager
def assert_no_variable_creations():
  """Assert no variables are created in this context manager scope."""
  def invalid_variable_creator(next_creator, **kwargs):
    raise ValueError("Attempted to create a new variable instead of reusing an existing one. Args: {}".format(kwargs))

  with tf.variable_creator_scope(invalid_variable_creator):
    yield

@contextmanager
def catch_and_raise_created_variables():
  """Raise all variables created within this context manager scope (if any)."""
  created_vars = []
  def variable_catcher(next_creator, **kwargs):
    var = next_creator(**kwargs)
    created_vars.append(var)
    return var

  with tf.variable_creator_scope(variable_catcher):
    yield
  if created_vars:
    raise ValueError("Created vars:", created_vars)

İlk kapsam ( assert_no_variable_creations() ), kapsam içinde bir değişken oluşturmayı denediğinizde hemen bir hata verecektir. Bu, mevcut olanı yeniden kullanmak yerine tam olarak hangi kod satırlarının bir değişken oluşturduğunu anlamak için yığın izini incelemenize (ve etkileşimli hata ayıklamayı kullanmanıza) olanak tanır.

İkinci kapsam ( catch_and_raise_created_variables() ), herhangi bir değişkenin yaratılması sona ererse, kapsamın sonunda bir istisna oluşturacaktır. Bu istisna, kapsamda oluşturulan tüm değişkenlerin listesini içerecektir. Bu, genel kalıpları tespit edebilmeniz durumunda modelinizin oluşturduğu tüm ağırlıkların kümesinin ne olduğunu bulmak için kullanışlıdır. Ancak, bu değişkenlerin oluşturulduğu tam kod satırlarını belirlemek için daha az kullanışlıdır.

Şim tabanlı InceptionResnetV2 katmanının ilk çağrıdan sonra (muhtemelen bunları yeniden kullanarak) yeni değişkenler oluşturmadığını doğrulamak için aşağıdaki her iki kapsamı kullanın.

model = InceptionResnetV2(1000)
height, width = 299, 299
num_classes = 1000

inputs = tf.ones( (1, height, width, 3))
# Create all weights on the first call
model(inputs)

# Verify that no new weights are created in followup calls
with assert_no_variable_creations():
  model(inputs)
with catch_and_raise_created_variables():
  model(inputs)
tutucu11 l10n-yer
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py:2212: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  warnings.warn('`layer.apply` is deprecated and '
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tf_slim/layers/layers.py:684: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  outputs = layer.apply(inputs, training=is_training)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/legacy_tf_layers/core.py:332: UserWarning: `tf.layers.flatten` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Flatten` instead.
  warnings.warn('`tf.layers.flatten` is deprecated and '

Aşağıdaki örnekte, bu dekoratörlerin, mevcut olanları yeniden kullanmak yerine her seferinde yanlış bir şekilde yeni ağırlıklar oluşturan bir katman üzerinde nasıl çalıştığını gözlemleyin.

class BrokenScalingLayer(tf.keras.layers.Layer):
  """Scaling layer that incorrectly creates new weights each time:"""

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    var = tf.Variable(initial_value=2.0)
    bias = tf.Variable(initial_value=2.0, name='bias')
    return inputs * var + bias
model = BrokenScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)

try:
  with assert_no_variable_creations():
    model(inputs)
except ValueError as err:
  import traceback
  traceback.print_exc()
Traceback (most recent call last):
  File "/tmp/ipykernel_27382/1128777590.py", line 7, in <module>
    model(inputs)
  File "/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "/tmp/ipykernel_27382/3224979076.py", line 6, in call
    var = tf.Variable(initial_value=2.0)
  File "/tmp/ipykernel_27382/1829430118.py", line 5, in invalid_variable_creator
    raise ValueError("Attempted to create a new variable instead of reusing an existing one. Args: {}".format(kwargs))
ValueError: Exception encountered when calling layer "broken_scaling_layer" (type BrokenScalingLayer).

Attempted to create a new variable instead of reusing an existing one. Args: {'initial_value': 2.0, 'trainable': None, 'validate_shape': True, 'caching_device': None, 'name': None, 'variable_def': None, 'dtype': None, 'import_scope': None, 'constraint': None, 'synchronization': <VariableSynchronization.AUTO: 0>, 'aggregation': <VariableAggregation.NONE: 0>, 'shape': None}

Call arguments received:
  • inputs=tf.Tensor(shape=(1, 299, 299, 3), dtype=float32)
model = BrokenScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)

try:
  with catch_and_raise_created_variables():
    model(inputs)
except ValueError as err:
  print(err)
('Created vars:', [<tf.Variable 'broken_scaling_layer_1/Variable:0' shape=() dtype=float32, numpy=2.0>, <tf.Variable 'broken_scaling_layer_1/bias:0' shape=() dtype=float32, numpy=2.0>])

Ağırlıkları yalnızca bir kez oluşturduğundan ve ardından her seferinde yeniden kullandığından emin olarak katmanı düzeltebilirsiniz.

class FixedScalingLayer(tf.keras.layers.Layer):
  """Scaling layer that incorrectly creates new weights each time:"""
  def __init__(self):
    super().__init__()
    self.var = None
    self.bias = None

  @tf.compat.v1.keras.utils.track_tf1_style_variables
  def call(self, inputs):
    if self.var is None:
      self.var = tf.Variable(initial_value=2.0)
      self.bias = tf.Variable(initial_value=2.0, name='bias')
    return inputs * self.var + self.bias

model = FixedScalingLayer()
inputs = tf.ones( (1, height, width, 3))
model(inputs)

with assert_no_variable_creations():
  model(inputs)
with catch_and_raise_created_variables():
  model(inputs)

Sorun giderme

Modelinizin mevcut olanları yeniden kullanmak yerine yanlışlıkla yeni ağırlıklar oluşturmasının bazı yaygın nedenleri şunlardır:

  1. Önceden oluşturulmuş tf.Variables yeniden kullanmadan açık bir tf.Variable çağrısı kullanır. Bunu, önce oluşturulup oluşturulmadığını kontrol ederek, ardından mevcut olanları yeniden kullanarak düzeltin.
  2. Her seferinde doğrudan ileri geçişte bir Keras katmanı veya modeli oluşturur ( tf.compat.v1.layers yerine). Bunu, önce oluşturulup oluşturulmadığını kontrol ederek, ardından mevcut olanları yeniden kullanarak düzeltin.
  3. tf.compat.v1.layers üzerine inşa edilmiştir, ancak tüm compat.v1.layers açık bir ad atayamaz veya compat.v1.layer kullanımınızı adlandırılmış bir variable_scope içine sararak, otomatik oluşturulan katman adlarının artmasına neden olur. Her model çağrısı. Tüm tf.compat.v1.layers kullanımınızı saran altlık süslemeli yönteminizin içine adlandırılmış bir tf.compat.v1.variable_scope koyarak bunu düzeltin.

2. Adım: Değişken sayıları, adları ve şekillerinin eşleşip eşleşmediğini kontrol edin

İkinci adım, TF2'de çalışan katmanınızın, karşılık gelen kodun TF1.x'te yaptığı gibi aynı şekillerle aynı sayıda ağırlık oluşturduğundan emin olmaktır.

Eşleştiklerini görmek için manuel olarak kontrol etmenin ve aşağıda gösterildiği gibi bir birim testinde programlı olarak kontrollerin bir karışımını yapabilirsiniz.

# Build the forward pass inside a TF1.x graph, and 
# get the counts, shapes, and names of the variables
graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
  height, width = 299, 299
  num_classes = 1000
  inputs = tf.ones( (1, height, width, 3))

  out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)

  tf1_variable_names_and_shapes = {
      var.name: (var.trainable, var.shape) for var in tf.compat.v1.global_variables()}
  num_tf1_variables = len(tf.compat.v1.global_variables())
tutucu19 l10n-yer
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer_v1.py:1694: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  warnings.warn('`layer.apply` is deprecated and '

Ardından, aynısını TF2'deki şim sarılı katman için yapın. Ağırlıkları almadan önce modelin birden çok kez çağrıldığına dikkat edin. Bu, değişken yeniden kullanımını etkin bir şekilde test etmek için yapılır.

height, width = 299, 299
num_classes = 1000

model = InceptionResnetV2(num_classes)
# The weights will not be created until you call the model

inputs = tf.ones( (1, height, width, 3))
# Call the model multiple times before checking the weights, to verify variables
# get reused rather than accidentally creating additional variables
out, endpoints = model(inputs, training=False)
out, endpoints = model(inputs, training=False)

# Grab the name: shape mapping and the total number of variables separately,
# because in TF2 variables can be created with the same name
num_tf2_variables = len(model.variables)
tf2_variable_names_and_shapes = {
    var.name: (var.trainable, var.shape) for var in model.variables}
2021-12-04 02:27:27.209445: 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.
-yer tutucu22 l10n-yer
# Verify that the variable counts, names, and shapes all match:
assert num_tf1_variables == num_tf2_variables
assert tf1_variable_names_and_shapes == tf2_variable_names_and_shapes

Şim tabanlı InceptionResnetV2 katmanı bu testi geçer. Ancak, eşleşmemeleri durumunda, farklılıkların nerede olduğunu görmek için bir fark (metin veya diğer) üzerinden çalıştırabilirsiniz.

Bu, modelin hangi bölümünün beklendiği gibi davranmadığına dair bir ipucu sağlayabilir. İstekli yürütmeyle, modelin şüpheli görünen kısımlarını kazmak ve neyin yanlış gittiğini daha derinlemesine ayıklamak için pdb, etkileşimli hata ayıklama ve kesme noktalarını kullanabilirsiniz.

Sorun giderme

  • Doğrudan açık tf.Variable çağrıları ve Keras katmanları/modelleri tarafından oluşturulan değişkenlerin adlarına çok dikkat edin, çünkü bunların değişken adı oluşturma semantikleri, TF1.x grafikleri ile istekli yürütme ve tf.function gibi TF2 işlevleri arasında her şey olsa bile biraz farklılık gösterebilir. başka düzgün çalışıyor. Sizin için durum buysa, testinizi biraz farklı adlandırma semantiğini hesaba katacak şekilde ayarlayın.

  • Bazen eğitim döngünüzün ileri geçişinde oluşturulan tf.Variable s, tf.keras.layers.Layer s veya tf.keras.Model lerin değişkenler koleksiyonu tarafından yakalanmış olsalar bile TF2 değişkenler listenizde eksik olduğunu görebilirsiniz. TF1.x'te. İleri geçişinizin oluşturduğu değişkenleri/katmanları/modelleri modelinizdeki örnek niteliklerine atayarak bunu düzeltin. Daha fazla bilgi için buraya bakın.

Adım 3: Tüm değişkenleri sıfırlayın, tüm rastgelelik devre dışı bırakılarak sayısal denkliği kontrol edin

Sonraki adım, modeli rastgele sayı üretimi olmayacak şekilde sabitlediğinizde (çıkarım sırasında olduğu gibi) hem gerçek çıktılar hem de düzenlileştirme kaybı takibi için sayısal denkliği doğrulamaktır.

Bunu yapmanın tam yolu, belirli modelinize bağlı olabilir, ancak çoğu modelde (bunun gibi), bunu şu şekilde yapabilirsiniz:

  1. Ağırlıkları rastgele olmadan aynı değere başlatma. Bu, oluşturulduktan sonra sabit bir değere sıfırlanarak yapılabilir.
  2. Rastgele kaynak olabilecek herhangi bir bırakma katmanını tetiklemekten kaçınmak için modeli çıkarım modunda çalıştırmak.

Aşağıdaki kod, TF1.x ve TF2 sonuçlarını bu şekilde nasıl karşılaştırabileceğinizi gösterir.

graph = tf.Graph()
with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
  height, width = 299, 299
  num_classes = 1000
  inputs = tf.ones( (1, height, width, 3))

  out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)

  # Rather than running the global variable initializers,
  # reset all variables to a constant value
  var_reset = tf.group([var.assign(tf.ones_like(var) * 0.001) for var in tf.compat.v1.global_variables()])
  sess.run(var_reset)

  # Grab the outputs & regularization loss
  reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
  tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
  tf1_output = sess.run(out)

print("Regularization loss:", tf1_regularization_loss)
tf1_output[0][:5]
tutucu24 l10n-yer
Regularization loss: 0.001182976
array([0.00299837, 0.00299837, 0.00299837, 0.00299837, 0.00299837],
      dtype=float32)

TF2 sonuçlarını alın.

height, width = 299, 299
num_classes = 1000

model = InceptionResnetV2(num_classes)

inputs = tf.ones((1, height, width, 3))
# Call the model once to create the weights
out, endpoints = model(inputs, training=False)

# Reset all variables to the same fixed value as above, with no randomness
for var in model.variables:
  var.assign(tf.ones_like(var) * 0.001)
tf2_output, endpoints = model(inputs, training=False)

# Get the regularization loss
tf2_regularization_loss = tf.math.add_n(model.losses)

print("Regularization loss:", tf2_regularization_loss)
tf2_output[0][:5]
Regularization loss: tf.Tensor(0.0011829757, shape=(), dtype=float32)
<tf.Tensor: shape=(5,), dtype=float32, numpy=
array([0.00299837, 0.00299837, 0.00299837, 0.00299837, 0.00299837],
      dtype=float32)>
yer tutucu27 l10n-yer
# Create a dict of tolerance values
tol_dict={'rtol':1e-06, 'atol':1e-05}
# Verify that the regularization loss and output both match
# when we fix the weights and avoid randomness by running inference:
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)

Rastgelelik kaynaklarını kaldırdığınızda sayılar TF1.x ve TF2 arasında eşleşir ve TF2 uyumlu InceptionResnetV2 katmanı testi geçer.

Kendi modelleriniz için farklılaşan sonuçları gözlemliyorsanız, sonuçların nerede ve neden farklılaşmaya başladığını belirlemek için yazdırma veya pdb ve etkileşimli hata ayıklamayı kullanabilirsiniz. İstekli yürütme, bunu önemli ölçüde kolaylaştırabilir. Modelin yalnızca küçük kısımlarını sabit ara girdilerde çalıştırmak ve sapmanın gerçekleştiği yeri yalıtmak için bir ablasyon yaklaşımı da kullanabilirsiniz.

Uygun bir şekilde, birçok ince ağ (ve diğer modeller), inceleyebileceğiniz ara uç noktaları da ortaya çıkarır.

Adım 4: Rastgele sayı üretimini hizalayın, hem eğitimde hem de çıkarımda sayısal denkliği kontrol edin

Son adım, değişken başlatmada ve ileri geçişin kendisinde (ileri geçiş sırasında bırakma katmanları gibi) rasgele sayı üretimi hesaba katıldığında bile, TF2 modelinin sayısal olarak TF1.x modeliyle eşleştiğini doğrulamaktır.

Bunu, TF1.x grafikleri/oturumları ve istekli yürütme arasında rasgele sayı üretme semantiği eşleştirmesi yapmak için aşağıdaki test aracını kullanarak yapabilirsiniz.

TF1 eski grafikleri/oturumları ve TF2 istekli yürütmesi, farklı durum bilgisi olan rasgele sayı oluşturma semantikleri kullanır.

tf.compat.v1.Session s'de, herhangi bir tohum belirtilmemişse, rastgele sayı üretimi, rastgele işlemin eklendiği anda grafikte kaç işlem olduğuna ve grafiğin kaç kez çalıştırıldığına bağlıdır. İstekli yürütmede, durum bilgisi olan rasgele sayı üretimi, genel kaynağa, rasgele tohum işlemine ve verilen rasgele tohumla işlemle işlemin kaç kez çalıştırıldığına bağlıdır. Daha fazla bilgi için tf.random.set_seed bakın.

Aşağıdaki v1.keras.utils.DeterministicRandomTestTool sınıfı, durum bilgisi olan rastgele işlemlerin hem TF1 grafiklerinde/oturumlarında hem de istekli yürütmede aynı tohumu kullanmasını sağlayan bir bağlam yöneticisi scope() sağlar.

Araç iki test modu sağlar:

  1. kaç kez çağrıldığına bakılmaksızın her bir işlem için aynı tohumu kullanan constant ve,
  2. İşlem çekirdeği olarak önceden gözlemlenen durum bilgisi olan rastgele işlemlerin sayısını kullanan num_random_ops .

Bu, hem değişkenleri oluşturmak ve başlatmak için kullanılan durum bilgisi olan rasgele işlemler hem de hesaplamada kullanılan durum bilgisi olan rasgele işlemler (örneğin bırakma katmanları için) için geçerlidir.

Oturumlar ve istekli yürütme arasında durum bilgisi olan rastgele sayı oluşturma eşleşmesi yapmak için bu aracın nasıl kullanılacağını göstermek için üç rastgele tensör oluşturun.

random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    a = tf.random.uniform(shape=(3,1))
    a = a * 3
    b = tf.random.uniform(shape=(3,3))
    b = b * 3
    c = tf.random.uniform(shape=(3,3))
    c = c * 3
    graph_a, graph_b, graph_c = sess.run([a, b, c])

graph_a, graph_b, graph_c
(array([[2.5063772],
        [2.7488918],
        [1.4839486]], dtype=float32),
 array([[2.5063772, 2.7488918, 1.4839486],
        [1.5633398, 2.1358476, 1.3693532],
        [0.3598416, 1.8287641, 2.5314465]], dtype=float32),
 array([[2.5063772, 2.7488918, 1.4839486],
        [1.5633398, 2.1358476, 1.3693532],
        [0.3598416, 1.8287641, 2.5314465]], dtype=float32))
random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
  a = tf.random.uniform(shape=(3,1))
  a = a * 3
  b = tf.random.uniform(shape=(3,3))
  b = b * 3
  c = tf.random.uniform(shape=(3,3))
  c = c * 3

a, b, c
(<tf.Tensor: shape=(3, 1), dtype=float32, numpy=
 array([[2.5063772],
        [2.7488918],
        [1.4839486]], dtype=float32)>,
 <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
 array([[2.5063772, 2.7488918, 1.4839486],
        [1.5633398, 2.1358476, 1.3693532],
        [0.3598416, 1.8287641, 2.5314465]], dtype=float32)>,
 <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
 array([[2.5063772, 2.7488918, 1.4839486],
        [1.5633398, 2.1358476, 1.3693532],
        [0.3598416, 1.8287641, 2.5314465]], dtype=float32)>)
# Demonstrate that the generated random numbers match
np.testing.assert_allclose(graph_a, a.numpy(), **tol_dict)
np.testing.assert_allclose(graph_b, b.numpy(), **tol_dict)
np.testing.assert_allclose(graph_c, c.numpy(), **tol_dict)

Bununla birlikte, constant modda b ve c aynı tohumla oluşturulduğu ve aynı şekle sahip olduğu için tamamen aynı değerlere sahip olacağına dikkat edin.

np.testing.assert_allclose(b.numpy(), c.numpy(), **tol_dict)

Sipariş takibi

constant modda bazı rasgele sayıların eşleşmesinden, sayısal denklik testinize olan güveninizi azaltacağından endişeleniyorsanız (örneğin, aynı başlatmaları birkaç ağırlık alıyorsa), bundan kaçınmak için num_random_ops modunu kullanabilirsiniz. num_random_ops modunda, oluşturulan rasgele sayılar, programdaki rasgele işlemlerin sırasına bağlı olacaktır.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    a = tf.random.uniform(shape=(3,1))
    a = a * 3
    b = tf.random.uniform(shape=(3,3))
    b = b * 3
    c = tf.random.uniform(shape=(3,3))
    c = c * 3
    graph_a, graph_b, graph_c = sess.run([a, b, c])

graph_a, graph_b, graph_c
(array([[2.5063772],
        [2.7488918],
        [1.4839486]], dtype=float32),
 array([[0.45038545, 1.9197761 , 2.4536333 ],
        [1.0371652 , 2.9898582 , 1.924583  ],
        [0.25679827, 1.6579313 , 2.8418403 ]], dtype=float32),
 array([[2.9634383 , 1.0862181 , 2.6042497 ],
        [0.70099247, 2.3920312 , 1.0470468 ],
        [0.18173039, 0.8359269 , 1.0508587 ]], dtype=float32))
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  a = tf.random.uniform(shape=(3,1))
  a = a * 3
  b = tf.random.uniform(shape=(3,3))
  b = b * 3
  c = tf.random.uniform(shape=(3,3))
  c = c * 3

a, b, c
(<tf.Tensor: shape=(3, 1), dtype=float32, numpy=
 array([[2.5063772],
        [2.7488918],
        [1.4839486]], dtype=float32)>,
 <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
 array([[0.45038545, 1.9197761 , 2.4536333 ],
        [1.0371652 , 2.9898582 , 1.924583  ],
        [0.25679827, 1.6579313 , 2.8418403 ]], dtype=float32)>,
 <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
 array([[2.9634383 , 1.0862181 , 2.6042497 ],
        [0.70099247, 2.3920312 , 1.0470468 ],
        [0.18173039, 0.8359269 , 1.0508587 ]], dtype=float32)>)
# Demonstrate that the generated random numbers match
np.testing.assert_allclose(graph_a, a.numpy(), **tol_dict)
np.testing.assert_allclose(graph_b, b.numpy(), **tol_dict )
np.testing.assert_allclose(graph_c, c.numpy(), **tol_dict)
# Demonstrate that with the 'num_random_ops' mode,
# b & c took on different values even though
# their generated shape was the same
assert not np.allclose(b.numpy(), c.numpy(), **tol_dict)

Ancak, bu modda rasgele oluşturmanın program sırasına duyarlı olduğuna ve bu nedenle aşağıdaki oluşturulan rasgele sayıların eşleşmediğine dikkat edin.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  a = tf.random.uniform(shape=(3,1))
  a = a * 3
  b = tf.random.uniform(shape=(3,3))
  b = b * 3

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  b_prime = tf.random.uniform(shape=(3,3))
  b_prime = b_prime * 3
  a_prime = tf.random.uniform(shape=(3,1))
  a_prime = a_prime * 3

assert not np.allclose(a.numpy(), a_prime.numpy())
assert not np.allclose(b.numpy(), b_prime.numpy())

İzleme sırasından kaynaklanan hata ayıklama varyasyonlarına izin vermek için, num_random_ops modunda DeterministicRandomTestTool , Operation_seed özelliğiyle kaç rastgele operation_seed izlendiğini görmenize olanak tanır.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  print(random_tool.operation_seed)
  a = tf.random.uniform(shape=(3,1))
  a = a * 3
  print(random_tool.operation_seed)
  b = tf.random.uniform(shape=(3,3))
  b = b * 3
  print(random_tool.operation_seed)
tutucu43 l10n-yer
0
1
2

Testlerinizde değişen izleme sırasını hesaba katmanız gerekiyorsa, otomatik artan operation_seed açıkça ayarlayabilirsiniz. Örneğin, bunu iki farklı program sırası arasında rastgele sayı üretme eşleştirmesi yapmak için kullanabilirsiniz.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  print(random_tool.operation_seed)
  a = tf.random.uniform(shape=(3,1))
  a = a * 3
  print(random_tool.operation_seed)
  b = tf.random.uniform(shape=(3,3))
  b = b * 3

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  random_tool.operation_seed = 1
  b_prime = tf.random.uniform(shape=(3,3))
  b_prime = b_prime * 3
  random_tool.operation_seed = 0
  a_prime = tf.random.uniform(shape=(3,1))
  a_prime = a_prime * 3

np.testing.assert_allclose(a.numpy(), a_prime.numpy(), **tol_dict)
np.testing.assert_allclose(b.numpy(), b_prime.numpy(), **tol_dict)
tutucu45 l10n-yer
0
1

Ancak, DeterministicRandomTestTool , önceden kullanılmış işlem tohumlarının yeniden kullanılmasına izin vermez, bu nedenle otomatik artan dizilerin çakışmadığından emin olun. Bunun nedeni, istekli yürütmenin aynı işlem çekirdeğinin sonraki kullanımları için farklı sayılar oluşturması, ancak TF1 grafikleri ve oturumları oluşturmamasıdır, bu nedenle bir hatanın yükseltilmesi, oturumun ve istekli durum bilgili rasgele sayı üretiminin aynı hizada tutulmasına yardımcı olur.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  random_tool.operation_seed = 1
  b_prime = tf.random.uniform(shape=(3,3))
  b_prime = b_prime * 3
  random_tool.operation_seed = 0
  a_prime = tf.random.uniform(shape=(3,1))
  a_prime = a_prime * 3
  try:
    c = tf.random.uniform(shape=(3,1))
    raise RuntimeError("An exception should have been raised before this, " +
                     "because the auto-incremented operation seed will " +
                     "overlap an already-used value")
  except ValueError as err:
    print(err)
tutucu47 l10n-yer
This `DeterministicRandomTestTool` object is trying to re-use the already-used operation seed 1. 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.

Çıkarımın Doğrulanması

Artık InceptionResnetV2 modelinin rastgele ağırlık başlatmayı kullanırken bile çıkarımda eşleştiğinden emin olmak için DeterministicRandomTestTool kullanabilirsiniz. Eşleşen program sırası nedeniyle daha güçlü bir test koşulu için num_random_ops modunu kullanın.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    height, width = 299, 299
    num_classes = 1000
    inputs = tf.ones( (1, height, width, 3))

    out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=False)

    # Initialize the variables
    sess.run(tf.compat.v1.global_variables_initializer())

    # Grab the outputs & regularization loss
    reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
    tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
    tf1_output = sess.run(out)

  print("Regularization loss:", tf1_regularization_loss)
Regularization loss: 1.2254326
height, width = 299, 299
num_classes = 1000

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  model = InceptionResnetV2(num_classes)

  inputs = tf.ones((1, height, width, 3))
  tf2_output, endpoints = model(inputs, training=False)

  # Grab the regularization loss as well
  tf2_regularization_loss = tf.math.add_n(model.losses)

print("Regularization loss:", tf2_regularization_loss)
Regularization loss: tf.Tensor(1.2254325, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool:
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)

Doğrulama Eğitimi

DeterministicRandomTestTool tüm durum bilgisi olan rasgele işlemler için çalıştığından (hem ağırlık başlatma hem de bırakma katmanları gibi hesaplama dahil), eğitim modunda da modellerin eşleştiğini doğrulamak için kullanabilirsiniz. Durum bilgisi olan rastgele işlemlerin program sırası eşleştiğinden, num_random_ops modunu tekrar kullanabilirsiniz.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    height, width = 299, 299
    num_classes = 1000
    inputs = tf.ones( (1, height, width, 3))

    out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=True)

    # Initialize the variables
    sess.run(tf.compat.v1.global_variables_initializer())

    # Grab the outputs & regularization loss
    reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
    tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
    tf1_output = sess.run(out)

  print("Regularization loss:", tf1_regularization_loss)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/layers/normalization/batch_normalization.py:532: _colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
Regularization loss: 1.22548
height, width = 299, 299
num_classes = 1000

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  model = InceptionResnetV2(num_classes)

  inputs = tf.ones((1, height, width, 3))
  tf2_output, endpoints = model(inputs, training=True)

  # Grab the regularization loss as well
  tf2_regularization_loss = tf.math.add_n(model.losses)

print("Regularization loss:", tf2_regularization_loss)
Regularization loss: tf.Tensor(1.2254798, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)

Artık tf.keras.layers.Layer çevresinde dekoratörlerle hevesle çalışan InceptionResnetV2 modelinin TF1 grafiklerinde ve oturumlarında çalışan ince ağla sayısal olarak eşleştiğini doğruladınız.

Örneğin, InceptionResnetV2 katmanını doğrudan training=True ile çağırmak, ağ oluşturma sırasına göre bırakma sırasına göre değişken başlatmayı serpiştirir.

Öte yandan, önce tf.keras.layers.Layer dekoratörünü bir Keras işlevsel modeline yerleştirmek ve ancak ondan sonra modeli training=True ile çağırmak, tüm değişkenleri başlatmaya ve ardından bırakma katmanını kullanmaya eşdeğerdir. Bu, farklı bir izleme sırası ve farklı bir rasgele sayı kümesi üretir.

Ancak, varsayılan mode='constant' , izleme sırasındaki bu farklılıklara duyarlı değildir ve katmanı Keras işlevsel modeline gömerken bile fazladan çalışma olmadan geçer.

random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    height, width = 299, 299
    num_classes = 1000
    inputs = tf.ones( (1, height, width, 3))

    out, endpoints = inception_resnet_v2(inputs, num_classes, is_training=True)

    # Initialize the variables
    sess.run(tf.compat.v1.global_variables_initializer())

    # Get the outputs & regularization losses
    reg_losses = tf.compat.v1.get_collection(tf.compat.v1.GraphKeys.REGULARIZATION_LOSSES)
    tf1_regularization_loss = sess.run(tf.math.add_n(reg_losses))
    tf1_output = sess.run(out)

  print("Regularization loss:", tf1_regularization_loss)
Regularization loss: 1.2239965
height, width = 299, 299
num_classes = 1000

random_tool = v1.keras.utils.DeterministicRandomTestTool()
with random_tool.scope():
  keras_input = tf.keras.Input(shape=(height, width, 3))
  layer = InceptionResnetV2(num_classes)
  model = tf.keras.Model(inputs=keras_input, outputs=layer(keras_input))

  inputs = tf.ones((1, height, width, 3))
  tf2_output, endpoints = model(inputs, training=True)

  # Get the regularization loss
  tf2_regularization_loss = tf.math.add_n(model.losses)

print("Regularization loss:", tf2_regularization_loss)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/keras/engine/base_layer.py:1345: 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.
  warnings.warn('`layer.updates` will be removed in a future version. '
/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)
Regularization loss: tf.Tensor(1.2239964, shape=(), dtype=float32)
# Verify that the regularization loss and output both match
# when using the DeterministicRandomTestTool
np.testing.assert_allclose(tf1_regularization_loss, tf2_regularization_loss.numpy(), **tol_dict)
np.testing.assert_allclose(tf1_output, tf2_output.numpy(), **tol_dict)

Adım 3b veya 4b (isteğe bağlı): Önceden var olan kontrol noktalarıyla test etme

Yukarıdaki adım 3 veya adım 4'ten sonra, varsa, önceden var olan ada dayalı kontrol noktalarından başlayarak sayısal denklik testlerinizi çalıştırmanız faydalı olabilir. Bu, hem eski kontrol noktası yüklemenizin doğru çalıştığını hem de modelin kendisinin doğru çalıştığını test edebilir. TF1.x kontrol noktalarını yeniden kullanma kılavuzu , önceden var olan TF1.x kontrol noktalarınızı nasıl yeniden kullanacağınızı ve bunları TF2 kontrol noktalarına nasıl aktaracağınızı kapsar.

Ek Test ve Sorun Giderme

Daha fazla sayısal denklik testi ekledikçe, degrade hesaplamanızın (hatta optimize edici güncellemelerinizin) eşleşmesini doğrulayan bir test eklemeyi de seçebilirsiniz.

Geri yayılım ve gradyan hesaplaması, model ileri geçişlere göre kayan noktalı sayısal kararsızlıklara daha yatkındır. Bu, denklik testleriniz antrenmanınızın izole edilmemiş daha fazla bölümünü kapsadığı için, tamamen hevesle koşmak ile TF1 grafikleriniz arasında önemsiz olmayan sayısal farklar görmeye başlayabileceğiniz anlamına gelir. Bu, TensorFlow'un bir grafikteki alt ifadeleri daha az matematiksel işlemle değiştirmek gibi şeyler yapan grafik optimizasyonlarından kaynaklanabilir.

Durumun böyle olup olmayacağını belirlemek için, TF1 kodunuzu, tamamen hevesli bir hesaplama yerine bir tf.function (TF1 grafiğiniz gibi grafik optimizasyon geçişlerini uygulayan) içinde gerçekleşen TF2 hesaplamasıyla karşılaştırabilirsiniz. Alternatif olarak, sonucun sayısal olarak TF2 hesaplama sonuçlarınıza sayısal olarak daha yakın olup olmadığını görmek için TF1 hesaplamanızdan önce "arithmetic_optimization" gibi optimizasyon geçişlerini devre dışı bırakmak için tf.config.optimizer.set_experimental_options kullanmayı deneyebilirsiniz. Gerçek eğitim çalışmalarınızda, performans nedenleriyle etkinleştirilen optimizasyon geçişleriyle tf.function kullanmanız önerilir, ancak sayısal eşdeğerlik birim testlerinizde bunları devre dışı bırakmayı yararlı bulabilirsiniz.

Benzer şekilde, temsil ettikleri matematiksel formüller aynı olsa bile, tf.compat.v1.train optimize edicilerinin ve TF2 optimize edicilerinin TF2 optimize edicilerinden biraz farklı kayan nokta sayısal özelliklerine sahip olduğunu da görebilirsiniz. Antrenman koşularınızda bunun bir sorun olması daha az olasıdır, ancak eşdeğerlik birim testlerinde daha yüksek sayısal tolerans gerektirebilir.