مسارات بيانات سرعة وحدة معالجة الموتّر: tf.data.Dataset وTFRecords

1. نظرة عامة

إنّ وحدات معالجة الموتّرات سريعة جدًا. يجب أن يكون تدفق بيانات التدريب متناسبًا مع سرعة تدريبهم. في هذا التمرين المعملي، ستتعرّف على كيفية تحميل البيانات من GCS باستخدام واجهة برمجة التطبيقات tf.data.Dataset API لإطعام وحدة TPU.

هذه التجربة هي الجزء 1 من سلسلة "Keras على وحدات معالجة النطاق الفائق (TPU)". يمكنك القيام بها بالترتيب التالي أو بشكل مستقل.

ca8cc21f6838eccc.png

المُعطيات

  • لاستخدام واجهة برمجة التطبيقات tf.data.Dataset API لتحميل بيانات التدريب
  • لاستخدام تنسيق TFRecord لتحميل بيانات التدريب بكفاءة من GCS

الملاحظات

إذا لاحظت أي مشكلة في مختبر الرموز البرمجية هذا، يُرجى إبلاغنا بها. يمكن تقديم الملاحظات من خلال مشاكل GitHub [ رابط الملاحظات].

2. دليل البدء السريع لخدمة Google Colaboratory

يستخدم هذا المختبر Google Collaboratory ولا يتطلّب أي إعداد من جانبك. Colaboratory هي منصة لأوراق الملاحظات على الإنترنت مخصَّصة لأغراض التعليم. وهو يوفر تدريبًا مجانيًا على استخدام وحدة المعالجة المركزية (CPU) ووحدة معالجة الرسومات ووحدة معالجة الموتّرات.

688858c21e3beff2.png

يمكنك فتح نموذج دفتر ملاحظات هذا والاطّلاع على بضع خلايا للتعرّف على Colaboratory.

c3df49e90e5a654f.png Welcome to Colab.ipynb

اختيار واجهة خلفية لوحدة معالجة TPU

8832c6208c99687d.png

في قائمة Colab، اختَر "بيئة التشغيل" > "تغيير نوع بيئة التشغيل"، ثم اختَر "وحدة معالجة الموتّرات". سوف تستخدم في هذا التمرين المعملي وحدة معالجة بيانات (TPU) قوية للتدريب الذي يتم تسريعه باستخدام الأجهزة. سيتم الاتصال ببيئة التشغيل تلقائيًا عند التنفيذ الأول، أو يمكنك استخدام الزر "اتصال" في أعلى يسار الصفحة.

تنفيذ "دفتر ملاحظات Google"

76d05caa8b4db6da.png

نفِّذ الخلايا واحدة تلو الأخرى عن طريق النقر على خلية واستخدام Shift-ENTER. يمكنك أيضًا تشغيل دفتر الملاحظات بالكامل باستخدام بيئة التشغيل > تشغيل الكل.

جدول المحتويات

429f106990037ec4.png

تحتوي جميع أوراق الملاحظات على جدول محتويات. يمكنك فتحه باستخدام السهم الأسود على اليمين.

الخلايا المخفية

edc3dba45d26f12a.png

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

المصادقة

cdd4b41413100543.png

يمكن لمنصة Colab الوصول إلى حِزمك الخاصة في Google Cloud Storage شرط أن تتم المصادقة باستخدام حساب مفوَّض. سيؤدي مقتطف الرمز أعلاه إلى بدء عملية مصادقة.

3- [INFO] ما هي وحدات معالجة Tensor (TPU)؟

الملخّص

f88cf6facfc70166.png

رمز تدريب نموذج على وحدة معالجة الموتّرات في Keras (والرجوع إلى وحدة معالجة الرسومات أو وحدة المعالجة المركزية في حال عدم توفّر وحدة معالجة الموتّرات):

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

سنستخدم اليوم وحدات معالجة الموتّرات لإنشاء مصنِّف زهور وتحسينه بالسرعات التفاعلية (دقائق لكل تمرين تدريبي).

688858c21e3beff2.png

لماذا وحدات معالجة النصوص البرمجية؟

