TensorFlow.js — التعرف على الأرقام المكتوبة بخط اليد باستخدام شبكات CNN

1. مقدمة

في هذا البرنامج التعليمي، سننشئ نموذج TensorFlow.js للتعرّف على الأرقام المكتوبة بخط اليد باستخدام شبكة عصبية التفافية. أولاً، سندرب المصنّف من خلال جعله "ينظر" إلى آلاف الصور للأرقام المكتوبة بخط اليد وتصنيفاتها. بعد ذلك، سنقيّم دقة المصنّف باستخدام بيانات اختبار لم يسبق للنموذج أن اطّلع عليها.

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

ما ستنشئه

ستنشئ صفحة ويب تستخدم TensorFlow.js لتدريب نموذج في المتصفح. عند تقديم صورة بالأبيض والأسود بحجم معيّن، سيتم تصنيف الرقم الذي يظهر في الصورة. في ما يلي الخطوات المعنية:

  • حمِّل البيانات.
  • حدِّد بنية النموذج.
  • درِّب النموذج وراقِب أدائه أثناء التدريب.
  • قيِّم النموذج المدرَّب من خلال وضع بعض التوقعات.

ما ستتعلمه

  • بنية TensorFlow.js لإنشاء نماذج التفافية باستخدام واجهة برمجة التطبيقات للطبقات في TensorFlow.js
  • صياغة مهام التصنيف في TensorFlow.js
  • كيفية مراقبة التدريب داخل المتصفّح باستخدام مكتبة tfjs-vis

المتطلبات

يجب أيضًا أن تكون على دراية بالمواد الواردة في الدليل التعليمي الأول.

2. طريقة الإعداد

إنشاء صفحة HTML وتضمين JavaScript

96914ff65fc3b74c.pngانسخ الرمز التالي في ملف html باسم

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TensorFlow.js Tutorial</title>

  <!-- Import TensorFlow.js -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
  <!-- Import tfjs-vis -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.0.2/dist/tfjs-vis.umd.min.js"></script>

  <!-- Import the data file -->
  <script src="data.js" type="module"></script>

  <!-- Import the main script file -->
  <script src="script.js" type="module"></script>

</head>

<body>
</body>
</html>

إنشاء ملفات JavaScript للبيانات والرمز

  1. في المجلد نفسه الذي يحتوي على ملف HTML أعلاه، أنشئ ملفًا باسم data.js وانسخ المحتوى من هذا الرابط إلى هذا الملف.
  2. في المجلد نفسه الذي استخدمته في الخطوة الأولى، أنشئ ملفًا باسم script.js وضَع فيه الرمز التالي.
console.log('Hello TensorFlow');

تجربة الميزة

بعد إنشاء ملفات HTML وJavaScript، اختبِرها. افتح ملف index.html في المتصفّح وافتح وحدة تحكّم أدوات المطوّرين.

إذا كان كل شيء يعمل بشكل صحيح، من المفترض أن يتم إنشاء متغيرَين عامَين. tf هو مرجع إلى مكتبة TensorFlow.js، وtfvis هو مرجع إلى مكتبة tfjs-vis.

من المفترض أن تظهر لك الرسالة Hello TensorFlow، وفي حال ظهورها، يمكنك الانتقال إلى الخطوة التالية.

3- تحميل البيانات

في هذا البرنامج التعليمي، ستدرّب نموذجًا على التعرّف على الأرقام في الصور، مثل الصور أدناه. هذه الصور هي صور ذات تدرّج رمادي بحجم 28×28 بكسل من مجموعة بيانات تُعرف باسم MNIST.

mnist 4 mnist 3 mnist 8

لقد وفّرنا رمزًا لتحميل هذه الصور من ملف sprite خاص (يبلغ حجمه حوالي 10 ميغابايت) أنشأناه لك حتى نتمكّن من التركيز على جزء التدريب.

يمكنك الاطّلاع على ملف data.js لفهم كيفية تحميل البيانات. أو بعد الانتهاء من هذا البرنامج التعليمي، يمكنك إنشاء طريقتك الخاصة لتحميل البيانات.

يحتوي الرمز البرمجي المقدَّم على فئة MnistData تتضمّن طريقتَين عامتَين:

  • تعرض nextTrainBatch(batchSize) مجموعة عشوائية من الصور وتصنيفاتها من مجموعة التدريب.
  • nextTestBatch(batchSize): تعرض مجموعة من الصور وتصنيفاتها من مجموعة الاختبار

