يعمل TensorFlow.js في المتصفح و Node.js ، وهناك العديد من التكوينات المختلفة المتاحة في كلا النظامين. لكل منصة مجموعة فريدة من الاعتبارات التي ستؤثر على طريقة تطوير التطبيقات.
في المتصفح ، يدعم TensorFlow.js الأجهزة المحمولة وكذلك أجهزة سطح المكتب. يحتوي كل جهاز على مجموعة محددة من القيود ، مثل واجهات برمجة تطبيقات WebGL المتاحة ، والتي يتم تحديدها وتهيئتها تلقائيًا لك.
في Node.js ، يدعم TensorFlow.js الارتباط مباشرة بواجهة برمجة تطبيقات TensorFlow أو التشغيل باستخدام تطبيقات وحدة المعالجة المركزية الفانيليا الأبطأ.
البيئات
عند تنفيذ برنامج TensorFlow.js ، يُطلق على التكوين المحدد اسم البيئة. تتكون البيئة من خلفية عالمية واحدة بالإضافة إلى مجموعة من العلامات التي تتحكم في الميزات الدقيقة لـ TensorFlow.js.
الخلفية
يدعم TensorFlow.js العديد من الخلفيات الخلفية المختلفة التي تنفذ تخزين الموتر والعمليات الحسابية. في أي وقت ، تكون خلفية واحدة فقط نشطة. في معظم الأوقات ، سيختار TensorFlow.js تلقائيًا أفضل واجهة خلفية بالنسبة لك في ظل البيئة الحالية. ومع ذلك ، من المهم أحيانًا معرفة الخلفية المستخدمة وكيفية تبديلها.
للعثور على الخلفية التي تستخدمها:
console.log(tf.getBackend());
إذا كنت تريد تغيير الواجهة الخلفية يدويًا:
tf.setBackend('cpu');
console.log(tf.getBackend());
خلفية WebGL
تعد واجهة WebGL الخلفية ، "webgl" ، أقوى واجهة خلفية للمتصفح حاليًا. هذه الواجهة الخلفية أسرع بما يصل إلى 100 مرة من الخلفية الفانيليا لوحدة المعالجة المركزية. يتم تخزين الموترات على هيئة نسيج WebGL ويتم تنفيذ العمليات الحسابية في تظليل WebGL. إليك بعض الأشياء المفيدة التي يجب معرفتها عند استخدام هذه الخلفية: \
تجنب حظر مؤشر ترابط واجهة المستخدم
عندما يتم استدعاء عملية ، مثل tf.matMul (a ، b) ، يتم إرجاع tf.Tensor الناتج بشكل متزامن ، ولكن حساب ضرب المصفوفة قد لا يكون جاهزًا بالفعل بعد. هذا يعني أن tf.Tensor الذي تم إرجاعه هو مجرد مؤشر للحساب. عند استدعاء x.data()
أو x.array()
، سيتم حل القيم عند اكتمال الحساب بالفعل. هذا يجعل من المهم استخدام x.data()
و x.array()
غير المتزامنة على نظيراتها المتزامنة x.dataSync()
و x.arraySync()
لتجنب حظر مؤشر ترابط واجهة المستخدم أثناء اكتمال الحساب.
إدارة الذاكرة
أحد التحذيرات عند استخدام الواجهة الخلفية لـ WebGL هو الحاجة إلى إدارة صريحة للذاكرة. WebGLTextures ، حيث يتم تخزين بيانات Tensor في النهاية ، لا يتم جمعها تلقائيًا بواسطة المتصفح.
لتدمير ذاكرة tf.Tensor
، يمكنك استخدام التابع dispose()
:
const a = tf.tensor([[1, 2], [3, 4]]);
a.dispose();
من الشائع جدًا ربط عمليات متعددة معًا في أحد التطبيقات. يمكن أن يؤدي الاحتفاظ بمرجع إلى جميع المتغيرات الوسيطة للتخلص منها إلى تقليل قابلية قراءة الكود. لحل هذه المشكلة ، يوفر TensorFlow.js طريقة tf.tidy()
التي تنظف جميع tf.Tensor
التي لم يتم إرجاعها بواسطة دالة بعد تنفيذها ، على غرار الطريقة التي يتم بها تنظيف المتغيرات المحلية عند تنفيذ الوظيفة:
const a = tf.tensor([[1, 2], [3, 4]]);
const y = tf.tidy(() => {
const result = a.square().log().neg();
return result;
});
دقة
على الأجهزة المحمولة ، قد يدعم WebGL نسيج النقطة العائمة 16 بت فقط. ومع ذلك ، يتم تدريب معظم نماذج التعلم الآلي باستخدام أوزان وتنشيطات النقطة العائمة 32 بت. يمكن أن يتسبب هذا في مشكلات تتعلق بالدقة عند نقل نموذج لجهاز محمول حيث يمكن للأرقام العائمة 16 بت أن تمثل فقط أرقامًا في النطاق [0.000000059605, 65504]
. هذا يعني أنه يجب أن تكون حريصًا على ألا تتجاوز الأوزان والتنشيطات في نموذجك هذا النطاق. للتحقق مما إذا كان الجهاز يدعم مواد 32 بت ، تحقق من قيمة tf.ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE')
، إذا كان هذا خطأ ، فإن الجهاز يدعم فقط مواد ذات فاصلة عائمة 16 بت. يمكنك استخدام tf.ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED')
للتحقق مما إذا كان TensorFlow.js يستخدم حاليًا مواد ذات 32 بت.
تجميع شادر وتحميل الملمس
ينفذ TensorFlow.js العمليات على وحدة معالجة الرسومات عن طريق تشغيل برامج WebGL shader. يتم تجميع هذه المظلات وتجميعها بتكاسل عندما يطلب المستخدم تنفيذ عملية ما. يحدث تجميع تظليل على وحدة المعالجة المركزية على الخيط الرئيسي ويمكن أن يكون بطيئًا. TensorFlow.js سوف يخزن التظليل المترجمة تلقائيًا ، مما يجعل الاستدعاء الثاني لنفس العملية مع موتر الإدخال والإخراج من نفس الشكل أسرع بكثير. عادةً ما تستخدم تطبيقات TensorFlow.js العمليات نفسها عدة مرات في عمر التطبيق ، وبالتالي فإن المرور الثاني عبر نموذج التعلم الآلي يكون أسرع بكثير.
يقوم TensorFlow.js أيضًا بتخزين بيانات tf.Tensor على هيئة WebGLTextures. عندما يتم إنشاء tf.Tensor
، فإننا لا نقوم بتحميل البيانات على الفور إلى وحدة معالجة الرسومات ، بل نحتفظ بالبيانات على وحدة المعالجة المركزية حتى يتم استخدام tf.Tensor
في عملية ما. إذا تم استخدام tf.Tensor
للمرة الثانية ، فإن البيانات موجودة بالفعل على وحدة معالجة الرسومات (GPU) لذلك لا توجد تكلفة تحميل. في نموذج التعلم الآلي النموذجي ، يعني هذا أنه يتم تحميل الأوزان أثناء التوقع الأول من خلال النموذج وسيكون المرور الثاني عبر النموذج أسرع بكثير.
إذا كنت تهتم بأداء التوقع الأول من خلال النموذج الخاص بك أو رمز TensorFlow.js ، فإننا نوصي بتسخين النموذج عن طريق تمرير Tensor للإدخال من نفس الشكل قبل استخدام البيانات الحقيقية.
فمثلا:
const model = await tf.loadLayersModel(modelUrl);
// Warmup the model before using real data.
const warmupResult = model.predict(tf.zeros(inputShape));
warmupResult.dataSync();
warmupResult.dispose();
// The second predict() will be much faster
const result = model.predict(userData);
Node.js TensorFlow الخلفية
في TensorFlow Node.js backend ، "العقدة" ، يتم استخدام TensorFlow C API لتسريع العمليات. سيستخدم هذا تسريع الأجهزة المتاح للجهاز ، مثل CUDA ، إذا كان متاحًا.
في هذه الخلفية ، تمامًا مثل WebGL الخلفية ، ترجع العمليات tf.Tensor
s بشكل متزامن. ومع ذلك ، على عكس الواجهة الخلفية لـ WebGL ، تكتمل العملية قبل استعادة الموتر. هذا يعني أن استدعاء tf.matMul(a, b)
سوف يحظر مؤشر ترابط واجهة المستخدم.
لهذا السبب ، إذا كنت تنوي استخدام هذا في تطبيق إنتاج ، فيجب عليك تشغيل TensorFlow.js في سلاسل عمليات العاملين حتى لا تحظر مؤشر الترابط الرئيسي.
لمزيد من المعلومات حول Node.js ، راجع هذا الدليل.
WASM الخلفية
يوفر TensorFlow.js واجهة WebAssembly الخلفية ( wasm
) ، والتي توفر تسريع وحدة المعالجة المركزية ويمكن استخدامها كبديل لوحدة المعالجة cpu
(CPU) و WebGL المسرّعة ( webgl
). لتستخدمها:
// Set the backend to WASM and wait for the module to be ready.
tf.setBackend('wasm');
tf.ready().then(() => {...});
إذا كان الخادم الخاص بك يقدم ملف .wasm
على مسار مختلف أو اسم مختلف ، فاستخدم setWasmPath
قبل تهيئة الواجهة الخلفية. راجع قسم "استخدام الحزم" في README لمزيد من المعلومات:
import {setWasmPath} from '@tensorflow/tfjs-backend-wasm';
setWasmPath(yourCustomPath);
tf.setBackend('wasm');
tf.ready().then(() => {...});
لماذا WASM؟
تم تقديم WASM في عام 2015 كتنسيق ثنائي جديد قائم على الويب ، مما يوفر برامج مكتوبة بلغة JavaScript و C و C ++ وما إلى ذلك ، هدف تجميع للتشغيل على الويب. تم دعم WASM بواسطة Chrome و Safari و Firefox و Edge منذ عام 2017 ، وهو مدعوم بنسبة 90٪ من الأجهزة حول العالم.
أداء
تستفيد الواجهة الخلفية لـ WASM من مكتبة XNNPACK من أجل التنفيذ الأمثل لمشغلي الشبكات العصبية.
مقابل JavaScript : تعد ثنائيات WASM بشكل عام أسرع بكثير من حزم JavaScript بالنسبة للمتصفحات لتحميلها وتحليلها وتنفيذها. يتم كتابة JavaScript ديناميكيًا وجمع البيانات المهملة ، مما قد يتسبب في حدوث تباطؤ في وقت التشغيل.
مقابل WebGL : يعد WebGL أسرع من WASM لمعظم الطرز ، ولكن بالنسبة للنماذج الصغيرة ، يمكن لـ WASM أن يتفوق على WebGL بسبب التكاليف العامة الثابتة لتنفيذ تظليل WebGL. يناقش قسم "متى يجب استخدام WASM" أدناه الأساليب الاستدلالية لاتخاذ هذا القرار.
قابلية وثبات
يحتوي WASM على حساب تعويم محمول 32 بت ، مما يوفر تكافؤًا دقيقًا عبر جميع الأجهزة. من ناحية أخرى ، يعد WebGL خاصًا بالأجهزة ويمكن أن يكون للأجهزة المختلفة دقة متفاوتة (على سبيل المثال ، الرجوع إلى عوامات 16 بت على أجهزة iOS).
مثل WebGL ، يتم دعم WASM رسميًا من قبل جميع المتصفحات الرئيسية. على عكس WebGL ، يمكن تشغيل WASM في Node.js ، ويمكن استخدامه من جانب الخادم دون الحاجة إلى تجميع مكتبات أصلية.
متى يجب علي استخدام WASM؟
حجم النموذج والطلب الحسابي
بشكل عام ، يعد WASM اختيارًا جيدًا عندما تكون الطرز أصغر أو عندما تهتم بالأجهزة ذات النهاية المنخفضة التي تفتقر إلى دعم WebGL (امتداد OES_texture_float
) أو بها وحدات معالجة رسومات أقل قوة. يوضح الرسم البياني أدناه أوقات الاستدلال (اعتبارًا من TensorFlow.js 1.5.2) في Chrome على 2018 MacBook Pro لـ 5 من طرزنا المدعومة رسميًا عبر WebGL و WASM و CPU الخلفية:
نماذج أصغر
نموذج | WebGL | كان م | وحدة المعالجة المركزية | ذاكرة |
---|---|---|---|---|
BlazeFace | 22.5 مللي ثانية | 15.6 مللي ثانية | 315.2 مللي ثانية | .4 ميغا بايت |
FaceMesh | 19.3 مللي ثانية | 19.2 مللي ثانية | 335 مللي ثانية | 2.8 ميجا بايت |
نماذج أكبر
نموذج | WebGL | كان م | وحدة المعالجة المركزية | ذاكرة |
---|---|---|---|---|
بوسنت | 42.5 مللي ثانية | 173.9 مللي ثانية | 1514.7 مللي ثانية | 4.5 ميجا بايت |
BodyPix | 77 مللي ثانية | 188.4 مللي ثانية | 2683 مللي ثانية | 4.6 ميجا بايت |
موبايل نت v2 | 37 مللي ثانية | 94 مللي ثانية | 923.6 مللي ثانية | 13 ميجا بايت |
يوضح الجدول أعلاه أن WASM أسرع بمقدار 10-30 مرة من الواجهة الخلفية لوحدة المعالجة المركزية JS العادية عبر الطرز ، ومنافسة مع WebGL للطرز الأصغر مثل BlazeFace ، وهي خفيفة الوزن (400 كيلو بايت) ، ومع ذلك تحتوي على عدد مناسب من العمليات (~ 140). بالنظر إلى أن برامج WebGL لها تكلفة ثابتة لكل عملية تنفيذ ، فإن هذا يفسر سبب كون نماذج مثل BlazeFace أسرع على WASM.
ستختلف هذه النتائج حسب جهازك. أفضل طريقة لتحديد ما إذا كان WASM مناسبًا لتطبيقك هو اختباره على خلفياتنا الخلفية المختلفة.
الاستدلال مقابل التدريب
لمعالجة حالة الاستخدام الأساسية لنشر النماذج المدربة مسبقًا ، سيعطي تطوير الواجهة الخلفية لـ WASM الأولوية للاستدلال على دعم التدريب . راجع قائمة محدثة من العمليات المدعومة في WASM وأخبرنا إذا كان نموذجك يحتوي على عملية غير مدعومة. بالنسبة لنماذج التدريب ، نوصي باستخدام الواجهة الخلفية Node (TensorFlow C ++) أو الواجهة الخلفية لـ WebGL.
خلفية وحدة المعالجة المركزية
تعد الواجهة الخلفية لوحدة المعالجة المركزية ، "وحدة المعالجة المركزية" ، الواجهة الخلفية الأقل أداءً ، ولكنها أبسطها. يتم تنفيذ جميع العمليات في Vanilla JavaScript ، مما يجعلها أقل قابلية للتوازي. كما أنها تمنع مؤشر ترابط واجهة المستخدم.
يمكن أن تكون هذه الواجهة الخلفية مفيدة جدًا للاختبار ، أو على الأجهزة التي لا يتوفر فيها WebGL.
أعلام
يحتوي TensorFlow.js على مجموعة من علامات البيئة التي يتم تقييمها تلقائيًا وتحديد أفضل تكوين في النظام الأساسي الحالي. هذه العلامات داخلية في الغالب ، ولكن يمكن التحكم في عدد قليل من العلامات العالمية باستخدام واجهة برمجة التطبيقات العامة.
-
tf.enableProdMode():
يُمكّن وضع الإنتاج ، والذي سيزيل التحقق من صحة النموذج ، وفحوصات NaN ، وفحوصات الصحة الأخرى لصالح الأداء. -
tf.enableDebugMode()
: يُمكّن وضع التصحيح ، والذي سيسجل إلى وحدة التحكم في كل عملية يتم تنفيذها ، بالإضافة إلى معلومات أداء وقت التشغيل مثل مساحة الذاكرة وإجمالي وقت تنفيذ kernel. لاحظ أن هذا سيؤدي إلى إبطاء تطبيقك بشكل كبير ، فلا تستخدمه في الإنتاج.