المسرع الخلفي

من السهل جدًا وصف حساب Tensor ، ولكن متى وكيف يتم إجراء هذا الحساب سيعتمد على الواجهة الخلفية المستخدمة في Tensor ومتى تكون النتائج مطلوبة على وحدة المعالجة المركزية المضيفة.

خلف الكواليس، يتم إرسال العمليات على Tensor إلى المسرعات مثل وحدات معالجة الرسومات أو وحدات المعالجة المركزية ( TPU) ، أو يتم تشغيلها على وحدة المعالجة المركزية (CPU) في حالة عدم توفر مسرع. يحدث هذا تلقائيًا بالنسبة لك، ويجعل من السهل إجراء حسابات متوازية معقدة باستخدام واجهة عالية المستوى. ومع ذلك، قد يكون من المفيد فهم كيفية حدوث هذا الإرسال والقدرة على تخصيصه للحصول على الأداء الأمثل.

يحتوي Swift for TensorFlow على واجهتين خلفيتين لإجراء العمليات الحسابية المتسارعة: وضع TensorFlow المتحمّس وX10. الواجهة الخلفية الافتراضية هي وضع TensorFlow المتلهف، ولكن يمكن تجاوز ذلك. يتوفر برنامج تعليمي تفاعلي يرشدك خلال استخدام هذه الواجهات الخلفية المختلفة.

وضع TensorFlow حريصة

تعمل الواجهة الخلفية لوضع TensorFlow على الاستفادة من واجهة برمجة تطبيقات TensorFlow C لإرسال كل عملية Tensor إلى وحدة معالجة الرسومات أو وحدة المعالجة المركزية عند مواجهتها. ثم يتم استرداد نتيجة تلك العملية وتمريرها إلى العملية التالية.

يعد إرسال كل عملية على حدة أمرًا سهل الفهم ولا يتطلب أي تكوين صريح داخل التعليمات البرمجية الخاصة بك. ومع ذلك، في كثير من الحالات، لا يؤدي ذلك إلى الأداء الأمثل بسبب النفقات العامة الناتجة عن إرسال العديد من العمليات الصغيرة، بالإضافة إلى عدم وجود دمج العمليات وتحسينها الذي يمكن أن يحدث عند وجود رسوم بيانية للعمليات. أخيرًا، وضع TensorFlow حريصًا غير متوافق مع وحدات TPU، ولا يمكن استخدامه إلا مع وحدات المعالجة المركزية (CPU) ووحدات معالجة الرسومات (GPU).

X10 (التتبع المستند إلى XLA)

X10 هو اسم الواجهة الخلفية Swift for TensorFlow التي تستخدم تتبع الموتر البطيء ومترجم تحسين XLA لتحسين الأداء بشكل كبير في كثير من الحالات عبر إرسال كل عملية على حدة. بالإضافة إلى ذلك، فهو يضيف التوافق مع وحدات TPU ، والمسرعات المُحسّنة خصيصًا لأنواع الحسابات الموجودة في نماذج التعلم الآلي.

إن استخدام X10 لحسابات Tensor ليس هو الخيار الافتراضي، لذا يتعين عليك الاشتراك في هذه الواجهة الخلفية. يتم ذلك عن طريق تحديد وضع Tensor على جهاز XLA:

let tensor1 = Tensor<Float>([0.0, 1.0, 2.0], on: Device.defaultXLA)
let tensor2 = Tensor<Float>([1.5, 2.5, 3.5], on: Device.defaultXLA)

بعد هذه النقطة، يكون وصف العملية الحسابية هو نفسه تمامًا كما هو الحال في وضع TensorFlow المتلهف:

let tensor3 = tensor1 + tensor2

يمكن توفير مزيد من التفاصيل عند إنشاء Tensor ، مثل نوع المسرّع الذي يجب استخدامه وحتى أي واحد منه متاح، إذا كان هناك العديد منه. على سبيل المثال، يمكن إنشاء Tensor على جهاز TPU الثاني (بافتراض أنه مرئي للمضيف الذي يعمل عليه البرنامج) باستخدام ما يلي:

