تنفيذ حريص

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

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

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

  • واجهة سهلة الاستخدام -Structure التعليمات البرمجية بشكل طبيعي واستخدام هياكل البيانات بيثون. كرر بسرعة على النماذج الصغيرة والبيانات الصغيرة.
  • التصحيح أسهل التقاط اتصل بالرقم مباشرة لتفقد نماذج تشغيل واختبار التغييرات. استخدم أدوات تصحيح أخطاء 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 الكائنات القيم الخرسانة المرجعية بدلا من مقابض رمزية لالعقد في الرسم البياني الحسابية. حيث لا يوجد رسم بياني الحسابي لبناء وتشغيل في وقت لاحق في الدورة، فإنه من السهل أن تفقد النتائج باستخدام 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)
# 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.01775933 -0.01194787 -0.08372174 -0.06535977  0.00338565 -0.01974326
  -0.04763228  0.00904049 -0.00144051 -0.01944664]]

في حين 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 تشبه القيم الوصول إليها خلال التدريب لجعل التمايز التلقائي أسهل.

يمكن تغليف مجموعات المتغيرات في طبقات أو نماذج ، جنبًا إلى جنب مع الطرق التي تعمل عليها. انظر طبقات 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: 69.909
Loss at step 000: 67.145
Loss at step 020: 30.170
Loss at step 040: 13.859
Loss at step 060: 6.659
Loss at step 080: 3.479
Loss at step 100: 2.074
Loss at step 120: 1.453
Loss at step 140: 1.178
Loss at step 160: 1.056
Loss at step 180: 1.003
Loss at step 200: 0.979
Loss at step 220: 0.968
Loss at step 240: 0.963
Loss at step 260: 0.961
Loss at step 280: 0.960
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.960
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.9515867233276367, B = 2.0210201740264893

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

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 :

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

المقاييس الموجهة للكائنات

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.1632342765.kokoro-gcp-ubuntu-prod-230753280.22287.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

أداء

يتم إلغاء تحميل الحساب تلقائيًا إلى وحدات معالجة الرسومات أثناء التنفيذ الحثيث. إذا كنت تريد السيطرة على حيث يدير حساب يمكنك احتوائه في tf.device('/gpu:0') كتلة (أو ما يعادلها CPU):

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: 1.007401466369629 secs
GPU: 0.04124784469604492 secs

A 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_22287/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_22287/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 دليل.