احفظ التاريخ! يعود مؤتمر Google I / O من 18 إلى 20 مايو. سجل الآن
ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

تنفيذ حريص

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يعد تنفيذ TensorFlow الحثيث بيئة برمجة إلزامية تقوم بتقييم العمليات على الفور ، دون إنشاء الرسوم البيانية: تعيد العمليات قيمًا ملموسة بدلاً من إنشاء رسم بياني حسابي لتشغيله لاحقًا. هذا يجعل من السهل البدء في نماذج TensorFlow وتصحيح الأخطاء ، كما أنه يقلل من المستوى المعياري أيضًا. لمتابعة هذا الدليل ، قم بتشغيل نماذج التعليمات البرمجية أدناه في مترجم python تفاعلي.

التنفيذ الحثيث هو عبارة عن منصة تعلم آلي مرنة للبحث والتجريب ، مما يوفر:

  • واجهة سهلة الاستخدام - قم ببناء الكود الخاص بك بشكل طبيعي واستخدم هياكل بيانات Python. كرر بسرعة على النماذج الصغيرة والبيانات الصغيرة.
  • تصحيح أخطاء أسهل - قم بالاتصال مباشرة لفحص النماذج قيد التشغيل واختبار التغييرات. استخدم أدوات تصحيح أخطاء Python القياسية للإبلاغ الفوري عن الأخطاء.
  • تدفق التحكم الطبيعي - استخدم تدفق التحكم في Python بدلاً من تدفق التحكم في الرسم البياني ، مما يبسط مواصفات النماذج الديناميكية.

يدعم التنفيذ الحثيث معظم عمليات TensorFlow وتسريع وحدة معالجة الرسومات.

الإعداد والاستخدام الأساسي

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 - والآن يقومون على الفور بتقييم قيمهم وإعادتها إلى Python. tf.Tensor تشير كائنات tf.Tensor إلى قيم محددة بدلاً من المقابض الرمزية للعقد في الرسم البياني الحسابي. نظرًا لعدم وجود رسم بياني حسابي ليتم إنشاؤه وتشغيله لاحقًا في الجلسة ، فمن السهل فحص النتائج باستخدام print() أو مصحح الأخطاء. تقييم وطباعة وفحص قيم الموتر لا يكسر التدفق لحساب التدرجات.

يعمل التنفيذ الحثيث بشكل جيد مع NumPy . تقبل عمليات tf.Tensor وسيطات tf.Tensor . تقوم عمليات TensorFlow tf.math بتحويل كائنات Python ومصفوفات 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

يحتوي هذا على شروط تعتمد على قيم الموتر ويقوم بطباعة هذه القيم في وقت التشغيل.

تدريب حريص

تدرجات الحوسبة

التمايز التلقائي مفيد لتنفيذ خوارزميات التعلم الآلي مثل backpropagation لتدريب الشبكات العصبية. أثناء التنفيذ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]')

بي إن جي

المتغيرات والمحسنات

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

الادخار القائم على الكائن

A 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 إلى 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 للاستدعاء ، واسترداد النتيجة باستخدام طريقة 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 لتسجيل ملخصات المتغير في التنفيذ 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

أداء

يتم إلغاء تحميل الحساب تلقائيًا إلى وحدات معالجة الرسومات أثناء التنفيذ الحثيث. إذا كنت تريد التحكم في مكان تشغيل الحساب ، فيمكنك 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 يمكن tf.function بتنفيذ tf.function . لكن هذه الفجوة تنمو بشكل أكبر بالنسبة للنماذج ذات العمليات الحسابية الأقل ، وهناك عمل يتعين القيام به لتحسين مسارات الشفرة الساخنة للنماذج التي تحتوي على الكثير من العمليات الصغيرة.

العمل مع الوظائف

في حين أن التنفيذ الجاد يجعل التطوير وتصحيح الأخطاء أكثر تفاعلية ، فإن تنفيذ الرسم البياني بنمط TensorFlow 1.x له مزايا للتدريب الموزع وتحسينات الأداء ونشر الإنتاج. لسد هذه الفجوة ، يقدم TensorFlow 2.0 function عبر واجهة برمجة تطبيقات tf.function . لمزيد من المعلومات ، راجع دليل وظيفة tf .