![]() | ![]() | ![]() | ![]() |
يعد تنفيذ 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.04267077 -0.02450868 -0.0284728 0.02962056 0.01268288 -0.02380248 0.01629823 0.02717735 0.05674956 -0.02006865]]
بينما تحتوي نماذج 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])
التالي:
- قم بإنشاء النموذج.
- مشتقات دالة الخسارة فيما يتعلق بمعلمات النموذج.
- استراتيجية لتحديث المتغيرات بالاعتماد على المشتقات.
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)))
0a5assigna9f0 print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 1.027
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 3.0401711463928223, B = 2.0334768295288086
الادخار القائم على الكائن
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('./ckpt/')
'./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 0x7f9354a431d0>
المقاييس الموجهة للكائنات
يتم تخزين 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.1613010233.kokoro-gcp-ubuntu-prod-1675300897.1619.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.9964873790740967 secs GPU: 0.04042506217956543 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 .