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

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

اجرای مشتاق TensorFlow یک محیط برنامه نویسی ضروری است که عملیات را بلافاصله بدون ایجاد نمودار ارزیابی می کند: عملیات به جای ساختن یک نمودار محاسباتی که بعداً اجرا شود ، مقادیر مشخصی را برمی گرداند. این باعث می شود که بتوانید با TensorFlow و مدلهای اشکال زدایی شروع به کار کنید و صفحه دیگ بخار را نیز کاهش دهید. برای همراهی با این راهنما، اجرای نمونه کد زیر در تعاملی python مفسر.

اجرای مشتاق یک پلت فرم یادگیری ماشین انعطاف پذیر برای تحقیق و آزمایش است که شامل موارد زیر است:

  • یک رابط بصری -Structure کد خود را به طور طبیعی و با استفاده از ساختمان داده پایتون. به سرعت در مدل های کوچک و داده های کوچک تکرار کنید.
  • آسان تر اشکال زدایی عملیات، تماس به طور مستقیم به بازرسی در حال اجرا مدل ها و تغییرات آزمون. از ابزارهای استاندارد اشکال زدایی پایتون برای گزارش فوری خطاها استفاده کنید.
  • کنترل طبیعی جریان کنترل جریان استفاده پایتون به جای کنترل جریان نمودار، ساده مشخصات مدل های پویا.

اجرای مشتاق از اکثر عملیات 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() و یا یک دیباگر. ارزیابی ، چاپ و بررسی مقادیر تانسور ، جریان محاسبه گرادیان را قطع نمی کند.

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

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 [==============================] - 1s 0us/step
11501568/11490434 [==============================] - 1s 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.01776254  0.03069138 -0.01169398  0.04716408  0.00278952 -0.0160556
   0.00397673 -0.02701374  0.01099346 -0.01109808]]

در حالی که مدل های 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 مانند ارزش دیده در طول آموزش به تمایز اتوماتیک آسان تر است.

مجموعه متغیرها را می توان در لایه ها یا مدل ها ، همراه با روش هایی که بر روی آنها کار می کنند ، قرار داد. مشاهده لایه های سفارشی 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: 67.455
Loss at step 000: 64.856
Loss at step 020: 29.757
Loss at step 040: 13.947
Loss at step 060: 6.824
Loss at step 080: 3.613
Loss at step 100: 2.165
Loss at step 120: 1.512
Loss at step 140: 1.218
Loss at step 160: 1.085
Loss at step 180: 1.025
Loss at step 200: 0.998
Loss at step 220: 0.985
Loss at step 240: 0.980
Loss at step 260: 0.977
Loss at step 280: 0.976
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.976
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.9953086376190186, B = 2.0608654022216797

صرفه جویی مبتنی بر شی

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 0x7f0d4c6a38d0>

معیارهای شی گرا

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.1630113988.kokoro-gcp-ubuntu-prod-1335170857.27045.0.v2

موضوعات تمایز خودکار پیشرفته

مدلهای پویا

tf.GradientTape همچنین می توانید در مدل های پویا استفاده می شود. این مثال برای یک خط عقبگرد جستجو الگوریتم به نظر می رسد مانند کد نرمال نامپای، به جز شیب وجود دارد و مشتقپذیر است، با وجود کنترل جریان پیچیده:

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

کارایی

محاسبات در حین اجرای مشتاقانه به طور خودکار بر روی GPU بارگیری می شود. اگر شما می خواهید کنترل بر که در آن محاسبات اجرا می شود شما می توانید آن را در یک محصور 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.8828294277191162 secs
GPU: 0.04031491279602051 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 /tmp/ipykernel_27045/406964202.py: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 /tmp/ipykernel_27045/406964202.py: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 بازدید کنندگان از طریق tf.function API. برای اطلاعات بیشتر، نگاه کنید به tf.function راهنمای.