لدي سؤال؟ تواصل مع المجتمع في منتدى زيارة منتدى TensorFlow

TensorFlow الفعال 2

هناك العديد من التغييرات في TensorFlow 2.0 لجعل مستخدمي TensorFlow أكثر إنتاجية. يزيل TensorFlow 2.0 واجهات برمجة التطبيقات الفائضة ، ويجعل واجهات برمجة التطبيقات أكثر اتساقًا ( RNNs الموحدة ، والمحسنون الموحدون ) ، ويتكامل بشكل أفضل مع وقت تشغيل Python مع تنفيذ Eager .

شرح العديد من طلبات التعليقات (RFC) التغييرات التي أدخلت على TensorFlow 2.0. يقدم هذا الدليل رؤية لما يجب أن يبدو عليه التطوير في TensorFlow 2.0. من المفترض أن لديك بعض الإلمام بـ TensorFlow 1.x.

ملخص موجز للتغييرات الرئيسية

تنظيف API

العديد من واجهات برمجة التطبيقات إما اختفت أو تم نقلها في TF 2.0. تتضمن بعض التغييرات الرئيسية إزالة tf.app و tf.flags و tf.logging لصالح absl-py مفتوحة المصدر الآن ، وإعادة توجيه المشاريع التي عاشت في tf.contrib ، وتنظيف مساحة الاسم الرئيسية tf.* بواسطة نقل الوظائف الأقل استخدامًا إلى tf.math مثل tf.math . تم استبدال بعض واجهات برمجة التطبيقات بمكافئاتها 2.0 - tf.summary و tf.keras.metrics و tf.keras.optimizers . أسهل طريقة لتطبيق عمليات إعادة التسمية هذه تلقائيًا هي استخدام البرنامج النصي لترقية الإصدار 2 .

تنفيذ حريص

يتطلب TensorFlow 1.X من المستخدمين تجميع شجرة بناء جملة مجردة (الرسم البياني) يدويًا عن طريق إجراء استدعاءات tf.* API. ثم يتطلب من المستخدمين تجميع شجرة التركيب المجردة يدويًا عن طريق تمرير مجموعة من موترات الإخراج وموترات الإدخال إلى استدعاء session.run() . يتم تنفيذ TensorFlow 2.0 بلهفة (كما تفعل Python عادةً) وفي الإصدار 2.0 ، يجب أن تبدو الرسوم البيانية والجلسات وكأنها تفاصيل التنفيذ.

أحد النتائج الثانوية البارزة للتنفيذ tf.control_dependencies() هو أن tf.control_dependencies() لم يعد مطلوبًا ، حيث يتم تنفيذ جميع أسطر التعليمات البرمجية بالترتيب (داخل tf.function ، يتم تنفيذ التعليمات البرمجية ذات الآثار الجانبية بالترتيب المكتوب).

لا مزيد من الكرة الأرضية

اعتمد TensorFlow 1.X بشكل كبير على مساحات الأسماء العالمية ضمنيًا. عند استدعاء tf.Variable() ، سيتم وضعه في الرسم البياني الافتراضي ، وسيظل هناك ، حتى إذا فقدت مسار متغير Python الذي يشير إليه. يمكنك بعد ذلك استعادة هذا tf.Variable ، ولكن فقط إذا كنت تعرف الاسم الذي تم إنشاؤه به. كان هذا صعبًا إذا لم تكن متحكمًا في إنشاء المتغير. نتيجة لذلك ، تكاثرت جميع أنواع الآليات لمحاولة مساعدة المستخدمين في العثور على متغيراتهم مرة أخرى ، tf.get_global_step() على أطر عمل للعثور على المتغيرات التي أنشأها المستخدم: نطاقات المتغيرات ، والمجموعات العالمية ، والطرق المساعدة مثل tf.get_global_step() ، tf.global_variables_initializer() ، يحسب محسنون ضمنيًا التدرجات على جميع المتغيرات القابلة للتدريب ، وما إلى ذلك. يلغي TensorFlow 2.0 كل هذه الآليات ( Variables 2.0 RFC ) لصالح الآلية الافتراضية: تتبع متغيراتك! إذا فقدت مسار أحد tf.Variable ، tf.Variable جمع القمامة.

