TF2 Geçişli Eğitim İşlem Hattında Hata Ayıklama

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

Bu not defteri, TF2'ye geçiş yapılırken eğitim hattında nasıl hata ayıklanacağını gösterir. Aşağıdaki bileşenlerden oluşur:

  1. Eğitim hattında hata ayıklamak için önerilen adımlar ve kod örnekleri
  2. Hata ayıklama araçları
  3. Diğer ilgili kaynaklar

Bir varsayım, karşılaştırma için TF1.x kodunuz ve eğitimli modelleriniz var ve benzer doğrulama doğruluğu sağlayan bir TF2 modeli oluşturmak istiyorsunuz.

Bu dizüstü bilgisayar, eğitim/çıkarım hızı veya bellek kullanımı için hata ayıklama performans sorunlarını KAPSAMAZ .

Hata ayıklama iş akışı

Aşağıda, TF2 eğitim işlem hatlarınızda hata ayıklamaya yönelik genel bir iş akışı verilmiştir. Bu adımları sırayla izlemeniz gerekmediğini unutmayın. Modeli bir ara adımda test ettiğiniz ve hata ayıklama kapsamını daralttığınız ikili arama yaklaşımını da kullanabilirsiniz.

  1. Derleme ve çalışma zamanı hatalarını düzeltin

  2. Tek ileri geçiş doğrulaması (ayrı bir kılavuzda )

    a. Tek CPU cihazında

    • Değişkenlerin yalnızca bir kez oluşturulduğunu doğrulayın
    • Değişken sayıları, adları ve şekillerin eşleşmesini kontrol edin
    • Tüm değişkenleri sıfırlayın, tüm rastgelelik devre dışı bırakılarak sayısal denkliği kontrol edin
    • Rastgele sayı üretimini hizalayın, çıkarımda sayısal denkliği kontrol edin
    • (İsteğe bağlı) Kontrol noktalarının düzgün yüklenip yüklenmediğini ve TF1.x/TF2 modelleri aynı çıktıyı üretir

    B. Tek GPU/TPU cihazında

    C. Çoklu cihaz stratejileri ile

  3. Birkaç adım için model eğitimi sayısal denklik doğrulaması (kod örnekleri aşağıda mevcuttur)

    a. Tek CPU cihazında küçük ve sabit veriler kullanılarak tek eğitim adımı doğrulaması. Spesifik olarak, aşağıdaki bileşenler için sayısal denkliği kontrol edin

    • kayıp hesaplama
    • metrikler
    • öğrenme oranı
    • gradyan hesaplama ve güncelleme

    B. Tek CPU cihazında sabit verilerle momentum gibi optimize edici davranışlarını doğrulamak için 3 veya daha fazla adımı eğittikten sonra istatistikleri kontrol edin

    C. Tek GPU/TPU cihazında

    D. Çoklu cihaz stratejileriyle (en alttaki MultiProcessRunner girişine bakın)

  4. Gerçek veri kümesi üzerinde uçtan uca kapsama testi

    a. TensorBoard ile eğitim davranışlarını kontrol edin

    • SGD gibi basit optimize ediciler ve önce tf.distribute.OneDeviceStrategy basit dağıtım stratejileri kullanın
    • eğitim metrikleri
    • değerlendirme metrikleri
    • doğal rastgelelik için makul toleransın ne olduğunu anlayın

    B. Gelişmiş optimize edici/öğrenme oranı planlayıcı/dağıtım stratejileri ile denkliği kontrol edin

    C. Karma hassasiyet kullanırken denkliği kontrol edin

  5. Ek ürün karşılaştırmaları

Kurmak

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

Tek ileri geçiş doğrulaması

Kontrol noktası yüklemesi de dahil olmak üzere tek ileri geçiş doğrulaması, farklı bir ortak çalışma kapsamında ele alınmaktadır .

import sys
import unittest
import numpy as np

import tensorflow as tf
import tensorflow.compat.v1 as v1

Birkaç adım için model eğitimi sayısal denklik doğrulaması

Model konfigürasyonunu ayarlayın ve sahte bir veri seti hazırlayın.

params = {
    'input_size': 3,
    'num_classes': 3,
    'layer_1_size': 2,
    'layer_2_size': 2,
    'num_train_steps': 100,
    'init_lr': 1e-3,
    'end_lr': 0.0,
    'decay_steps': 1000,
    'lr_power': 1.0,
}

# make a small fixed dataset
fake_x = np.ones((2, params['input_size']), dtype=np.float32)
fake_y = np.zeros((2, params['num_classes']), dtype=np.int32)
fake_y[0][0] = 1
fake_y[1][1] = 1

step_num = 3

TF1.x modelini tanımlayın.