يتم تنظيم وحدات معالجة الرسومات الحديثة حول "الوحدات الأساسية" القابلة للبرمجة، وهي بنية مرنة جدًا تسمح لها بمعالجة مجموعة متنوعة من المهام، مثل العروض الثلاثية الأبعاد والتعلّم العميق والمحاكاة الفيزيائية وما إلى ذلك. من ناحية أخرى، تُزوّد وحدات TPU بمعالج رسومات كلاسيكي ووحدة مخصّصة لضرب المصفوفات، وهي تُحقّق أداءً ممتازًا في أي مهمة تُستخدم فيها عمليات ضرب المصفوفات الكبيرة، مثل الشبكات العصبية.

8eb3e718b8e2ed08.png

صورة توضيحية: طبقة شبكة عصبية كثيفة على شكل عملية ضرب مصفوفة، مع مجموعة من ثماني صور تتم معالجتها من خلال الشبكة العصبية في آنٍ واحد يرجى تنفيذ عملية ضرب العمود في سطر واحد للتأكد من أنها تُخرِج مجموع ترجيح لجميع قيم وحدات البكسل في الصورة. يمكن أيضًا تمثيل الطبقات التجميعية على أنّها عمليات ضرب مصفوفات، على الرغم من أنّها أكثر تعقيدًا قليلاً (الشرح هنا في القسم 1).

الأجهزة

وحدة معالجة الوسائط (MXU) ووحدة معالجة الفيديو (VPU)

يتكوّن الإصدار الثاني من وحدة معالجة الموتّرات من وحدة مصفوفة مصفوفة (MXU) تعمل على تنفيذ عمليات ضرب المصفوفة ووحدة معالجة المتّجهات (VPU) لجميع المهام الأخرى مثل عمليات التفعيل وsoftmax وغير ذلك. ويعالج VPU العمليات الحسابية float32 وint32. من ناحية أخرى، يعمل MXU بتنسيق نقطة عائمة بدقة مختلطة تتراوح بين 16 و32 بت.

7d68944718f76b18.png

نقطة عائمة بدقة مختلطة وbfloat16

تُحسِّب وحدة MXU عمليات ضرب المصفوفات باستخدام مدخلات bfloat16 ومخرجات float32. ويتم تنفيذ التراكمات المتوسطة بدقة float32.

19c5fc432840c714.png

عادةً ما يكون تدريب الشبكات العصبية مقاومًا للضوضاء الناتجة عن انخفاض دقة النقطة العائمة. هناك حالات يساعد فيها الضجيج في التقارب أيضًا. عادةً ما يتم استخدام دقة النقطة العائمة بتنسيق 16 بت لتسريع العمليات الحسابية، غير أنّ النطاقَين float16 وfloat32 لديهما نطاقات مختلفة جدًا. يؤدي عادةً تقليل الدقة من float32 إلى float16 إلى حدوث عمليات تجاوز حدود الحد الأدنى والحد الأقصى. تتوفّر حلول، ولكن عادةً ما يلزم إجراء عمل إضافي لاستخدام float16.

لهذا السبب، طرحت Google تنسيق bfloat16 في وحدات TPU. وbfloat16 هو تنسيق float32 مقطوع يتضمّن القيمة نفسها تمامًا لبتّي الأس والفاصل كما في float32. هذا بالإضافة إلى حقيقة أنّ وحدات معالجة الموتّرات تحتسب عمليات ضرب المصفوفات بدقة مختلطة مع مخرجات bfloat16 والمخرجات float32، وهو ما يعني أنّه لا يلزم عادةً إجراء أي تغييرات في الرموز للاستفادة من دقة الأداء المحسّنة.

صفيف الضغط الانقباضي

تنفِّذ وحدة MXU عمليات ضرب المصفوفات في الأجهزة باستخدام بنية تُعرف باسم "المصفوفة الانبساطية" التي تتدفق فيها عناصر البيانات من خلال صفيف من وحدات الحساب في الأجهزة. (في الطب، يشير "الانقباض" إلى تقلّصات القلب وتدفق الدم، ويشير هنا إلى تدفق البيانات).

العنصر الأساسي لعملية ضرب المصفوفة هو ناتج الضرب النقطي بين خط من مصفوفة واحدة وعمود من المصفوفة الأخرى (راجع الرسم التوضيحي أعلى هذا القسم). في عملية ضرب المصفوفات Y=X*W، سيكون عنصر واحد من النتيجة على النحو التالي:

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

