TensorFlow.js — CNN-এর সাথে হাতে লেখা অঙ্কের স্বীকৃতি

১. ভূমিকা

এই টিউটোরিয়ালে, আমরা একটি কনভল্যুশনাল নিউরাল নেটওয়ার্ক ব্যবহার করে হাতে লেখা সংখ্যা শনাক্ত করার জন্য একটি TensorFlow.js মডেল তৈরি করব। প্রথমে, আমরা হাজার হাজার হাতে লেখা সংখ্যার ছবি এবং সেগুলোর লেবেল দেখিয়ে ক্লাসিফায়ারটিকে প্রশিক্ষণ দেব। এরপর, আমরা এমন টেস্ট ডেটা ব্যবহার করে ক্লাসিফায়ারটির নির্ভুলতা মূল্যায়ন করব যা মডেলটি আগে কখনও দেখেনি।

এই কাজটি একটি ক্লাসিফিকেশন টাস্ক হিসেবে বিবেচিত হয়, কারণ আমরা ইনপুট ইমেজটিকে একটি ক্যাটাগরি (ইমেজে থাকা সংখ্যাটি) নির্ধারণ করার জন্য মডেলটিকে প্রশিক্ষণ দিচ্ছি। আমরা সঠিক আউটপুটের সাথে বিভিন্ন ইনপুটের অনেক উদাহরণ দেখিয়ে মডেলটিকে প্রশিক্ষণ দেব। একে সুপারভাইজড লার্নিং বলা হয়।

আপনি যা তৈরি করবেন

আপনি এমন একটি ওয়েবপেজ তৈরি করবেন যা ব্রাউজারে একটি মডেলকে প্রশিক্ষণ দেওয়ার জন্য TensorFlow.js ব্যবহার করবে। একটি নির্দিষ্ট আকারের সাদা-কালো ছবি দেওয়া হলে, এটি ছবিতে কোন সংখ্যাটি রয়েছে তা শ্রেণীবদ্ধ করবে। এর ধাপগুলো হলো:

  • ডেটা লোড করুন।
  • মডেলটির স্থাপত্য কাঠামো সংজ্ঞায়িত করুন।
  • মডেলটিকে প্রশিক্ষণ দিন এবং প্রশিক্ষণ চলাকালীন এর কর্মক্ষমতা পর্যবেক্ষণ করুন।
  • কিছু পূর্বাভাস তৈরি করে প্রশিক্ষিত মডেলটি মূল্যায়ন করুন।

আপনি যা শিখবেন

  • TensorFlow.js Layers API ব্যবহার করে কনভোলিউশনাল মডেল তৈরির জন্য TensorFlow.js সিনট্যাক্স।
  • TensorFlow.js-এ শ্রেণিবিন্যাস কার্য প্রণয়ন
  • tfjs-vis লাইব্রেরি ব্যবহার করে কীভাবে ইন-ব্রাউজার ট্রেনিং মনিটর করা যায়।

আপনার যা যা লাগবে

আমাদের প্রথম প্রশিক্ষণ টিউটোরিয়ালের বিষয়বস্তুর সাথেও আপনার স্বচ্ছন্দ থাকা উচিত।

২. প্রস্তুত হন

একটি HTML পৃষ্ঠা তৈরি করুন এবং জাভাস্ক্রিপ্ট অন্তর্ভুক্ত করুন।

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>

ডেটা এবং কোডের জন্য জাভাস্ক্রিপ্ট ফাইলগুলো তৈরি করুন।

  1. উপরের HTML ফাইলটির একই ফোল্ডারে data.js নামে একটি ফাইল তৈরি করুন এবং এই লিঙ্ক থেকে কন্টেন্টগুলো সেই ফাইলে কপি করুন।
  2. প্রথম ধাপের ফোল্ডারটিতে script.js নামে একটি ফাইল তৈরি করুন এবং এর মধ্যে নিম্নলিখিত কোডটি রাখুন।
console.log('Hello TensorFlow');

পরীক্ষা করে দেখুন