let tpuTensor = Tensor<Float>([0.0, 1.0, 2.0], on: Device(kind: .TPU, ordinal: 1, backend: .XLA))

لا يتم إجراء أي حركة ضمنية لـ Tensor بين الأجهزة، لذلك إذا تم استخدام Tensor على أجهزة مختلفة في عملية معًا، فسيحدث خطأ في وقت التشغيل. لنسخ محتويات Tensor يدويًا إلى جهاز جديد، يمكنك استخدام مُهيئ Tensor(copying:to:) . تحتوي بعض الهياكل واسعة النطاق التي تحتوي على Tensor بداخلها، مثل النماذج والمحسنات، على وظائف مساعدة لنقل جميع Tensor الداخلية إلى جهاز جديد في خطوة واحدة.

على عكس وضع TensorFlow المتلهف، لا يتم إرسال العمليات التي تستخدم الواجهة الخلفية X10 بشكل فردي عند مواجهتها. بدلاً من ذلك، لا يتم تشغيل الإرسال إلى المسرع إلا من خلال قراءة القيم المحسوبة مرة أخرى إلى المضيف أو عن طريق وضع حاجز واضح. الطريقة التي يعمل بها هذا الأمر هي أن وقت التشغيل يبدأ من القيمة التي تتم قراءتها للمضيف (أو الحساب الأخير قبل الحاجز اليدوي) ويتتبع الرسم البياني للحسابات التي تؤدي إلى تلك القيمة.

يتم بعد ذلك تحويل هذا الرسم البياني المتتبع إلى التمثيل الوسيط لـ XLA HLO وتمريره إلى مترجم XLA ليتم تحسينه وتجميعه للتنفيذ على المسرع. ومن هناك، يتم إرسال العملية الحسابية بأكملها إلى المسرع ويتم الحصول على النتيجة النهائية.

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

بالنسبة لنماذج التعلم الآلي، غالبًا ما تتضمن عملية التدريب حلقة حيث يخضع النموذج لنفس سلسلة الحسابات مرارًا وتكرارًا. ستحتاج إلى أن يُنظر إلى كل تمريرة من هذه التمريرات على أنها تكرار لنفس الأثر، بدلاً من رسم بياني طويل يحتوي على وحدات متكررة بداخله. يتم تمكين ذلك عن طريق الإدخال اليدوي لاستدعاء وظيفة LazyTensorBarrier() في المواقع الموجودة في التعليمات البرمجية الخاصة بك حيث ترغب في إنهاء التتبع.

دعم الدقة المختلطة في X10

يتم دعم التدريب بدقة مختلطة عبر X10 ويتم توفير واجهة برمجة التطبيقات (API) ذات المستوى المنخفض والعالي للتحكم فيه. توفر واجهة برمجة التطبيقات ذات المستوى المنخفض خاصيتين محسوبتين: toReducedPrecision و toFullPrecision اللتين تقومان بالتحويل بين الدقة الكاملة والمخفضة، إلى جانب isReducedPrecision للاستعلام عن الدقة. إلى جانب Tensor ، يمكن تحويل النماذج والمحسنات بين الدقة الكاملة والمخفضة باستخدام واجهة برمجة التطبيقات هذه.

لاحظ أن التحويل إلى دقة منخفضة لا يغير النوع المنطقي لل Tensor . إذا كان t عبارة عن Tensor<Float> ، فإن t.toReducedPrecision هو أيضًا Tensor<Float> مع تمثيل أساسي منخفض الدقة.

كما هو الحال مع الأجهزة، لا يُسمح بالعمليات بين الموترات ذات الدقة المختلفة. يؤدي هذا إلى تجنب الترويج الصامت وغير المرغوب فيه لعوامات 32 بت، والتي سيكون من الصعب اكتشافها من قبل المستخدم.