דגמי אימון

מדריך זה מניח שאתה כבר קראת את המודלים ואת שכבות המדריך.

ב-TensorFlow.js יש שתי דרכים לאמן מודל למידת מכונה:

  1. באמצעות ה- API שכבות עם LayersModel.fit() או LayersModel.fitDataset() .
  2. באמצעות ה- API Core עם Optimizer.minimize() .

ראשית, נבחן את Layers API, שהוא API ברמה גבוהה יותר לבניית מודלים והדרכה. לאחר מכן, נראה כיצד לאמן את אותו מודל באמצעות Core API.

מבוא

מודל למידה המכונה הוא פונקציה עם פרמטרים ללמידה ממפה קלט לפלט רצוי. הפרמטרים האופטימליים מתקבלים על ידי אימון המודל על נתונים.

האימון כולל מספר שלבים:

  • קבלת אצווה של נתונים למודל.
  • מבקש מהמודל לעשות תחזית.
  • השוואת התחזית הזו לערך "האמיתי".
  • החלטה כמה לשנות כל פרמטר כדי שהמודל יוכל לבצע חיזוי טוב יותר בעתיד עבור אותה אצווה.

מודל מאומן היטב יספק מיפוי מדויק מהקלט לפלט הרצוי.

פרמטרים של דגם

בואו נגדיר מודל דו-שכבתי פשוט באמצעות Layers API:

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

מתחת למכסה המנוע, יש מודלים פרמטרים (המכונה לעתים קרובות משקולות) כי הם ללמידה על ידי אימון על נתונים. בואו נדפיס את שמות המשקולות הקשורות לדגם זה ואת צורותיהם:

model.weights.forEach(w => {
 console.log(w.name, w.shape);
});

אנו מקבלים את הפלט הבא:

> dense_Dense1/kernel [784, 32]
> dense_Dense1/bias [32]
> dense_Dense2/kernel [32, 10]
> dense_Dense2/bias [10]

יש 4 משקולות בסך הכל, 2 לכל שכבה צפופה. זו צפויה מאז שכבות עבות מייצגים פונקציה הממפה לטנזור קלט x אל מותח פלט y באמצעות המשוואה y = Ax + b שבו (הקרנל) ו A b (ההטיה) הם פרמטרים של השכבה צפופה.

הערה: כברירת מחדל שכבות עבות כוללות הטיה, אבל אתה יכול להוציא את זה על ידי ציון {useBias: false} ב האופציות בעת יצירת שכבה צפופה.

model.summary() הוא שיטה שימושית אם אתה רוצה לקבל סקירה של המודל שלך ולראות את המספר הכולל של פרמטרים:

שכבה (סוג) צורת פלט פראם מס'
צפוף_צפוף1 (צפוף) [null,32] 25120
dense_Dense2 (צפוף) [null,10] 330
סה"כ פרמים: 25450
פרמטרים ניתנים לאימון: 25450
פרמטרים שאינם ניתנים לאימון: 0

משקל כל במודל backend ידי Variable האובייקט. בשנת TensorFlow.js, A Variable היא נקודה צופה Tensor עם עוד שיטה אחת assign() משמשות לעדכון וערכיה. ה-Layers API מאתחל את המשקולות באופן אוטומטי באמצעות שיטות עבודה מומלצות. למען ההפגנה, נוכל להחליף את המשקולות על ידי התקשרות assign() על המשתנים הבסיסיים:

model.weights.forEach(w => {
  const newVals = tf.randomNormal(w.shape);
  // w.val is an instance of tf.Variable
  w.val.assign(newVals);
});

מייעל, הפסד ומדד

לפני שאתה עושה אימון כלשהו, ​​אתה צריך להחליט על שלושה דברים:

  1. מייעל. תפקידו של האופטימיזר הוא להחליט כמה לשנות כל פרמטר במודל, בהתחשב בתחזית המודל הנוכחית. בעת השימוש בממשק ה- Layers, אתה יכול לספק גם מזהה מחרוזת של האופטימיזציה קיים (כגון 'sgd' או 'adam' ), או מופע של Optimizer בכיתה.
  2. פונקציה הפסד. מטרה שהמודל ינסה למזער. המטרה שלו היא לתת מספר בודד ל"כמה שגוי" התחזית של המודל הייתה. ההפסד מחושב על כל אצווה של נתונים כך שהמודל יוכל לעדכן את משקלו. בעת השימוש בממשק ה- Layers, אתה יכול לספק גם מזהה מחרוזת של פונקצית הפסד קיימת (כגון 'categoricalCrossentropy' ), או כול פונקציה שמתייחסת חזה לבין ערך אמיתי וחוזר פסד. ראה רשימה של הפסדים זמינים ב docs API שלנו.
  3. רשימת מדדים. בדומה להפסדים, מדדים מחשבים מספר בודד, המסכמים עד כמה המודל שלנו מצליח. המדדים מחושבים בדרך כלל על כל הנתונים בסוף כל תקופה. לכל הפחות, אנחנו רוצים לעקוב שההפסד שלנו יורד עם הזמן. עם זאת, לעתים קרובות אנו רוצים מדד ידידותי יותר לאדם כמו דיוק. בעת השימוש בממשק ה- Layers, אתה יכול לספק גם מזהה מחרוזת של הקיים מטרי (כגון 'accuracy' ), או כול פונקציה שמתייחסת חזה לבין ערך אמיתי וחוזר ציון. ראה רשימה של ערכים זמינים ב docs API שלנו.

לאחר שהחלטת, ללקט LayersModel ידי התקשרות model.compile() עם האפשרויות המופיעות:

model.compile({
  optimizer: 'sgd',
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy']
});