# Assume there is an existing TF1.x model using estimator API
# Wrap the model_fn to log necessary tensors for result comparison
class SimpleModelWrapper():
  def __init__(self):
    self.logged_ops = {}
    self.logs = {
        'step': [],
        'lr': [],
        'loss': [],
        'grads_and_vars': [],
        'layer_out': []}

  def model_fn(self, features, labels, mode, params):
      out_1 = tf.compat.v1.layers.dense(features, units=params['layer_1_size'])
      out_2 = tf.compat.v1.layers.dense(out_1, units=params['layer_2_size'])
      logits = tf.compat.v1.layers.dense(out_2, units=params['num_classes'])
      loss = tf.compat.v1.losses.softmax_cross_entropy(labels, logits)

      # skip EstimatorSpec details for prediction and evaluation 
      if mode == tf.estimator.ModeKeys.PREDICT:
          pass
      if mode == tf.estimator.ModeKeys.EVAL:
          pass
      assert mode == tf.estimator.ModeKeys.TRAIN

      global_step = tf.compat.v1.train.get_or_create_global_step()
      lr = tf.compat.v1.train.polynomial_decay(
        learning_rate=params['init_lr'],
        global_step=global_step,
        decay_steps=params['decay_steps'],
        end_learning_rate=params['end_lr'],
        power=params['lr_power'])

      optmizer = tf.compat.v1.train.GradientDescentOptimizer(lr)
      grads_and_vars = optmizer.compute_gradients(
          loss=loss,
          var_list=graph.get_collection(
              tf.compat.v1.GraphKeys.TRAINABLE_VARIABLES))
      train_op = optmizer.apply_gradients(
          grads_and_vars,
          global_step=global_step)

      # log tensors
      self.logged_ops['step'] = global_step
      self.logged_ops['lr'] = lr
      self.logged_ops['loss'] = loss
      self.logged_ops['grads_and_vars'] = grads_and_vars
      self.logged_ops['layer_out'] = {
          'layer_1': out_1,
          'layer_2': out_2,
          'logits': logits}

      return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

  def update_logs(self, logs):
    for key in logs.keys():
      model_tf1.logs[key].append(logs[key])

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.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
tutucu6 l10n-yer
WARNING:tensorflow:From /tmp/ipykernel_26769/2689227634.py:1: The name tf.keras.utils.DeterministicRandomTestTool is deprecated. Please use tf.compat.v1.keras.utils.DeterministicRandomTestTool instead.

TF1.x modelini grafik modunda çalıştırın. Sayısal denklik karşılaştırması için ilk 3 eğitim adımı için istatistikleri toplayın.

with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    model_tf1 = SimpleModelWrapper()
    # build the model
    inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
    labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
    spec = model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
    train_op = spec.train_op

    sess.run(tf.compat.v1.global_variables_initializer())
    for step in range(step_num):
      # log everything and update the model for one step
      logs, _ = sess.run(
          [model_tf1.logged_ops, train_op],
          feed_dict={inputs: fake_x, labels: fake_y})
      model_tf1.update_logs(logs)
tutucu8 l10n-yer
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: 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/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)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  from ipykernel import kernelapp as app
/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()

TF2 modelini tanımlayın.

class SimpleModel(tf.keras.Model):
  def __init__(self, params, *args, **kwargs):
    super(SimpleModel, self).__init__(*args, **kwargs)
    # define the model
    self.dense_1 = tf.keras.layers.Dense(params['layer_1_size'])
    self.dense_2 = tf.keras.layers.Dense(params['layer_2_size'])
    self.out = tf.keras.layers.Dense(params['num_classes'])
    learning_rate_fn = tf.keras.optimizers.schedules.PolynomialDecay(
      initial_learning_rate=params['init_lr'],
      decay_steps=params['decay_steps'],
      end_learning_rate=params['end_lr'],
      power=params['lr_power'])  
    self.optimizer = tf.keras.optimizers.SGD(learning_rate_fn)
    self.compiled_loss = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
    self.logs = {
        'lr': [],
        'loss': [],
        'grads': [],
        'weights': [],
        'layer_out': []}

  def call(self, inputs):
    out_1 = self.dense_1(inputs)
    out_2 = self.dense_2(out_1)
    logits = self.out(out_2)
    # log output features for every layer for comparison
    layer_wise_out = {
        'layer_1': out_1,
        'layer_2': out_2,
        'logits': logits}
    self.logs['layer_out'].append(layer_wise_out)
    return logits

  def train_step(self, data):
    x, y = data
    with tf.GradientTape() as tape:
      logits = self(x)
      loss = self.compiled_loss(y, logits)
    grads = tape.gradient(loss, self.trainable_weights)
    # log training statistics
    step = self.optimizer.iterations.numpy()
    self.logs['lr'].append(self.optimizer.learning_rate(step).numpy())
    self.logs['loss'].append(loss.numpy())
    self.logs['grads'].append(grads)
    self.logs['weights'].append(self.trainable_weights)
    # update model
    self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
    return