تتضمّن فئة MnistData أيضًا الخطوات المهمة لخلط البيانات وتسويتها.

هناك إجمالي 65,000 صورة، وسنستخدم ما يصل إلى 55,000 صورة لتدريب النموذج، مع الاحتفاظ بـ 10,000 صورة يمكننا استخدامها لاختبار أداء النموذج بعد الانتهاء من تدريبه. وسننفّذ كل ذلك في المتصفّح.

لنحمّل البيانات ونتأكّد من تحميلها بشكل صحيح.

96914ff65fc3b74c.png أضِف الرمز التالي إلى ملف script.js.

import {MnistData} from './data.js';

async function showExamples(data) {
  // Create a container in the visor
  const surface =
    tfvis.visor().surface({ name: 'Input Data Examples', tab: 'Input Data'});  

  // Get the examples
  const examples = data.nextTestBatch(20);
  const numExamples = examples.xs.shape[0];
  
  // Create a canvas element to render each example
  for (let i = 0; i < numExamples; i++) {
    const imageTensor = tf.tidy(() => {
      // Reshape the image to 28x28 px
      return examples.xs
        .slice([i, 0], [1, examples.xs.shape[1]])
        .reshape([28, 28, 1]);
    });
    
    const canvas = document.createElement('canvas');
    canvas.width = 28;
    canvas.height = 28;
    canvas.style = 'margin: 4px;';
    await tf.browser.toPixels(imageTensor, canvas);
    surface.drawArea.appendChild(canvas);

    imageTensor.dispose();
  }
}

async function run() {  
  const data = new MnistData();
  await data.load();
  await showExamples(data);
}

document.addEventListener('DOMContentLoaded', run);

أعِد تحميل الصفحة وبعد بضع ثوانٍ، من المفترض أن تظهر لوحة على اليمين تتضمّن عددًا من الصور.

6dff857738b54eed.png

4. تحديد مفهوم مهمتنا

تبدو بيانات الإدخال على النحو التالي.

6dff857738b54eed.png

هدفنا هو تدريب نموذج يأخذ صورة واحدة ويتعلّم التنبؤ بنتيجة لكل فئة من الفئات العشر المحتملة التي قد تنتمي إليها الصورة (الأرقام من 0 إلى 9).

يبلغ عرض كل صورة 28 بكسل وارتفاعها 28 بكسل، وتحتوي على قناة ألوان واحدة لأنّها صورة بتدرّج الرمادي. إذًا، شكل كل صورة هو [28, 28, 1].

تذكَّر أنّنا نُجري عملية ربط من واحد إلى عشرة، بالإضافة إلى شكل كل مثال إدخال، لأنّ ذلك مهم للقسم التالي.

5- تحديد بنية النموذج

في هذا القسم، سنكتب رمزًا لوصف بنية النموذج. بشكل مبسط، تعني بنية النموذج "الوظائف التي سينفّذها النموذج عند تشغيله"، أو "الخوارزمية التي سيستخدمها النموذج لحساب إجاباته".

في تعلُّم الآلة، نحدّد بنية (أو خوارزمية) ونسمح لعملية التدريب بتعلُّم مَعلمات هذه الخوارزمية.

96914ff65fc3b74c.png أضِف الدالة التالية إلى

script.js ملف لتحديد بنية النموذج

function getModel() {
  const model = tf.sequential();
  
  const IMAGE_WIDTH = 28;
  const IMAGE_HEIGHT = 28;
  const IMAGE_CHANNELS = 1;  
  
  // In the first layer of our convolutional neural network we have 
  // to specify the input shape. Then we specify some parameters for 
  // the convolution operation that takes place in this layer.
  model.add(tf.layers.conv2d({
    inputShape: [IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS],
    kernelSize: 5,
    filters: 8,
    strides: 1,
    activation: 'relu',
    kernelInitializer: 'varianceScaling'
  }));

  // The MaxPooling layer acts as a sort of downsampling using max values
  // in a region instead of averaging.  
  model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
  
  // Repeat another conv2d + maxPooling stack. 
  // Note that we have more filters in the convolution.
  model.add(tf.layers.conv2d({
    kernelSize: 5,
    filters: 16,
    strides: 1,
    activation: 'relu',
    kernelInitializer: 'varianceScaling'
  }));
  model.add(tf.layers.maxPooling2d({poolSize: [2, 2], strides: [2, 2]}));
  
  // Now we flatten the output from the 2D filters into a 1D vector to prepare
  // it for input into our last layer. This is common practice when feeding
  // higher dimensional data to a final classification output layer.
  model.add(tf.layers.flatten());

  // Our last layer is a dense layer which has 10 output units, one for each
  // output class (i.e. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9).
  const NUM_OUTPUT_CLASSES = 10;
  model.add(tf.layers.dense({
    units: NUM_OUTPUT_CLASSES,
    kernelInitializer: 'varianceScaling',
    activation: 'softmax'
  }));

  
  // Choose an optimizer, loss function and accuracy metric,
  // then compile and return the model
  const optimizer = tf.train.adam();
  model.compile({
    optimizer: optimizer,
    loss: 'categoricalCrossentropy',
    metrics: ['accuracy'],
  });

  return model;
}