এখন যেহেতু আপনি HTML এবং JavaScript ফাইলগুলো তৈরি করে ফেলেছেন, সেগুলো পরীক্ষা করে দেখুন। আপনার ব্রাউজারে index.html ফাইলটি খুলুন এবং devtools কনসোলটি খুলুন।

সবকিছু ঠিকঠাক কাজ করলে, দুটি গ্লোবাল ভেরিয়েবল তৈরি হবে। tf হলো TensorFlow.js লাইব্রেরির একটি রেফারেন্স, tfvis হলো tfjs-vis লাইব্রেরির একটি রেফারেন্স।

আপনি Hello TensorFlow লেখা একটি বার্তা দেখতে পাবেন , যদি তাই হয়, তাহলে আপনি পরবর্তী ধাপে যাওয়ার জন্য প্রস্তুত।

৩. ডেটা লোড করুন

এই টিউটোরিয়ালে আপনি নিচের ছবিগুলোর মতো ছবি থেকে সংখ্যা শনাক্ত করতে একটি মডেলকে প্রশিক্ষণ দেবেন। এই ছবিগুলো MNIST নামক একটি ডেটাসেট থেকে নেওয়া ২৮x২৮ পিক্সেলের গ্রেস্কেল ছবি।

এমএনআইএসটি ৪এমএনআইএসটি ৩এমএনআইএসটি ৮

আমরা আপনার জন্য তৈরি করা একটি বিশেষ স্প্রাইট ফাইল (~১০ মেগাবাইট) থেকে এই ছবিগুলো লোড করার জন্য কোড দিয়েছি, যাতে আমরা ট্রেনিং অংশের উপর মনোযোগ দিতে পারি।

ডেটা কীভাবে লোড করা হয় তা বোঝার জন্য data.js ফাইলটি নির্দ্বিধায় অধ্যয়ন করুন। অথবা এই টিউটোরিয়ালটি শেষ করার পর, ডেটা লোড করার জন্য আপনার নিজস্ব পদ্ধতি তৈরি করুন।

প্রদত্ত কোডে MnistData নামে একটি ক্লাস রয়েছে, যার দুটি পাবলিক মেথড আছে:

  • nextTrainBatch(batchSize) : ট্রেনিং সেট থেকে এলোমেলোভাবে একগুচ্ছ ছবি এবং তাদের লেবেল ফেরত দেয়।
  • nextTestBatch(batchSize) : টেস্ট সেট থেকে একগুচ্ছ ছবি এবং তাদের লেবেল ফেরত দেয়।

MnistData ক্লাসটি ডেটা শাফলিং এবং নর্মালাইজিং- এর মতো গুরুত্বপূর্ণ ধাপগুলোও সম্পাদন করে।

মোট ৬৫,০০০ ছবি আছে, আমরা মডেলটিকে প্রশিক্ষণ দিতে সর্বোচ্চ ৫৫,০০০ ছবি ব্যবহার করব এবং বাকি ১০,০০০ ছবি রেখে দেব যা প্রশিক্ষণ শেষে মডেলটির কার্যকারিতা পরীক্ষা করার জন্য ব্যবহার করা যাবে। আর এই পুরো কাজটিই আমরা ব্রাউজারে করব!

চলুন ডেটা লোড করে পরীক্ষা করে দেখি যে তা সঠিকভাবে লোড হয়েছে কিনা।

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

৪. আমাদের কাজের ধারণা তৈরি করুন

আমাদের ইনপুট ডেটা দেখতে এইরকম।

6dff857738b54eed.png

আমাদের লক্ষ্য হলো এমন একটি মডেলকে প্রশিক্ষণ দেওয়া, যা একটি ছবি নিয়ে সেই ছবিটি যে ১০টি সম্ভাব্য শ্রেণীর (০-৯ অঙ্ক) অন্তর্ভুক্ত হতে পারে, তার প্রতিটির জন্য একটি স্কোর ভবিষ্যদ্বাণী করতে শিখবে।

প্রতিটি ছবির প্রস্থ ২৮ পিক্সেল এবং উচ্চতা ২৮ পিক্সেল। যেহেতু এটি একটি গ্রেস্কেল ছবি, তাই এতে ১টি কালার চ্যানেল রয়েছে। সুতরাং প্রতিটি ছবির আকৃতি হলো [28, 28, 1]

