واجهة برمجة تطبيقات طبقات TensorFlow.js لمستخدمي Keras

تم تصميم واجهة برمجة تطبيقات الطبقات الخاصة بـ TensorFlow.js على غرار Keras ونحن نسعى جاهدين لجعل واجهة برمجة تطبيقات الطبقات مشابهة لـ Keras بقدر معقول نظرًا للاختلافات بين JavaScript وPython. وهذا يسهل على المستخدمين ذوي الخبرة في تطوير نماذج Keras في Python الانتقال إلى طبقات TensorFlow.js في JavaScript. على سبيل المثال، يتم ترجمة كود Keras التالي إلى JavaScript:

# Python:
import keras
import numpy as np

# Build and compile model.
model = keras.Sequential()
model.add(keras.layers.Dense(units=1, input_shape=[1]))
model.compile(optimizer='sgd', loss='mean_squared_error')

# Generate some synthetic data for training.
xs = np.array([[1], [2], [3], [4]])
ys = np.array([[1], [3], [5], [7]])

# Train model with fit().
model.fit(xs, ys, epochs=1000)

# Run inference with predict().
print(model.predict(np.array([[5]])))
// JavaScript:
import * as tf from '@tensorflow/tfjs';

// Build and compile model.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});

// Generate some synthetic data for training.
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);
const ys = tf.tensor2d([[1], [3], [5], [7]], [4, 1]);

// Train model with fit().
await model.fit(xs, ys, {epochs: 1000});

// Run inference with predict().
model.predict(tf.tensor2d([[5]], [1, 1])).print();

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

يأخذ المنشئون كائنات JavaScript كتكوينات

قارن بين خطوط Python وJavaScript التالية من المثال أعلاه: كلاهما ينشئ طبقة كثيفة .

# Python:
keras.layers.Dense(units=1, inputShape=[1])
// JavaScript:
tf.layers.dense({units: 1, inputShape: [1]});

لا تحتوي وظائف JavaScript على ما يعادل وسيطات الكلمات الرئيسية في وظائف Python. نريد تجنب تنفيذ خيارات المنشئ كوسائط موضعية في JavaScript، والتي قد يكون من الصعب تذكرها واستخدامها بشكل خاص للمنشئات التي تحتوي على عدد كبير من وسائط الكلمات الرئيسية (على سبيل المثال، LSTM ). ولهذا السبب نستخدم كائنات تكوين JavaScript. توفر مثل هذه الكائنات نفس المستوى من الثبات الموضعي والمرونة مثل وسيطات الكلمات الأساسية في Python.

بعض أساليب فئة النموذج، على سبيل المثال، Model.compile() ، تأخذ أيضًا كائن تكوين JavaScript كمدخل. ومع ذلك، ضع في اعتبارك أن Model.fit() و Model.evaluate() و Model.predict() مختلفان قليلًا. نظرًا لأن هذه الطريقة تأخذ بيانات x (الميزات) و y (التسميات أو الأهداف) الإلزامية كمدخلات؛ x و y هما وسيطتان موضعيتان منفصلتان عن كائن التكوين التالي الذي يلعب دور وسيطات الكلمة الأساسية. على سبيل المثال:

// JavaScript:
await model.fit(xs, ys, {epochs: 1000});

Model.fit() غير متزامن

Model.fit() هي الطريقة الأساسية التي يستخدمها المستخدمون لإجراء تدريب نموذجي في TensorFlow.js. غالبًا ما تكون هذه الطريقة طويلة الأمد، وتدوم لثواني أو دقائق. لذلك، نستخدم ميزة async في لغة جافا سكريبت، بحيث يمكن استخدام هذه الوظيفة بطريقة لا تمنع سلسلة واجهة المستخدم الرئيسية عند التشغيل في المتصفح. وهذا مشابه للوظائف الأخرى التي قد تكون طويلة الأمد في JavaScript، مثل async fetch . لاحظ أن async هو بناء غير موجود في بايثون. بينما يقوم التابع fit() في Keras بإرجاع كائن History، فإن نظير التابع fit() في JavaScript يُرجع وعدًا بالتاريخ، والذي يمكن انتظاره (كما في المثال أعلاه) أو استخدامه مع التابعthen().