تخلق متطلبات تتبع المتغيرات بعض العمل الإضافي للمستخدم ، ولكن مع كائنات Keras (انظر أدناه) ، يتم تقليل العبء إلى الحد الأدنى.

وظائف وليس جلسات

تشبه استدعاء session.run() استدعاء دالة تقريبًا: يمكنك تحديد المدخلات والوظيفة التي سيتم استدعاؤها ، وستحصل على مجموعة من المخرجات. في TensorFlow 2.0 ، يمكنك تزيين دالة Python باستخدام tf.function() من أجل تجميع JIT بحيث يقوم TensorFlow بتشغيلها كرسم بياني واحد ( Functions 2.0 RFC ). تسمح هذه الآلية لـ TensorFlow 2.0 باكتساب جميع مزايا وضع الرسم البياني:

  • الأداء: يمكن تحسين الوظيفة (تقليم العقدة ، اندماج النواة ، إلخ.)
  • قابلية النقل: يمكن تصدير / إعادة استيراد الوظيفة ( SavedModel 2.0 RFC ) ، مما يسمح للمستخدمين بإعادة استخدام وظائف TensorFlow المعيارية ومشاركتها.
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TensorFlow 2.0
outputs = f(input)

مع القدرة على تداخل كود Python و TensorFlow بحرية ، يمكن للمستخدمين الاستفادة من تعبير Python. ولكن يتم تنفيذ TensorFlow المحمول في سياقات بدون مترجم Python ، مثل mobile و C ++ و JavaScript. لمساعدة المستخدمين على تجنب الاضطرار إلى إعادة كتابة التعليمات البرمجية الخاصة بهم عند إضافة @tf.function ، توقيعه تحويل مجموعة فرعية من بنيات بيثون في حكمه TensorFlow على:

  • for / while -> tf.while_loop ( break و continue معتمدة)
  • if -> tf.cond
  • for _ in dataset -> dataset.reduce for _ in dataset

يدعم AutoGraph التداخل التعسفي لتدفق التحكم ، مما يجعل من الممكن تنفيذ العديد من برامج ML المعقدة بأداء ودقة مثل نماذج التسلسل ، والتعلم المعزز ، وحلقات التدريب المخصصة ، والمزيد.

توصيات اصطلاحية TensorFlow 2.0

أعد بناء الكود الخاص بك إلى وظائف أصغر

نمط الاستخدام الشائع في TensorFlow 1.X كان استراتيجية "حوض المطبخ" ، حيث تم وضع اتحاد جميع الحسابات الممكنة بشكل استباقي ، ثم تم تقييم الموترات المختارة عبر session.run() . في TensorFlow 2.0 ، يجب على المستخدمين إعادة تشكيل الكود الخاص بهم إلى وظائف أصغر يتم استدعاؤها حسب الحاجة. بشكل عام ، ليس من الضروري تزيين كل من هذه الوظائف الأصغر بوظيفة tf.function . استخدم فقط tf.function لتزيين الحسابات عالية المستوى - على سبيل المثال ، خطوة واحدة من التدريب أو التمرير الأمامي tf.function .

استخدم طبقات ونماذج Keras لإدارة المتغيرات

تقدم نماذج وطبقات Keras variables الملائمة وخصائص variables القابلة trainable_variables ، والتي تجمع بشكل متكرر جميع المتغيرات التابعة. هذا يجعل من السهل إدارة المتغيرات محليًا إلى حيث يتم استخدامها.

مقابلة:

def dense(x, W, b):
  return tf.nn.sigmoid(tf.matmul(x, W) + b)

