Lihat di TensorFlow.org | Jalankan di Google Colab | Lihat sumber di GitHub | Unduh buku catatan |
Notebook ini mendemonstrasikan cara men-debug pipeline pelatihan saat bermigrasi ke TF2. Ini terdiri dari komponen berikut:
- Langkah-langkah yang disarankan dan contoh kode untuk men-debug saluran pelatihan
- Alat untuk debugging
- Sumber daya terkait lainnya
Satu asumsi adalah Anda memiliki kode TF1.x dan model terlatih untuk perbandingan, dan Anda ingin membuat model TF2 yang mencapai akurasi validasi serupa.
Notebook ini TIDAK mencakup masalah kinerja debug untuk pelatihan/kecepatan inferensi atau penggunaan memori.
Alur kerja debug
Di bawah ini adalah alur kerja umum untuk men-debug saluran pelatihan TF2 Anda. Perhatikan bahwa Anda tidak perlu mengikuti langkah-langkah ini secara berurutan. Anda juga dapat menggunakan pendekatan pencarian biner di mana Anda menguji model dalam langkah menengah dan mempersempit ruang lingkup debugging.
Perbaiki kesalahan kompilasi dan runtime
Validasi forward pass tunggal (dalam panduan terpisah)
sebuah. Pada perangkat CPU tunggal
- Verifikasi variabel dibuat hanya sekali
- Periksa jumlah variabel, nama, dan bentuk yang cocok
- Setel ulang semua variabel, periksa kesetaraan numerik dengan semua keacakan dinonaktifkan
- Sejajarkan pembuatan angka acak, periksa kesetaraan numerik dalam inferensi
- (Opsional) Periksa pos pemeriksaan dimuat dengan benar dan model TF1.x/TF2 menghasilkan keluaran yang identik
B. Pada perangkat GPU/TPU tunggal
C. Dengan strategi multi-perangkat
Model pelatihan validasi kesetaraan numerik untuk beberapa langkah (contoh kode tersedia di bawah)
sebuah. Validasi langkah pelatihan tunggal menggunakan data kecil dan tetap pada perangkat CPU tunggal. Secara khusus, periksa kesetaraan numerik untuk komponen berikut:
- perhitungan kerugian
- metrik
- kecepatan belajar
- perhitungan dan pembaruan gradien
B. Periksa statistik setelah melatih 3 langkah atau lebih untuk memverifikasi perilaku pengoptimal seperti momentum, masih dengan data tetap pada perangkat CPU tunggal
C. Pada perangkat GPU/TPU tunggal
D. Dengan strategi multi-perangkat (periksa intro untuk MultiProcessRunner di bagian bawah)
Pengujian cakupan ujung-ke-ujung pada dataset nyata
sebuah. Periksa perilaku pelatihan dengan TensorBoard
- gunakan pengoptimal sederhana misalnya SGD dan strategi distribusi sederhana misalnya
tf.distribute.OneDeviceStrategy
terlebih dahulu - metrik pelatihan
- metrik evaluasi
- cari tahu apa toleransi yang masuk akal untuk keacakan bawaan
B. Periksa kesetaraan dengan pengoptimal tingkat lanjut/penjadwal tingkat pembelajaran/strategi distribusi
C. Periksa kesetaraan saat menggunakan presisi campuran
- gunakan pengoptimal sederhana misalnya SGD dan strategi distribusi sederhana misalnya
Tolok ukur produk tambahan
Mempersiapkan
pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is only available in
# Tensorflow 2.8
pip install -q tf-nightly
Validasi umpan maju tunggal
Validasi forward pass tunggal, termasuk pemuatan pos pemeriksaan, tercakup dalam colab yang berbeda.
import sys
import unittest
import numpy as np
import tensorflow as tf
import tensorflow.compat.v1 as v1
Model pelatihan validasi kesetaraan numerik untuk beberapa langkah
Siapkan konfigurasi model dan siapkan dataset palsu.
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
Tentukan model TF1.x.
# 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])
Kelas v1.keras.utils.DeterministicRandomTestTool
berikut menyediakan scope()
yang dapat membuat operasi acak stateful menggunakan benih yang sama di kedua grafik/sesi TF1 dan eksekusi bersemangat,
Alat ini menyediakan dua mode pengujian:
-
constant
yang menggunakan benih yang sama untuk setiap operasi tidak peduli berapa kali dipanggil dan, -
num_random_ops
yang menggunakan jumlah operasi acak stateful yang diamati sebelumnya sebagai benih operasi.
Ini berlaku baik untuk operasi acak stateful yang digunakan untuk membuat dan menginisialisasi variabel, dan untuk operasi acak stateful yang digunakan dalam komputasi (seperti untuk lapisan putus sekolah).
random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
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.
Jalankan model TF1.x dalam mode grafik. Kumpulkan statistik untuk 3 langkah pelatihan pertama untuk perbandingan kesetaraan numerik.
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)
/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()
Tentukan model TF2.
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
Jalankan model TF2 dalam mode bersemangat. Kumpulkan statistik untuk 3 langkah pelatihan pertama untuk perbandingan kesetaraan numerik.
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])
Bandingkan kesetaraan numerik untuk beberapa langkah pelatihan pertama.
Anda juga dapat memeriksa buku catatan Validasi kebenaran & kesetaraan numerik untuk saran tambahan untuk kesetaraan numerik.
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])
Tes unit
Ada beberapa jenis pengujian unit yang dapat membantu men-debug kode migrasi Anda.
- Validasi umpan maju tunggal
- Model pelatihan validasi kesetaraan numerik untuk beberapa langkah
- Kinerja inferensi tolok ukur
- Model yang terlatih membuat prediksi yang benar pada titik data yang tetap dan sederhana
Anda dapat menggunakan @parameterized.parameters
untuk menguji model dengan konfigurasi yang berbeda. Detail dengan contoh kode .
Perhatikan bahwa dimungkinkan untuk menjalankan API sesi dan eksekusi bersemangat dalam kasus pengujian yang sama. Cuplikan kode di bawah ini menunjukkan caranya.
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)
Alat debug
tf.print
tf.print vs print/logging.info
- Dengan argumen yang dapat dikonfigurasi,
tf.print
dapat secara rekursif menampilkan beberapa elemen pertama dan terakhir dari setiap dimensi untuk tensor tercetak. Periksa dokumen API untuk detailnya. - Untuk eksekusi yang bersemangat,
print
dantf.print
mencetak nilai tensor. Tetapiprint
mungkin melibatkan salinan perangkat-ke-host, yang berpotensi memperlambat kode Anda. - Untuk mode grafik termasuk penggunaan di dalam
tf.function
, Anda perlu menggunakantf.print
untuk mencetak nilai tensor yang sebenarnya.tf.print
dikompilasi menjadi sebuah op dalam grafik, sedangkanprint
danlogging.info
hanya masuk pada waktu penelusuran, yang seringkali bukan yang Anda inginkan. -
tf.print
juga mendukung pencetakan komposit tensor sepertitf.RaggedTensor
dantf.sparse.SparseTensor
. - Anda juga dapat menggunakan panggilan balik untuk memantau metrik dan variabel. Silakan periksa cara menggunakan panggilan balik khusus dengan dict log dan atribut self.model .
tf.print vs cetak di dalam tf.function
# `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]
Tensor("add:0", shape=(1,), dtype=float32) [2]
tf.distribute.Strategy
- Jika
tf.function
yang berisitf.print
dijalankan pada pekerja, misalnya saat menggunakanTPUStrategy
atauParameterServerStrategy
, Anda perlu memeriksa log server pekerja/parameter untuk menemukan nilai yang dicetak. - Untuk
print
ataulogging.info
, log akan dicetak pada koordinator saat menggunakanParameterServerStrategy
, dan log akan dicetak pada STDOUT pada worker0 saat menggunakan TPU.
tf.keras.Model
- Saat menggunakan model API Sequential dan Fungsional, jika Anda ingin mencetak nilai, misalnya input model atau fitur perantara setelah beberapa lapisan, Anda memiliki opsi berikut.
- Tulis lapisan khusus yang
tf.print
inputnya. - Sertakan keluaran antara yang ingin Anda periksa dalam keluaran model.
- Tulis lapisan khusus yang
- Lapisan
tf.keras.layers.Lambda
memiliki batasan (de)serialization. Untuk menghindari masalah pemuatan pos pemeriksaan, tulislah lapisan subkelas khusus sebagai gantinya. Periksa dokumen API untuk detail selengkapnya. - Anda tidak dapat
tf.print
output perantara ditf.keras.callbacks.LambdaCallback
jika Anda tidak memiliki akses ke nilai sebenarnya, tetapi hanya ke objek tensor Keras simbolis.
Opsi 1: tulis lapisan khusus
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])
[[-0.327884018] [-0.109294668] [-0.218589336]] 1/1 [==============================] - 0s 280ms/step - loss: 0.6077 <keras.callbacks.History at 0x7f63d46bf190>
Opsi 2: sertakan keluaran antara yang ingin Anda periksa dalam keluaran model.
Perhatikan bahwa dalam kasus seperti itu, Anda mungkin memerlukan beberapa penyesuaian untuk menggunakan Model.fit
.
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
Anda dapat menggunakan pdb di terminal dan Colab untuk memeriksa nilai antara untuk proses debug.
Visualisasikan grafik dengan TensorBoard
Anda dapat memeriksa grafik TensorFlow dengan TensorBoard . TensorBoard juga didukung di colab . TensorBoard adalah alat yang hebat untuk memvisualisasikan ringkasan. Anda dapat menggunakannya untuk membandingkan kecepatan pembelajaran, bobot model, skala gradien, metrik pelatihan/validasi, atau bahkan memodelkan keluaran antara antara model TF1.x dan model TF2 yang dimigrasikan melalui proses pelatihan dan melihat apakah nilainya terlihat seperti yang diharapkan.
Profiler TensorFlow
TensorFlow Profiler dapat membantu Anda memvisualisasikan timeline eksekusi pada GPU/TPU. Anda dapat melihat Demo Colab ini untuk penggunaan dasarnya.
MultiProcessRunner
MultiProcessRunner adalah alat yang berguna saat debugging dengan MultiWorkerMirroredStrategy dan ParameterServerStrategy. Anda dapat melihat contoh konkret ini untuk penggunaannya.
Khusus untuk kasus kedua strategi ini, Anda disarankan untuk 1) tidak hanya memiliki pengujian unit untuk menutupi alirannya, 2) tetapi juga mencoba mereproduksi kegagalan menggunakannya dalam pengujian unit untuk menghindari peluncuran tugas terdistribusi nyata setiap kali mereka mencoba perbaikan.