TF2 modelini istekli modda çalıştırın. Sayısal denklik karşılaştırması için ilk 3 eğitim adımı için istatistikleri toplayın.

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  model_tf2 = SimpleModel(params)
  for step in range(step_num):
    model_tf2.train_step([fake_x, fake_y])

İlk birkaç eğitim adımı için sayısal denkliği karşılaştırın.

Sayısal denklik için ek tavsiyeler için Doğruluğu doğrulama ve sayısal denklik not defterine de bakabilirsiniz.

np.testing.assert_allclose(model_tf1.logs['lr'], model_tf2.logs['lr'])
np.testing.assert_allclose(model_tf1.logs['loss'], model_tf2.logs['loss'])
for step in range(step_num):
  for name in model_tf1.logs['layer_out'][step]:
    np.testing.assert_allclose(
        model_tf1.logs['layer_out'][step][name],
        model_tf2.logs['layer_out'][step][name])

Birim testleri

Taşıma kodunuzda hata ayıklamaya yardımcı olabilecek birkaç birim testi türü vardır.

  1. Tek ileri geçiş doğrulaması
  2. Birkaç adım için model eğitimi sayısal denklik doğrulaması
  3. Karşılaştırmalı çıkarım performansı
  4. Eğitilmiş model, sabit ve basit veri noktalarında doğru tahminler yapar

Farklı konfigürasyonlara sahip modelleri test etmek için @parameterized.parameters kullanabilirsiniz. Kod örneği ile ayrıntılar .

Aynı test senaryosunda oturum API'lerini ve istekli yürütmeyi çalıştırmanın mümkün olduğunu unutmayın. Aşağıdaki kod parçacıkları nasıl olduğunu gösterir.

import unittest

class TestNumericalEquivalence(unittest.TestCase):

  # copied from code samples above
  def setup(self):
    # record statistics for 100 training steps
    step_num = 100

    # setup TF 1 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      # run TF1.x code in graph mode with context management
      graph = tf.Graph()
      with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
        self.model_tf1 = SimpleModelWrapper()
        # build the model
        inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
        labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
        spec = self.model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
        train_op = spec.train_op

        sess.run(tf.compat.v1.global_variables_initializer())
        for step in range(step_num):
          # log everything and update the model for one step
          logs, _ = sess.run(
              [self.model_tf1.logged_ops, train_op],
              feed_dict={inputs: fake_x, labels: fake_y})
          self.model_tf1.update_logs(logs)

    # setup TF2 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      self.model_tf2 = SimpleModel(params)
      for step in range(step_num):
        self.model_tf2.train_step([fake_x, fake_y])

  def test_learning_rate(self):
    np.testing.assert_allclose(
        self.model_tf1.logs['lr'],
        self.model_tf2.logs['lr'])

  def test_training_loss(self):
    # adopt different tolerance strategies before and after 10 steps
    first_n_step = 10

    # abosolute difference is limited below 1e-5
    # set `equal_nan` to be False to detect potential NaN loss issues
    abosolute_tolerance = 1e-5
    np.testing.assert_allclose(
        actual=self.model_tf1.logs['loss'][:first_n_step],
        desired=self.model_tf2.logs['loss'][:first_n_step],
        atol=abosolute_tolerance,
        equal_nan=False)

    # relative difference is limited below 5%
    relative_tolerance = 0.05
    np.testing.assert_allclose(self.model_tf1.logs['loss'][first_n_step:],
                               self.model_tf2.logs['loss'][first_n_step:],
                               rtol=relative_tolerance,
                               equal_nan=False)

Hata ayıklama araçları

tf.baskı

tf.print ve print/logging.info karşılaştırması

  • Yapılandırılabilir argümanlarla, tf.print , basılı tensörler için her boyutun ilk ve son birkaç öğesini yinelemeli olarak gösterebilir. Ayrıntılar için API belgelerine bakın.
  • İstekli yürütme için, hem print hem de tf.print , tensörün değerini yazdırır. Ancak print , kodunuzu potansiyel olarak yavaşlatabilecek aygıttan ana bilgisayara kopyalamayı içerebilir.
  • tf.function içindeki kullanımı içeren grafik modu için, gerçek tensör değerini yazdırmak için tf.print kullanmanız gerekir. tf.print grafikte bir op olarak derlenirken, print ve logging.info yalnızca izleme zamanında oturum açar, bu genellikle istediğiniz şey değildir.
  • tf.print ayrıca tf.RaggedTensor ve tf.sparse.SparseTensor gibi bileşik tensörlerin yazdırılmasını da destekler.
  • Metrikleri ve değişkenleri izlemek için bir geri arama da kullanabilirsiniz. Lütfen günlükler dict ve self.model özniteliği ile özel geri aramaların nasıl kullanılacağını kontrol edin.