لا يوجد NumPy لـ TensorFlow.js

غالبًا ما يستخدم مستخدمو Python Keras NumPy لإجراء العمليات الرقمية والمصفوفات الأساسية، مثل إنشاء موترات ثنائية الأبعاد في المثال أعلاه.

# Python:
xs = np.array([[1], [2], [3], [4]])

في TensorFlow.js، يتم تنفيذ هذا النوع من العمليات الرقمية الأساسية باستخدام الحزمة نفسها. على سبيل المثال:

// JavaScript:
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);

توفر مساحة الاسم tf.* أيضًا عددًا من الوظائف الأخرى لعمليات المصفوفة والجبر الخطي مثل ضرب المصفوفات. راجع الوثائق الأساسية لـ TensorFlow.js لمزيد من المعلومات.

استخدم أساليب المصنع، وليس المنشئين

هذا السطر في بايثون (من المثال أعلاه) هو استدعاء منشئ:

# Python:
model = keras.Sequential()

إذا تمت ترجمته بدقة إلى JavaScript، فسيبدو استدعاء المنشئ المكافئ كما يلي:

// JavaScript:
const model = new tf.Sequential();  // !!! DON'T DO THIS !!!

ومع ذلك، قررنا عدم استخدام المنشئات "الجديدة" لأن 1) الكلمة الأساسية "جديدة" ستجعل الكود أكثر تضخمًا و2) يعتبر المنشئ "الجديد" جزءًا "سيئًا" من JavaScript: وهو مأزق محتمل، كما تمت مناقشته في JavaScript: الأجزاء الجيدة . لإنشاء نماذج وطبقات في TensorFlow.js، يمكنك استدعاء أساليب المصنع، التي لها أسماء LowerCamelCase، على سبيل المثال:

// JavaScript:
const model = tf.sequential();

const layer = tf.layers.batchNormalization({axis: 1});

قيم سلسلة الخيار هي LowerCamelCase، وليس Snake_case

في جافا سكريبت، من الشائع استخدام حالة الجمل لأسماء الرموز (على سبيل المثال، راجع دليل أنماط جافا سكريبت من Google )، مقارنةً ببايثون، حيث تكون حالة الثعبان شائعة (على سبيل المثال، في Keras). على هذا النحو، قررنا استخدام LowerCamelCase لقيم السلسلة للخيارات بما في ذلك ما يلي:

  • DataFormat، على سبيل المثال، channelsFirst بدلاً من channels_first
  • المُهيئ، على سبيل المثال، glorotNormal بدلاً من glorot_normal
  • الخسارة والمقاييس، على سبيل المثال، meanSquaredError بدلاً من mean_squared_error و categoricalCrossentropy بدلاً من categorical_crossentropy .

على سبيل المثال، كما في المثال أعلاه:

// JavaScript:
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});

فيما يتعلق بتسلسل النموذج وإلغاء التسلسل، كن مطمئنًا. تضمن الآلية الداخلية لـ TensorFlow.js معالجة حالات الثعبان في كائنات JSON بشكل صحيح، على سبيل المثال، عند تحميل النماذج المدربة مسبقًا من Python Keras.

قم بتشغيل كائنات الطبقة باستخدام application()، وليس عن طريق استدعائها كوظائف

في Keras، يحتوي كائن الطبقة على طريقة __call__ محددة. ولذلك يمكن للمستخدم استدعاء منطق الطبقة عن طريق استدعاء الكائن كوظيفة، على سبيل المثال،

# Python:
my_input = keras.Input(shape=[2, 4])
flatten = keras.layers.Flatten()

print(flatten(my_input).shape)

يتم تنفيذ سكر بناء جملة Python كأسلوب application() في TensorFlow.js:

// JavaScript:
const myInput = tf.input({shape: [2, 4]});
const flatten = tf.layers.flatten();

console.log(flatten.apply(myInput).shape);

يدعم Layer.apply() التقييم الحتمي (الحريص) على الموترات الخرسانية