במהלך הקומפילציה, המודל יבצע אימות מסוים כדי לוודא שהאפשרויות שבחרת תואמות זו לזו.

הַדְרָכָה

ישנן שתי דרכים להכשיר LayersModel :

  • שימוש model.fit() ומספקת את הנתונים כפי מותח אחד גדול.
  • שימוש model.fitDataset() ומספקת את הנתונים באמצעות Dataset אובייקט.

model.fit()

אם מתאים במערך שלך בזיכרון הראשי, והוא זמין כמו מותח אחת, אתה יכול לאמן מודל באמצעות פנייה fit() שיטה:

// Generate dummy data.
const data = tf.randomNormal([100, 784]);
const labels = tf.randomUniform([100, 10]);

function onBatchEnd(batch, logs) {
  console.log('Accuracy', logs.acc);
}

// Train for 5 epochs with batch size of 32.
model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: {onBatchEnd}
 }).then(info => {
   console.log('Final accuracy', info.history.acc);
 });

מתחת למכסה המנוע, model.fit() יכול לעשות הרבה עבורנו:

  • מפצל את הנתונים לרכבת ולסט אימות, ומשתמש בערכת האימות כדי למדוד התקדמות במהלך האימון.
  • מערבב את הנתונים אבל רק לאחר הפיצול. כדי להיות בטוח, כדאי מראש לערבב את הנתונים לפני העברתו fit() .
  • פיצולי לטנזור נתונים גדולים לתוך tensors קטן בגודל batchSize.
  • שיחות optimizer.minimize() תוך חישוב ההפסד של המודל ביחס אצווה של נתונים.
  • זה יכול להודיע ​​לך על ההתחלה והסיום של כל תקופה או אצווה. במקרה שלנו, אנו מקבלים הודעה בסוף כל אצווה באמצעות callbacks.onBatchEnd האופציה. אפשרויות אחרות כוללות: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd ו onBatchBegin .
  • זה נכנע לחוט הראשי כדי להבטיח שניתן לטפל במשימות בתור בלולאת האירועים של JS בזמן.

למידע נוסף, עיין בתיעוד של fit() . שים לב שאם תבחר להשתמש ב-Core API, תצטרך ליישם את ההיגיון הזה בעצמך.

model.fitDataset()

אם הנתונים שלך לא מתאים לחלוטין בזיכרון, או מוזרמים, אתה יכול לאמן מודל ידי התקשרות fitDataset() , אשר לוקח Dataset אובייקט. הנה אותו קוד אימון אבל עם מערך נתונים שעוטף פונקציית מחולל:

function* data() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomNormal([784]);
 }
}

function* labels() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomUniform([10]);
 }
}

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// We zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

// Train the model for 5 epochs.
model.fitDataset(ds, {epochs: 5}).then(info => {
 console.log('Accuracy', info.history.acc);
});

למידע נוסף על מערכי נתונים, עיין בתיעוד של model.fitDataset() .

חיזוי נתונים חדשים

לאחר המודל הוכשר, אתה יכול להתקשר model.predict() לבצע תחזיות על נתונים סמויים:

// Predict 3 random samples.
const prediction = model.predict(tf.randomNormal([3, 784]));
prediction.print();

Core API

קודם לכן, הזכרנו שיש שתי דרכים לאמן מודל למידת מכונה ב-TensorFlow.js.

כלל האצבע הכללי הוא לנסות להשתמש תחילה ב-Layers API, מכיוון שהוא מעוצב לפי ה-Keras API המאומץ היטב. ה-API של Layers מציע גם פתרונות מדף שונים כמו אתחול משקל, סדרת מודלים, הדרכות ניטור, ניידות ובדיקת בטיחות.

ייתכן שתרצה להשתמש ב-Core API בכל פעם:

  • אתה צריך גמישות או שליטה מקסימלית.
  • ואתה לא צריך סריאליזציה, או שאתה יכול ליישם את היגיון ההסדרה שלך.

לקבלת מידע נוסף אודות ה- API הזה, לקרוא את הקטע "API הליבה" מודלי שכבות המדריך.

אותו דגם כמו לעיל שנכתב באמצעות Core API נראה כך:

// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));

function model(x) {
  return x.matMul(w1).add(b1).relu().matMul(w2).add(b2);
}

בנוסף ל-Layers API, ה-Data API גם עובד בצורה חלקה עם Core API. בואו לעשות שימוש חוזר במערך כי הגדרנו קודם לכן model.fitDataset () סעיף, אשר אין דשדוש ומינון בשבילנו:

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// Zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

בואו נאמן את הדגם:

const optimizer = tf.train.sgd(0.1 /* learningRate */);
// Train for 5 epochs.
for (let epoch = 0; epoch < 5; epoch++) {
  await ds.forEachAsync(({xs, ys}) => {
    optimizer.minimize(() => {
      const predYs = model(xs);
      const loss = tf.losses.softmaxCrossEntropy(ys, predYs);
      loss.data().then(l => console.log('Loss', l));
      return loss;
    });
  });
  console.log('Epoch', epoch);
}

הקוד למעלה הוא המתכון הסטנדרטי בעת אימון מודל עם Core API:

  • לולאה על מספר העידנים.
  • בתוך כל תקופה, בצע לולאה על קבוצות הנתונים שלך. בעת שימוש Dataset , dataset.forEachAsync() היא דרך נוחה לולאה מעל אצוות שלך.
  • עבור כל אצווה, שיחת optimizer.minimize(f) , אשר מבצעת f וממזער את תפוקתו על ידי מחשוב הדרגתיים ביחס ארבעת המשתנים שהגדרנו קודם לכן.
  • f מחשב את ההפסד. הוא קורא לאחת מפונקציות ההפסד המוגדרות מראש תוך שימוש בחיזוי המודל והערך האמיתי.