دعونا نلقي نظرة على هذا الموضوع بمزيد من التفصيل.

الالتفافات

model.add(tf.layers.conv2d({
  inputShape: [IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS],
  kernelSize: 5,
  filters: 8,
  strides: 1,
  activation: 'relu',
  kernelInitializer: 'varianceScaling'
}));

نستخدم هنا نموذجًا تسلسليًا.

نستخدم طبقة conv2d بدلاً من طبقة كثيفة. لا يمكننا تقديم جميع التفاصيل حول طريقة عمل الالتفافات، ولكن إليك بعض المراجع التي تشرح العملية الأساسية:

في ما يلي تفصيل لكل وسيطة في عنصر الإعدادات الخاص بـ conv2d:

  • inputShape: شكل البيانات التي ستنتقل إلى الطبقة الأولى من النموذج في هذه الحالة، تكون أمثلة MNIST عبارة عن صور بالأبيض والأسود بحجم 28×28 بكسل. التنسيق الأساسي لبيانات الصور هو [row, column, depth]، لذا نريد هنا ضبط شكل [28, 28, 1]. 28 صفًا وعمودًا لعدد وحدات البكسل في كل بُعد، وعمق 1 لأنّ صورنا تحتوي على قناة ألوان واحدة فقط. يُرجى العِلم أنّنا لا نحدّد حجم الدفعة في شكل الإدخال. تم تصميم الطبقات لتكون مستقلة عن حجم الدُفعات، وبالتالي يمكنك تمرير موتر بأي حجم دفعة أثناء الاستدلال.
  • kernelSize. حجم نوافذ فلتر الالتفاف المنزلق التي سيتم تطبيقها على بيانات الإدخال. هنا، نضبط kernelSize على 5، ما يحدّد نافذة التفافية مربّعة بحجم 5×5.
  • filters: عدد نوافذ الفلترة ذات الحجم kernelSize التي سيتم تطبيقها على بيانات الإدخال. سنطبّق هنا 8 فلاتر على البيانات.
  • strides. "حجم الخطوة" للنافذة المنزلقة، أي عدد وحدات البكسل التي سيتم نقل الفلتر بها في كل مرة يتحرك فيها فوق الصورة في هذا المثال، نحدّد خطوات بمقدار 1، ما يعني أنّ الفلتر سينزلق فوق الصورة بخطوات مقدارها بكسل واحد.
  • activation: دالة التنشيط التي سيتم تطبيقها على البيانات بعد اكتمال الالتفاف. في هذه الحالة، نطبّق دالّة وحدة خطية مصحَّحة (ReLU)، وهي دالّة تفعيل شائعة جدًا في نماذج تعلُّم الآلة.
  • kernelInitializer: الطريقة المستخدَمة لتهيئة أوزان النموذج بشكل عشوائي، وهي مهمة جدًا لديناميكيات التدريب. لن نتناول تفاصيل عملية التهيئة هنا، ولكن VarianceScaling (المستخدَمة هنا) هي بشكل عام خيار جيد لعملية التهيئة.

تسوية تمثيل البيانات

model.add(tf.layers.flatten());

الصور هي بيانات عالية الأبعاد، وتميل عمليات الالتفاف إلى زيادة حجم البيانات التي تم إدخالها فيها. قبل تمريرها إلى طبقة التصنيف النهائية، علينا تسوية البيانات في مصفوفة طويلة واحدة. لا تأخذ الطبقات الكثيفة (التي نستخدمها كطبقة نهائية) سوى tensor1d، لذا فإنّ هذه الخطوة شائعة في العديد من مهام التصنيف.