মনে রাখবেন যে আমরা এক থেকে দশের একটি ম্যাপিং করি, এবং সেইসাথে প্রতিটি ইনপুট উদাহরণের আকৃতিও বিবেচনা করি, কারণ এটি পরবর্তী অংশের জন্য গুরুত্বপূর্ণ।

৫. মডেলের স্থাপত্য কাঠামো নির্ধারণ করুন।

এই অংশে আমরা মডেল আর্কিটেকচার বর্ণনা করার জন্য কোড লিখব। মডেল আর্কিটেকচার হলো "মডেলটি কার্যকর হওয়ার সময় কোন ফাংশনগুলো চালাবে" অথবা অন্যভাবে বললে , "আমাদের মডেল তার উত্তর গণনা করার জন্য কোন অ্যালগরিদম ব্যবহার করবে"—এই কথাটি বলার একটি পরিশীলিত উপায়।

মেশিন লার্নিং-এ আমরা একটি আর্কিটেকচার (বা অ্যালগরিদম) নির্ধারণ করি এবং প্রশিক্ষণ প্রক্রিয়ার মাধ্যমে সেই অ্যালগরিদমের প্যারামিটারগুলো শিখে নিই।

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 উদাহরণগুলো হলো ২৮x২৮-পিক্সেলের সাদা-কালো ছবি। ইমেজ ডেটার জন্য আদর্শ ফরম্যাট হলো [row, column, depth] , তাই এখানে আমরা [28, 28, 1] আকৃতিটি কনফিগার করতে চাই। প্রতিটি ডাইমেনশনে পিক্সেলের সংখ্যার জন্য ২৮টি সারি ও কলাম এবং গভীরতা ১, কারণ আমাদের ছবিগুলোতে কেবল ১টি কালার চ্যানেল আছে। লক্ষ্য করুন যে, আমরা ইনপুট শেপে কোনো ব্যাচ সাইজ নির্দিষ্ট করি না। লেয়ারগুলোকে এমনভাবে ডিজাইন করা হয়েছে যাতে এগুলো ব্যাচ সাইজের ওপর নির্ভরশীল না হয়, ফলে ইনফারেন্সের সময় আপনি যেকোনো ব্যাচ সাইজের টেনসর পাস করতে পারেন।
  • kernelSize ইনপুট ডেটার উপর প্রয়োগ করার জন্য স্লাইডিং কনভোলিউশনাল ফিল্টার উইন্ডোগুলোর আকার। এখানে, আমরা kernelSize এর মান 5 নির্ধারণ করেছি, যা একটি বর্গাকার, ৫x৫ কনভোলিউশনাল উইন্ডো নির্দেশ করে।
  • filters । ইনপুট ডেটার উপর প্রয়োগ করার জন্য kernelSize আকারের ফিল্টার উইন্ডোর সংখ্যা। এখানে, আমরা ডেটার উপর ৮টি ফিল্টার প্রয়োগ করব।
  • strides হলো স্লাইডিং উইন্ডোর 'ধাপের আকার'—অর্থাৎ, প্রতিবার ছবির উপর দিয়ে যাওয়ার সময় ফিল্টারটি কত পিক্সেল সরে যাবে। এখানে, আমরা স্ট্রাইডস ১ নির্দিষ্ট করেছি, যার মানে হলো ফিল্টারটি ১ পিক্সেলের ধাপে ছবির উপর দিয়ে স্লাইড করবে।
  • 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'
}));

আমরা ১০টি সম্ভাব্য শ্রেণীর উপর সম্ভাব্যতা বিন্যাস গণনা করার জন্য সফটম্যাক্স অ্যাক্টিভেশন সহ একটি ডেন্স লেয়ার ব্যবহার করব। সর্বোচ্চ স্কোরযুক্ত শ্রেণীটিই হবে পূর্বাভাসিত অঙ্ক।

একটি অপ্টিমাইজার এবং লস ফাংশন নির্বাচন করুন

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

আমরা একটি অপটিমাইজার , লস ফাংশন এবং যে মেট্রিকগুলোর হিসাব রাখতে চাই, তা নির্দিষ্ট করে মডেলটি কম্পাইল করি।

