عرض على TensorFlow.org | تشغيل في Google Colab | عرض المصدر على جيثب | تحميل دفتر |
ملخص
ينتقل هذا الدليل أسفل سطح TensorFlow و Keras لتوضيح كيفية عمل TensorFlow. إذا كنت تريد بدلاً من ذلك البدء فورًا في استخدام Keras ، فراجع مجموعة أدلة Keras .
في هذا الدليل ، ستتعلم كيف يسمح لك TensorFlow بإجراء تغييرات بسيطة على التعليمات البرمجية الخاصة بك للحصول على الرسوم البيانية ، وكيفية تخزين الرسوم البيانية وتمثيلها ، وكيف يمكنك استخدامها لتسريع النماذج الخاصة بك.
هذه نظرة عامة شاملة تغطي كيف تتيح لك tf.function
التبديل من التنفيذ الحثيث إلى تنفيذ الرسم البياني. للحصول على مواصفات أكثر اكتمالاً tf.function
، انتقل إلى دليل tf.function
.
ما هي الرسوم البيانية؟
في الأدلة الثلاثة السابقة ، قمت بتشغيل TensorFlow بلهفة . هذا يعني أن عمليات TensorFlow يتم تنفيذها بواسطة Python ، والتشغيل عن طريق العملية ، وإرجاع النتائج إلى Python.
في حين أن التنفيذ الحثيث له العديد من المزايا الفريدة ، فإن تنفيذ الرسم البياني يتيح إمكانية النقل خارج Python ويميل إلى تقديم أداء أفضل. يعني تنفيذ الرسم البياني أن حسابات الموتر يتم تنفيذها كرسم بياني TensorFlow ، يشار إليه أحيانًا باسم tf.Graph
أو ببساطة "رسم بياني".
الرسوم البيانية هي هياكل بيانات تحتوي على مجموعة من tf.Operation
، والتي تمثل وحدات حسابية ؛ و tf.Tensor
كائنات المستشعر ، والتي تمثل وحدات البيانات التي تتدفق بين العمليات. يتم تعريفها في سياق tf.Graph
. نظرًا لأن هذه الرسوم البيانية عبارة عن هياكل بيانات ، فيمكن حفظها وتشغيلها واستعادتها جميعًا بدون كود Python الأصلي.
هذا ما يبدو عليه رسم TensorFlow الذي يمثل شبكة عصبية من طبقتين عند تصويره في TensorBoard.
فوائد الرسوم البيانية
مع الرسم البياني ، لديك قدر كبير من المرونة. يمكنك استخدام الرسم البياني TensorFlow الخاص بك في البيئات التي لا تحتوي على مترجم Python ، مثل تطبيقات الهاتف ، والأجهزة المضمنة ، والخوادم الخلفية. يستخدم TensorFlow الرسوم البيانية كتنسيق للنماذج المحفوظة عند تصديرها من Python.
يتم أيضًا تحسين الرسوم البيانية بسهولة ، مما يسمح للمجمع بإجراء تحويلات مثل:
- استنتج بشكل ثابت قيمة الموترات عن طريق طي العقد الثابتة في حساباتك ("الطي الثابت") .
- افصل الأجزاء الفرعية من الحساب المستقل وقسمها بين الخيوط أو الأجهزة.
- تبسيط العمليات الحسابية عن طريق حذف التعابير الفرعية الشائعة.
يوجد نظام تحسين كامل ، Grappler ، لأداء هذا التسريع وغيره.
باختصار ، تعد الرسوم البيانية مفيدة للغاية وتتيح تشغيل TensorFlow بسرعة ، والعمل بالتوازي ، والعمل بكفاءة على أجهزة متعددة .
ومع ذلك ، ما زلت ترغب في تحديد نماذج التعلم الآلي الخاصة بك (أو الحسابات الأخرى) في Python للراحة ، ثم إنشاء الرسوم البيانية تلقائيًا عند الحاجة إليها.
يثبت
import tensorflow as tf
import timeit
from datetime import datetime
الاستفادة من الرسوم البيانية
يمكنك إنشاء وتشغيل رسم بياني في tf.function
باستخدام وظيفة tf ، إما كمكالمة مباشرة أو كمصمم. tf.function
يأخذ وظيفة عادية كمدخل ويعيد Function
. Function
هي لغة Python قابلة للاستدعاء تقوم ببناء الرسوم البيانية TensorFlow من دالة Python. يمكنك استخدام Function
بنفس طريقة استخدام مكافئها في Python.
# Define a Python function.
def a_regular_function(x, y, b):
x = tf.matmul(x, y)
x = x + b
return x
# `a_function_that_uses_a_graph` is a TensorFlow `Function`.
a_function_that_uses_a_graph = tf.function(a_regular_function)
# Make some tensors.
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)
orig_value = a_regular_function(x1, y1, b1).numpy()
# Call a `Function` like a Python function.
tf_function_value = a_function_that_uses_a_graph(x1, y1, b1).numpy()
assert(orig_value == tf_function_value)
في الخارج ، تبدو Function
وكأنها وظيفة عادية تكتبها باستخدام عمليات TensorFlow. لكن الأمر مختلف تمامًا في الأسفل. تقوم Function
بتغليف العديد من tf.Graph
خلف واجهة برمجة تطبيقات واحدة . هذه هي الطريقة التي تستطيع بها Function
أن تمنحك مزايا تنفيذ الرسم البياني ، مثل السرعة وقابلية النشر.
tf.function
تنطبق على وظيفة وجميع الوظائف الأخرى التي تستدعيها:
def inner_function(x, y, b):
x = tf.matmul(x, y)
x = x + b
return x
# Use the decorator to make `outer_function` a `Function`.
@tf.function
def outer_function(x):
y = tf.constant([[2.0], [3.0]])
b = tf.constant(4.0)
return inner_function(x, y, b)
# Note that the callable will create a graph that
# includes `inner_function` as well as `outer_function`.
outer_function(tf.constant([[1.0, 2.0]])).numpy()
array([[12.]], dtype=float32)
إذا كنت قد استخدمت TensorFlow 1.x ، فستلاحظ أنك لم تحتاج في أي وقت إلى تحديد Placeholder
أو tf.Session
.
تحويل دوال بايثون إلى رسوم بيانية
ستحتوي أي وظيفة تكتبها باستخدام TensorFlow على مزيج من عمليات TF المضمنة ومنطق Python ، مثل جمل if-then
، والحلقات ، break
، return
، continue
، والمزيد. بينما يتم التقاط عمليات TensorFlow بسهولة بواسطة tf.Graph
، فإن المنطق الخاص ببايثون يحتاج إلى الخضوع لخطوة إضافية ليصبح جزءًا من الرسم البياني. تستخدم tf.function
مكتبة تسمى AutoGraph ( tf.autograph
) لتحويل كود Python إلى كود لإنشاء الرسم البياني.
def simple_relu(x):
if tf.greater(x, 0):
return x
else:
return 0
# `tf_simple_relu` is a TensorFlow `Function` that wraps `simple_relu`.
tf_simple_relu = tf.function(simple_relu)
print("First branch, with graph:", tf_simple_relu(tf.constant(1)).numpy())
print("Second branch, with graph:", tf_simple_relu(tf.constant(-1)).numpy())
First branch, with graph: 1 Second branch, with graph: 0
على الرغم من أنه من غير المحتمل أنك ستحتاج إلى عرض الرسوم البيانية مباشرة ، يمكنك فحص المخرجات للتحقق من النتائج الدقيقة. هذه ليست سهلة القراءة ، لذلك لا داعي للبحث بعناية!
# This is the graph-generating output of AutoGraph.
print(tf.autograph.to_code(simple_relu))
def tf__simple_relu(x): with ag__.FunctionScope('simple_relu', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope: do_return = False retval_ = ag__.UndefinedReturnValue() def get_state(): return (do_return, retval_) def set_state(vars_): nonlocal retval_, do_return (do_return, retval_) = vars_ def if_body(): nonlocal retval_, do_return try: do_return = True retval_ = ag__.ld(x) except: do_return = False raise def else_body(): nonlocal retval_, do_return try: do_return = True retval_ = 0 except: do_return = False raise ag__.if_stmt(ag__.converted_call(ag__.ld(tf).greater, (ag__.ld(x), 0), None, fscope), if_body, else_body, get_state, set_state, ('do_return', 'retval_'), 2) return fscope.ret(retval_, do_return)
# This is the graph itself.
print(tf_simple_relu.get_concrete_function(tf.constant(1)).graph.as_graph_def())
node { name: "x" op: "Placeholder" attr { key: "_user_specified_name" value { s: "x" } } attr { key: "dtype" value { type: DT_INT32 } } attr { key: "shape" value { shape { } } } } node { name: "Greater/y" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node { name: "Greater" op: "Greater" input: "x" input: "Greater/y" attr { key: "T" value { type: DT_INT32 } } } node { name: "cond" op: "StatelessIf" input: "Greater" input: "x" attr { key: "Tcond" value { type: DT_BOOL } } attr { key: "Tin" value { list { type: DT_INT32 } } } attr { key: "Tout" value { list { type: DT_BOOL type: DT_INT32 } } } attr { key: "_lower_using_switch_merge" value { b: true } } attr { key: "_read_only_resource_inputs" value { list { } } } attr { key: "else_branch" value { func { name: "cond_false_34" } } } attr { key: "output_shapes" value { list { shape { } shape { } } } } attr { key: "then_branch" value { func { name: "cond_true_33" } } } } node { name: "cond/Identity" op: "Identity" input: "cond" attr { key: "T" value { type: DT_BOOL } } } node { name: "cond/Identity_1" op: "Identity" input: "cond:1" attr { key: "T" value { type: DT_INT32 } } } node { name: "Identity" op: "Identity" input: "cond/Identity_1" attr { key: "T" value { type: DT_INT32 } } } library { function { signature { name: "cond_false_34" input_arg { name: "cond_placeholder" type: DT_INT32 } output_arg { name: "cond_identity" type: DT_BOOL } output_arg { name: "cond_identity_1" type: DT_INT32 } } node_def { name: "cond/Const" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Const_1" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Const_2" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node_def { name: "cond/Const_3" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Identity" op: "Identity" input: "cond/Const_3:output:0" attr { key: "T" value { type: DT_BOOL } } } node_def { name: "cond/Const_4" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node_def { name: "cond/Identity_1" op: "Identity" input: "cond/Const_4:output:0" attr { key: "T" value { type: DT_INT32 } } } ret { key: "cond_identity" value: "cond/Identity:output:0" } ret { key: "cond_identity_1" value: "cond/Identity_1:output:0" } attr { key: "_construction_context" value { s: "kEagerRuntime" } } arg_attr { key: 0 value { attr { key: "_output_shapes" value { list { shape { } } } } } } } function { signature { name: "cond_true_33" input_arg { name: "cond_identity_1_x" type: DT_INT32 } output_arg { name: "cond_identity" type: DT_BOOL } output_arg { name: "cond_identity_1" type: DT_INT32 } } node_def { name: "cond/Const" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Identity" op: "Identity" input: "cond/Const:output:0" attr { key: "T" value { type: DT_BOOL } } } node_def { name: "cond/Identity_1" op: "Identity" input: "cond_identity_1_x" attr { key: "T" value { type: DT_INT32 } } } ret { key: "cond_identity" value: "cond/Identity:output:0" } ret { key: "cond_identity_1" value: "cond/Identity_1:output:0" } attr { key: "_construction_context" value { s: "kEagerRuntime" } } arg_attr { key: 0 value { attr { key: "_output_shapes" value { list { shape { } } } } } } } } versions { producer: 898 min_consumer: 12 }
في معظم الأحيان ، ستعمل tf.function
دون اعتبارات خاصة. ومع ذلك ، هناك بعض التحذيرات ، ويمكن أن يساعد دليل وظيفة tf هنا ، بالإضافة إلى مرجع AutoGraph الكامل
تعدد الأشكال: Function
واحدة ، العديد من الرسوم البيانية
tf.Graph
لنوع معين من المدخلات (على سبيل المثال ، dtype
محدد أو كائنات بنفس id()
).
في كل مرة تقوم فيها باستدعاء Function
مع أنواع وأشكال جديدة في dtypes
، تقوم Function
بإنشاء tf.Graph
جديد للوسيطات الجديدة. تُعرف أنواع وأشكال tf.Graph
dtypes
توقيع الإدخال أو مجرد توقيع .
تخزن Function
tf.Graph
المناظر لذلك التوقيع في وظيفة ConcreteFunction
. الوظيفة ConcreteFunction
عبارة عن غلاف حول رسم tf.Graph
.
@tf.function
def my_relu(x):
return tf.maximum(0., x)
# `my_relu` creates new graphs as it observes more signatures.
print(my_relu(tf.constant(5.5)))
print(my_relu([1, -1]))
print(my_relu(tf.constant([3., -3.])))
tf.Tensor(5.5, shape=(), dtype=float32) tf.Tensor([1. 0.], shape=(2,), dtype=float32) tf.Tensor([3. 0.], shape=(2,), dtype=float32)
إذا تم استدعاء Function
بالفعل بهذا التوقيع ، فإن Function
لا تنشئ رسمًا tf.Graph
جديدًا.
# These two calls do *not* create new graphs.
print(my_relu(tf.constant(-2.5))) # Signature matches `tf.constant(5.5)`.
print(my_relu(tf.constant([-1., 1.]))) # Signature matches `tf.constant([3., -3.])`.
tf.Tensor(0.0, shape=(), dtype=float32) tf.Tensor([0. 1.], shape=(2,), dtype=float32)
نظرًا لأنها مدعومة برسوم بيانية متعددة ، فإن Function
متعددة الأشكال . يمكّنه ذلك من دعم أنواع إدخال أكثر مما يمكن أن يمثله tf.Graph
واحد ، بالإضافة إلى تحسين كل tf.Graph
للحصول على أداء أفضل.
# There are three `ConcreteFunction`s (one for each graph) in `my_relu`.
# The `ConcreteFunction` also knows the return type and shape!
print(my_relu.pretty_printed_concrete_signatures())
my_relu(x) Args: x: float32 Tensor, shape=() Returns: float32 Tensor, shape=() my_relu(x=[1, -1]) Returns: float32 Tensor, shape=(2,) my_relu(x) Args: x: float32 Tensor, shape=(2,) Returns: float32 Tensor, shape=(2,)
باستخدام tf.function
لقد تعلمت حتى الآن كيفية تحويل دالة Python إلى رسم بياني ببساطة باستخدام tf.function
كديكور أو غلاف. ولكن من الناحية العملية ، قد يكون tf.function
تعمل بشكل صحيح أمرًا صعبًا! في الأقسام التالية ، ستتعلم كيف يمكنك جعل الكود الخاص بك يعمل كما هو متوقع مع tf.function
.
تنفيذ الرسم البياني مقابل التنفيذ الشغوف
يمكن تنفيذ الكود في Function
بشغف وكرسوم بيانية. بشكل افتراضي ، تنفذ Function
كودها كرسم بياني:
@tf.function
def get_MSE(y_true, y_pred):
sq_diff = tf.pow(y_true - y_pred, 2)
return tf.reduce_mean(sq_diff)
y_true = tf.random.uniform([5], maxval=10, dtype=tf.int32)
y_pred = tf.random.uniform([5], maxval=10, dtype=tf.int32)
print(y_true)
print(y_pred)
tf.Tensor([1 0 4 4 7], shape=(5,), dtype=int32) tf.Tensor([3 6 3 0 6], shape=(5,), dtype=int32)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=11>
للتحقق من أن الرسم البياني Function
يقوم بنفس العمليات الحسابية لوظيفة Python المكافئة ، يمكنك جعله ينفذ بفارغ الصبر باستخدام tf.config.run_functions_eagerly(True)
. هذا مفتاح يعمل على إيقاف تشغيل قدرة Function
على إنشاء الرسوم البيانية وتشغيلها ، بدلاً من تنفيذ التعليمات البرمجية بشكل طبيعي.
tf.config.run_functions_eagerly(True)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=11>
# Don't forget to set it back when you are done.
tf.config.run_functions_eagerly(False)
ومع ذلك ، يمكن أن تتصرف Function
بشكل مختلف تحت الرسم البياني والتنفيذ الحثيث. تعد وظيفة print
Python أحد الأمثلة على كيفية اختلاف هذين الوضعين. دعنا نتحقق مما يحدث عندما تقوم بإدخال عبارة print
إلى وظيفتك واستدعائها بشكل متكرر.
@tf.function
def get_MSE(y_true, y_pred):
print("Calculating MSE!")
sq_diff = tf.pow(y_true - y_pred, 2)
return tf.reduce_mean(sq_diff)
لاحظ ما هو مطبوع:
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE!
هل الإخراج مفاجئ؟ get_MSE
تتم طباعته مرة واحدة فقط بالرغم من أنه تم استدعاؤه ثلاث مرات.
للتوضيح ، يتم تنفيذ جملة print
عندما تقوم Function
بتشغيل الكود الأصلي من أجل إنشاء الرسم البياني في عملية تعرف باسم "التتبع" . يلتقط التتبع عمليات TensorFlow في رسم بياني ، ولا يتم التقاط print
في الرسم البياني. ثم يتم تنفيذ هذا الرسم البياني لجميع المكالمات الثلاثة دون تشغيل كود Python مرة أخرى .
للتحقق من سلامة البيانات ، دعنا نوقف تنفيذ الرسم البياني للمقارنة:
# Now, globally set everything to run eagerly to force eager execution.
tf.config.run_functions_eagerly(True)
# Observe what is printed below.
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE! Calculating MSE! Calculating MSE!
tf.config.run_functions_eagerly(False)
يعد print
أحد الآثار الجانبية لـ Python ، وهناك اختلافات أخرى يجب أن تكون على دراية بها عند تحويل دالة إلى Function
. تعرف على المزيد في قسم القيود من دليل الأداء الأفضل باستخدام tf.function .
التنفيذ غير الصارم
ينفذ تنفيذ الرسم البياني فقط العمليات الضرورية لإنتاج التأثيرات الملحوظة ، والتي تشمل:
- القيمة المرجعة للدالة
- الآثار الجانبية الموثقة والمعروفة مثل:
- عمليات الإدخال / الإخراج ، مثل
tf.print
- عمليات التصحيح ، مثل وظائف التأكيد في
tf.debugging
- طفرات
tf.Variable
- عمليات الإدخال / الإخراج ، مثل
يُعرف هذا السلوك عادةً باسم "التنفيذ غير الصارم" ، ويختلف عن التنفيذ الحثيث ، والذي يمر عبر جميع عمليات البرنامج ، سواء أكان مطلوبًا أم لا.
على وجه الخصوص ، لا يعتبر فحص أخطاء وقت التشغيل تأثيرًا يمكن ملاحظته. إذا تم تخطي عملية ما لأنها غير ضرورية ، فلا يمكن أن تظهر أي أخطاء في وقت التشغيل.
في المثال التالي ، تم تخطي العملية "غير الضرورية" tf.gather
أثناء تنفيذ الرسم البياني ، لذلك لا يظهر خطأ وقت التشغيل InvalidArgumentError
لأنه سيكون في حالة تنفيذ حثيثة. لا تعتمد على ظهور خطأ أثناء تنفيذ الرسم البياني.
def unused_return_eager(x):
# Get index 1 will fail when `len(x) == 1`
tf.gather(x, [1]) # unused
return x
try:
print(unused_return_eager(tf.constant([0.0])))
except tf.errors.InvalidArgumentError as e:
# All operations are run during eager execution so an error is raised.
print(f'{type(e).__name__}: {e}')
tf.Tensor([0.], shape=(1,), dtype=float32)
@tf.function
def unused_return_graph(x):
tf.gather(x, [1]) # unused
return x
# Only needed operations are run during graph exection. The error is not raised.
print(unused_return_graph(tf.constant([0.0])))
tf.Tensor([0.], shape=(1,), dtype=float32)
أفضل ممارسات tf.function
قد يستغرق الأمر بعض الوقت لتعتاد على سلوك Function
. للبدء بسرعة ، يجب على المستخدمين لأول مرة اللعب مع وظائف تزيين اللعبة باستخدام وظيفة @tf.function
للحصول على خبرة في الانتقال من تنفيذ الشغف إلى الرسم البياني.
قد يكون التصميم tf.function
هو أفضل رهان لك لكتابة برامج TensorFlow المتوافقة مع الرسم البياني. هنا بعض النصائح:
- قم بالتبديل بين التنفيذ الشغوف والرسم البياني مبكرًا وغالبًا باستخدام
tf.config.run_functions_eagerly
لتحديد ما إذا / عندما يتباعد الوضعان. - قم
tf.Variable
خارج دالة Python وقم بتعديلها من الداخل. الشيء نفسه ينطبق على الكائنات التي تستخدمtf.Variable
، مثلkeras.layers
وkeras.Model
s وtf.optimizers
. - تجنب كتابة الدوال التي تعتمد على متغيرات بايثون الخارجية ، باستثناء
tf.Variable
s و Keras. - يفضل كتابة الدوال التي تأخذ الموترات وأنواع TensorFlow الأخرى كمدخلات. يمكنك تمرير أنواع أخرى من الكائنات ولكن كن حذرًا !
- قم بتضمين أكبر قدر ممكن من العمليات الحسابية ضمن
tf.function
لتعظيم مكاسب الأداء. على سبيل المثال ، قم بتزيين خطوة تدريب كاملة أو حلقة التدريب بأكملها.
رؤية التسريع
tf.function
عادةً على تحسين أداء التعليمات البرمجية الخاصة بك ، لكن مقدار التسريع يعتمد على نوع الحساب الذي تقوم بتشغيله. يمكن السيطرة على الحسابات الصغيرة عن طريق استدعاء الرسم البياني. يمكنك قياس الفرق في الأداء مثل:
x = tf.random.uniform(shape=[10, 10], minval=-1, maxval=2, dtype=tf.dtypes.int32)
def power(x, y):
result = tf.eye(10, dtype=tf.dtypes.int32)
for _ in range(y):
result = tf.matmul(x, result)
return result
print("Eager execution:", timeit.timeit(lambda: power(x, 100), number=1000))
Eager execution: 2.5637862179974036
power_as_graph = tf.function(power)
print("Graph execution:", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))
Graph execution: 0.6832536700021592
تُستخدم tf.function
بشكل شائع لتسريع حلقات التدريب ، ويمكنك معرفة المزيد عنها في كتابة حلقة تدريب من البداية باستخدام Keras.
الأداء والمفاضلات
يمكن للرسوم البيانية تسريع التعليمات البرمجية الخاصة بك ، ولكن عملية إنشائها تنطوي على بعض النفقات العامة. بالنسبة لبعض الوظائف ، يستغرق إنشاء الرسم البياني وقتًا أطول من تنفيذ الرسم البياني. عادةً ما يتم سداد هذا الاستثمار بسرعة من خلال تعزيز الأداء لعمليات التنفيذ اللاحقة ، ولكن من المهم أن تدرك أن الخطوات القليلة الأولى لأي تدريب على نموذج كبير يمكن أن تكون أبطأ بسبب التتبع.
بغض النظر عن حجم النموذج الخاص بك ، فأنت تريد تجنب التتبع بشكل متكرر. يناقش دليل tf.function
كيفية تعيين مواصفات الإدخال واستخدام وسيطات الموتر لتجنب الاسترداد. إذا وجدت أنك تحصل على أداء ضعيف بشكل غير عادي ، فمن الجيد التحقق مما إذا كنت تتعقب عن طريق الخطأ.
ما هي Function
تتبع؟
لمعرفة متى يتم تتبع Function
، أضف عبارة print
إلى كودها. كقاعدة عامة ، ستقوم Function
بتنفيذ جملة print
في كل مرة تتعقب فيها.
@tf.function
def a_function_with_python_side_effect(x):
print("Tracing!") # An eager-only side effect.
return x * x + tf.constant(2)
# This is traced the first time.
print(a_function_with_python_side_effect(tf.constant(2)))
# The second time through, you won't see the side effect.
print(a_function_with_python_side_effect(tf.constant(3)))
Tracing! tf.Tensor(6, shape=(), dtype=int32) tf.Tensor(11, shape=(), dtype=int32)
# This retraces each time the Python argument changes,
# as a Python argument could be an epoch count or other
# hyperparameter.
print(a_function_with_python_side_effect(2))
print(a_function_with_python_side_effect(3))
Tracing! tf.Tensor(6, shape=(), dtype=int32) Tracing! tf.Tensor(11, shape=(), dtype=int32)
تؤدي دائمًا وسيطات Python الجديدة إلى إنشاء رسم بياني جديد ، ومن ثم التتبع الإضافي.
الخطوات التالية
يمكنك معرفة المزيد حول tf.function
على صفحة مرجع API ومن خلال اتباع دليل أداء أفضل مع tf.function
.