حساب توزيع الاحتمالية النهائي

const NUM_OUTPUT_CLASSES = 10;
model.add(tf.layers.dense({
  units: NUM_OUTPUT_CLASSES,
  kernelInitializer: 'varianceScaling',
  activation: 'softmax'
}));

سنستخدم طبقة كثيفة مع تفعيل دالة softmax لاحتساب توزيعات الاحتمالات على الفئات العشر المحتملة. وستكون الفئة التي حصلت على أعلى نتيجة هي الرقم المتوقّع.

اختيار أداة تحسين ودالة خسارة

const optimizer = tf.train.adam();
model.compile({
  optimizer: optimizer,
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy'],
});

نجمع النموذج من خلال تحديد محسِّن ودالة خسارة والمقاييس التي نريد تتبُّعها.

على عكس البرنامج التعليمي الأول، نستخدم هنا categoricalCrossentropy كدالة خسارة. وكما يوحي الاسم، يتم استخدام هذا النوع عندما يكون ناتج النموذج عبارة عن توزيع احتمالي. تقيس categoricalCrossentropy الخطأ بين توزيع الاحتمالات الذي أنشأته الطبقة الأخيرة من نموذجنا وتوزيع الاحتمالات الذي توفّره التصنيفات الصحيحة.

على سبيل المثال، إذا كان الرقم يمثّل 7 فعلاً، قد نحصل على النتائج التالية

المؤشر

0

1

2

3

4

5

6

7

8

9

التصنيف الصحيح

0

0

0

0

0

0

0

1

0

0

التوقّع

0.1

0.01

0.01

0.01

0.20

0.01

0.01

0.60

0.03

0.02

ستنتج الدالة "الإنتروبيا المتقاطعة الفئوية" رقمًا واحدًا يشير إلى مدى تشابه متجه التوقّع مع متجه التصنيف الفعلي.

يُطلق على طريقة عرض البيانات المستخدَمة هنا للتصنيفات اسم الترميز الأحادي، وهي شائعة في مشاكل التصنيف. لكل فئة احتمال مرتبط بها لكل مثال. عندما نعرف القيمة الصحيحة، يمكننا ضبط الاحتمال على 1 وضبط الاحتمالات الأخرى على 0. يمكنك الاطّلاع على هذه الصفحة للحصول على مزيد من المعلومات حول الترميز أحادي.

المقياس الآخر الذي سنراقبه هو accuracy، وهو يمثّل في مشكلة التصنيف النسبة المئوية للتوقعات الصحيحة من بين جميع التوقعات.

6. تدريب النموذج

96914ff65fc3b74c.pngانسخ الدالة التالية إلى ملف script.js.

async function train(model, data) {
  const metrics = ['loss', 'val_loss', 'acc', 'val_acc'];
  const container = {
    name: 'Model Training', tab: 'Model', styles: { height: '1000px' }
  };
  const fitCallbacks = tfvis.show.fitCallbacks(container, metrics);
  
  const BATCH_SIZE = 512;
  const TRAIN_DATA_SIZE = 5500;
  const TEST_DATA_SIZE = 1000;

  const [trainXs, trainYs] = tf.tidy(() => {
    const d = data.nextTrainBatch(TRAIN_DATA_SIZE);
    return [
      d.xs.reshape([TRAIN_DATA_SIZE, 28, 28, 1]),
      d.labels
    ];
  });

  const [testXs, testYs] = tf.tidy(() => {
    const d = data.nextTestBatch(TEST_DATA_SIZE);
    return [
      d.xs.reshape([TEST_DATA_SIZE, 28, 28, 1]),
      d.labels
    ];
  });

  return model.fit(trainXs, trainYs, {
    batchSize: BATCH_SIZE,
    validationData: [testXs, testYs],
    epochs: 10,
    shuffle: true,
    callbacks: fitCallbacks
  });
}

96914ff65fc3b74c.png بعد ذلك، أضِف الرمز التالي إلى

دالة run

const model = getModel();
tfvis.show.modelSummary({name: 'Model Architecture', tab: 'Model'}, model);
  
await train(model, data);

أعِد تحميل الصفحة، وبعد بضع ثوانٍ، من المفترض أن تظهر لك بعض الرسومات البيانية التي تعرض مدى تقدّم التدريب.

a2c7628dc47d465.png

لنلقِ نظرة على ذلك بمزيد من التفصيل.

