مدل های آموزشی

این راهنما فرض می کند که شما قبلاً راهنمای مدل ها و لایه ها را خوانده اید.

در TensorFlow.js دو راه برای آموزش مدل یادگیری ماشین وجود دارد:

  1. با استفاده از Layers API با LayersModel.fit() یا LayersModel.fitDataset() .
  2. با استفاده از Core API با Optimizer.minimize() .

ابتدا لایه‌های API را بررسی می‌کنیم که یک API سطح بالاتر برای ساخت و آموزش مدل‌ها است. سپس، نحوه آموزش همان مدل را با استفاده از Core API نشان خواهیم داد.

مقدمه

مدل یادگیری ماشین تابعی با پارامترهای قابل یادگیری است که ورودی را به خروجی دلخواه نگاشت می کند. پارامترهای بهینه با آموزش مدل بر روی داده ها به دست می آیند.

آموزش شامل چندین مرحله است:

  • دریافت دسته ای از داده ها به مدل
  • درخواست از مدل برای پیش بینی.
  • مقایسه آن پیش بینی با مقدار "واقعی".
  • تصمیم گیری در مورد میزان تغییر هر پارامتر تا مدل بتواند پیش بینی بهتری در آینده برای آن دسته داشته باشد.

یک مدل به خوبی آموزش دیده یک نقشه برداری دقیق از ورودی به خروجی مورد نظر ارائه می دهد.

پارامترهای مدل

بیایید یک مدل 2 لایه ساده با استفاده از 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() یک روش مفید است اگر می خواهید یک نمای کلی از مدل خود داشته باشید و تعداد کل پارامترها را ببینید:

لایه (نوع) شکل خروجی پارامتر #
dense_Dense1 (متراکم) [null,32] 25120
dense_Dense2 (متراکم) [null,10] 330
مجموع پارامترها: 25450
پارامترهای قابل آموزش: 25450
پارامترهای غیر قابل آموزش: 0

هر وزن در مدل توسط یک شی Variable پشتیبانی می شود. در TensorFlow.js، یک 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. یک بهینه ساز وظیفه بهینه ساز این است که با توجه به پیش بینی مدل فعلی، تصمیم بگیرد که هر پارامتر در مدل چقدر تغییر کند. هنگام استفاده از لایه‌های API، می‌توانید یک شناسه رشته از بهینه‌ساز موجود (مانند 'sgd' یا 'adam' ) یا یک نمونه از کلاس Optimizer ارائه دهید.
  2. یک تابع از دست دادن . هدفی که مدل سعی خواهد کرد آن را به حداقل برساند. هدف آن ارائه یک عدد واحد برای «چقدر اشتباه» پیش‌بینی مدل است. از دست دادن در هر دسته از داده ها محاسبه می شود تا مدل بتواند وزن خود را به روز کند. هنگام استفاده از Layers API، می‌توانید یک شناسه رشته از یک تابع ضرر موجود (مانند 'categoricalCrossentropy' ) یا هر تابعی که یک مقدار پیش‌بینی‌شده و واقعی را می‌گیرد و ضرر را برمی‌گرداند، ارائه کنید. فهرستی از ضررهای موجود را در اسناد API ما مشاهده کنید.
  3. فهرست معیارها مشابه با ضرر، معیارها یک عدد واحد را محاسبه می‌کنند و به طور خلاصه نشان می‌دهند که مدل ما چقدر خوب عمل می‌کند. معیارها معمولاً بر روی کل داده ها در پایان هر دوره محاسبه می شوند. حداقل، ما می خواهیم نظارت کنیم که ضرر ما در طول زمان کاهش می یابد. با این حال، ما اغلب معیارهای انسان دوستانه‌تری مانند دقت می‌خواهیم. هنگام استفاده از لایه‌های API، می‌توانید یک شناسه رشته‌ای از یک متریک موجود (مانند 'accuracy' )، یا هر تابعی که یک مقدار پیش‌بینی‌شده و یک مقدار واقعی دریافت می‌کند و یک امتیاز برمی‌گرداند، ارائه کنید. فهرستی از معیارهای موجود را در اسناد 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() از قبل مخلوط کنید.
  • تانسور داده بزرگ را به تانسورهای کوچکتر با اندازه 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();

هسته API

قبلاً اشاره کردیم که دو روش برای آموزش مدل یادگیری ماشین در TensorFlow.js وجود دارد.

قانون کلی این است که ابتدا سعی کنید از لایه های API استفاده کنید، زیرا از API به خوبی پذیرفته شده Keras مدل شده است. Layers API همچنین راه‌حل‌های مختلفی مانند مقدار دهی اولیه وزن، سریال‌سازی مدل، آموزش نظارت، قابلیت حمل و بررسی ایمنی را ارائه می‌دهد.

ممکن است بخواهید از Core API هر زمان که:

  • شما به حداکثر انعطاف یا کنترل نیاز دارید.
  • و شما نیازی به سریال سازی ندارید یا می توانید منطق سریال سازی خود را پیاده سازی کنید.

برای اطلاعات بیشتر در مورد این API، بخش "Core 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 ضرر را محاسبه می کند. یکی از توابع ضرر از پیش تعریف شده را با استفاده از پیش بینی مدل و مقدار واقعی فراخوانی می کند.