tf.print vs tf.function içindeki baskı

# `print` prints info of tensor object
# `tf.print` prints the tensor value
@tf.function
def dummy_func(num):
  num += 1
  print(num)
  tf.print(num)
  return num

_ = dummy_func(tf.constant([1.0]))

# Output:
# Tensor("add:0", shape=(1,), dtype=float32)
# [2]
tutucu14 l10n-yer
Tensor("add:0", shape=(1,), dtype=float32)
[2]

tf.distribute.Strateji

  • tf.function içeren tf.print , örneğin TPUStrategy veya ParameterServerStrategy kullanırken işçiler üzerinde yürütülürse, yazdırılan değerleri bulmak için çalışan/parametre sunucusu günlüklerini kontrol etmeniz gerekir.
  • print veya logging.info için, ParameterServerStrategy kullanılırken günlükler koordinatörde yazdırılacak ve TPU'lar kullanılırken günlükler işçi0 üzerindeki STDOUT'ta yazdırılacaktır.

tf.keras.Model

  • Sıralı ve Fonksiyonel API modellerini kullanırken bazı katmanlardan sonra model girdileri veya ara özellikler gibi değerleri yazdırmak istiyorsanız aşağıdaki seçeneklere sahipsiniz.
    1. Girdileri tf.print özel bir katman yazın .
    2. İncelemek istediğiniz ara çıktıları model çıktılarına dahil edin.
  • tf.keras.layers.Lambda katmanları (de)serileştirme sınırlamalarına sahiptir. Kontrol noktası yükleme sorunlarını önlemek için bunun yerine özel bir alt sınıf katmanı yazın. Daha fazla ayrıntı için API belgelerine bakın.
  • Gerçek değerlere erişiminiz yoksa, bunun yerine yalnızca sembolik Keras tensör nesnelerine erişiminiz varsa, bir tf.print içinde ara çıktıları tf.keras.callbacks.LambdaCallback .

Seçenek 1: özel bir katman yazın

class PrintLayer(tf.keras.layers.Layer):
  def call(self, inputs):
    tf.print(inputs)
    return inputs

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # use custom layer to tf.print intermediate features
  out_3 = PrintLayer()(out_2)
  model = tf.keras.Model(inputs=inputs, outputs=out_3)
  return model

model = get_model()
model.compile(optimizer="adam", loss="mse")
model.fit([1, 2, 3], [0.0, 0.0, 1.0])
tutucu16 l10n-yer
[[-0.327884018]
 [-0.109294668]
 [-0.218589336]]
1/1 [==============================] - 0s 280ms/step - loss: 0.6077
<keras.callbacks.History at 0x7f63d46bf190>

Seçenek 2: incelemek istediğiniz ara çıktıları model çıktılarına dahil edin.

Böyle bir durumda Model.fit kullanmak için bazı özelleştirmelere ihtiyacınız olabileceğini unutmayın.

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # include intermediate values in model outputs
  model = tf.keras.Model(
      inputs=inputs,
      outputs={
          'inputs': inputs,
          'out_1': out_1,
          'out_2': out_2})
  return model

pdb

Hata ayıklama için ara değerleri incelemek için hem terminalde hem de Colab'da pdb'yi kullanabilirsiniz.

Grafiği TensorBoard ile görselleştirin

TensorFlow grafiğini TensorBoard ile inceleyebilirsiniz . TensorBoard ayrıca colab üzerinde desteklenir . TensorBoard, özetleri görselleştirmek için harika bir araçtır. Öğrenme hızını, model ağırlıklarını, gradyan ölçeğini, eğitim/doğrulama ölçümlerini karşılaştırmak ve hatta eğitim süreci aracılığıyla TF1.x modeli ile taşınan TF2 modeli arasındaki ara çıktıları modellemek ve değerlerin beklendiği gibi görünüp görünmediğini görmek için kullanabilirsiniz.

TensorFlow Profil Oluşturucu

TensorFlow Profiler , GPU'larda/TPU'larda yürütme zaman çizelgesini görselleştirmenize yardımcı olabilir. Temel kullanımı için bu Colab Demosuna göz atabilirsiniz.

MultiProcessRunner

MultiProcessRunner , MultiWorkerMirrorredStrategy ve ParameterServerStrategy ile hata ayıklama yaparken kullanışlı bir araçtır. Kullanımı için bu somut örneğe göz atabilirsiniz.

Spesifik olarak bu iki stratejinin durumları için, 1) yalnızca akışlarını kapsayacak birim testlerine sahip olmanız değil, 2) aynı zamanda her girişimde gerçek dağıtılmış işi başlatmaktan kaçınmak için birim testinde kullanarak hataları yeniden oluşturmaya çalışmanız önerilir. bir düzeltme.