في وحدة معالجة الرسومات، يتم برمجة هذا الضرب النقطي إلى "نواة" في وحدة معالجة الرسومات، ثم تنفيذه على أكبر عدد ممكن من "النواة" بالتوازي لمحاولة حساب كل قيمة في المصفوفة الناتجة دفعة واحدة. إذا كانت المصفوفة الناتجة كبيرة بحجم 128×128، فقد يتطلب ذلك توفر "نواة" قيمتها 128x128=16K، وهو أمر لا يكون ممكنًا عادةً. تحتوي أكبر وحدات معالجة الرسومات على 4,000 نواة تقريبًا. من ناحية أخرى، تستخدم وحدة معالجة الموتّرات الحدّ الأدنى من الأجهزة لوحدات الحوسبة في وحدة معالجة الموتّرات (MXU): bfloat16 x bfloat16 => float32 مُراكمات الضرب فقط، وليس هناك أي شيء آخر. هذه العمليات صغيرة جدًا لدرجة أنّ وحدة TPU يمكنها تنفيذ 16 ألف عملية منها في وحدة MXU بحجم 128x128 ومعالجة عملية ضرب المصفوفات هذه دفعة واحدة.

f1b283fc45966717.gif

صورة توضيحية: صفيفة MXU الانقباضية. عناصر الحوسبة هي أدوات تجميع الضرب. يتم تحميل قيم مصفوفة واحدة في الصفيف (النقاط الحمراء). تتدفق قيم المصفوفة الأخرى عبر الصفيف (النقاط الرمادية). تنشر الخطوط العمودية القيم لأعلى. تنشر الخطوط الأفقية المجاميع الجزئية. نترك للمستخدم تمرينًا للتأكّد من أنّه عندما تتدفق البيانات عبر الصفيف، ستحصل على نتيجة ضرب المصفوفة من الجانب الأيمن.

علاوة على ذلك، أثناء احتساب حاصل الضرب النقطي (MXU)، تتدفق المجاميع المتوسطة ببساطة بين وحدات الحوسبة المتجاورة. لا حاجة إلى تخزينها واستردادها إلى/من الذاكرة أو حتى ملف السجلّ. والنتيجة النهائية هي أنّ بنية صفيف وحدات معالجة الموتّرات تتمتع بكثافة وقوة كبيرة، بالإضافة إلى سرعة لا يستهان بها مقارنةً بوحدة معالجة الرسومات عند احتساب عمليات ضرب المصفوفات.

وحدة معالجة الموتّرات في السحابة الإلكترونية

عند طلب "Cloud TPU v2" واحدًا على Google Cloud Platform، ستحصل على جهاز افتراضي (VM) يحتوي على لوحة TPU مرفقة بمنفذ PCI. تحتوي لوحة TPU على أربع شرائح TPU ثنائية النواة. يتضمّن كل نواة من نوى TPU وحدة معالجة المتجهات (VPU) ووحدة MXU بحجم 128x128 (وحدة ضرب المصفوفات). يتم عادةً توصيل "وحدة معالجة الموتّرات" في السحابة الإلكترونية من خلال الشبكة بالجهاز الافتراضي الذي طلبها. لكي تبدو الصورة الكاملة على النحو التالي:

dfce5522ed644ece.png

رسم توضيحي: جهازك الظاهري مع مسرع "Cloud TPU" المرتبط بالشبكة إنّ وحدة معالجة الموتّرات في السحابة الإلكترونية Cloud TPU مصنوعة من جهاز افتراضي (VM) مزوّد بلوحة TPU مرفقة بمنفذ PCI وعليها أربع شرائح TPU ثنائية النواة.

لوحات TPU

يتم ربط وحدات معالجة الموتّرات في مراكز بيانات Google بشبكة حوسبة عالية الأداء (HPC) يمكن أن تجعلها تظهر كمسرّع كبير جدًا. وتُطلق Google على هذه المجموعات اسم "الوحدات"، ويمكن أن تتضمّن ما يصل إلى 512 نواة من TPU v2 أو 2048 نواة من TPU v3.

2ec1e0d341e7fc34.jpeg

صورة توضيحية: لوحة TPU v3 يتم توصيل لوحات ورفوف وحدة معالجة الموتّرات من خلال وصلة HPC.

