קלט / פלט של גוגל חוזר 18-20 במאי! שמור מקום ובנה את לוח הזמנים שלך הירשם עכשיו

ביצוע להוט

צפה ב- TensorFlow.org הפעל בגוגל קולאב צפה במקור ב- GitHub הורד מחברת

הביצוע הלהוט של TensorFlow הוא סביבת תכנות הכרחית שמעריכה פעולות באופן מיידי, מבלי לבנות גרפים: פעולות מחזירות ערכים קונקרטיים במקום לבנות גרף חישובי להפעלה מאוחר יותר. זה מקל על תחילת העבודה עם מודלים של TensorFlow וניקוי באגים, וזה מפחית גם את הדוד. כדי לעקוב אחר המדריך הזה, הפעל את דוגמאות הקוד למטה במתורגמן python אינטראקטיבי.

ביצוע להוט הוא פלטפורמת למידת מכונה גמישה למחקר וניסויים, המספקת:

  • ממשק אינטואיטיבי - בנה את הקוד שלך באופן טבעי והשתמש במבני נתונים של Python. חזרו במהירות על דגמים קטנים ונתונים קטנים.
  • איתור באגים קל יותר - התקשר ישירות למבצעים כדי לבדוק מודלים פועלים ולבדוק שינויים. השתמש בכלי איתור באגים רגילים של Python לדיווח מיידי על שגיאות.
  • זרימת בקרה טבעית - השתמש בזרימת בקרת פייתון במקום בזרימת בקרת גרפים, ופשט את המפרט של מודלים דינמיים.

ביצוע להוט תומך ברוב פעולות TensorFlow והאצת GPU.

התקנה ושימוש בסיסי

import os

import tensorflow as tf

import cProfile

ב- Tensorflow 2.0, ביצוע להוט מופעל כברירת מחדל.

tf.executing_eagerly()
True

עכשיו אתה יכול להפעיל פעולות TensorFlow והתוצאות יחזרו מיד:

x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))
hello, [[4.]]

הפעלת ביצוע נלהב משנה את אופן הפעולה של TensorFlow - כעת הם מעריכים מיד ומחזירים את הערכים שלהם לפייתון. אובייקטים tf.Tensor מתייחסים לערכים קונקרטיים במקום לידיות סמליות לצמתים בגרף חישובי. מכיוון שאין גרף חישובי לבנייה ולהפעלה מאוחר יותר בפגישה, קל לבדוק תוצאות באמצעות print() או איתור באגים. הערכה, הדפסה ובדיקת ערכי טנסור אינם מפרים את הזרימה עבור שיפועי מחשוב.

ביצוע להוטים עובד יפה עם NumPy . פעולות tf.Tensor מקבלות טיעוני tf.Tensor . פעולות tf.math tf.math tf.math אובייקטים של פייתון ומערכי tf.Tensor לאובייקטים tf.Tensor . השיטה tf.Tensor.numpy מחזירה את ערך האובייקט כ- ndarray .

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)
tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32)
# Broadcasting support
b = tf.add(a, 1)
print(b)
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32)
# Operator overloading is supported
print(a * b)
tf.Tensor(
[[ 2  6]
 [12 20]], shape=(2, 2), dtype=int32)
# Use NumPy values
import numpy as np

c = np.multiply(a, b)
print(c)
[[ 2  6]
 [12 20]]
# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]
[[1 2]
 [3 4]]

זרימת בקרה דינמית

יתרון מרכזי בביצוע להוט הוא שכל הפונקציונליות של שפת המארח זמינה בזמן שהמודל שלך פועל. כך, למשל, קל לכתוב fizzbuzz :

def fizzbuzz(max_num):
  counter = tf.constant(0)
  max_num = tf.convert_to_tensor(max_num)
  for num in range(1, max_num.numpy()+1):
    num = tf.constant(num)
    if int(num % 3) == 0 and int(num % 5) == 0:
      print('FizzBuzz')
    elif int(num % 3) == 0:
      print('Fizz')
    elif int(num % 5) == 0:
      print('Buzz')
    else:
      print(num.numpy())
    counter += 1
fizzbuzz(15)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

יש לכך תנאים התלויים בערכי טנסור והוא מדפיס ערכים אלה בזמן הריצה.