تتبُّع المقاييس

const metrics = ['loss', 'val_loss', 'acc', 'val_acc'];

نحدّد هنا المقاييس التي سنراقبها. سنراقب معدّل الخطأ والدقة في مجموعة التدريب، بالإضافة إلى معدّل الخطأ والدقة في مجموعة التحقّق (val_loss وval_acc على التوالي). سنتحدث أكثر عن مجموعة التحقّق أدناه.

إعداد البيانات كمتوترات

const BATCH_SIZE = 512;
const TRAIN_DATA_SIZE = 5500;
const TEST_DATA_SIZE = 1000;

const [trainXs, trainYs] = tf.tidy(() => {
  const d = data.nextTrainBatch(TRAIN_DATA_SIZE);
  return [
    d.xs.reshape([TRAIN_DATA_SIZE, 28, 28, 1]),
    d.labels
  ];
});

const [testXs, testYs] = tf.tidy(() => {
  const d = data.nextTestBatch(TEST_DATA_SIZE);
  return [
    d.xs.reshape([TEST_DATA_SIZE, 28, 28, 1]),
    d.labels
  ];
});

في هذه الخطوة، ننشئ مجموعتَي بيانات، وهما مجموعة تدريب سيتم تدريب النموذج عليها، ومجموعة تحقّق سيتم اختبار النموذج عليها في نهاية كل حقبة، ولكن لا يتم عرض البيانات في مجموعة التحقّق على النموذج أبدًا أثناء التدريب.

تسهّل فئة البيانات التي قدّمناها الحصول على موترات من بيانات الصور. ومع ذلك، نعيد تشكيل الموترات إلى الشكل الذي يتوقّعه النموذج، وهو [num_examples, image_width, image_height, channels]، قبل أن نتمكّن من إدخالها إلى النموذج. بالنسبة إلى كل مجموعة بيانات، لدينا مدخلات (X) وتصنيفات (Y).

return model.fit(trainXs, trainYs, {
  batchSize: BATCH_SIZE,
  validationData: [testXs, testYs],
  epochs: 10,
  shuffle: true,
  callbacks: fitCallbacks
});

نستدعي model.fit لبدء حلقة التدريب. نمرّر أيضًا السمة validationData للإشارة إلى البيانات التي يجب أن يستخدمها النموذج لاختبار نفسه بعد كل حقبة (ولكن لا يستخدمها للتدريب).

إذا حقّقنا نتائج جيدة على بيانات التدريب ولكن ليس على بيانات التحقّق من الصحة، يعني ذلك أنّه من المحتمل أن يكون النموذج المطابقة بشكل مفرط لبيانات التدريب ولن يتم تعميمه بشكل جيد على البيانات التي لم يسبق له رؤيتها.

7. تقييم النموذج

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

هناك طريقتان في tfjs-vis يمكن أن تساعداك في ذلك.

96914ff65fc3b74c.png أضِف الرمز التالي إلى أسفل ملف script.js

const classNames = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'];

function doPrediction(model, data, testDataSize = 500) {
  const IMAGE_WIDTH = 28;
  const IMAGE_HEIGHT = 28;
  const testData = data.nextTestBatch(testDataSize);
  const testxs = testData.xs.reshape([testDataSize, IMAGE_WIDTH, IMAGE_HEIGHT, 1]);
  const labels = testData.labels.argMax(-1);
  const preds = model.predict(testxs).argMax(-1);

  testxs.dispose();
  return [preds, labels];
}


async function showAccuracy(model, data) {
  const [preds, labels] = doPrediction(model, data);
  const classAccuracy = await tfvis.metrics.perClassAccuracy(labels, preds);
  const container = {name: 'Accuracy', tab: 'Evaluation'};
  tfvis.show.perClassAccuracy(container, classAccuracy, classNames);

  labels.dispose();
}

async function showConfusion(model, data) {
  const [preds, labels] = doPrediction(model, data);
  const confusionMatrix = await tfvis.metrics.confusionMatrix(labels, preds);
  const container = {name: 'Confusion Matrix', tab: 'Evaluation'};
  tfvis.render.confusionMatrix(container, {values: confusionMatrix, tickLabels: classNames});

  labels.dispose();
}

ماذا تفعل هذه التعليمات البرمجية؟

  • يُجري تنبؤًا.
  • تحسب هذه الدالة مقاييس الدقة.
  • تعرِض هذه السمة المقاييس.