أثناء التدريب، يتم تبادل التدرجات بين نوى وحدة معالجة الموتّرات باستخدام الخوارزمية الخافتة ( شرح جيد لاستنتاج كل الخوارزمية هنا). يمكن للنموذج الذي يتم تدريبه الاستفادة من الأجهزة من خلال التدريب على مجموعات كبيرة من البيانات.

d97b9cc5d40fdb1d.gif

رسم توضيحي: مزامنة التدرجات أثناء التدريب باستخدام خوارزمية all-reduce على شبكة HPC ثنائية الأبعاد للشبكة الحلزونية في Google TPU

البرنامج

تدريب باستخدام حِزم كبيرة

يبلغ حجم الدُفعة المثالي لوحدات معالجة الموتّرات ما يصل إلى 128 عنصر بيانات لكل وحدة معالجة مركزية (TPU) أساسية، ولكن يمكن أن تُظهر الأجهزة استخدامًا جيدًا من 8 عناصر بيانات لكل وحدة معالجة معالجة مركزية (TPU). تذكَّر أنّ وحدة معالجة الموتّرات في السحابة الإلكترونية تضمّ 8 أنوية.

في هذا الدرس التطبيقي حول الرموز البرمجية، سنستخدم واجهة برمجة التطبيقات Keras API. في Keras، يكون الحِزمة التي تحدّدها هي حجم الحِزمة العام لوحدة TPU بأكملها. وسيتم تقسيم دُفعاتك تلقائيًا إلى 8 نوى وتشغيلها على 8 نوى لوحدة معالجة الموتّرات.

da534407825f01e3.png

للحصول على نصائح إضافية بشأن الأداء، يمكنك الاطّلاع على دليل أداء TPU. بالنسبة إلى أحجام الدُفعات الكبيرة جدًا، قد يلزم توخي الحذر في بعض الطُرز، ويمكنك الاطّلاع على LARSOptimizer للحصول على مزيد من التفاصيل.

الجانب الداخلي: XLA

تحدِّد برامج Tensorflow الرسومات الحسابية. لا تُشغِّل وحدات معالجة النطاق الفائق (TPU) رمز Python مباشرةً، بل تُشغِّل الرسم البياني الحسابي الذي يحدِّده برنامج Tensorflow. في الخيارات المتقدمة، يعمل المحول البرمجي المسمى XLA (محول الجبر الخطي المسرّع) على تحويل الرسم البياني TensorFlow لعقد العملية الحسابية إلى رمز جهاز وحدة معالجة الموتّرات. يُجري هذا المُجمِّع أيضًا العديد من التحسينات المتقدّمة على الرمز البرمجي وتنسيق الذاكرة. وتتم عملية التجميع تلقائيًا أثناء إرسال العمل إلى وحدة معالجة الموتّرات. لست بحاجة إلى تضمين XLA في سلسلة الإنشاء بشكل صريح.

edce61112cd57972.png

صورة توضيحية: للتشغيل على وحدة معالجة الموتّرات، تتم أولاً ترجمة الرسم البياني للاحتساب الذي حدّده برنامج Tensorflow إلى تمثيل مبرمج الجبر الخطي المسرّع XLA، ثم تجميعه في رمز XLA إلى رمز جهاز TPU.

استخدام وحدات معالجة الموتّرات في Keras

يمكن استخدام وحدات معالجة النطاق الفائق (TPU) من خلال واجهة برمجة التطبيقات Keras API اعتبارًا من الإصدار 2.1 من Tensorflow. يعمل دعم Keras على وحدات معالجة الموتّرات ومجموعات وحدات معالجة الموتّرات. في ما يلي مثال يعمل على وحدات TPU ووحدات معالجة الرسومات ووحدات المعالجة المركزية:

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

في مقتطف الرمز البرمجي هذا:

  • يعثر محرّك البحث TPUClusterResolver().connect() على وحدة معالجة الموتّرات على الشبكة. يعمل هذا الإجراء بدون مَعلمات على معظم أنظمة Google Cloud (مهام "منصّة الذكاء الاصطناعي" وCollaboratory وKubeflow وأجهزة افتراضية لتعلم الآلة تم إنشاؤها من خلال الأداة "ctpu up"). تعرف هذه الأنظمة مكان وحدة معالجة الموتّرات الخاصة بها بفضل متغيّر بيئة TPU_NAME. في حال إنشاء TPU_NAME يدويًا، يمكنك ضبط بيئة TPU_NAME على الجهاز الافتراضي الذي تستخدمه منه، أو طلب TPUClusterResolver مع المعلَمات الواضحة: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy هو الجزء الذي ينفذ توزيع الخوارزمية و"تجميع كل القيم" لمزامنة التدرّج.
  • يتم تطبيق الإستراتيجية من خلال نطاق. يجب تحديد النموذج ضمن نطاق الاستراتيجية().
  • تتوقّع الدالة tpu_model.fit كائن tf.data.Dataset كمدخل لتدريب TPU.