আমাদের প্রথম টিউটোরিয়ালের বিপরীতে, এখানে আমরা লস ফাংশন হিসেবে categoricalCrossentropy ব্যবহার করি। নাম থেকেই বোঝা যায়, এটি তখন ব্যবহৃত হয় যখন আমাদের মডেলের আউটপুট একটি সম্ভাব্যতা বিন্যাস (probability distribution) হয়। categoricalCrossentropy আমাদের মডেলের শেষ স্তর দ্বারা উৎপন্ন সম্ভাব্যতা বিন্যাস এবং আমাদের প্রকৃত লেবেল দ্বারা প্রদত্ত সম্ভাব্যতা বিন্যাসের মধ্যকার ত্রুটি পরিমাপ করে।

উদাহরণস্বরূপ, যদি আমাদের অঙ্কটি প্রকৃতপক্ষে ৭ হয়, তাহলে আমরা নিম্নলিখিত ফলাফলগুলো পেতে পারি।

সূচী

ট্রু লেবেল

ভবিষ্যদ্বাণী

০.১

০.০১

০.০১

০.০১

০.২০

০.০১

০.০১

০.৬০

০.০৩

০.০২

ক্যাটেগরিক্যাল ক্রস এন্ট্রপি একটি একক সংখ্যা প্রদান করবে, যা নির্দেশ করবে প্রেডিকশন ভেক্টরটি আমাদের প্রকৃত লেবেল ভেক্টরের সাথে কতটা সাদৃশ্যপূর্ণ।

এখানে লেবেলগুলির জন্য ব্যবহৃত ডেটা উপস্থাপনাকে ওয়ান-হট এনকোডিং বলা হয় এবং এটি ক্লাসিফিকেশন সমস্যাগুলিতে প্রচলিত। প্রতিটি উদাহরণের জন্য প্রতিটি ক্লাসের সাথে একটি সম্ভাবনা যুক্ত থাকে। যখন আমরা সঠিকভাবে জানি যে এটি কী হওয়া উচিত, তখন আমরা সেই সম্ভাবনাটিকে ১ এবং বাকিগুলিকে ০ সেট করতে পারি। ওয়ান-হট এনকোডিং সম্পর্কে আরও তথ্যের জন্য এই পৃষ্ঠাটি দেখুন।

আরেকটি মেট্রিক যা আমরা পর্যবেক্ষণ করব তা হলো accuracy , যা একটি ক্লাসিফিকেশন সমস্যার ক্ষেত্রে হলো সমস্ত প্রেডিকশনের মধ্যে সঠিক প্রেডিকশনের শতাংশ।

৬. মডেলটিকে প্রশিক্ষণ দিন

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 প্রপার্টি পাস করি।

যদি আমরা আমাদের ট্রেনিং ডেটাতে ভালো ফল করি কিন্তু ভ্যালিডেশন ডেটাতে না করি, তার মানে হলো মডেলটি সম্ভবত ট্রেনিং ডেটার সাথে ওভারফিটিং করছে এবং আগে দেখেনি এমন ইনপুটের ক্ষেত্রে ভালোভাবে জেনারেলাইজ করতে পারবে না।

৭. আমাদের মডেলটি মূল্যায়ন করুন।

ভ্যালিডেশন অ্যাকুরেসি একটি ভালো ধারণা দেয় যে, আমাদের মডেল আগে না দেখা ডেটার উপর কতটা ভালো কাজ করবে (যদি সেই ডেটা কোনো না কোনোভাবে ভ্যালিডেশন সেটের অনুরূপ হয়)। তবে, আমরা বিভিন্ন ক্লাসের মধ্যে পারফরম্যান্সের আরও বিস্তারিত বিভাজন চাইতে পারি।

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];
}      

প্রথমে আমাদের কিছু অনুমান করতে হবে। এখানে আমরা ৫০০টি ছবি নেব এবং সেগুলোতে কোন অঙ্কটি আছে তা অনুমান করব (পরে আরও বেশি সংখ্যক ছবির ওপর পরীক্ষা করার জন্য আপনি এই সংখ্যাটি বাড়াতে পারেন)।