حاليًا، في Keras، يمكن أن تعمل طريقة الاتصال فقط على كائنات tf.Tensor الخاصة بـ TensorFlow (بايثون) (بافتراض الواجهة الخلفية لـ TensorFlow)، وهي رمزية ولا تحتوي على قيم رقمية فعلية. وهذا ما يظهر في المثال في القسم السابق. ومع ذلك، في TensorFlow.js، يمكن أن تعمل طريقة application() للطبقات في كلا الوضعين الرمزي والضروري. إذا تم استدعاء apply() باستخدام SymonicTensor (تشبيه وثيق لـ tf.Tensor)، فستكون القيمة المرجعة هي SymonicTensor. يحدث هذا عادةً أثناء بناء النموذج. ولكن إذا تم استدعاء apply() بقيمة Tensor ملموسة فعلية، فسوف يُرجع Tensor ملموسة. على سبيل المثال:

// JavaScript:
const flatten = tf.layers.flatten();

flatten.apply(tf.ones([2, 3, 4])).print();

تذكرنا هذه الميزة بـ (Python) TensorFlow's Eager Execution . فهو يوفر قدرًا أكبر من التفاعل وقابلية التصحيح أثناء تطوير النموذج، بالإضافة إلى فتح الأبواب لتكوين شبكات عصبية ديناميكية.

أدوات تحسين الأداء قيد التدريب. ، وليس المحسنين.

في Keras، توجد مُنشئات كائنات Optimizer ضمن مساحة الاسم keras.optimizers.* . في طبقات TensorFlow.js، توجد أساليب المصنع الخاصة بـ Optimizers ضمن مساحة الاسم tf.train.* . على سبيل المثال:

# Python:
my_sgd = keras.optimizers.sgd(lr=0.2)
// JavaScript:
const mySGD = tf.train.sgd({lr: 0.2});

يتم تحميل LoadLayersModel() من عنوان URL، وليس من ملف HDF5

في Keras، عادةً ما يتم حفظ النماذج كملف HDF5 (.h5)، والذي يمكن تحميله لاحقًا باستخدام طريقة keras.models.load_model() . يأخذ الأسلوب مسارًا إلى الملف .h5. نظير load_model() في TensorFlow.js هو tf.loadLayersModel() . نظرًا لأن HDF5 ليس تنسيق ملف مناسبًا للمتصفح، tf.loadLayersModel() يأخذ تنسيقًا خاصًا بـ TensorFlow.js. يأخذ tf.loadLayersModel() ملف model.json كوسيطة إدخال خاصة به. يمكن تحويل model.json من ملف Keras HDF5 باستخدام حزمة النقاط Tensorflowjs.

// JavaScript:
const model = await tf.loadLayersModel('https://foo.bar/model.json');

لاحظ أيضًا أن tf.loadLayersModel() يُرجع Promise بـ tf.Model .

بشكل عام، يتم حفظ وتحميل tf.Model s في TensorFlow.js باستخدام طريقتي tf.Model.save و tf.loadLayersModel ، على التوالي. لقد صممنا واجهات برمجة التطبيقات هذه لتكون مشابهة لواجهة برمجة تطبيقات save وload_model الخاصة بـ Keras. لكن بيئة المتصفح تختلف تمامًا عن البيئة الخلفية التي تعمل عليها أطر التعلم العميق الأساسية مثل Keras، لا سيما في مجموعة المسارات لاستمرار البيانات ونقلها. ومن ثم هناك بعض الاختلافات المثيرة للاهتمام بين واجهات برمجة التطبيقات للحفظ/التحميل في TensorFlow.js وفي Keras. راجع برنامجنا التعليمي حول حفظ وتحميل tf.Model لمزيد من التفاصيل.

استخدم fitDataset() لتدريب النماذج باستخدام كائنات tf.data.Dataset

في tf.keras الخاص بـ Python TensorFlow، يمكن تدريب النموذج باستخدام كائن Dataset . تقبل طريقة fit() الخاصة بالنموذج مثل هذا الكائن مباشرة. يمكن تدريب نموذج TensorFlow.js باستخدام ما يعادل JavaScript لكائنات Dataset أيضًا (راجع وثائق tf.data API في TensorFlow.js ). ومع ذلك، على عكس لغة بايثون، يتم التدريب القائم على مجموعة البيانات من خلال طريقة مخصصة، وهي fitDataset . طريقة fit() مخصصة فقط للتدريب على النماذج المستندة إلى الموتر.

إدارة الذاكرة لكائنات الطبقة والنموذج

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