المهام الشائعة لنقل بيانات وحدة معالجة الموتّرات

  • في حين أنّ هناك العديد من الطرق لتحميل البيانات في نموذج Tensorflow، إلا أنّه يجب استخدام واجهة برمجة التطبيقات tf.data.Dataset API بالنسبة إلى وحدات معالجة الموتّرات.
  • فوحدات معالجة الموتّرات سريعة جدًا وغالبًا ما يصبح نقل البيانات العائق عند تشغيلها. تتوفّر أدوات يمكنك استخدامها لرصد المؤثِّرات السلبية على البيانات ونصائح أخرى بشأن الأداء في دليل أداء TPU.
  • يتم التعامل مع الأرقام int8 أو int16 على أنّها int32. لا تتضمّن وحدات TPU أجهزة عددية تعمل بأقل من 32 بت.
  • بعض عمليات TensorFlow غير متاحة. القائمة هنا. الخبر السار هو أن هذا القيد لا ينطبق إلا على التعليمات البرمجية للتدريب، أي الانتقال للأمام والخلف من خلال نموذجك. سيظل بإمكانك استخدام جميع عمليات Tensorflow في مسار إدخال البيانات لأنّه سيتم تنفيذها على وحدة المعالجة المركزية.
  • لا يمكن استخدام tf.py_func على TPU.

4. تحميل البيانات

c0ecb860e4cad0a9.jpeg cc4781a7739c49ae.jpeg 81236b00f8bbf39e.jpeg 961e2228974076bb.jpeg 7517dc163bdffcd5.jpeg 96392df4767f566d.png

سوف نعمل على مجموعة بيانات لصور الزهور. والهدف هو تعلُّم تصنيفها إلى 5 أنواع من الزهور. يتم تحميل البيانات باستخدام واجهة برمجة تطبيقات tf.data.Dataset. أولاً، لنتعرّف على واجهة برمجة التطبيقات.

التدريب العملي

يُرجى فتح دفتر البيانات التالي وتنفيذ الخلايا (Shift-ENTER) واتّباع التعليمات كلما ظهر لك تصنيف "مطلوب إجراء".

c3df49e90e5a654f.png Fun with tf.data.Dataset (playground).ipynb

معلومات إضافية

لمحة عن مجموعة بيانات "الزهور"

تم تنظيم مجموعة البيانات في 5 مجلدات. يحتوي كل مجلد على زهور من نوع واحد. وهذه المجلدات تُسمى زهور دوار الشمس، وأقحوانه، والهندباء البرية، والتوليب، والورود. يتم استضافة البيانات في حزمة عامة على Google Cloud Storage. مقتطف:

gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg

ما سبب أهمية tf.data.Dataset؟

يقبل كل من Keras وTensorflow مجموعات البيانات في جميع وظائف التدريب والتقييم التابعة لهما. بمجرد تحميل البيانات في مجموعة بيانات، توفر واجهة برمجة التطبيقات جميع الوظائف الشائعة المفيدة لبيانات تدريب الشبكة العصبية:

dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training

يمكنك الاطّلاع على نصائح حول الأداء وأفضل الممارسات المتعلّقة بمجموعات البيانات في هذه المقالة. يمكنك العثور على المستندات المرجعية هنا.

أساسيات tf.data.Dataset

تأتي البيانات عادةً في ملفات متعددة، وهنا الصور. يمكنك إنشاء مجموعة بيانات لأسماء الملفات عن طريق استدعاء:

filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.

يمكنك بعد ذلك "تعيين" دالة لكل اسم ملف سيتم عادةً تحميل الملف وفك ترميزه في بيانات فعلية في الذاكرة:

def decode_jpeg(filename):
  bits = tf.io.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  return image

image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)