উল্লেখ্য যে argmax ফাংশনটিই আমাদের সর্বোচ্চ সম্ভাবনাময় ক্লাসের সূচকটি দেয়। মনে রাখবেন যে, মডেলটি প্রতিটি ক্লাসের জন্য একটি সম্ভাবনা আউটপুট করে। এখানে আমরা সর্বোচ্চ সম্ভাবনাটি খুঁজে বের করি এবং সেটিকে পূর্বাভাস হিসেবে ব্যবহার করি।

আপনি হয়তো আরও লক্ষ্য করবেন যে, আমরা একবারে সব ৫০০টি উদাহরণের উপরই পূর্বাভাস দিতে পারি। এটাই হলো ভেক্টরাইজেশনের শক্তি যা 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();
}  

একটি কনফিউশন ম্যাট্রিক্স প্রতি-শ্রেণী নির্ভুলতার (per class accuracy) মতোই, তবে এটি ভুল শ্রেণীকরণের ধরণ দেখানোর জন্য বিষয়টিকে আরও বিশদভাবে বিশ্লেষণ করে। এর মাধ্যমে আপনি দেখতে পারেন যে মডেলটি শ্রেণীগুলোর কোনো নির্দিষ্ট জোড়া নিয়ে বিভ্রান্ত হচ্ছে কি না।

মূল্যায়ন প্রদর্শন করুন

96914ff65fc3b74c.png মূল্যায়ন দেখানোর জন্য আপনার রান ফাংশনের শেষে নিম্নলিখিত কোডটি যোগ করুন।

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

আপনি নিচের ছবির মতো একটি ডিসপ্লে দেখতে পাবেন।

82458197bd5e7f52.png

অভিনন্দন! আপনি এইমাত্র একটি কনভল্যুশনাল নিউরাল নেটওয়ার্ককে প্রশিক্ষণ দিয়েছেন!

৮. মূল শিক্ষা

ইনপুট ডেটার বিভাগগুলো অনুমান করাকে ক্লাসিফিকেশন টাস্ক বলা হয়।

শ্রেণিবিন্যাসের কাজগুলোর জন্য লেবেলগুলোর একটি উপযুক্ত ডেটা উপস্থাপনা প্রয়োজন।

  • লেবেলের সাধারণ উপস্থাপনাগুলোর মধ্যে ক্যাটাগরির ওয়ান-হট এনকোডিং অন্তর্ভুক্ত।

আপনার ডেটা প্রস্তুত করুন:

  • প্রশিক্ষণের সময় মডেলটি কখনো দেখে না এমন কিছু ডেটা আলাদা করে রাখা উপকারী, যা মডেলটি মূল্যায়ন করতে ব্যবহার করা যেতে পারে। একে ভ্যালিডেশন সেট বলা হয়।

আপনার মডেলটি তৈরি ও চালান:

  • দেখা গেছে যে কনভল্যুশনাল মডেলগুলো ইমেজ সংক্রান্ত কাজে ভালো পারফর্ম করে।
  • শ্রেণীবিভাগ সমস্যাগুলিতে সাধারণত লস ফাংশন হিসেবে ক্যাটেগরিক্যাল ক্রস এন্ট্রপি ব্যবহার করা হয়।
  • ক্ষতির পরিমাণ কমছে এবং নির্ভুলতা বাড়ছে কিনা তা দেখার জন্য প্রশিক্ষণ পর্যবেক্ষণ করুন।

আপনার মডেল মূল্যায়ন করুন

  • আপনার মডেলটি প্রশিক্ষিত হয়ে গেলে, আপনি যে প্রাথমিক সমস্যাটি সমাধান করতে চেয়েছিলেন তাতে এটি কতটা ভালো করছে তা দেখার জন্য, এটি মূল্যায়ন করার একটি উপায় ঠিক করুন।
  • শুধুমাত্র সামগ্রিক নির্ভুলতার চেয়ে শ্রেণিভিত্তিক নির্ভুলতা এবং কনফিউশন ম্যাট্রিক্স আপনাকে মডেলের পারফরম্যান্সের আরও সূক্ষ্ম বিশ্লেষণ দিতে পারে।