אימונים נלהבים

שיפועי מחשוב

בידול אוטומטי שימושי להטמעת אלגוריתמים של למידת מכונה, כגון התאמת גב לאימון רשתות עצביות. במהלך ביצוע להוט, השתמש ב-tf.GradientTape כדי לעקוב אחר פעולות לצורך שיפוע מחשוב מאוחר יותר.

אתה יכול להשתמש ב-tf.GradientTape כדי לאמן ו / או לחשב שיפועיםtf.GradientTape . זה שימושי במיוחד עבור לולאות אימון מסובכות.

מכיוון שפעולות שונות יכולות להתרחש במהלך כל שיחה, כל פעולות העברת ההעברה מוקלטות ל"קלטת ". כדי לחשב את השיפוע, הפעל את הקלטת לאחור ואז זרוק אותה.tf.GradientTape מסוים יכול לחשב שיפוע אחד בלבד; שיחות עוקבות מביאות שגיאת זמן ריצה.

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

לאמן מודל

הדוגמה הבאה יוצרת מודל רב שכבתי המסווג את הספרות הסטנדרטיות של MNIST בכתב יד. זה מדגים את ממשקי ה- API של האופטימיזציה והשכבה לבניית גרפים שאפשר להכשיר בסביבת ביצוע נלהבת.

# Fetch and format the mnist data
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
   tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
# Build the model
mnist_model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu',
                         input_shape=(None, None, 1)),
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])

גם ללא הכשרה, התקשר למודל ובדוק את התפוקה בביצוע נלהב:

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[ 0.03667693 -0.03049762 -0.00575869 -0.03993434  0.08212403 -0.04499513
  -0.00077433  0.08982861  0.0706538  -0.02175808]]

בעוד שלמודלים של keras יש לולאת אימונים מובנית (בשיטת fit ), לפעמים אתה צריך התאמה אישית רבה יותר. הנה דוגמה לולאת אימונים המיושמת בלהיטות:

optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

loss_history = []
def train_step(images, labels):
  with tf.GradientTape() as tape:
    logits = mnist_model(images, training=True)

    # Add asserts to check the shape of the output.
    tf.debugging.assert_equal(logits.shape, (32, 10))

    loss_value = loss_object(labels, logits)

  loss_history.append(loss_value.numpy().mean())
  grads = tape.gradient(loss_value, mnist_model.trainable_variables)
  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
def train(epochs):
  for epoch in range(epochs):
    for (batch, (images, labels)) in enumerate(dataset):
      train_step(images, labels)
    print ('Epoch {} finished'.format(epoch))
train(epochs = 3)
Epoch 0 finished
Epoch 1 finished
Epoch 2 finished
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
Text(0, 0.5, 'Loss [entropy]')

png

משתנים ואופטימיזציה

tf.Variable אובייקטים משתנים tf.Tensor ערכים דמויי tf.Tensor משתנים אליהם ניגשת במהלך האימון כדי להקל על הבחנה אוטומטית.

את אוספי המשתנים ניתן לעסוק בשכבות או מודלים, יחד עם שיטות הפועלות עליהם. ראה שכבות ודגמי Keras מותאמים אישית לפרטים. ההבדל העיקרי בין שכבות ומודלים הוא שמודלים מוסיפים שיטות כמו Model.fit , Model.evaluate ו- Model.save .

לדוגמה, ניתן לשכתב את דוגמת הבידול האוטומטית שלמעלה:

class Linear(tf.keras.Model):
  def __init__(self):
    super(Linear, self).__init__()
    self.W = tf.Variable(5., name='weight')
    self.B = tf.Variable(10., name='bias')
  def call(self, inputs):
    return inputs * self.W + self.B
# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# The loss function to be optimized
def loss(model, inputs, targets):
  error = model(inputs) - targets
  return tf.reduce_mean(tf.square(error))

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return tape.gradient(loss_value, [model.W, model.B])

הַבָּא:

  1. צור את המודל.
  2. הנגזרים של אובדן מתפקדים ביחס לפרמטרים של המודל.
  3. אסטרטגיה לעדכון המשתנים על בסיס הנגזרות.
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