للتكرار التحسيني في مجموعة بيانات:

for data in my_dataset:
  print(data)

مجموعات بيانات الصفوف

في التعلّم الخاضع للإشراف، تتكون مجموعة بيانات التدريب عادةً من أزواج من بيانات التدريب والإجابات الصحيحة. للسماح بذلك، يمكن أن تعرض دالة فك التشفير مجموعات ثلاثية. سيكون لديك بعد ذلك مجموعة بيانات من الصفوف وسيتم إرجاع الصفوف عند التكرار التحسيني. القيم المعروضة هي مصفوفات Tensorflow جاهزة لاستخدامها في النموذج. يمكنك الاتصال .numpy() بها للاطّلاع على القيم الأوّلية:

def decode_jpeg_and_label(filename):
  bits = tf.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  label = ... # extract flower name from folder name
  return image, label

image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs 

for image, label in dataset:
  print(image.numpy().shape, label.numpy())

الخاتمة: إنّ تحميل الصور الواحدة تلو الأخرى بطيء.

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

الحلّ

ها هو دفتر الحل. يمكنك استخدامه إذا واجهتك مشكلة.

c3df49e90e5a654f.png Fun with tf.data.Dataset (solution).ipynb

المواضيع التي تناولناها

  • 🎉 tf.data.Dataset.list_files
  • 👀 tf.data.Dataset.map
  • 🎉 مجموعات بيانات الصفوف
  • 😀 تكرار مجموعات البيانات

يُرجى تخصيص بعض الوقت للاطّلاع على قائمة التحقّق هذه.

5- تحميل البيانات بسرعة

تتميز مسرِّعات الأجهزة لوحدة معالجة Tensor (TPU) التي سنستخدمها في هذا التمرين بالسرعة الكبيرة جدًا. غالبًا ما يتمثل التحدي في إطعامهم البيانات بسرعة كافية لإبقائهم مشغولين. يمكن لـ Google Cloud Storage (GCS) الحفاظ على معدل نقل بيانات مرتفع جدًا، ولكن كما هو الحال مع جميع أنظمة التخزين السحابي، يؤدي بدء الاتصال إلى بعض عمليات النقل في الشبكة ذهابًا وإيابًا. ولذلك، ليس من المثالي تخزين بياناتنا كآلاف من الملفات الفردية. سنجمّعها في عدد أقل من الملفات ونستخدم إمكانات tf.data.Dataset للقراءة من ملفات متعددة بشكل موازٍ.

القراءة

يمكنك العثور على الرمز الذي يحمّل ملفات الصور ويغيّر حجمها إلى حجم شائع ثم يخزّنها في 16 ملفًا من ملفات TFRecord في دفتر البيانات التالي. يرجى قراءته بسرعة. ليس من الضروري تنفيذه لأنّه سيتم توفير بيانات منسَّقة بشكل صحيح بتنسيق TFRecord في بقية ورشة رموز البرامج.

c3df49e90e5a654f.png Flower pictures to TFRecords.ipynb

تنسيق مثالي للبيانات لضمان سرعة معالجة البيانات في GCS

تنسيق ملف TFRecord

إنّ تنسيق الملف المفضّل لمنصة Tensorflow لتخزين البيانات هو تنسيق TFRecord المستند إلى protobuf. يمكن استخدام تنسيقات التسلسل الأخرى أيضًا، ولكن يمكنك تحميل مجموعة بيانات من ملفات TFRecord مباشرةً عن طريق كتابة:

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

للحصول على الأداء الأمثل، ننصحك باستخدام الرمز البرمجي الأكثر تعقيدًا للقراءة من ملفات TFRecord متعددة في الوقت نفسه. سيقرأ هذا الرمز من N ملفًا بشكل موازٍ ويتجاهل ترتيب البيانات لصالح سرعة القراءة.

AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

ورقة الملاحظات الموجزة عن TFRecord

يمكن تخزين ثلاثة أنواع من البيانات في TFRecords: سلاسل البايت (قائمة البايتات) والأعداد الصحيحة بسعة 64 بت والأعداد العشرية بسعة 32 بت. يتم تخزينها دائمًا كقوائم، وسيكون عنصر البيانات المفرد قائمة بحجم 1. يمكنك استخدام الدوال المساعِدة التالية لتخزين البيانات في TFRecords.

