سخنرانی ها ، جلسات محصول ، کارگاه ها و موارد دیگر را از لیست پخش Google I / O مشاهده کنید

اعدام با اشتیاق

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

اجرای مشتاق TensorFlow یک محیط برنامه نویسی ضروری است که بدون ایجاد نمودار ، بلافاصله عملیات را ارزیابی می کند: عملیات به جای ساختن نمودار محاسباتی برای اجرای بعدی ، مقادیر مشخصی را برمی گرداند. این کار شروع به کار با مدلهای TensorFlow و اشکال زدایی را آسان می کند ، و همچنین باعث کاهش دیگ بخار می شود. برای دنبال کردن این راهنما ، نمونه های کد زیر را در یک مفسر تعاملی 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 اشیا tf.Tensor به جای دسته های نمادین به گره ها در یک نمودار محاسباتی ، مقادیر بتن را ارجاع می دهند. از آنجا که نمودار محاسباتی برای ساختن و اجرای بعداً در یک جلسه وجود ندارد ، بازرسی نتایج با استفاده از print() یا اشکال زدایی آسان است. ارزیابی ، چاپ و بررسی مقادیر تانسور جریان شیب های محاسباتی را نمی شکند.

اعدام مشتاقانه با NumPy به راحتی کار می کند. عملیات NumPy آرگومان های tf.Tensor را می tf.Tensor . عملیات tf.math پایتون و آرایه های NumPy را به اشیا tf.Tensor می کند. روش tf.Tensor.numpy مقدار شی را به عنوان یک تقسیم 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 خاص فقط می تواند یک شیب را محاسبه کند. تماس های بعدی خطای زمان اجرا ایجاد می کند.

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 کنند. مقادیر مانند 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 بدون نیاز به متغیرهای پنهان ، حالت داخلی اشیا را ذخیره می کند. برای ثبت وضعیت یک 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

شیب های سفارشی

شیب های سفارشی راهی آسان برای کنار زدن شیب ها است. در تابع forward ، شیب را با توجه به ورودی ها ، خروجی ها یا نتایج متوسط ​​تعریف کنید. به عنوان مثال ، در اینجا یک روش آسان برای کوتاه کردن هنجار شیب ها در گذر عقب وجود دارد:

@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.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

کارایی

محاسبات در هنگام اجرای مشتاقانه به طور خودکار به پردازنده های گرافیکی بارگیری می شود. اگر می خواهید جایی را که یک محاسبه اجرا می شود کنترل کنید می توانید آن را در یک 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 دارای مزایایی برای آموزش توزیع شده ، بهینه سازی عملکرد و استقرار تولید است. برای tf.function این شکاف ، TensorFlow 2.0 function s را از طریق tf.function API tf.function کند. برای اطلاعات بیشتر ، به راهنمای عملکرد tf.f مراجعه کنید .