TensorFlow.js שכבות API עבור משתמשי Keras

ה-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, למשל, 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 הוא מבנה שלא קיים ב-Python. בעוד ששיטת 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: החלקים הטובים . כדי ליצור מודלים ושכבות ב-TensorFlow.js, אתה קורא לשיטות factory, שיש להן שמות LowerCamelCase, למשל:

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

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

ערכי מחרוזת אפשרויות הם lowerCamelCase, לא snake_case

ב-JavaScript, נפוץ יותר להשתמש במארז גמלים עבור שמות סמלים (למשל, ראה מדריך סגנון ה-JavaScript של 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.

הפעל אובייקטים של Layer עם application(), לא על ידי קריאה אליהם כפונקציות

ב-Keras, לאובייקט שכבה מוגדרת השיטה __call__ . לכן המשתמש יכול להפעיל את הלוגיקה של השכבה על ידי קריאה לאובייקט כפונקציה, למשל,

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

print(flatten(my_input).shape)

סוכר תחביר פייתון זה מיושם כשיטת ה-apply() ב-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) אובייקטי tf.Tensor של TensorFlow (בהנחה של TensorFlow backend), שהם סמליים ואינם מכילים ערכים מספריים ממשיים. זה מה שמוצג בדוגמה בסעיף הקודם. עם זאת, ב-TensorFlow.js, שיטת ה-apply() של שכבות יכולה לפעול הן במצב סימבולי והן במצב ציווי. אם apply() מופעל עם SymbolicTensor (אנלוגיה קרובה של tf.Tensor), ערך ההחזרה יהיה SymbolicTensor. זה קורה בדרך כלל במהלך בניית מודל. אבל אם מופעלת apply() עם ערך טנסור ממשי, הוא יחזיר טנסור קונקרטי. לדוגמה:

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

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

תכונה זו מזכירה את (Python) TensorFlow של Eager Execution . זה מאפשר אינטראקטיביות רבה יותר ואפשרות ניפוי באגים במהלך פיתוח המודל, בנוסף לפתיחת דלתות לחיבור רשתות עצביות דינמיות.

כלי האופטימיזציה נמצאים בהרכבה. , לא מייעלים.

ב-Keras, הבנאים עבור אובייקטי Optimizer נמצאים תחת מרחב השמות keras.optimizers.* . ב- TensorFlow.js Layers, שיטות היצרן עבור 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 pip.

// 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 , בהתאמה. תכננו ממשקי API אלה להיות דומים לממשק ה-API של save and load_model של Keras. אבל סביבת הדפדפן שונה בתכלית מסביבת הקצה האחורית שעליה פועלות מסגרות למידה עמוקות כמו Keras, במיוחד במערך המסלולים לעמידה והעברת נתונים. מכאן שיש כמה הבדלים מעניינים בין ממשקי ה-API לשמירה/טעינה ב-TensorFlow.js וב-Keras. עיין במדריך שלנו בנושא שמירה וטעינה של tf.Model לפרטים נוספים.

השתמש fitDataset() כדי לאמן מודלים באמצעות אובייקטי tf.data.Dataset

ב-tf.keras של Python TensorFlow, ניתן לאמן מודל באמצעות אובייקט Dataset . שיטת fit() של המודל מקבלת אובייקט כזה ישירות. ניתן לאמן מודל TensorFlow.js גם עם המקבילה ל-JavaScript של אובייקטי Dataset (ראה את התיעוד של ה-API של tf.data ב-TensorFlow.js ). עם זאת, שלא כמו ב-Python, אימון מבוסס ערכת נתונים נעשה באמצעות שיטה ייעודית, כלומר fitDataset . שיטת fit() מיועדת רק לאימון מודלים מבוסס טנזור.

ניהול זיכרון של אובייקטי שכבה ומודל

TensorFlow.js פועל על WebGL בדפדפן, כאשר המשקולות של אובייקטי Layer ו-Model מגובים על ידי טקסטורות WebGL. עם זאת, ל-WebGL אין תמיכה מובנית באיסוף אשפה. אובייקטי שכבה ומודל מנהלים באופן פנימי את זיכרון הטנזור עבור המשתמש במהלך שיחות ההסקה וההדרכה שלו. אבל הם גם מאפשרים למשתמש להיפטר מהם כדי לשחרר את זיכרון ה-WebGL שהוא תופס. זה שימושי במקרים שבהם מופעי מודל רבים נוצרים ומשוחררים בתוך טעינת עמוד בודדת. כדי להשליך אובייקט שכבה או דגם, השתמש בשיטת dispose() .