كتابة سلاسل البايت

# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))

كتابة الأعداد الصحيحة

def _int_feature(list_of_ints): # int64
  return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

كتابة عبارات قصيرة

def _float_feature(list_of_floats): # float32
  return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))

كتابة TFRecord باستخدام وسائل المساعدة المذكورة أعلاه

# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
  feature = {
    "image": _bytestring_feature([my_img_bytes]), # one image in the list
    "class": _int_feature([my_class]),            # one class in the list
    "size": _int_feature([my_height, my_width]),  # fixed length (2) list of ints
    "float_data": _float_feature(my_floats)       # variable length  list of floats
  }
  tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
  out_file.write(tf_record.SerializeToString())

لقراءة البيانات من TFRecords، يجب أولاً الإفصاح عن تنسيق السجلّات التي خزّنتها. في البيان، يمكنك الوصول إلى أيّ حقل مُعنوَن كقائمة ذات طول ثابت أو قائمة ذات طول متغيّر:

القراءة من TFRecords

def read_tfrecord(data):
  features = {
    # tf.string = byte string (not text string)
    "image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
    "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar, i.e. a single item
    "size": tf.io.FixedLenFeature([2], tf.int64),  # two integers
    "float_data": tf.io.VarLenFeature(tf.float32)  # a variable number of floats
  }

  # decode the TFRecord
  tf_record = tf.io.parse_single_example(data, features)

  # FixedLenFeature fields are now ready to use
  sz = tf_record['size']

  # Typical code for decoding compressed images
  image = tf.io.decode_jpeg(tf_record['image'], channels=3)

  # VarLenFeature fields require additional sparse.to_dense decoding
  float_data = tf.sparse.to_dense(tf_record['float_data'])

  return image, sz, float_data

# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)

مقتطفات الرموز المفيدة:

قراءة عناصر بيانات فردية

tf.io.FixedLenFeature([], tf.string)   # for one byte string
tf.io.FixedLenFeature([], tf.int64)    # for one int
tf.io.FixedLenFeature([], tf.float32)  # for one float

قراءة قوائم العناصر الثابتة الحجم

tf.io.FixedLenFeature([N], tf.string)   # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64)    # list of N ints
tf.io.FixedLenFeature([N], tf.float32)  # list of N floats

قراءة عدد متغيّر لعناصر البيانات

tf.io.VarLenFeature(tf.string)   # list of byte strings
tf.io.VarLenFeature(tf.int64)    # list of ints
tf.io.VarLenFeature(tf.float32)  # list of floats

تعرض VarLenFeature متجهًا متفرقًا ويجب تنفيذ خطوة إضافية بعد فك ترميز TFRecord:

dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])

من الممكن أيضًا أن تكون هناك حقول اختيارية في TFRecords. في حال تحديد قيمة تلقائية عند قراءة حقل، سيتم عرض القيمة التلقائية بدلاً من خطأ في حال عدم توفّر الحقل.

tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional

المواضيع التي تناولناها

  • 🤔 تقسيم ملفات البيانات للوصول السريع إليها من GCS
  • 😓 كيفية كتابة TFRecords (هل نسيت البنية؟ لا بأس، يمكنك وضع إشارة مرجعية لهذه الصفحة كدليل إرشادي)
  • 🤔 تحميل مجموعة بيانات من TFRecords باستخدام TFRecordDataset

يُرجى تخصيص بعض الوقت للاطّلاع على قائمة التحقّق هذه.

6- تهانينا!

يمكنك الآن تزويد وحدة معالجة TPU بالبيانات. يُرجى المتابعة إلى الدرس التطبيقي التالي.

استخدام وحدات معالجة الموتّرات في التطبيقات

تتوفّر وحدات معالجة النصوص ووحدات معالجة الرسومات على منصّة الذكاء الاصطناعي من Google Cloud:

أخيرًا، يسرّنا تلقّي ملاحظاتك. يُرجى إخبارنا بما إذا لاحظت أمرًا غير صحيح في هذا التمرين المعملي أو إذا كنت تعتقد أنه ينبغي تحسينه. يمكن تقديم الملاحظات من خلال مشاكل GitHub [ رابط الملاحظات].

HR.png

Martin Görner ID small.jpg
الكاتب: "مارتن جورنر"
Twitter: @martin_gorner