@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
  x = dense(x, w0, b0)
  x = dense(x, w1, b1)
  x = dense(x, w2, b2)
  ...

# You still have to manage w_i and b_i, and their shapes are defined far away from the code.

مع إصدار Keras:

# Each layer can be called, with a signature equivalent to linear(x)
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)

# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]

ترث طبقات / نماذج tf.train.Checkpointable من tf.train.Checkpointable ويتم دمجها مع @tf.function ، مما يجعل من الممكن مباشرة نقطة تفتيش أو تصدير SavedModels من كائنات Keras. لا يتعين عليك بالضرورة استخدام واجهة برمجة تطبيقات .fit() الخاصة بـ .fit() للاستفادة من عمليات الدمج هذه.

إليك مثال تعلم النقل الذي يوضح كيف تجعل Keras من السهل تجميع مجموعة فرعية من المتغيرات ذات الصلة. لنفترض أنك تقوم بتدريب نموذج متعدد الرؤوس بجذع مشترك:

trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])

path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])

# Train on primary dataset
for x, y in main_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path1(x, training=True)
    loss = loss_fn_head1(prediction, y)
  # Simultaneously optimize trunk and head1 weights.
  gradients = tape.gradient(loss, path1.trainable_variables)
  optimizer.apply_gradients(zip(gradients, path1.trainable_variables))

# Fine-tune second head, reusing the trunk
for x, y in small_dataset:
  with tf.GradientTape() as tape:
    # training=True is only needed if there are layers with different
    # behavior during training versus inference (e.g. Dropout).
    prediction = path2(x, training=True)
    loss = loss_fn_head2(prediction, y)
  # Only optimize head2 weights, not trunk weights
  gradients = tape.gradient(loss, head2.trainable_variables)
  optimizer.apply_gradients(zip(gradients, head2.trainable_variables))

# You can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)

اجمع بين tf.data.Datasets و @ tf.function

عند التكرار على بيانات التدريب التي تتلاءم مع الذاكرة ، لا تتردد في استخدام تكرار Python العادي. خلاف ذلك ، فإنtf.data.Dataset هي أفضل طريقة لدفق بيانات التدريب من القرص. مجموعات البيانات هي عناصر متكررة (وليست مكررات) ، وتعمل تمامًا مثل متغيرات Python الأخرى في الوضع Eager. يمكنك الاستفادة الكاملة من ميزات الجلب المسبق / التدفق غير المتزامن tf.function() البيانات عن طريق تغليف الكود الخاص بك في tf.function() ، والذي يستبدل تكرار Python بعمليات الرسم البياني المكافئة باستخدام AutoGraph.

@tf.function
def train(model, dataset, optimizer):
  for x, y in dataset:
    with tf.GradientTape() as tape:
      # training=True is only needed if there are layers with different
      # behavior during training versus inference (e.g. Dropout).
      prediction = model(x, training=True)
      loss = loss_fn(prediction, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

إذا كنت تستخدم واجهة برمجة تطبيقات Keras .fit() ، فلن تقلق بشأن تكرار مجموعة البيانات.

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)

استفد من AutoGraph مع تدفق التحكم في Python

يوفر AutoGraph طريقة لتحويل تدفق التحكم المعتمد على البيانات إلى مكافئات وضع الرسم البياني مثل tf.cond و tf.while_loop . tf.while_loop .

أحد الأماكن الشائعة حيث يظهر تدفق التحكم المعتمد على البيانات هو نماذج التسلسل. يلف tf.keras.layers.RNN خلية RNN ، مما يسمح لك tf.keras.layers.RNN بشكل ثابت أو ديناميكي. من أجل العرض التوضيحي ، يمكنك إعادة تنفيذ إلغاء الالتحاق الديناميكي على النحو التالي:

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell

  def call(self, input_data):
    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    outputs = tf.TensorArray(tf.float32, input_data.shape[0])
    state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
    for i in tf.range(input_data.shape[0]):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state