لنلقِ نظرة فاحصة على كل خطوة.

تقديم التوقعات

function doPrediction(model, data, testDataSize = 500) {
  const IMAGE_WIDTH = 28;
  const IMAGE_HEIGHT = 28;
  const testData = data.nextTestBatch(testDataSize);
  const testxs = testData.xs.reshape([testDataSize, IMAGE_WIDTH, IMAGE_HEIGHT, 1]);
  const labels = testData.labels.argMax(-1);
  const preds = model.predict(testxs).argMax(-1);

  testxs.dispose();
  return [preds, labels];
}      

أولاً، علينا إجراء بعض التوقعات. سنأخذ هنا 500 صورة ونتوقّع الرقم الذي تتضمّنه (يمكنك زيادة هذا العدد لاحقًا للاختبار على مجموعة أكبر من الصور).

والجدير بالذكر أنّ الدالة argmax هي التي تمنحنا فهرس الفئة ذات الاحتمالية الأعلى. تذكَّر أنّ النموذج يعرض احتمالية لكل فئة. في هذه الخطوة، نحدّد الاحتمالية الأكبر ونستخدمها كقيمة متوقّعة.

قد تلاحظ أيضًا أنّه يمكننا إجراء توقّعات بشأن جميع الأمثلة الـ 500 في الوقت نفسه. هذه هي قوة تحويل البيانات إلى متجهات التي يوفّرها TensorFlow.js.

عرض الدقة لكل فئة

async function showAccuracy() {
  const [preds, labels] = doPrediction();
  const classAccuracy = await tfvis.metrics.perClassAccuracy(labels, preds);
  const container = { name: 'Accuracy', tab: 'Evaluation' };
  tfvis.show.perClassAccuracy(container, classAccuracy, classNames);

  labels.dispose();
}      

باستخدام مجموعة من التوقعات والتصنيفات، يمكننا حساب الدقة لكل فئة.

عرض مصفوفة نجاح التوقّعات

async function showConfusion() {
  const [preds, labels] = doPrediction();
  const confusionMatrix = await tfvis.metrics.confusionMatrix(labels, preds);
  const container = { name: 'Confusion Matrix', tab: 'Evaluation' };
  tfvis.render.confusionMatrix(container, {values: confusionMatrix, tickLabels: classNames});

  labels.dispose();
}  

تشبه مصفوفة نجاح التوقعات دقة كل فئة، ولكنّها تقسمها أكثر لعرض أنماط التصنيف الخاطئ. يتيح لك معرفة ما إذا كان النموذج يواجه صعوبة في التمييز بين أي أزواج معيّنة من الفئات.

عرض التقييم

96914ff65fc3b74c.png أضِف الرمز التالي إلى أسفل دالة التشغيل لعرض التقييم.

await showAccuracy(model, data);
await showConfusion(model, data);

من المفترض أن يظهر لك عرض يشبه ما يلي.

82458197bd5e7f52.png

تهانينا! لقد درّبت للتو شبكة عصبونية التفافية.

8. الخلاصات الرئيسية

تُعرف عملية التنبؤ بالفئات للبيانات المدخلة باسم مهمة التصنيف.

تتطلّب مهام التصنيف تمثيلاً مناسبًا للبيانات من أجل التصنيفات

  • تشمل التمثيلات الشائعة للتصنيفات الترميز الأحادي للفئات

إعداد البيانات:

  • من المفيد الاحتفاظ ببعض البيانات التي لا يراها النموذج أبدًا أثناء التدريب والتي يمكنك استخدامها لتقييم النموذج. ويُطلق على هذه المجموعة اسم مجموعة التحقّق.

إنشاء النموذج وتشغيله:

  • وقد تبيّن أنّ النماذج الالتفافية تقدّم أداءً جيدًا في مهام الصور.
  • تستخدم مشاكل التصنيف عادةً دالة الإنتروبيا المتقاطعة الفئوية لدوال الخسارة.
  • راقِب التدريب لمعرفة ما إذا كان معدّل الخطأ ينخفض ومعدّل الدقة يرتفع.

تقييم النموذج

  • حدِّد طريقة لتقييم النموذج بعد تدريبه لمعرفة مدى نجاحه في حل المشكلة الأولية التي أردت حلّها.
  • يمكن أن تمنحك دقة كل فئة ومصفوفات الالتباس تفصيلاً أدق لأداء النموذج مقارنةً بالدقة الإجمالية فقط.