steps = 300
for i in range(steps):
  grads = grad(model, training_inputs, training_outputs)
  optimizer.apply_gradients(zip(grads, [model.W, model.B]))
  if i % 20 == 0:
    print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))
Initial loss: 68.712
Loss at step 000: 66.034
Loss at step 020: 30.012
Loss at step 040: 13.941
Loss at step 060: 6.772
Loss at step 080: 3.573
Loss at step 100: 2.146
Loss at step 120: 1.509
Loss at step 140: 1.225
Loss at step 160: 1.098
Loss at step 180: 1.042
Loss at step 200: 1.016
Loss at step 220: 1.005
Loss at step 240: 1.000
Loss at step 260: 0.998
Loss at step 280: 0.997
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.997
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 3.022096633911133, B = 2.0270628929138184

חיסכון מבוסס עצמים

מודל tf.keras.Model כולל שיטת save_weights נוחה המאפשרת ליצור נקודת ביקורת בקלות:

model.save_weights('weights')
status = model.load_weights('weights')

באמצעות tf.train.Checkpoint אתה יכול לקחת שליטה מלאה על תהליך זה.

סעיף זה הוא גרסה מקוצרת של המדריך למחסומי הדרכה .

x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
x.assign(2.)   # Assign a new value to the variables and save.
checkpoint_path = './ckpt/'
checkpoint.save(checkpoint_path)
'./ckpt/-1'
x.assign(11.)  # Change the variable after saving.

# Restore values from the checkpoint
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))

print(x)  # => 2.0
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>

tf.train.Checkpoint וטעינה של מודלים, tf.train.Checkpoint מאחסן את המצב הפנימי של אובייקטים, מבלי לדרוש משתנים מוסתרים. כדי להקליט את מצב model , optimizer והצעד הגלובלי, העבירו אותם ל- tf.train.Checkpoint :

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = 'path/to/model_dir'
if not os.path.exists(checkpoint_dir):
  os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
                           model=model)

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7ff0c18b14e0>

מדדים מונחים עצמים

tf.keras.metrics נשמרים כאובייקטים. עדכן מדד על ידי העברת הנתונים החדשים להתקשרות, ואחזר את התוצאה בשיטת tf.keras.metrics.result , למשל:

m = tf.keras.metrics.Mean("loss")
m(0)
m(5)
m.result()  # => 2.5
m([8, 9])
m.result()  # => 5.5
<tf.Tensor: shape=(), dtype=float32, numpy=5.5>

סיכומים ו- TensorBoard

TensorBoard הוא כלי הדמיה להבנה, ניפוי באגים ואופטימיזציה של תהליך אימון המודל. הוא משתמש באירועי סיכום שנכתבים בזמן ביצוע התוכנית.

אתה יכול להשתמש ב- tf.summary כדי להקליט סיכומי משתנה בביצוע להוט. לדוגמא, לתעד סיכומי loss אחת ל 100 שלבי אימון:

logdir = "./tb/"
writer = tf.summary.create_file_writer(logdir)

steps = 1000
with writer.as_default():  # or call writer.set_as_default() before the loop.
  for i in range(steps):
    step = i + 1
    # Calculate loss with your real train function.
    loss = 1 - 0.001 * step
    if step % 100 == 0:
      tf.summary.scalar('loss', loss, step=step)
ls tb/
events.out.tfevents.1617758981.kokoro-gcp-ubuntu-prod-1009344920.4448.636510.v2

נושאי בידול אוטומטי מתקדמים

דגמים דינמיים

tf.GradientTape יכול לשמש גם במודלים דינמיים. דוגמה זו עבור אלגוריתם חיפוש בקו מסלול חוזר נראית כמו קוד NumPy רגיל, אלא שיש שיפועים והוא נבדל, למרות זרימת הבקרה המורכבת:

def line_search_step(fn, init_x, rate=1.0):
  with tf.GradientTape() as tape:
    # Variables are automatically tracked.
    # But to calculate a gradient from a tensor, you must `watch` it.
    tape.watch(init_x)
    value = fn(init_x)
  grad = tape.gradient(value, init_x)
  grad_norm = tf.reduce_sum(grad * grad)
  init_value = value
  while value > init_value - rate * grad_norm:
    x = init_x - rate * grad
    value = fn(x)
    rate /= 2.0
  return x, value

