הצג באתר TensorFlow.org | הפעל בגוגל קולאב | צפה במקור ב-GitHub | הורד מחברת |
מחברת זו מדגים כיצד לנפות באגים בצינור הדרכה בעת הגירה ל-TF2. הוא מורכב מהרכיבים הבאים:
- שלבים מוצעים ודוגמאות קוד לאיתור באגים בצינור הדרכה
- כלים לניפוי באגים
- משאבים קשורים אחרים
הנחה אחת היא שיש לך קוד TF1.x ומודלים מאומנים להשוואה, ואתה רוצה לבנות מודל TF2 שישיג דיוק אימות דומה.
מחברת זו אינה מכסה בעיות ביצועי ניפוי באגים עבור מהירות אימון/הסקת מסקנות או שימוש בזיכרון.
זרימת עבודה של ניפוי באגים
להלן זרימת עבודה כללית לאיתור באגים בצינורות ההדרכה של TF2. שים לב שאינך צריך לבצע את השלבים הבאים לפי הסדר. אתה יכול גם להשתמש בגישת חיפוש בינארי שבה אתה בודק את המודל בשלב ביניים ומצמצם את היקף ניפוי הבאגים.
תקן שגיאות קומפילציה וזמן ריצה
אימות מעבר בודד קדימה ( במדריך נפרד)
א. במכשיר מעבד יחיד
- ודא שמשתנים נוצרים פעם אחת בלבד
- בדוק התאמה בין ספירת משתנים, שמות וצורות
- אפס את כל המשתנים, בדוק שקילות מספרית כאשר כל האקראיות מושבתת
- יישר יצירת מספרים אקראי, בדוק שקילות מספרית בהסקת מסקנות
- (אופציונלי) נקודות הבידוק נטענות כראוי ודגמי TF1.x/TF2 מייצרים פלט זהה
ב. במכשיר GPU/TPU יחיד
ג. עם אסטרטגיות ריבוי מכשירים
אימות שוויון מספרי של אימון מודל עבור כמה שלבים (דגימות קוד זמינות להלן)
א. אימות שלב אימון בודד באמצעות נתונים קטנים וקבועים במכשיר מעבד יחיד. באופן ספציפי, בדוק שקילות מספרית עבור הרכיבים הבאים
- חישוב הפסדים
- מדדים
- קצב למידה
- חישוב ועדכון שיפוע
ב. בדוק נתונים סטטיסטיים לאחר אימון של 3 שלבים או יותר כדי לאמת התנהגויות אופטימיזציה כמו המומנטום, עדיין עם נתונים קבועים במכשיר מעבד יחיד
ג. במכשיר GPU/TPU יחיד
ד. עם אסטרטגיות ריבוי מכשירים (בדוק את המבוא עבור MultiProcessRunner בתחתית)
בדיקת כיסוי מקצה לקצה על מערך נתונים אמיתי
א. בדוק התנהגויות אימון עם TensorBoard
- השתמש בכלי אופטימיזציה פשוטים כגון SGD ואסטרטגיות הפצה פשוטות כגון
tf.distribute.OneDeviceStrategy
תחילה - מדדי אימון
- מדדי הערכה
- להבין מהי הסובלנות הסבירה לאקראיות אינהרנטית
ב. בדוק שקילות עם אסטרטגיות מתקדמות למיטוב/תזמון קצב למידה/הפצה
ג. בדוק שקילות בעת שימוש בדיוק מעורב
- השתמש בכלי אופטימיזציה פשוטים כגון SGD ואסטרטגיות הפצה פשוטות כגון
מדדי מוצר נוספים
להכין
pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is only available in
# Tensorflow 2.8
pip install -q tf-nightly
אימות מעבר בודד קדימה
אימות מעבר בודד קדימה, כולל טעינת מחסום, מכוסה בקולאב אחר.
import sys
import unittest
import numpy as np
import tensorflow as tf
import tensorflow.compat.v1 as v1
אימון מודל אימות שקילות מספרית עבור כמה שלבים
הגדר תצורת מודל והכן מערך נתונים מזויף.
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.
# 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])
scope()
v1.keras.utils.DeterministicRandomTestTool
הכלי מספק שני מצבי בדיקה:
-
constant
שמשתמש באותו זרע עבור כל פעולה בודדת, לא משנה כמה פעמים הוא נקרא ו, -
num_random_ops
שמשתמש במספר הפעולות האקראיות הסטציונליות שנצפו קודם לכן בתור תחילת הפעולה.
זה חל הן על פעולות אקראיות מצב המשמשות ליצירה ואתחול משתנים, והן על פעולות אקראיות מצביות המשמשות בחישוב (כגון עבור שכבות נשירה).
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.
הפעל את מודל TF1.x במצב גרף. אסוף נתונים סטטיסטיים עבור 3 שלבי האימון הראשונים להשוואת שוויון מספרי.
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()
הגדר את דגם 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
הפעל את דגם TF2 במצב להוט. אסוף נתונים סטטיסטיים עבור 3 שלבי האימון הראשונים להשוואת שוויון מספרי.
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])
השווה שוויון מספרי עבור כמה צעדי אימון ראשונים.
אתה יכול גם לעיין במחברת אימות נכונות ושקילות מספרית לקבלת עצות נוספות לגבי שקילות מספרית.
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])
בדיקות יחידה
ישנם כמה סוגים של בדיקות יחידות שיכולות לעזור בניפוי באגים בקוד ההעברה שלך.
- אימות מעבר בודד קדימה
- אימון מודל אימות שקילות מספרית עבור כמה שלבים
- ביצועי מסקנות בנצ'מרק
- המודל המאומן עושה תחזיות נכונות על נקודות נתונים קבועות ופשוטות
אתה יכול להשתמש ב- @parameterized.parameters
כדי לבדוק מודלים עם תצורות שונות. פרטים עם דוגמת קוד .
שימו לב שאפשר להפעיל ממשקי API של הפעלה וביצוע נלהב באותו מקרה בדיקה. קטעי הקוד למטה מראים כיצד.
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)
כלי איתור באגים
tf.print
tf.print לעומת print/logging.info
- עם ארגומנטים הניתנים להגדרה,
tf.print
יכול להציג באופן רקורסיבי את האלמנטים הראשונים והאחרונים של כל מימד עבור טנזורים מודפסים. בדוק את מסמכי ה-API לקבלת פרטים. - לביצוע נלהב, גם
print
וגםtf.print
מדפיסים את הערך של הטנזור. אבלprint
עשויה לכלול העתקה ממכשיר למארח, מה שעלול להאט את הקוד שלך. - עבור מצב גרף כולל שימוש בתוך
tf.function
, עליך להשתמש ב-tf.print
כדי להדפיס את ערך הטנזור האמיתי.tf.print
מורכב לאופ בגרף, בעוד ש-print
ו-logging.info
נרשמים רק בזמן המעקב, וזה לרוב לא מה שאתה רוצה. -
tf.print
תומך גם בהדפסת טנסורים מרוכבים כמוtf.RaggedTensor
ו-tf.sparse.SparseTensor
. - אתה יכול גם להשתמש בהתקשרות חוזרת כדי לנטר מדדים ומשתנים. אנא בדוק כיצד להשתמש בהתקשרויות חוזרות מותאמות אישית עם יומנים dict ותכונת self.model .
tf.print לעומת הדפסה בתוך 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
- אם הפונקציה
tf.print
tf.function
על העובדים, למשל בעת שימוש ב-TPUStrategy
אוParameterServerStrategy
, עליך לבדוק את יומני שרת עובד/פרמטרים כדי למצוא את הערכים המודפסים. - עבור
print
אוlogging.info
, יומנים יודפסו על המתאם בעת שימוש ב-ParameterServerStrategy
, ויומנים יודפסו על STDOUT ב-worker0 בעת שימוש ב-TPUs.
tf.keras.Model
- בעת שימוש במודלים רציפים ופונקציונליים API, אם ברצונך להדפיס ערכים, למשל, קלט מודל או תכונות ביניים לאחר כמה שכבות, יש לך את האפשרויות הבאות.
- כתוב שכבה מותאמת אישית
tf.print
את התשומות. - כלול את תפוקות הביניים שברצונך לבדוק בתפוקות הדגם.
- כתוב שכבה מותאמת אישית
- לשכבות
tf.keras.layers.Lambda
.למבדה יש מגבלות (דה) בהמשכה. כדי להימנע מבעיות של טעינת נקודות ביקורת, כתוב במקום זאת שכבת משנה מותאמת אישית. בדוק את מסמכי ה-API לקבלת פרטים נוספים. - אינך יכול להדפיס פלטי ביניים ב-
tf.print
אםtf.keras.callbacks.LambdaCallback
לך גישה לערכים בפועל, אלא רק לאובייקטי הטנזור הסמליים של Keras.
אפשרות 1: כתוב שכבה מותאמת אישית
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>
אפשרות 2: כלול את תפוקות הביניים שברצונך לבדוק בפלטי הדגם.
שים לב שבמקרה כזה, ייתכן שתצטרך כמה התאמות אישיות כדי להשתמש ב- 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
אתה יכול להשתמש ב- pdb גם בטרמינל וגם ב-Colab כדי לבדוק ערכי ביניים לאיתור באגים.
דמיין גרף עם TensorBoard
אתה יכול לבחון את גרף TensorFlow עם TensorBoard . TensorBoard נתמך גם על colab . TensorBoard הוא כלי נהדר לדמיין סיכומים. אתה יכול להשתמש בו כדי להשוות קצב למידה, משקלי מודל, סולם שיפוע, מדדי אימון/אימות, או אפילו מודל פלטי ביניים בין מודל TF1.x למודל TF2 שעבר תהליך ההדרכה ולראות אם הערכים נראים כמצופה.
TensorFlow Profiler
TensorFlow Profiler יכול לעזור לך לדמיין את ציר הזמן של הביצוע ב-GPUs/TPUs. אתה יכול לבדוק את ההדגמה של Colab עבור השימוש הבסיסי שלו.
MultiProcessRunner
MultiProcessRunner הוא כלי שימושי בעת איתור באגים עם MultiWorkerMirroredStrategy ו- ParameterServerStrategy. אתה יכול להסתכל על דוגמה קונקרטית זו לשימוש בה.
במיוחד עבור המקרים של שתי האסטרטגיות הללו, מומלץ 1) לא רק לבצע בדיקות יחידה כדי לכסות את הזרימה שלהן, 2) אלא גם לנסות לשחזר כשלים באמצעותה בבדיקת יחידה כדי להימנע מהשקת עבודה מבוזרת אמיתית בכל פעם שהם מנסים. תיקון.