تم تصميم Layers API لـ TensorFlow.js على غرار Keras ونحن نسعى جاهدين لجعل Layers API مشابهة لـ 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 ، بحيث يمكن استخدام هذه الوظيفة بطريقة لا تحجب مؤشر ترابط واجهة المستخدم الرئيسي عند التشغيل في المتصفح. هذا مشابه للوظائف الأخرى التي يحتمل تشغيلها لفترة طويلة في JavaScript ، مثل الجلب غير async
. لاحظ أن عدم 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 Core لمزيد من المعلومات.
استخدم طرق المصنع وليس المصنّعين
هذا السطر في بايثون (من المثال أعلاه) هو استدعاء منشئ:
# Python:
model = keras.Sequential()
إذا تمت ترجمتها بدقة إلى JavaScript ، فسيبدو استدعاء المُنشئ المكافئ كما يلي:
// JavaScript:
const model = new tf.Sequential(); // !!! DON'T DO THIS !!!
ومع ذلك ، قررنا عدم استخدام المنشئات "الجديدة" لأن 1) الكلمة الرئيسية "الجديدة" ستجعل الشفرة أكثر تضخمًا و 2) يُنظر إلى المُنشئ "الجديد" على أنه "جزء سيء" من JavaScript: مشكلة محتملة ، مثل في JavaScript: the Good Parts . لإنشاء نماذج وطبقات في TensorFlow.js ، يمكنك استدعاء طرق المصنع ، والتي لها أسماء أقل من أحرف الجمل ، على سبيل المثال:
// JavaScript:
const model = tf.sequential();
const layer = tf.layers.batchNormalization({axis: 1});
قيم سلسلة الخيار هي LowerCamelCase ، وليس snake_case
في JavaScript ، من الشائع أكثر استخدام حالة الجمل لأسماء الرموز (على سبيل المثال ، راجع دليل أنماط جافا سكريبت من Google ) ، مقارنة ببايثون ، حيث تكون حالة الأفعى شائعة (على سبيل المثال ، في Keras). على هذا النحو ، قررنا استخدام LowerCamelCase لقيم السلسلة للخيارات بما في ذلك ما يلي:
- تنسيق البيانات ، على سبيل المثال ،
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)
يتم تنفيذ هذا السكر النحوي في لغة بايثون كطريقة 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 ، يمكن أن تعمل طريقة الاستدعاء فقط على (Python) TensorFlow's tf.Tensor
كائنات (بافتراض TensorFlow الخلفية) ، والتي تعتبر رمزية ولا تحتوي على قيم رقمية فعلية. هذا ما يظهر في المثال في القسم السابق. ومع ذلك ، في TensorFlow.js ، يمكن أن تعمل طريقة التطبيق () للطبقات في كل من الأوضاع الرمزية والضرورية. إذا تم استدعاء apply()
باستخدام SymbolicTensor (تشبيه وثيق لـ tf.Tensor) ، فستكون القيمة المعادة SymbolicTensor. يحدث هذا عادةً أثناء بناء النموذج. ولكن إذا تم استدعاء " apply()
مع قيمة "تنسور" ملموسة فعلية ، فإنه سيعيد "تنسور" ملموس. فمثلا:
// JavaScript:
const flatten = tf.layers.flatten();
flatten.apply(tf.ones([2, 3, 4])).print();
هذه الميزة تذكرنا بتنفيذ (Python) TensorFlow's Eager Execution . إنه يوفر قدرًا أكبر من التفاعل وإمكانية تصحيح الأخطاء أثناء تطوير النموذج ، بالإضافة إلى فتح الأبواب لتكوين شبكات عصبية ديناميكية.
Optimizers تحت التدريب. ، وليس المحسِّنون.
في Keras ، توجد أدوات إنشاء كائنات Optimizer ضمن مساحة الاسم keras.optimizers.*
. في طبقات TensorFlow.js ، تقع طرق المصنع الخاصة بالمحسِنين ضمن مساحة الاسم 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 pip.
// JavaScript:
const model = await tf.loadLayersModel('https://foo.bar/model.json');
لاحظ أيضًا أن tf.loadLayersModel()
ترجع tf.Model
Promise
بشكل عام ، يتم حفظ وتحميل tf.Model
s في TensorFlow.js باستخدام طرق tf.Model.save
و tf.loadLayersModel
، على التوالي. لقد صممنا واجهات برمجة التطبيقات هذه لتكون مشابهة لواجهة برمجة تطبيقات الحفظ والتحميل في Keras. لكن بيئة المتصفح مختلفة تمامًا عن بيئة الواجهة الخلفية التي تعمل عليها أطر عمل التعلم العميق الأساسية مثل Keras ، لا سيما في مجموعة المسارات لاستمرار البيانات ونقلها. ومن ثم هناك بعض الاختلافات المثيرة للاهتمام بين حفظ / تحميل واجهات برمجة التطبيقات في TensorFlow.js و Keras. راجع البرنامج التعليمي الخاص بنا حول حفظ نموذج tf وتحميله لمزيد من التفاصيل.
استخدم fitDataset()
لتدريب النماذج باستخدام كائنات tf.data.Dataset
في tf.keras من Python TensorFlow ، يمكن تدريب النموذج باستخدام كائن مجموعة البيانات . تقبل طريقة fit()
الخاصة بالنموذج مثل هذا الكائن مباشرة. يمكن تدريب نموذج TensorFlow.js باستخدام مكافئ JavaScript لكائنات مجموعة البيانات أيضًا (راجع توثيق واجهة برمجة تطبيقات tf.data في TensorFlow.js ). ومع ذلك ، على عكس Python ، يتم التدريب القائم على مجموعة البيانات من خلال طريقة مخصصة ، وهي fitDataset . طريقة fit () مخصصة فقط لتدريب النموذج القائم على الموتر.
إدارة ذاكرة كائنات الطبقة والنموذج
يعمل TensorFlow.js على WebGL في المتصفح ، حيث يتم دعم أوزان كائنات الطبقة والنموذج بواسطة مواد WebGL. ومع ذلك ، لا يحتوي WebGL على دعم مضمن لجمع البيانات المهملة. تدير كائنات الطبقة والنموذج داخليًا ذاكرة الموتر للمستخدم أثناء مكالمات الاستدلال والتدريب. لكنها تسمح أيضًا للمستخدم بالتخلص منها لتحرير ذاكرة WebGL التي يشغلونها. يكون هذا مفيدًا في الحالات التي يتم فيها إنشاء العديد من مثيلات النموذج وإصدارها أثناء تحميل صفحة واحدة. للتخلص من كائن Layer أو Model ، استخدم طريقة dispose()
.