שיפועים מותאמים אישית

שיפועים מותאמים אישית הם דרך קלה לעקוף שיפועים. בתוך הפונקציה קדימה, הגדר את מעבר הצבע ביחס לתשומות, תפוקות או תוצאות ביניים. לדוגמה, הנה דרך קלה לקטוע את נורמת השיפועים במעבר לאחור:

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
  y = tf.identity(x)
  def grad_fn(dresult):
    return [tf.clip_by_norm(dresult, norm), None]
  return y, grad_fn

שיפועים מותאמים אישית משמשים בדרך כלל כדי לספק שיפוע יציב מבחינה מספרית עבור רצף פעולות:

def log1pexp(x):
  return tf.math.log(1 + tf.exp(x))

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# The gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# However, x = 100 fails because of numerical instability.
grad_log1pexp(tf.constant(100.)).numpy()
nan

כאן, ניתן לפשט את הפונקציה log1pexp בצורה אנליטית עם שיפוע מותאם אישית. היישום להלן עושה שימוש חוזר בערך tf.exp(x) שמחושב במהלך המעבר קדימה - מה שהופך אותו ליעיל יותר על ידי ביטול חישובים מיותרים:

@tf.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.math.log(1 + e), grad

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# As before, the gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# And the gradient computation also works at x = 100.
grad_log1pexp(tf.constant(100.)).numpy()
1.0

ביצועים

חישוב יורד אוטומטית ל- GPUs במהלך ביצוע להוט. אם ברצונך לשלוט היכן פועל חישוב תוכל לכלול אותו tf.device('/gpu:0') (או tf.device('/gpu:0') למעבד):

import time

def measure(x, steps):
  # TensorFlow initializes a GPU the first time it's used, exclude from timing.
  tf.matmul(x, x)
  start = time.time()
  for i in range(steps):
    x = tf.matmul(x, x)
  # tf.matmul can return before completing the matrix multiplication
  # (e.g., can return after enqueing the operation on a CUDA stream).
  # The x.numpy() call below will ensure that all enqueued operations
  # have completed (and will also copy the result to host memory,
  # so we're including a little more than just the matmul operation
  # time).
  _ = x.numpy()
  end = time.time()
  return end - start

shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: {} secs".format(measure(tf.random.normal(shape), steps)))

# Run on GPU, if available:
if tf.config.list_physical_devices("GPU"):
  with tf.device("/gpu:0"):
    print("GPU: {} secs".format(measure(tf.random.normal(shape), steps)))
else:
  print("GPU: not found")
Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 0.8094048500061035 secs
GPU: 0.039966583251953125 secs

ניתן להעתיק אובייקט tf.Tensor להתקן אחר כדי לבצע את פעולותיו:

if tf.config.list_physical_devices("GPU"):
  x = tf.random.normal([10, 10])

  x_gpu0 = x.gpu()
  x_cpu = x.cpu()

  _ = tf.matmul(x_cpu, x_cpu)    # Runs on CPU
  _ = tf.matmul(x_gpu0, x_gpu0)  # Runs on GPU:0
WARNING:tensorflow:From <ipython-input-1-c99eaec55f9a>:4: _EagerTensorBase.gpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.
WARNING:tensorflow:From <ipython-input-1-c99eaec55f9a>:5: _EagerTensorBase.cpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.

מידות

עבור מודלים כבדים במחשוב , כגון אימון ResNet50 ב- GPU, ביצועי ביצוע נלהבים דומים לביצוע tf.function . אך הפער הזה הולך וגדל עבור מודלים עם פחות חישוב ויש עבודה לעשות אופטימיזציה של נתיבי קוד חם למודלים עם הרבה פעולות קטנות.

לעבוד עם פונקציות

בעוד שביצוע להוט הופך את הפיתוח והניפוי באגים לאינטראקטיביים יותר, לביצוע גרפים בסגנון TensorFlow 1.x יתרונות לאימונים מבוזרים, אופטימיזציה לביצועים ופריסת ייצור. כדי לגשר על פער זה, TensorFlow 2.0 מציג function באמצעות ה- API של tf.function . למידע נוסף, עיין במדריך tf.function .