للحصول على نظرة عامة أكثر تفصيلاً عن ميزات AutoGraph ، انظر الدليل .

tf.metrics تجمع البيانات وتسجيلها موجزًا

لتسجيل الملخصات ، استخدم tf.summary.(scalar|histogram|...) وأعد توجيهه إلى كاتب باستخدام مدير السياق. (إذا حذفت مدير السياق ، فلن يحدث شيء.) بخلاف TF 1.x ، يتم إرسال الملخصات مباشرة إلى الكاتب ؛ لا توجد عملية منفصلة "دمج" ولا يوجد add_summary() منفصل ، مما يعني أنه يجب توفير قيمة step في موقع الاستدعاء.

summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)

لتجميع البيانات قبل tf.metrics كملخصات ، استخدم tf.metrics . المقاييس ذات حالة: فهي تجمع القيم .result() نتيجة تراكمية عند استدعاء .result() . امسح القيم المتراكمة باستخدام .reset_states() .

def train(model, optimizer, dataset, log_freq=10):
  avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
  for images, labels in dataset:
    loss = train_step(model, optimizer, images, labels)
    avg_loss.update_state(loss)
    if tf.equal(optimizer.iterations % log_freq, 0):
      tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
      avg_loss.reset_states()

def test(model, test_x, test_y, step_num):
  # training=False is only needed if there are layers with different
  # behavior during training versus inference (e.g. Dropout).
  loss = loss_fn(model(test_x, training=False), test_y)
  tf.summary.scalar('loss', loss, step=step_num)

train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')

with train_summary_writer.as_default():
  train(model, optimizer, dataset)

with test_summary_writer.as_default():
  test(model, test_x, test_y, optimizer.iterations)

تصور الملخصات التي تم إنشاؤها عن طريق توجيه TensorBoard في دليل السجل الموجز:

tensorboard --logdir /tmp/summaries

استخدم tf.config.experimental_run_functions_eagerly () عند تصحيح الأخطاء

في TensorFlow 2.0 ، يتيح لك تنفيذ Eager تشغيل التعليمات البرمجية خطوة بخطوة لفحص الأشكال وأنواع البيانات والقيم. تم تصميم بعض واجهات برمجة التطبيقات ، مثل tf.function ، و tf.keras ، وما إلى ذلك لاستخدام تنفيذ الرسم البياني ، من أجل الأداء وقابلية النقل. عند تصحيح الأخطاء ، استخدم tf.config.experimental_run_functions_eagerly(True) لاستخدام تنفيذ Eager داخل هذا الرمز.

على سبيل المثال:

@tf.function
def f(x):
  if x > 0:
    import pdb
    pdb.set_trace()
    x = x + 1
  return x

tf.config.experimental_run_functions_eagerly(True)
f(tf.constant(1))
>>> f()
-> x = x + 1
(Pdb) l
  6     @tf.function
  7     def f(x):
  8       if x > 0:
  9         import pdb
 10         pdb.set_trace()
 11  ->     x = x + 1
 12       return x
 13
 14     tf.config.experimental_run_functions_eagerly(True)
 15     f(tf.constant(1))
[EOF]

يعمل هذا أيضًا داخل نماذج Keras وواجهات برمجة التطبيقات الأخرى التي تدعم تنفيذ Eager:

class CustomModel(tf.keras.models.Model):

  @tf.function
  def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
      return input_data
    else:
      import pdb
      pdb.set_trace()
      return input_data // 2


tf.config.experimental_run_functions_eagerly(True)
model = CustomModel()
model(tf.constant([-2, -4]))
>>> call()
-> return input_data // 2
(Pdb) l
 10         if tf.reduce_mean(input_data) > 0:
 11           return input_data
 12         else:
 13           import pdb
 14           pdb.set_trace()
 15  ->       return input_data // 2
 16
 17
 18     tf.config.experimental_run_functions_eagerly(True)
 19     model = CustomModel()
 20     model(tf.constant([-2, -4]))