ডিপ লার্নিং ও আর্টিফিশিয়াল নিউরাল নেটওয়ার্ক

Standard

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

ভুমিকা

দেরি করে হলেও ডিপ লার্নিং এর ব্যবহার ও প্রয়োজনীয়তা ইদানীং ব্যাপক হারে বাড়ছে। কম্পিউটার ভিশন, ন্যাচারাল ল্যাঙ্গুয়েজ প্রসেসিং সহ বেশ কিছু সেক্টরে এর প্রভাব লক্ষণীয়। ডিপ লার্নিং হচ্ছে মেশিন লার্নিং এর একটি ব্র্যাঞ্চ বা একটা মেশিন লার্নিং টেকনিক যা কিনা নিজে নিজেই সরাসরি ডাটা থেকে ফিচার এবং টাস্ক শিখে নিতে পারে। সেই ডাটা হতে পারে ইমেজ, টেক্সট এমনকি সাউন্ড। অনেকেই ডিপ লার্নিং -কে এন্ড টু এন্ড লার্নিং-ও বলে থাকেন। ডিপ লার্নিং টেকনিকের খুব পুরনো এবং বহুল পরিচিত ব্যাবহার হয় পোস্টাল সার্ভিসে খামের উপর বিভিন্ন ধরনের হাতের লেখা চিহ্নিত করতে। মোটামুটি ১৯৯০ সালের দিক থেকেই ডিপ লার্নিং এর এই প্রয়োগ চলে আসছে।
২০০৪/২০০৫ সালের দিক থেকে ডিপ লার্নিং এর ব্যবহার খুব উল্লেখ যোগ্য ভাবে বেড়ে চলছে। মূলত তিনটি কারণে — প্রথমত ইদানিং কালের ডিপ লার্নিং মেথড গুলো মানুষের চেয়ে অনেক বেশি ভালো ভাবে অবজেক্ট রিকগনিশনের বা ক্লাসিফিকেশনের কাজ করতে পারছে, দ্বিতীয়ত GPU এর কল্যাণে অনেক বড় আকারের ডিপ নেটওয়ার্ক খুব কম সময়ের মধ্যেই লার্নিং শেষ করে নিতে পারছে, তৃতীয়ত, খুব ইফেক্টিভ লার্নিং এর জন্য যে পরিমাণ ডাটার প্রয়োজন পরে সেই লেভেলের ডাটা গত ৫/৬ বছরে ব্যবহার উপযোগীভাবে তৈরি হচ্ছে বিভিন্ন সার্ভিসের মাধ্যমে।
বেশির ভাগ ডিপ লার্নিং মেথড নিউরাল নেটওয়ার্ক আর্কিটেকচার ফলো করে আর তাই ডিপ লার্নিং মডেলকে মাঝে মধ্যেই ডিপ নিউরাল নেটওয়ার্ক হিসেবেও বলা হয়ে থাকে। খুব পপুলার একটি ডিপ লার্নিং মডেল হচ্ছে কনভলিউশনাল নিউরাল নেটওয়ার্ক বা CNN. এ ধরনের নেটওয়ার্ক বিশেষ করে ইমেজ ডাটা নিয়ে কাজ করার সময় ব্যবহৃত হয়ে থাকে। যখন বেশ কিছু লেয়ার নিয়ে একটি নিউরাল নেটওয়ার্ক ডিজাইন করা হয় তখন এটাকেই ডীপ নিউরাল নেটওয়ার্ক বলে। এই লেয়ারের সংখ্যা হতে পারে ২-৩ টি থেকে শ-খানেক পর্যন্ত।
এ পর্যন্ত পড়ার পর যদি খুব অস্বস্তি চলে আসে তবে ভয় পাওয়ার কিছু নাই, নিচেই খুব ব্যাসিক কিছু উদাহরণ এর মাধ্যমে সব সহজ ভাবে আলোচনা করা হবে। আমরা একটা সমস্যা দেখবো এবং তার সমাধানের জন্য একটি নিউরাল নেটওয়ার্ক ডিজাইন করবো। তারপর পাইথনে কোড লিখে সেই নেটওয়ার্কের প্রোগ্রামেটিক ভার্শন লিখবো এবং সেটার লার্নিং করিয়ে সমস্যাটা সমাধানও করবো ইনসা আল্লাহ। তার আগে জেনে নেই, মেশিন লার্নিং এবং ডিপ লার্নিং এর মধ্যে পার্থক্য বা সম্পর্ক কোথায়।
মেশিন লার্নিং বনাম ডিপ লার্নিং
ইতোমধ্যে একটা ধারনা পেয়ে গেছেন যে, ডিপ লার্নিং এর মাধ্যমে বেশিরভাগ সময়েই ডাটা ক্লাসিফিকেশনের কাজ করা হয়ে থাকে। কিন্তু যদি আপনার মেশিন লার্নিং সম্পর্কে ধারনা থেকে থাকে তাহলে হয়ত এটাও জানেন যে, মেশিন লার্নিং এর বিভিন্ন অ্যালগরিদম ব্যবহার করেও ডাটা ক্লাসিফিকেশনের কাজ করা যায়। কিন্তু দুটো মাধ্যমের কাজ করার ধরনে বেশ কিছু পার্থক্য আছে। যেমন- মেশিন লার্নিং ব্যবহার করে ইমেজ ক্লাসিফিকেশনের কাজ করার সময় প্রথমেই ট্রেনিং ডাটা(ইমেজ) থেকে আপনার নিজেকেই ফিচার (যেমন-এইজ, কর্নার ইত্যাদি) এক্সট্র্যাক্ট করে নিতে হবে আপনার মেশিন লার্নিং মডেলকে ট্রেনিং করানোর জন্য। এরপর নতুন ডাটা(ইমেজ) নিয়ে সেটার ধরন প্রেডিক্ট করার সময় আপনার মেশিন লার্নিং মডেল সেই ফিচার গুলোকেই ভ্যারিয়েবল (চেনার হাতিয়ার) হিসেবে কাজে লাগিয়ে নতুন ইমেজটাকে অ্যানালাইস করে ডিসিশন নেয়। এভাবে ইমেজের মধ্যে কোন একটি নির্দিষ্ট অবজেক্ট রিকগনিশন বা ডিটেকশণ এর কাজও করা হয়ে থাকে।
অন্যদিকে ডিপ লার্নিং টেকনিকে কাজ করার সময় আপনি ম্যানুয়ালি সেই ফিচার এক্সট্র্যাকশনের কাজ থেকে বেঁচে যেতে পারেন। এক্ষেত্রে আপনি পুরো ইমেজটাকেই আপনার ডিপ নিউরাল নেটওয়ার্কে ইনপুট হিসেবে দিয়ে দিতে পারেন এবং সেই নেটওয়ার্ক স্বয়ংক্রিয় ভাবেই লেবেলের সাথে সম্পর্ক রেখে ওই ইমেজের গুরুত্বপূর্ণ ফিচারগুলোকে কন্সিডার করে লার্নিং করে নিতে পারবে যাতে করে সে পরবর্তীতে নতুন ইমেজ থেকে একই ধরনের অবজেক্ট খুঁজে নিতে পারে বা তার টাস্ক সম্পন্ন করতে পারে।
কখন আপনার জন্য মেশিন লার্নিং অ্যাপ্রোচ ভালো হবে এবং কখন আপনি ডিপ লার্নিং নিয়ে কাজ করলে সুবিধা হবে সেটা নির্ভর করে আপনার নির্দিষ্ট সমস্যাটির টাইপের উপর এবং আপনার কাছে থাকা ডাটার পরিমাণ ও ধরনের উপর। তবে খুব সহজ ভাবেও প্রাথমিক একটা সিদ্ধান্ত নিতে পারেন। যেমন- আপনার কাছে যদি তুলনামূলক কম পরিমাণ ডাটা থাকে এবং আপনার কম্পিউটেশন পাওয়ারও সীমাবদ্ধ হয় তাহলে আপনার জন্য মেশিন লার্নিং অ্যাপ্রোচ ভালো হবে। এতে করে আপনি একদিকে কম রিসোর্স ব্যবহার করেই সমস্যাটি নিয়ে কাজ করতে পারবেন এবং সাথে সাথে যেহেতু আপনি নিজেই ডাটা থেকে ফিচার পছন্দ করেন আর বর্তমানে অনেক গুলো মেশিন লার্নিং অ্যালগরিদম আছে তাই, বিভিন্ন ফিচার এবং অ্যালগরিদম এর কম্বিনেশন ব্যবহার করে আপনার মডেল এর পারফর্মেন্স চেক করে দেখতে পারেন।
অন্যদিকে যদি আপনার কাছে অনেক পরিমাণ ডাটা থাকে এবং সাথে সাথে আপনার কাছে যথেষ্ট পরিমাণ কম্পিউটেশন পাওয়ার থাকে তাহলে আপনার জন্য ডিপ লার্নিং অ্যাপ্রোচ ভালো হবে। এতে করে অনেক অনেক ডাটা থেকে ট্রেনিং করানোর সময় আপনার ডিজাইন করা নিউরাল নেটওয়ার্কটি অনেক বেশি পারফেকশন দেখাতে পারবে। এমনকি সেই ডাটা গুলো থেকে ধরে ধরে আপনাকে ফিচার পছন্দ না করে দিলেও চলবে। তবে এর জন্য মারাত্মক রকম কম্পিউটেশন পাওয়ার এবং সময়ও দরকার পরবে।

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

ভিত্তি
তো আমরা যদি একটু দুঃসাহস করে সত্যিকারের একটা নিউরনের কার্যনীতি দেখি তাহলে আমরা জানতে পারি যেএকটা নিউরনের কিছু ইনপুট দরকার এবং সেই ইনপুট গুলো আসে Dendrite নামের কিছু ডাল পালার মত অংশ দিয়ে, এরপর নিউরন বডি বা Soma নামের অংশে কিছু ক্যালকুলেশন হয়  সেই ইনপুট গুলোর উপর। অতঃপর Axon নামের লেজের মত একটা অংশ দিয়ে সেই ক্যালকুলেশনের আউটপুট বের হয় যা কিনা আবার অন্য এক বা একাধিক নিউরনের ইনপুট স্লট তথা Dendrite এ চলে যায়। একটি নিউরনের এক্সন এবং অন্য নিউরনের ডেন্ড্রাইটের মাঝে Synapse নামের কিছু তরল থাকে। এটাই বস্তুত এক নিউরন থেকে আরেক নিউরনের কাছে এক্সনের আউটপুট কে ডেন্ড্ররাইটে ইনপুট দেয়ার ক্ষেত্রে ট্রান্সমিশনের ভূমিকা রাখে। যদি একটি নিউরনের যথেষ্ট পরিমাণ সিন্যাপ্টিক ইনপুট ফায়ার (আশানুরূপ একটা ভ্যালু তৈরি করে) করে তাহলে সেই নিউরনটা ফায়ার করে বা বলা যেতে পারে যে, সেই নিউরনটা অ্যাকটিভ হয়। বিষয় হচ্ছেএই ঘটনাকেই চিন্তা করা বলে।

বানিয়ে ফেলি একটা নিউরাল নেটওয়ার্ক
উপরোক্ত প্রসেসটাকেই আমরা কম্পিউটারে প্রোগ্রাম লিখে সিমুলেট করতে পারি। তাহলেই কিন্তু একটা আর্টিফিশিয়াল নিউরন বানাতে পারছি বলে ধরে নয়া যায়। তাই না? তবে এটা সত্যিকারের নিউরনের মত জটিল হবে না কারণ, আগেই বলা হয়েছে যে আর্টিফিশিয়াল নিউরাল নেটওয়ার্ক শুধুমাত্র সত্যিকারের নিউরনের নেটওয়ার্কের কনসেপ্ট এর উপর ভিত্তি করে তৈরি। তার মানে এই না যে এটা শতভাগ একই। যাই হোক আমরা একটি সিঙ্গেল নিউরন তৈরি করি যার মাধ্যমেই আমরা ছোট্ট একটা সমস্যা সমাধানের চেষ্টা করবো। ধরে নেই আমাদের আর্টিফিশিয়াল ব্রেনে একটাই মাত্র নিউরন।

সমস্যাটা নিচের মত,

উপরের প্যাটার্ন গুলো নিয়ে একটু চিন্তা করলেই আমরা বুঝতে পারবো যে প্রত্যেকটি ইনপুট কম্বিনেশনের প্রথম ভ্যালুটি বস্তুত ওই কম্বিনেশনের আউটপুট। পরের দুটি ভ্যালু অনর্থক। তাই নতুন অচেনা কম্বিনেশন 1 0 0 এর আউটপুট হবে 1. আমরা নিজেরা এটা সহজেই চিন্তা করে ধরে ফেলেছি। এই কাজটাই আমরা আরটিফিশিয়াল নিউরনের মাধ্যমে করে দেখতে চাই।

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

এই নিউরনেরও তিনটা ইনপুট নেয়ার জন্য তিনটা ডেন্ড্রাইট আছে আর একটা এক্সন আছে যেখানে আমরা আউপুট পেয়ে যাবো কারণ এই ব্রেনে আর কোন নিউরন নাই যাকে এই এক্সনের আউপুটকে ইনপুট হিসেবে দিতে হবে।

তো, প্রশ্ন হচ্ছে কিভাবে এই নিউরনকে ট্রেনিং দেয়া যায়?
আমরা যেটা করতে পারিনিউরনটার তিনটা ইনপুটে আমাদের প্রথম উদাহরণের তিনটা ভ্যালু দেবো আর আউপুট প্রান্তে সেই উদাহরণ মোতাবেক সঠিক আউপুটটা রাখবো। এরপর ইনপুট লাইন (গ্রাফ কনসেপ্টে Edge) গুলোতে কিছু Weight (ভ্যালু) সেট করবো। এরপর প্রত্যেকটা ইনপুট ভ্যালুর সাথে ওই Edge এর ভ্যালু তথা Weight গুন করে নিউরন-বডি/Soma বা Node এ একটা Weighted Sum জমা করবো। এক্ষেত্রে এই Node টী হচ্ছে আমাদের আউপুট নোড। যাই হোক, এই নোডে জমা হওয়া ভ্যালুর পরিমাণ কিন্তু 1 এর অনেক বেশি বা 0 এর চেয়ে কম হতে পারে। কিন্তু আমরা তো চাই, ভ্যালুটা 1 আর 0 এর মাঝা মাঝি থাকুক যাতে করে আমরা আমাদের আগে থেকেই সেট করা আউপুট ভ্যালু (যেমন – প্রথম উদাহরণ মোতাবেক 0) –এর সাথে তুলনা করতে পারি। তাই আউটপুট নোডে জমা হওয়া ভ্যালুকে আমরা গণিতের একটা স্পেশাল গ্যারাকলে ফেলে কোন না কোন ভাবে 1 0 এর মাঝেই রাখবো। এটাকে বলে Activation Function (নিচেই আমরা এর চেহারা এবং ব্যবহার দেখবো)। এরপর সেই ক্যালকূলেটেড ভ্যালু এবং প্রথম উদাহরণ মোতাবেক আউটপুটের ভ্যালুর মধ্যে তুলনা করে আমরা ভুলের পরিমাণ দেখবো।

অর্থাৎ প্রথম ট্রেনিং হচ্ছেইনপুট দিলাম 0 0 1 এবং আউটপুট যেন হয় 0. কিন্তু ধরি Edge গুলোতে সেট করা আমাদের র‍্যান্ডম ওয়েট গুলো কন্সিডার করে ওয়েটেড সাম থেকে অ্যাক্টিভেশন ফাংশনের মাধ্যমে ভ্যালু পেলাম 0.9

তার মানে ট্রেনিং এর মাথা মুণ্ড কিছুই হয় নি। এরপর আমরা যা করতে পারি সেটা হল, সেই ওয়েট গুলোকে একটু চেঞ্জ (Adjust) করে দেখতে পারি। অর্থাৎ প্রথম লাইনে (Edge) যে ভ্যালু ছিল সেটাকে একটু বাড়িয়ে, আবার দ্বিতীয় লাইনের ওয়েটকে একটু কমিয়ে আবারও Activation Function এর আউটপুট দেখতে পারি। এবার যদি দেখি যে এর মান আসলো 0.4 তার মানে আউটপুটের সাথে মিল আসতেছে। আবারও একটু ওয়েট গুলোকে অ্যাডজাস্ট করে Activation Function এর আউটপুট দেখতে পারি। এবার যদি দেখি যে এর মান আসলো 0.1 তার মানে প্রথম ট্রেনিং সেট মোতাবেক যে 0 পাওয়ার চেষ্টা সেটা মোটামুটি সফল।

অর্থাৎ প্রথম ডাটা সেট (একটা Row যার ইনপুট/ভ্যারিয়েবল 0 0 1 এবং আউটপুট/লেবেল 0এর জন্য আমাদের নিউরনের ট্রেনিং সম্পন্ন। অর্থাৎ, নিউরনটি তার ওয়েট গুলোকে অ্যাডজাস্ট করে এমন একটা অবস্থায় নিয়ে এসেছে যে এর তিনটি ইনপুটে 0 0 1 দিলে আউটপুটে 0 এর কাছাকাছি একটা ভ্যালু আসে। এরপর আবার নিউরনকে দ্বিতীয় ট্রেনিং ডাটা সেট দেয়া হল। এবার তার কাজ হচ্ছে নতুন তিনটি ইনপুট 1 1 1 এবং এর জানা আউটপুট 1 এর সাপেক্ষে নিজের Edge গুলোর ওয়েট এমনভাবে অ্যাডজাস্ট করা, যাতে করে ওয়েটেড সাম এবং Activation Function এর কাজের পর আউটপুট মোটামুটি 1 এর কাছাকাছি আসে।

কিন্তু খেয়াল রাখতে হবে যে আগের ট্রেনিং সেটের ব্যাপারটাও যাতে ঠিক থাকে। অর্থাৎ, দ্বিতীয় ট্রেনিং সেটের জন্য ওয়েট অ্যাডজাস্ট করে ইনপুট আউটপুট মিলাতে গিয়ে যেন প্রথম ট্রেনিং সেটের বারোটা না বেজে যায়। তার মানে তাকে খুবি ধীরে সুস্থে এবং ক্ষুদ্র ক্ষুদ্র পরিমাণে ওয়েটের ভ্যালু অ্যাডজাস্ট করতে হবে যাতে 0 0 1 দিলেও 0 এর মত মান আসে আবার 1 1 1 দিলেও যাতে 1 এর মত মান আসে। তো, বোঝাই যাচ্ছে যে, একবার দুইবার অ্যাডজাস্ট করে এই কাজ হাসিল করা সম্ভব না। বার বার এরর চেক করে বার বার ওয়েট অ্যাডজাস্ট করে করে দেখতে হবে। মাথা গরম করার কিছু নাই, নিচে আবারও আমরা এসব কথা বার্তা আরেকবার ধাপে ধাপে দেখবো।

তবে বুঝতে পারছি যে ঠিক কি কি কাজ আমাদের করতে হবে একটা ট্রেনিং সাইকেল সম্পন্ন করতে হলেঃ

এক) ট্রেনিং ডাটা টেবিল থেকে একটা সেট নিয়ে ইনপুট গুলো দেবো। এইজ গুলোতে কিছু র‍্যান্ডম ওয়েট (ভ্যালু) সেট করবো। কিছু গুন আর যোগ করে এবং স্পেশাল একটা ফাংশনের মাধ্যমে এর আউটপুট বের করবো।

দুই) এরর এর পরিমাণ বের করবো অর্থাৎএই ধাপের আউটপুট এবং আসলেই ট্রেনিং সেট মোতাবেক আসল আউটপুটের পার্থক্য দেখবো।

তিন) এরর এর গতবিধি মোতাবেক ওয়েটগুলোকে খুব অল্প পরিমাণে অ্যাডজাস্ট করবো

চার) উপরের তিনটি ধাপকে হাজার হাজার বার রিপিট করাবো 

এভাবে সামনের দিকে ক্যালকুলেশন এগিয়ে নিয়ে (Forward Propogation) এরর সাথে তুলনা করে আবার পিছনে ফিরে এসে (Back Propogation) ভ্যালু (ইনপুট ভ্যালু না কিন্তু। ওয়েট বা আপনার সেট করা ভ্যালু) গুলোকে অ্যাডজাস্ট করে আবার আউটপুটের সাথে তুলনা করার যে চক্র তাকে বলে এক Epoch. এক Epoch = Forward Propogation + Back Propogation.

এক নাম্বার ধাপের কাজ করিপ্রত্যেকটা ইনপুটের সাথে প্রত্যেক লাইনের ওয়েট গুন করে যোগফল বের করার সূত্র হবে নিচের মতঃ

এর পর এই যোগফলকে 1 0 এর মাঝা মাঝি রাখার জন্য গণিতের একটা স্পেশাল ফাংশন যার নাম Sigmid Function (এখানে এটাই আমাদের Activation Function. এরকম আরও আছে।)  সেটাকে ব্যবহার করতে পারি।  এই ফাংশনের কাজ হচ্ছেএকে ইনপুট হিসেবে যে মাণই দেয়া হোক না কেন, আউটপুট আসবে 1 থেকে শুনের মধ্যেই। এটাই তো দরকার 🙂 যাই হোক ফাংশনের  ম্যাথেমেটিক্যাল রিপ্রেজেন্টেশন এবং গ্রাফটা দেখতে নিচের মত

তো আমরা আমাদের ওয়েটেড সাম কে এই ফাংশনের সাহায্যে 1 0 এর মধ্যে এনে ফেলতে পারি। Sigmoid Function নিয়ে পড়ার জায়গা এটা না। দরকার হলে আলাদা করে দেখে ফিরে আসতে পারেন এই পোস্টে।

দ্বিতীয় ধাপে – এরর এর পরিমাণ বের করবো। এটা খুবি সহজ কাজ। প্রত্যেকটি ইনপুট কম্বিনেশনের জন্য আউটপুট থেকে এই নিউরাল নেটওয়ার্কের হিসেব করা আউটপুটকে বিয়োগ দিতে হবে।

তৃতীয় ধাপে –  আমরা এররের উপর ভিত্তি করে ওয়েট অ্যাডজাস্ট করবো। কিন্তু কি পরিমাণে অ্যাডজাস্ট করবো? এক্ষেত্রেও আমরা একটা ফর্মুলা “Error Weighted Derivative” ব্যবহার করতে পারি। সূত্রটা দেখতে নিচের মতোঃ

সূত্রে বিভিন্ন ফ্যাক্টরের প্রয়োজনীয়তা নিয়ে প্রশ্ন আসতেই পারে। বিষয়টা সহজযেহেতু আমরা এরর সমানুপাতে ওয়েট অ্যাড জাস্ট করবো তাই এটাকে লাগছে। আবার সাথে আমরা ইনপুটকেও নিচ্ছি যাতে করে ইনপুট যদি 0 হয় তাহলে ওয়েট অ্যাডজাস্ট করবো না (ডান পাশে শুন্য আসবে)। আসলে ইনপুট শুন্য হলে অ্যাডজাস্ট করে লাভও নাই। ওই Edge এর মাণ এমনিতেই শূন্য আসবে। তিন নাম্বার ফ্যাক্টরটা গুরুত্বপূর্ণ যা কিনা একটি ভ্যালুর জন্য (এক্ষেত্রে আমাদের ক্যালকুলেট করা আউটপুট) প্রাপ্ত Sigmoid Curve এর Gradient (ঢাল)। সূত্রের ডান পাশে এই ফ্যাক্টর এর তাৎপর্য এরকম – Sigmoid Curve এর মাধ্যমে আমরা নিউরনের আউপুট হিসেবে করছি। যদি এই আউটপুটের মাণ খুব বেশি পজিটিভ বা খুব বেশি নেগেটিভ হয় তার মাণে নিউরনটি ট্রেনিং সেটের আউটপুট ভ্যালুর দিকে ঝুঁকতে খুবি আত্মবিশ্বাসী তথা ওয়েট অ্যাডজাস্ট করার খুব একটা দরকার নাই। অন্যদিকে আমরা Sigmoid Function এর গ্রাফ থেকে দেখতে পারি যে – ভ্যালু যত বেশি, এই Curve এর Gradient বা ঢাল তত কম। তাই এই ফ্যাক্টরকে ডান পাশে রাখলে এবং আউটপুট খুব বেশি পজিটিভ/নেগেটিভ আসলে এই ফ্যাক্টরের মাণও কম আসতেছে আর তাই বাম পাশে অ্যাডজাস্টের পরিমাণও কম হচ্ছে। বুদ্ধি 🙂

যাই হোক Sigmoid Curve এর Gradient বের করার সহজ সূত্র হচ্ছেঃ

অর্থাৎ Adjust weight by সমীকরণ দাড়ায়ঃ

ফিরে দেখা
এ অবস্থায় আমরা আমাদের সিঙ্গেল নিউরন বিশিষ্ট আর্টিফিশিয়াল নিউরাল নেটওয়ার্কের চেহারাটা একটু স্মার্ট ভাবে দেখি,

এখানে n এর মান 3 ধরলেই আমাদের সমস্যার সাথে উপরের ফিগারটি মিলে যাবে।

“Talk is cheap. Show me the code.”
এই বানীটি কার, তার নাম জানলে নিচে কমেন্ট করতে পারেন। এই যে আমরা নিউরাল নেটওয়ার্ক এর কাহিনীকে ফলো করে সেরকম নীতিতে আমাদের বাস্তবের কিছু সমস্যা সমাধানের জন্য একটা পদ্ধতি নিয়ে চিন্তা করলাম সেটা তো আর খাতা কলমে করে কুলাবে না। এই কাজটা কম্পিউটার দিয়ে করালে খুব দ্রুত আমাদের উদ্দেশ্য পুড়ন হবে। আর সবাই জানে, কম্পিউটারকে দিয়ে ইচ্ছামত কামলা খাটুনি খাটিয়ে নেয়া যায়। শুধুমাত্র তাকে তার ভাষায় আদেশ দিতে হবে। এর নাম নাকি আবার কম্পিউটার প্রোগ্রাম। তো, কি আর করা, লিখে ফেলি; কম্পিউটার বোঝে এবং আমাদের লিখতে সহজ এমন একটা ভাষায় একটা প্রোগ্রাম, যার মাধ্যমে বস্তুতপক্ষে আমরা উপড়ে আলোচ্য কাজ গুলোকেই করবো।

যদি আপনার পাইথন প্রোগ্রামিং ল্যাঙ্গুয়েজে ভালো দখল থাকে তাহলে আপনার জন্য ডাটা সায়েন্স, মেশিন লার্নিং এবং ডিপ লার্নিং নিয়ে কাজ করা সহজ হয়ে যায়। আমরা নিচে একটা পূর্ণ প্রোগ্রাম দেখবো যার মাধ্যমে তিনটি ইনপুট ওয়ালা একটি সিঙ্গেল নিউরন তৈরি করা হয়েছে এবং সেই ইনপুট এইজ গুলোতে প্রথমে কিছু র‍্যান্ডোম ওয়েট সেট করা হয়েছে। এরপর ওই নিউরনে ট্রেনিং ডাটাসেট অর্থাৎ কিছু ইনপুট row এবং row সাপেক্ষে একটি করে আউটপুট দিয়ে দেয়া হয়েছে। Sigmoid Function ব্যবহার করে নিউরনের চিন্তা অনুযায়ী আউটপুট বের করা হয়েছে। সত্যিকারের আউপুট এবং নিউরনের হিসাব করে বের করা আউটপুটের তুলনা করে এরর চেক করা হয়েছে। ১০০০০ বার লুপ চালিয়ে (ট্রেনিং করিয়ে) উপড়ে আলোচ্য ওয়েট অ্যাডজাস্ট করার সূত্র দিয়ে প্রত্যেক লুপের মধ্যে একবার করে ওয়েট অ্যাডজাস্ট করা হয়েছে। সবশেষে একই নিউরনে নতুন একটি ডাটাসেট দিয়ে তার আউপুট জানতে চাওয়া হয়েছে। যদি সে আমাদের ধারনা করা আউপুটকেই আউটপুট হিসেবে দিতে পারে তাহলে বলা যায় যে, এই সিঙ্গেল নিউরন ওয়ালা নেটওয়ার্কটি ৪টি ট্রেনিং ডাটাসেট থেকেই প্যাটার্ন খুঁজে নিতে সফল হয়েছে এবং সেই প্যাটার্ন মোতাবেক নতুন ডাটা সেটের জন্য আউটপুট বলে দিতে পারছে।

Medium কমিউনিটির ব্লগার @miloharper এর gist থেকে ফর্ক করা প্রোগ্রামটি নিচে দেয়া হলঃ

   

from numpy import exp, array, random, dot

class NeuralNetwork():
    def __init__(self):
        # Seed the random number generator, so it generates the same numbers
        # every time the program runs.
        random.seed(1)

        # We model a single neuron, with 3 input connections and 1 output connection.
        # We assign random weights to a 3 x 1 matrix, with values in the range -1 to 1
        # and mean 0.
        self.synaptic_weights = 2 * random.random((3, 1)) - 1

    # The Sigmoid function, which describes an S shaped curve.
    # We pass the weighted sum of the inputs through this function to
    # normalise them between 0 and 1.
    def __sigmoid(self, x):
        return 1 / (1 + exp(-x))

    # The derivative of the Sigmoid function.
    # This is the gradient of the Sigmoid curve.
    # It indicates how confident we are about the existing weight.
    def __sigmoid_derivative(self, x):
        return x * (1 - x)

    # We train the neural network through a process of trial and error.
    # Adjusting the synaptic weights each time.
    def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
        for iteration in range(number_of_training_iterations):
            # Pass the training set through our neural network (a single neuron).
            output = self.think(training_set_inputs)
            # print("\nOutput of the Above Function After Sigmoid Applied: \n",output)

            # Calculate the error (The difference between the desired output
            # and the predicted output).
            error = training_set_outputs - output
            # print("\nTraining Set Output Matrix: \n", training_set_outputs)
            # print("\nError: Training Set Output Matrix 4x1 - Above Matrix 4x1 \n", error)

            # Multiply the error by the input and again by the gradient of the Sigmoid curve.
            # This means less confident weights are adjusted more.
            # This means inputs, which are zero, do not cause changes to the weights.
            adjustment = dot(training_set_inputs.T, error * self.__sigmoid_derivative(output))
            # print("\nAdjustment Matrix: \n", adjustment)

            # Adjust the weights.
            self.synaptic_weights += adjustment

    # The neural network thinks.
    def think(self, inputs):
        dot_product = dot(inputs, self.synaptic_weights)
        # print("\nDot Product of Input Matrix and Weight Matrix: \n",dot_product)
        # Pass inputs through our neural network (our single neuron).
        return self.__sigmoid(dot_product)

if __name__ == "__main__":

    #Intialise a single neuron neural network.
    neural_network = NeuralNetwork()

    print ("\n\nRandom starting synaptic weights: ")
    print (neural_network.synaptic_weights)

    # The training set. We have 4 examples, each consisting of 3 input values
    # and 1 output value.
    training_set_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
    training_set_outputs = array([[0, 1, 1, 0]]).T

    # Train the neural network using a training set.
    # Do it 10,000 times and make small adjustments each time.
    neural_network.train(training_set_inputs, training_set_outputs, 10000)

    print ("\nNew synaptic weights after training: ")
    print (neural_network.synaptic_weights)

    # Test the neural network with a new situation.
    print ("\nConsidering new situation [1, 0, 0] -> ?: ")
    print (neural_network.think(array([1, 0, 0])))   

যদি প্রোগ্রামটির if __name__ == “__main__”: থেকে দেখা শুরু করেন তাহলে ধাপে ধাপে বুঝতে পারার কথা কিভাবে কোডের মাধ্যমে এই নিউরাল নেটওয়ার্ক তৈরি করা হয়েছে। আমি যথা সম্ভব আরেক্টূ সহজে ব্যাখ্যা করার চেষ্টা করছি। প্রোগ্রামের শুরুতেই numpy লাইব্রেরী যুক্ত  করা হয়েছে যাতে করে খুব সহজে ম্যাট্রিক্স পদ্ধতিতে কিছু ক্যালকুলেশনের কাজ করা যায় কারণ ন্যাটিভ পাইথনে ম্যাট্রিক্স টাইপের কোন ডাটা স্ট্রাকচার নাই। অন্যদিকে নিউরাল নেটওয়ার্কের গঠন মোতাবেক ইনপুট এবং ওয়েট নিয়ে গুন/যোগ ইত্যাদি করার সময় ম্যাট্রিক্স স্টাইল ভালো উপায়।

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

training_set_inputs = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
training_set_outputs = array([[0, 1, 1, 0]]).T

উল্লেখ্যআউপুট কলামের ডাটা গুলোকে প্রথমে একটি 1×4 সাইজের ম্যাট্রিক্সে স্টোর করে তারপর ট্রান্সপোজ করে 4×1 সাইজে কনভার্ট করা হয়েছে যাতে ভিজুয়াল রিপ্রেজেন্টেশন মনে করা যেতে পারে এমন

ইনপুট ম্যাট্রিক্স –

আউটপুট ম্যাট্রিক্স –

এভাবে ডাটা স্টোর করার ফলে আমরা একবারে পুরো ইনপুট ডাটা টেবিলকে আমাদের নিউরাল নেটওয়ার্কে ইনপুট দিয়ে খুব সহজে প্রত্যেকটা ইনপুট সেট (এ ক্ষেত্রে এক একটা row) -এর সাথে ওয়েট সেট ডট গুন করে একবারেই একটা আউটপুট ম্যাট্রিক্স পেয়ে যেতে পারি যেখানে ৪টা ইনপুট সেটের (৪টা row) জন্যই ৪টা আউটপুট ভ্যালু থাকবে 4×1 সাইজে। এতে করে প্রত্যেকটা Epoch এ পুরো অপারেশনটা একবার পুরোপুরি শেষ হবে।  এছাড়াও এই লাইব্রেরী থেকে আরও কিছু ফাংশনের সাহায্য নিয়ে কিছু অপারেশনকে সহজ বোধ্য করা হয়েছে।

স্ক্রিপ্ট হিসেবে এই প্রোগ্রামকে রান করালে ৫৮ নাম্বার লাইনে থেকেই এই প্রোগ্রামটির কার্যক্রম শুরু হয়। শুরুতেই NeuralNetwork ক্লাসের একটি অবজেক্ট তৈরি করা হয়েছে যার মাধ্যমে ফ্রেশ একটি নিউরাল নেটওয়ার্ক তৈরি করা যায়। তো, দেখে আসি  সেই ক্লাসের চেহারাটা। ৪নাম্বার লাইনে ক্লাসকে ডিফাইন করা হয়েছে। এর কন্সট্রাক্টরের মধ্যেই আমাদের সেই বহুল আলোচিত র‍্যান্ডম ওয়েট তিনটি তৈরি করা হচ্ছে।

যেহেতু আমাদের নিউরনের ৩টি ইনপুট তাই তিনটি ইনপুটের জন্য তিনটি ওয়েট নির্ধারণ করে ইনপুট গুলোর সাথে গুন করতে কাজ করার সুবিধার্থে 3×1 সাইজের একটি ম্যাট্রিক্স নেয়া/তৈরি করা হয়েছে synaptic_weights নামে। প্রথমবার অর্থাৎ ওয়েট অ্যাডজাস্ট হবার আগে এর চেহারা হতে পারে এমন

নোটঃ আপনি প্রোগ্রাম রান করানোর সময় আলাদা ভ্যালু পেতে পারেন কারন র‍্যান্ডমলি জেনারেটেড।

এই ক্লাসের মধ্যে আরেকটি মেথড বানানো হয়েছে যার মাধ্যমে Sigmoid Function ব্যবহার করে ভ্যালু নরমালাইজেশন অর্থাৎ আউটপুট ভ্যালুকে 1 0 মাঝে রাখা হয়। তার নিচেই আছে আরেকটি ফাংশন যার মাধ্যমে আমরা যেকোনো একটি আউটপুট ভ্যালুর জন্য Sigmoid Curve  এর Gradient বের করতে পারি। এটি কাজে লাগে ওয়েট অ্যাডজাস্টমেন্ট এর মান ঠিক করতে। উপড়ে এটা নিয়ে আলোচনা করা হয়েছে। এরপরেই আছে গুরুত্বপূর্ণ train ফাংশন যার মাধ্যমে আমাদের নিউরাল নেটওয়ার্কটি প্যাটার্ন চেনা শিখে নেয়।

প্রথমেই একটি লুপ চালানো হয়েছে যার মাণ নির্ধারণ করবে আপনি যতগুলো Epoch বা ট্রেনিং সাইকেল করাতে চান তার উপর। এখানে ১০০০০ বার Forward এবং Back Propogaion করাতে বলা হচ্ছে। ১০০০০ লুপের প্রথম iteration -এ  লুপের মধ্যের প্রথম কাজ হচ্ছে think ফাংশনের ব্যবহার করে এবং র‍্যান্ডম ওয়েটের উপর ভিত্তি করে একটা আউটপুট ম্যাট্রিক্স তৈরি করা যার মধ্যে নিউরনের হিসাব মোতাবেক পাওয়া আউটপুট গুলো থাকবে। এটির ডাইমেনশন হবে 4×1 অর্থাৎ ৪সেট ইনপুট ডাটার (৪টি row) জন্য ৪টি আউটপুট তথা নিচের মত একটি ম্যাট্রিক্স।

যদি think ফাংশনের কোড দেখি তাহলে দেখতে পারবো যে এখানে 4×3 সাইজের পুরো ইনপুট ডাটা টেবিল যাকে ম্যাট্রিক্সে কনভার্ট করা হয়েছে, তার সাথে 3×1 সাইজের ওয়েট ম্যাট্রিক্সের গুন করা হয়েছে। এতে করে বস্তুত প্রত্যেকটি ইনপুট সেট যেমন প্রথমত 0 0 1 এর সাথে তিনটি ওয়েট

– কে ডট গুন করা হয়েছে। আবার দ্বিতীয় ইনপুট সেট 1 1 1 এর সাথে একই ওয়েট ম্যাট্রিক্স

– কে ডট গুন করা হয়েছে। অর্থাৎ এভাবে সব গুলো ইনপুট কম্বিনেশনের সাথেই একবার করে ওই তিনটি ওয়েট ডট গুন করা হয়েছে। এভাবে যে আউটপুট ম্যাট্রিক্স পাওয়া যায় সেটাও কিন্তু 4×1 সাইজের ম্যাট্রিক্স। সেই ম্যাট্রিক্সকে একবার করে __sigmoid মধ্যে চালিয়ে নিয়ে ভ্যালু গুলোকে নরমালাইজ করা হয়েছে। তো, সব গুলো ইনপুট কম্বিনেশন এর সাথে ওয়েট গুলোর ডট গুন (গুন ও গুন গুলোর যোগ) করে নরমালাইজ করার পর নিচের মত একটি ম্যাট্রিক্স পাওয়া যাবে,

এই ম্যাট্রিক্সকে output ভ্যারিয়েবলে স্টোর করা হচ্ছে। এরপর এরর হিসাবের জন্য আমরা 4×1 সাইজের ট্রেনিং আউটপুট ম্যাট্রিক্স তথা,

থেকে উপরের 4×1 সাইজের output ম্যাট্রিক্স বিয়োগ করে নিচের মত একটি ম্যাট্রিক্স পেতে পারি,

এরপর এই এরর ম্যাট্রিক্স কে সাথে নিয়ে ইনপুট ডাটা সেট ম্যাট্রিক্স এবং Sigmoid Derivative কে কাজে লাগিয়ে অ্যাডজাস্টমেন্ট এর পরিমাণ বের করা হচ্ছে। এই অ্যাডজাস্টমেন্ট ম্যাট্রিক্সটিও ওয়েট ম্যাট্রিক্স এর মত 3×1 সাইজের। আর তাই train ফাংশনের শেষ লাইনে মুল ওয়েট ম্যাট্রিক্স এর সাথে এই অ্যাডজাস্ট ম্যাট্রিক্স যোগ করে ওয়েট ম্যাট্রিক্সে পরিবর্তন করে নেয়া হচ্ছে।

NeuralNetwork ক্লাসের কোড বোঝার পর আবারও ফিরে আসি পাইথন প্রোগ্রামের রেগুলার এক্সিকিউশন স্টেজে। ক্লাস ইনিসিয়ালাইজ করার পর পর্যবেক্ষণের স্বার্থে প্রথমবার সেট হওয়া র‍্যান্ডম ওয়েট ম্যাট্রিক্সকে প্রিন্ট করে দেখা হচ্ছে ওয়েট গুলো কি কি –

এরপর আমাদের ডাটা টেবিল থেকে ইনপুট এবং আউটপুট গুলোকে গুছিয়ে 4×3 সাইজের ট্রেনিং সেট ইনপুট এবং 4×1 সাইজের ট্রেনিং সেট আউটপুট ম্যাট্রিক্স বানিয়ে নেয়া হচ্ছে। এরপরেই উপড়ে আলোচ্য NeuralNetwork ক্লাসের অবজেক্ট neural_network –র মেথড, train এর মধ্যে এগুলো পাঠিয়ে দেয়া হচ্ছে। ১০০০০ বার চক্কর দেয়ার পর অপ্টিমাইজ ওয়েট ম্যাট্রিক্সটি কেমন রূপ ধারণ করলো সেটাও প্রিন্ট করা হচ্ছে।

সবশেষে, একটি নতুন ইনপুট সেট কে think ফাংশনে পাঠিয়ে আমাদের নিউরাল নেটওয়ার্ক এর কাছে আউটপুট জানতে চাওয়া হচ্ছে। এবার think ফাংশন, এই ইনপুট ডাটা সেট তথা 1×3 ম্যাট্রিক্সের সাথে আপডেটেড 3×1 ওয়েট ম্যাট্রিক্স এর ডট গুন করে Sigmoid অ্যাপ্লাই করে নরমালাইজ ডাটা তথা 1 থেকে 0 মধ্যের একটা ভ্যালুকে প্রিন্ট করে 1×1 সাইজের ম্যাট্রিক্স আকারে যেটা কিনা আমাদের নিউরাল নেটওয়ার্কের প্রেডিকশন।

আর সেটি হচ্ছে,

অর্থাৎ আমাদের নিউরাল নেটওয়ার্ক ভালোমতই ইনপুট ডাটা থেকে প্যাটার্ন খুঁজে তার উপর ভিত্তি করে পরবর্তী নতুন ইনপুট ডাটার জন্য তার আউটপুট কি হবে সেটা বলে দিতে পারছে।

আপনি যদি প্রথম iteration এর সব গুলো কাজের ধাপকে লগ করে দেখতে চান যে একটা ট্রেনিং লুপে কি কি ঘটছে তাহলে ৭৩ নাম্বার লাইনে 10000 এর পরিবর্তে 1 পাঠিয়ে এবং পুরো প্রোগ্রামের মধ্যে থাকা কমেন্ট করা প্রিন্ট স্টেটমেন্ট গুলোকে অ্যাক্টিভ করে দেখতে পারেন নিচের মত আউটপুট এবং সেগুলো ম্যানুয়ালি বিচার করতে পারেন।

পুরো ১০০০০ বার লুপের পর অর্থাৎ ট্রেনিং শেষের পর ওয়েটেড ম্যাট্রিক্স এর ফাইনাল রূপ আসবে নিচের মত,

তাহলে চলুন এবার খাতা কলম নিয়ে পরীক্ষায় বসে যাই কিভাবে এই কৃত্রিম নিউরনের নেটওয়ার্ক এই সিদ্ধান্ত নিতে পারলো। আপডেটেড ওয়েট গুলোকে এবার নিউরাল নেটওয়ার্কের ফিগারে বসাই,

অভিনন্দন আপনি একদম ব্যাসিক একটা নিউরাল নেটওয়ার্ক তৈরি করা শিখেছেন এবং এর ব্যাসিক কার্যনীতি বুঝে ফেলেছেন। আমাদের এই নিউরাল নেটওয়ার্কে একটা ইনপুট লেয়ার এবং একটা আউটপুট লেয়ার। সামনের পোস্টে নিচের সমস্যাটি সমাধান করা হবে যা কিনা এরকম ব্যাসিক নেটওয়ার্ক দিয়ে সমাধান করা সম্ভব নয় অর্থাৎ এরকম একটি নেটওয়ার্ক নিচের সমস্যা থেকে প্যাটার্ন খুঁজে পেতে অপারগ। এর জন্য  ডিপ নিউরাল নেটওয়ার্ক ডিজাইন করবো পরবর্তী পোস্টে। ততক্ষণ পর্যন্ত আপনি বোঝার চেষ্টা করুন তো কি প্যাটার্ন লুকিয়ে আছে এই সমস্যাটিতে এবং আউটপুট কি হতে পারে?

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

মাল্টি লেয়ার অর্থাৎ ডিপ নিউরাল নেটওয়ার্ক
এখানে প্যাটার্নটা হচ্ছে এরকমইনপুট কম্বিনেশনের তৃতীয় কলামের ভ্যালু অনর্থক এবং প্রথম দুই কলামের মধ্যে XOR অপারেশনের উপর ভিত্তি করে আউটপুট নির্ধারীত হচ্ছে। আর তাই, 1 1 0 এর আউটপুট হবে 1 XOR 1 = 0.

এই ধরনের প্যাটার্নকে Non Linear প্যাটার্ন বলা হয়ে থাকে। কারণ এখানে ইনপুট এবং আউটপুটের মধ্যে সরাসরি কোন one-to-one রিলেশন নাই।তাই এই প্যাটার্নকে উদ্ধার করার ক্ষমতা আমাদের আগের সিঙ্গেল নিউরন নেটওয়ার্কের নাই। বরং আমাদের একটি হিডেন লেয়ার ওয়ালা ডিপ নিউরাল নেটওয়ার্ক ডিজাইন করতে হবে।

এই নতুন লেয়ারে ৪টি নিউরন থাকতে পারে যেগুলো এই নিউরাল নেটওয়ার্ককে ইনপুট কম্বিনেশন গুলো নিয়ে একটু অন্যভাবে চিন্তা করাতে সাহায্য করে। চিন্তা কি জিনিষ আগেই একবার বলা হয়ে গেছে।

Screen Shot 2017-05-19 at 7.26.59 PM

উপরের ডায়াগ্রাম থেকে দেখা যাচ্ছে যে, Layer 1 এর আউটপুট গুলো Layer 2 এর ইনপুট হিসেবে যাচ্ছে। এভাবে আমাদের নিউরাল নেটওয়ার্ক, লেয়ার ১ এর আউটপুট এর সাথে ট্রেনিং সেট আউটপুটেরও একটা কোরিলেশন বের করতে পারবে। নিউরনের লার্নিং এর সাথে সাথে এই দুই লেয়ারের ওয়েট অ্যাডজাস্ট করে করে এই কোরিলেশন বাড়তে থাকবে।

বলে নেয়া ভালো, এই বিষয়টার সাথে ইমেজ রিকগনিশনের টেকনিকের মিল আছে। অর্থাৎ যদি আমরা একটি আপেলের ফটোর কথা চিন্তা করি, সেখানে কিন্তু প্রত্যেকটা পিক্সেল (ভ্যালু) এর সাথে বস্তুত আপেলের কোন সম্পর্ক নাই। দুইটা দুই জগতের জিনিষ। কিন্তু আবার [কিছু পিক্সেল কম্বিনেশন] এবং [আপেল] এই দুটো ফ্যাক্টরের রিলেশনশিপ আছে। অর্থাৎ উপরের নেটওয়ার্কে, প্রথম raw input এর সাথে আউটপুট এর সরাসরি কোন সম্পর্ক নাই (এটা আমরা জানি, ধরে নিচ্ছি) কিন্তু লেয়ার ১ এর আউটপুট তথা পিছনের কম্বিনেশনের সাথে মুল ডাটা সেটের একটা রিলেশন থাকতে পারে। আর তাই এখানে মধ্যবর্তী লেয়ারের আবির্ভাব এবং প্রয়োজনীয়তা।

এই যে, বিভিন্ন স্টেজের মধ্যেকার কোরিলেশনকে চেনার জন্য এবং কাজে লাগানোর জন্য এক বা একাধিক মধ্যবর্তী লেয়ারের সংযোজন, এটাকেই ডিপ লার্নিং বলে।

আবারও আমরা উপরের ডিজাইন করা ডিপ নিউরাল নেটওয়ার্কের একটা প্রোগ্রাম্যাটিক ভার্সন দেখবোঃ

from numpy import exp, array, random, dot

class NeuronLayer():
    def __init__(self, number_of_neurons, number_of_inputs_per_neuron):
        self.synaptic_weights = 2 * random.random((number_of_inputs_per_neuron, number_of_neurons)) - 1

class NeuralNetwork():
    def __init__(self, layer1, layer2):
        self.layer1 = layer1
        self.layer2 = layer2

    # The Sigmoid function, which describes an S shaped curve.
    # We pass the weighted sum of the inputs through this function to
    # normalise them between 0 and 1.
    def __sigmoid(self, x):
        return 1 / (1 + exp(-x))

    # The derivative of the Sigmoid function.
    # This is the gradient of the Sigmoid curve.
    # It indicates how confident we are about the existing weight.
    def __sigmoid_derivative(self, x):
        return x * (1 - x)

    # We train the neural network through a process of trial and error.
    # Adjusting the synaptic weights each time.
    def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
        for iteration in range(number_of_training_iterations):
            # Pass the training set through our neural network
            output_from_layer_1, output_from_layer_2 = self.think(training_set_inputs)

            # Calculate the error for layer 2 (The difference between the desired output
            # and the predicted output).
            layer2_error = training_set_outputs - output_from_layer_2
            layer2_delta = layer2_error * self.__sigmoid_derivative(output_from_layer_2)

            # Calculate the error for layer 1 (By looking at the weights in layer 1,
            # we can determine by how much layer 1 contributed to the error in layer 2).
            layer1_error = layer2_delta.dot(self.layer2.synaptic_weights.T)
            layer1_delta = layer1_error * self.__sigmoid_derivative(output_from_layer_1)

            # Calculate how much to adjust the weights by
            layer1_adjustment = training_set_inputs.T.dot(layer1_delta)
            layer2_adjustment = output_from_layer_1.T.dot(layer2_delta)

            # Adjust the weights.
            self.layer1.synaptic_weights += layer1_adjustment
            self.layer2.synaptic_weights += layer2_adjustment

    # The neural network thinks.
    def think(self, inputs):
        output_from_layer1 = self.__sigmoid(dot(inputs, self.layer1.synaptic_weights))
        output_from_layer2 = self.__sigmoid(dot(output_from_layer1, self.layer2.synaptic_weights))
        return output_from_layer1, output_from_layer2

    # The neural network prints its weights
    def print_weights(self):
        print ("    Layer 1 (4 neurons, each with 3 inputs): ")
        print (self.layer1.synaptic_weights)
        print ("    Layer 2 (1 neuron, with 4 inputs):")
        print (self.layer2.synaptic_weights)

if __name__ == "__main__":

    #Seed the random number generator
    random.seed(1)

    # Create layer 1 (4 neurons, each with 3 inputs)
    layer1 = NeuronLayer(4, 3)

    # Create layer 2 (a single neuron with 4 inputs)
    layer2 = NeuronLayer(1, 4)

    # Combine the layers to create a neural network
    neural_network = NeuralNetwork(layer1, layer2)

    print ("Stage 1) Random starting synaptic weights: ")
    neural_network.print_weights()

    # The training set. We have 7 examples, each consisting of 3 input values
    # and 1 output value.
    training_set_inputs = array([[0, 0, 1], [0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1], [0, 0, 0]])
    training_set_outputs = array([[0, 1, 1, 1, 1, 0, 0]]).T

    # Train the neural network using the training set.
    # Do it 60,000 times and make small adjustments each time.
    neural_network.train(training_set_inputs, training_set_outputs, 60000)

    print ("Stage 2) New synaptic weights after training: ")
    neural_network.print_weights()

    # Test the neural network with a new situation.
    print ("Stage 3) Considering a new situation [1, 1, 0] -> ?: ")
    hidden_state, output = neural_network.think(array([1, 1, 0]))
    print (output)

আমাদের সিঙ্গেল নিউরন ওয়ালা নেটওয়ার্কের কোডের সাথে অনেক কিছুই মিল আছে এখানে। কারণ, বেশ কিছু ফাংশনালিটি সব রকম নিউরাল নেটওয়ার্কেই লাগে। উপরের প্রোগ্রামে বাড়তি কিছু কোড আছে যেমনপ্রত্যেকবার একটি করে নতুন লেয়ার নেয়ার জন্য একটি ছোট্ট ক্লাস আছে NeuronLayer নামে (লাইন 4)। এই ক্লাসের অবজেক্ট তৈরির সময় “নিউরন সংখ্যা” এবং “প্রত্যেকটা নিউরনে আগত ইনপুটের সংখ্যা” ডিফাইন করে দিলেই ওরকম একটা লেয়ার তৈরি হয়ে যাবে। আমাদের ডায়াগ্রাম অনুযায়ী যেমন Layer 1 তৈরি করা হচ্ছে এভাবে।

এরপর আছে NeuralNetwork ক্লাস ( লাইন ৯ )  যেটা অনেকটাই আগের প্রোগ্রামের মতই। তবে গুরুত্বপূর্ণ কিছু পরিবর্তন আছে এই কোডে। যেমনএখানে নিউরাল নেটওয়ার্ক যখন Layer 2 –এ এসে এরর হিসাব করে তখন সেটা সে Back Propogate করে একদম শুরুতে না নিয়ে বরং Layer 1 এ নিয়ে যায় এবং ওয়েট অ্যাডজাস্ট করে। Layer 2 এর এরর নির্ভর করে লেয়ার ২ এর আউটপুট এবং আসল ট্রেনিং সেট এর আউটপুটের বিয়োগের ফলের উপর ( আগের মতই ) । সাথে অ্যাডজাস্টমেন্ট নির্ধারণের জন্য Sigmoid Derivative (লেয়ার ২ আউটপুট এর উপর ভিত্তি করে) এবং ইনপুট হিসেবে লেয়ার ১ এর আউটপুট তো আছেই (৩৬ এবং ৪৫ নং লাইন খেয়াল করুন)

আর Layer 1 এর এরর কিসের উপর নির্ভর করছে সেটা একটু বুঝে শুনে খেয়াল করা উচিৎ। এখানে পার্থক্যটা (Error) এমন না যে আসল আউটপুট এবং এক্সপেক্টেড আউটপুট বিয়োগ করেই এররের ধারনা পাওয়া যাবে কারণ Layer 1 এর তো কোন ব্যবহার উপযোগী আউটপুট নাই। বরং এই লেয়ার পরবর্তী লেয়ারের এররের উপর ভূমিকা রাখে। তাই এই লেয়ারের এরর ফ্যাক্টরটা বস্তুত Layer 2 এর ওয়েট এবং এরর ডেরিভেটিভ এর সমন্বয়ের অবস্থাটা। এরপর এই লেয়ারের অ্যাডজাস্টমেন্ট এর জন্য ইনপুট ফ্যাক্টর হিসেবে লাগছে মুল ইনপুট ভ্যালু গুলো, আর আউটপুট হিসেবে এই লেয়ারের আউটপুটের Sigmoid Derivative ( ৪১ এবং ৪৪ নং লাইন ). 

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

উপরের প্রোগ্রামটি রান করালে নিচের মত আউটপুট আসতে পারেঃ

Screen Shot 2017-05-19 at 7.41.03 PM

পুরো ঘটনাকে ৩টী স্টেজে ভাগ করে নিলে আমরা দেখতে পাই যেপ্রথম ধাপে শুধুমাত্র দুই লেয়ারের প্রত্যেকটি Edge এর ওয়েটকে র‍্যান্ডোমলি নির্ধারণ করা হচ্ছে। পরবর্তী ধাপে পুরো ট্রেনিং প্রসেস শেষে দুটো লেয়ারের প্রত্যেকটি এইজের আপডেটেড এবং অপ্টিমাইজড ওয়েট গুলো দেখতে পাচ্ছি। এবং তৃতীয় ধাপে নিউরাল নেটওয়ার্কে নতুন একটি অচেনা ইনপুট কম্বিনেশন দিয়ে আমরা অউটপুট পাচ্ছি 0.0078 অর্থাৎ সফলভাবে 0  প্রেডিক্ট করতে পারছে আমাদের ডিপ নিউরাল নেটওয়ার্ক 🙂 😀

খাতা কলমে পরীক্ষা করে দেখা –

Screen Shot 2017-05-19 at 8.27.39 PM

কনভলিউশনাল নিউরাল নেটওয়ার্ক
এতক্ষণ পর্যন্ত খেয়াল করেছেন যে, বার বার আমরা ম্যাট্রিক্স নিয়ে কাজ করছি। আর কাজের কাজ বলতে আমরা যা করেছি তা হচ্ছে ডাটার মধ্যে থেকে প্যাটার্ন খুঁজে বের করা এবং সেই খুঁজে পাওয়া প্যাটার্নকে কাজে লাগিয়ে পরবর্তীতে ওই রকম ডাটা সম্পর্কিত বিষয়ে প্রেডিকশন দেয়া। মজার ব্যাপার হচ্ছে, আমরা সবাই জানিডিজিটাল ইমেজ বা ফটো কিন্তু আর কিছুই না একটা 2D অ্যারে বা ম্যাট্রিক্স (গ্রে স্কেল বা সাদাকালো ফটোর ক্ষেত্রে)। সেই ম্যাট্রিক্সের প্রত্যেকটি সেল হচ্ছে এক একটি পিক্সেল। আর সেলের ভ্যালু হচ্ছে পিক্সেল ভ্যালু বা কালার এর মান। আবার ম্যাট্রিক্সটার (row সংখ্যা x column সংখ্যা) মানেই হচ্ছে ওই ফটোর রেজোল্যুশন। তাহলে বিষয়টা কি দাঁড়ালো?

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

সহজ উদাহরণ
চলুন আমরা একটা জগতের কথা চিন্তা করি যে জগতে একটা কম্পিউটার আছে যার ডিসপ্লে মাত্র 2×2 পিক্সেল সাইজের। আর ওই জগতে সব মিলে ২টা ক্যারেক্টার বা বর্ণ আছে যেগুলো হচ্ছে, \ এবং / অর্থাৎ ওখানকার কিবোর্ড দিয়ে একটা ফরওয়ার্ড স্ল্যাস অথবা একটা ব্যাক স্ল্যাস লেখা যায় 😛 অনেকটা নিচের মত

এখন আমরা এই কম্পিউটারের জন্য একটা ইমেজ ক্লাসিফায়ার সফটওয়্যার বানাতে চাই যাতে করে যখন আমরা কম্পিউটারকে নিচের ইমেজটি ইনপুট দেবো তখন সে যাতে সেটা চিনে বলতে পারে যে এটা একটা \. (ব্যাক স্ল্যাস)

এবং একই ভাবে ফরওয়ার্ড স্ল্যাসটাকেও চিনতে পারে।

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

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

পাইছি এবার। খেয়াল করুন এই দুটা আলাদা ইমেজের জন্য যে ফাইনাল ডাটা স্ট্রাকচার দাঁড়ালো সেগুলোকে কিন্তু আমরা আমাদের সেই প্রথম দিকের ইনপুট কম্বিনেশন সমস্যার সাথেই তুলনা করতে পারি। অর্থাৎ 1 -1 -1 1 কম্বিনেশনের আউটপুট ধরি 1 (ধরি 1 মানে ব্যাক স্ল্যাস) আর -1 1 1 -1 কম্বিনেশনের আউটপুট ধরি 0 (ধরি 0 মানে ফরওয়ার্ড স্ল্যাস)

তাহলে যদি আমরা এই ইনপুট কম্বিনেশন গুলোতে সঠিক ভাবে কিছু ওয়েট সেট করতে পারি এবং দুইটা আলাদা ইনপুট কম্বিনেশনের জন্য দুটো আলাদা রেজাল্ট আসে (একটা শূন্যের কাছা কাছি আরেকটা এক এর কাছাকাছি। তাহলেই কিন্তু আমাদের ইমেজ ক্লাসিফায়ার তৈরি হয়ে গেলো। ওই ক্লাসিফায়ারে যতবারই [1 -1 -1 1] তথা ব্যাক স্ল্যাসের ইমেজের একটি ডাটা ম্যাট্রিক্স দেয়া হবে ততবার সে ওই ইনপুট গুলোর সাথে ওয়েট এর গুন যোগ করে আউটপুট দিবে ১ এর কাছাকাছি একটা মান আর আমরা জানি ১ মানে ব্যাক স্ল্যাস। তাই চিনে যাবো এই ইমেজ একটা ব্যাক স্ল্যাস। তো, চলুন এই সিম্পল ক্লাসিফায়ারের জন্য কিছু অপ্টিমাইজড ওয়েট বের করি।

প্রথমেই সব ওয়েট মনে করি 1. তাহলে [1 -1 -1 1] এর জন্য

(1*1) + (-1*1) + (-1*1) + (1*1) = 1 – 1 – 1 + 1 = 0

আর [-1 1 1 -1] এর জন্য

(-1*1)+(1*1)+(1*1)*(-1*1) = -1 + 1 + 1 – 1 = 0

লাভ হল না, দুইটার ক্ষেত্রেই শূন্য আসছে অর্থার ক্লাসিফাই করার মত সলিড Rule এটা হয় নি বা বলা যায় ওয়েট গুলো সঠিক হয় নি। ওয়েট গুলো একটু অ্যাডজাস্ট করে নিচের মত ট্রাই করি। অর্থাৎ প্রথম এইজের ওয়েট ধরি 1, দ্বিতীয় এইজের ওয়েট ধরি -1, তৃতীয় এইজের ওয়েট ধরি -1 এবং চতুর্থ এইজের ওয়েট ধরি 1. (যেহেতু চারটা Edge ধরে ৪টা ইনপুট আসছে একটা নিউরনের দিকে)

তাহলে [1 -1 -1 1] এর জন্য

(1*1) + (-1*-1) + (-1*-1) + (1*1) = 1 + 1 + 1 + 1 = 4 Sigmoid করে 0.98

আর [-1 1 1 -1] এর জন্য

(-1*1)+(1*-1)+(1*-1)*(-1*1) = -1 – 1 – 1 – 1 = -4 Sigmoid করে 0.01

অর্থাৎ আমরা মোটামুটি সঠিক ওয়েট এর খোঁজ পেয়েছি যেগুলো একটি ব্যাসিক নিউরাল নেটওয়ার্কে ব্যবহার করলে দুটা আলাদা ইনপুট কম্বিনেশনের জন্য দুটো আলাদা আউটপুট আসে এবং তার সাহায্যে আমরা দুটো ইমেজকে ক্লাসিফাই বা আলাদা করে চিনতে পারি 😀 একটু পরীক্ষা করেও দেখতে পারেন যে আসলেই সঠিক ওয়েটের খোঁজ পাওয়া গেছে কিনা। যেমননিচের দুটো ইমেজের কথা চিন্তা করুন,

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

তাহলে প্রথম ইমেজ অর্থাৎ [1 1 -1 1] এর জন্য

(1*1) + (1*-1) + (-1*-1) + (1*1) = 1 – 1 + 1 + 1 = 2 Sigmoid করে 0.88 (1 এর কাছাকাছি অর্থাৎ ব্যাক স্ল্যাস)

আর [-1 -1 1 -1] এর জন্য

(-1*1)+(-1*-1)+(1*-1)*(-1*1) = -1 + 1 – 1 – 1 = -2 Sigmoid করে 0.11 (0 এর কাছাকাছি অর্থাৎ ফরওয়ার্ড ল্যাস)

গ্রেট, এরকম ভাঙ্গা হাতের লেখাকেও আমাদের ক্লাসিফায়ার ঠিকি ধরতে পারছে 🙂 কিন্তু ভুলে গেলে চলবে না, এই যে, হুট করে সব ওয়েট [1 1 1 1] এর কথা চিন্তা করে তারপর অপ্টিমাইজড ওয়েট [1 -1 -1 1] –এ আসতে পারা, এখানে কিন্তু সেই এরর, অ্যাডজাস্ট, লার্নিং লুপেরই কাজ করতে হবে। এসব আগেই আলোচনা হয়ে গেছে 🙂 আমরা বোঝার জন্য এক লাফেই অপ্টাইজ ওয়েট নিয়ে পরীক্ষা করেছি। 

এবার চলুন একটু জটিল আরেকটা জগতের কথা চিন্তা করি যে জগতে একটা কম্পিউটার আছে যার ডিসপ্লে 3×3 পিক্সেল সাইজের। আর ওই জগতে সব মিলে ৪টা ক্যারেক্টার বা বর্ণ আছে যেগুলো হচ্ছে – \ / X O অর্থাৎ ওখানকার কিবোর্ড দিয়ে একটা ফরওয়ার্ড স্ল্যাস, একটা ব্যাক স্ল্যাস, একটা এক্স, আরেকটা ও লেখা যায় 😛 অনেকটা নিচের মত

এখন মনে করুন যে ওই ৪টি বর্ণের কোন একটিকে কম্পিউটারে টাইপ করলে এর মনিটরে নিচের মত করে সেই ক্যারেক্টারটি রেন্ডার হয়

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

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

আচ্ছা, এবার আমরা একটু 2×2 পিক্সেলের জগত থেকে হেল্প নেবো। সেখানে আমাদের ব্যাক এবং ফরওয়ার্ড স্ল্যাস আছে। খেয়াল করুন, সেগুলাই কিন্তু X এর হাত গুলোর মতই। অর্থাৎ একভাবে খেয়াল করলে বলা যায় যেতিন পিক্সেল ওয়ালা জগতের X, O, \, /  গুলো বস্তুত দুই পিক্সেল ওয়ালা জগতের \ এবং / এর সমন্বয়েই তৈরি। নিচের ফিগারটা একটু খেয়াল করি,

উপরের ডায়ারগ্রামটাই কিন্তু একটা কনভলিউশনাল নিউরাল নেটওয়ার্কের ব্লক ডায়াগ্রাম। (ভয়ের কিছু নাই বিস্তারিত এড়িয়ে যাওয়া হবে না)। দুটি স্টেজে একটা কনভলিউশনাল নিউরাল নেটওয়ার্কের কাজকে বর্ণনা করা যায়। প্রথম স্টেজে অর্থাৎ বামের দিকে একটি বড় ইমেজ থেকে Convolution এবং Pooling টেকনিকের মাধ্যমে ছোট কিন্তু অর্থবহ ইমেজ বের করে আনা হয়। Convolution এর জন্য ছোট ইমেজ ব্যবহার করা হয় যেটাকে ফিল্টার বলা হয়। যেমন X ওয়ালা বড় একটা ইমেজের উপর আমরা \ এর ইমেজ এবং / এর ইমেজ নিয়ে Convolution করতে পারি কারণ পুরো X এর মধ্যে বস্তুত এগুলোরই অবস্থান। আর তাই X এর হাত গুলোকে চিনে নেয়ার জন্য আমরা শুধু (কাটা) হাতের ফটোকে ফিল্টার হিসেবে ব্যবহার করতে পারি। 

এরপর সেই ছোট আকারের ইমেজ গুলোকে নিয়ে পরের স্টেজে নিউরাল নেটওয়ার্ক এর কাজ করা হয়। এই স্টেজে নিউরাল নেটওয়ার্কের লজিক, ওয়েট ইত্যাদি ফিক্স করে, এর আগের স্টেজের ইমেজ অর্থাৎ Pooled ইমেজের উপর কাজ করা হয় এবং পিক্সেল কম্বিনেশন যাচাই করে পার্থক্য বা চেনার কাজ করা হয়। এই দ্বিতীয় স্টেজটাকে বলে Fully Connected Layer আর প্রথম স্টেজকে বলে Convolution Layer (এই স্টেজে পুলিং বা অন্যান্য আরও কিছু ফাংশনের ব্যবহার থাকতে পারে)

একটু বিস্তারিতভাবে এবার এই কাজ গুলো করে দেখি। নিচের ফিগারটি খেয়াল করুন,

এখানে বাম পাশে একটা X ওয়ালা ইমেজ আছে। তার ডানে আমরা দুটো ফিল্টার নিয়েছি। একটা ফিল্টার আসলে ব্যাক স্ল্যাস চেনার ফিল্টার। এই ফিল্টার দিয়ে বড় ইমেজের উপর ঘুরে বেড়ালে (Convolution করলে) যেখানেই হাই ভ্যালু পাবে সেখানেই একটা ব্যাক স্ল্যাস পাওয়া গেছে বলে ধরে নেয়া যাবে। আগের মত চিন্তা করলে এটা ব্যাক স্ল্যাস চেনার সেই ওয়েট ম্যাট্রিক্স। শুধু +1 আর -1 কে + এবংএ চিহ্নিত করা হয়েছে (অর্থাৎ [1 -1 -1 1] => [+ – – +].   আরেকটা ফিল্টার হচ্ছে ফরওয়ার্ড স্ল্যাস চেনার ফিল্টার। এই ফিল্টারকে বড় ইমেজের উপড়ে ঘুরিয়ে নিয়ে বেড়ালে যখনই হাই ভ্যালু পাবে তখন সেখানে একটা ফরওয়ার্ড স্ল্যাস আছে বলে জানা যাবে।

Convolution শুরু করা যাক

প্রথমেই আমরা উপড়ের ফিল্টার কে সাথে নিয়ে বড় ইমেজের টপ লেফট সাইডে বসিয়েছি এবং ওখানকার পিক্সেল ভ্যালুর সাথে ফিল্টার এর সমন্বয় ঘটিয়ে (গুন যোগ) ভ্যালু পেয়েছি 4. পরের ধাপে বলা হচ্ছে যদি তুমি একটা হাই ভ্যালু পাও তার মানে হচ্ছে তুমি যে অংশ (অঙ্গ) খুজতেছিলা সেটা পাওয়া গেছে। অর্থাৎ  Convolution এর এই ধাপে একটা \ পাওয়া গেছে। কারণ \ এর ফিল্টার দিয়ে চেক করা হচ্ছিল এবং ভ্যালু হাই এসেছে। এরপর ফিল্টারকে টপ রাইটে স্লাইড করে নিয়ে যেতে হবে নিচের মত,

এই অবস্থায় ভ্যালু এসেছে -4 যা আমাদের ফিল্টার দিয়ে অংশ চেনার লজিক অনুযায়ী মিথ্যা। তাই পরের ধাপ বলছে আমি কোন ব্যাক স্লাসের অস্তিত্ব পাই নাই তাই Pooled ইমেজে গ্রে বসায় রাখলাম। আবার ফিল্টারকে স্লাইড করে বোটম লেফট কর্নারে সেট করলাম এবং নিচের অবস্থা পেলাম,

আবারও ফিল্টারকে বোটম রাইট কর্নারে নিয়ে সেট করলাম এবং নিচের মত অবস্থা পর্যবেক্ষণ করলাম যে অনুযায়ী বলা যায়এইবার আবারও একটা \ এর অস্তিত্ব পাওয়া গেছে।

এবার একই ভাবে আমরা ফরওয়ার্ড স্ল্যাস খোজার ফিল্টার দিয়ে বড় ইমেজের উপর Convolution করে নিচের মত আপডেট পাবো। অর্থাৎ যেখানে যেখানে ফিল্টার এর সমন্বয় হাই ভ্যালু পেয়েছে সেখানে একটি করে / এর অস্তিত্ব পাওয়া গেছে,

মনে রাখবেন, প্রত্যেকটি ফিল্টারই কিন্তু উপরে বাম থেকে শুরু করে, উপড়ে ডানে এবং তারপর নিচে বাম থেকে, নিচে ডানে গিয়ে কাজ/চেক/কনভলিউশন শেষ করে।

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

এরপর ডান পাশের অর্থাৎ পুলিং লেয়ার থেকে পাওয়া দুটো আলাদা ইমেজকে আমরা একসাথে করতে পারি নিচের মত,

অর্থাৎ এখন থেকে কম্পিউটার ভেবে নিবে যে বাম পাশের 3×3 পিক্সেলের যে ফটো সেটারই একটা সিমপ্লিফায়েড ভার্সন হচ্ছে ডান পাশের 2×2 পিক্সেলের ইমেজ যেটা কিনা কিছু \ / (সেই অংশ বা অঙ্গ যাই বলেন) এরসমন্বয়।

একই ভাবে আমরা O ওয়ালা বড় ইমেজকে ওই দুটো ফিল্টার দিয়েই Convolute  করেও নিচের মত পুলিং লেয়ারের সাহায্যে সিমপ্লিফায়েড ভার্সনে কনভার্ট করতে পারি।

এভাবে আমাদের ৪ বর্ণ ওয়ালা জগতের বাকি দুটো বর্ণ \ এবং / এর জন্যও কাজ করে নিতে পারেন। সেক্ষেত্রেও তিন পিক্সেল ওয়ালা স্ল্যাসের সাপেক্ষে থ্রেসহোল্ড মেনে পুলিং লেয়ারের কাজ শেষে দুই পিক্সেল ওয়ালা স্ল্যাস পাবেন।

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

ফুলি কানেক্টেড লেয়ার
এবার আসুন এই লেয়ারের কাজ নিয়ে ভাবিএই লেয়ার ইনপুট হিসেবে নেয় কনভলিউশন এবং পুলিং লেয়ার কাছ থেকে পাওয়া প্রসেসড ইমেজ এবং তার উপর চিন্তা (সেই চিন্তা) এবং ট্রেনিং   করে প্যাটার্ন বুঝে নেয় এবং ঠিক করে কোনটা কোন ইমেজ।

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

অর্থাৎ X এর পুলিং লেয়ারের পর ফ্ল্যাট রিপ্রেজেন্টেশনে প্রথমটা ব্যাক স্ল্যাস তাই আমরা স্টোর ম্যাট্রিক্সের প্রথম ভ্যালু সেট করলাম 1. আবার ফ্ল্যাট রিপ্রেজেন্টেশনের দ্বিতীয় এলিমেন্টটা ব্যাক স্ল্যাস না তাই স্টোরে ম্যাট্রিক্সের প্রথম সারির দ্বিতীয় কলামে  -1 এভাবে,

ফাইনালি আমরা সব গুলো ফিল্টার পাবো নিচের মত,

এখন আমরা ফিল্টারের 1, -1 কে যদি + এবং মাইনাসে প্রকাশ করি তাহলে ব্যবহার উপযোগী ফিল্টার ধরতে পারি নিচের মত,

এরপর আমরা যেটা করতে পারি তা হল, আমরা একটা নির্দিষ্ট বর্ণের জন্য প্রাপ্ত 2D ম্যাট্রিক্স এর সাথে সবগুলো ফিল্টার (+ – ওয়ালা ম্যাট্রিক্স) এর তুলনা করবো। যেমননিচে X এর জন্য প্রাপ্ত ম্যাট্রিক্স এর সাথে সবগুলা ফিল্টার এর সমন্বয় (গুন যোগ) করা হয়েছে

এবং X এর ফিল্টার এর সাথেই সব চেয়ে বেশি স্কোর এসেছে (আসাটাই স্বাভাবিক কারন 2D ম্যাট্রিক্স আর ফিল্টার ম্যাট্রিক্স একই দিকের মান নির্দেশ করে)। তাই বলা যায় এই ইমেজটি X এর ইমেজ 🙂 😀 আবার O এর জন্য এই ফুলি কানেক্টেড লেয়ারটির ক্যালকুলেশন ট্রাই করে দেখি,

এক্ষেত্রেও O এর ফিল্টারের সাথেই বেশি স্কোর আসছে তাই সঠিক উত্তর, O.

কমপ্লিট কনভলিউশনাল নিউরাল নেটওয়ার্ক
নিচের ফিগারটার দিকে একবার চোখ বুলাই

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

পরীক্ষা করে দেখা যাক
আবার X এর ফটো ইনপুট হিসেবে দিয়েই পরীক্ষা করি পুরো কনভলিউশনাল নিউরাল নেটওয়ার্ক আসলেই X  কে চিনতে পারে কিনা।

খেয়াল করুন, প্রথমে X এর ইমেজের উপর আমাদের \ / ফিল্টার চালিয়ে দেখা হয়েছে এবং পুলিং লেয়ারের কাছে শুধু ৪টি অবস্থা ভ্যালিড বা ফায়ার হয়েছে। ব্যাক স্ল্যাস ফিল্টার দিয়ে ঘোরার সময় যে দুটা অবস্থায় ব্যাক স্ল্যাস পাওয়া গেছে এবং ফরওয়ার্ড স্ল্যাস ফিল্টার দিয়ে ট্রাভেল করার সময় যে দুটা জায়গায় ফরওয়ার্ড স্ল্যাসের অস্তিত্ব পাওয়া গেছে (তাই পুলিং লেয়ারের ইনপুটে ৪টি কেইস)। এরপর পুলিং লেয়ার 2×2 পিক্সেলেটেড ইমেজ কে বিশেষ ম্যাট্রিক্সে কনভার্ট করছে এবং পরীক্ষার কোন এক সিচুয়েশনে এই ম্যাট্রিক্সটি ডান পাশের ফুলি কানেক্টেড লেয়ারের প্রত্যেকটি ফিল্টারের সাথে মাল্টিপ্লাইড হচ্ছে। ফাইনালি সে ডান পাশে অর্থাৎ আউপুটপুট লেয়ারে রেজাল্ট হিসেবে জানাচ্ছে তার পাওয়া স্কোর গুলো। আর স্কোর দেখে খুব সহজেই বুঝে নেয়া যাচ্ছে X এর উপরেই এই CNN এর কনফিডেন্স বেশি 🙂

বার বার মনে করিয়ে দিচ্ছি, এখানে বেশ কিছু হেল্পার ফাংশনের কাজ এড়িয়ে যাওয়া হয়েছে শুধু নিউরাল নেটওয়ার্কের ওয়ার্কিং প্রিন্সিপল সহজে বোঝানোর জন্য। যেমনকম্পিউটারকে পারফেক্ট ফিল্টার বুঝতে, কনভলিউশন করাতে, ফুলি কানেক্টেড লেয়ারের ওয়েট/এইজ উদ্ধার করতে লক্ষ্য লক্ষ্য বার ঘুরে ফিরে কাজ করতে হয়। কারণ, শুরুতেই কম্পিউটার সব কিছুর জন্য (ফিল্টার, কনভলিউশন ইত্যাদি) র‍্যান্ডম কিছু ভ্যালু ধরে নেয়। তারপর ট্রেনিং ডাটা সেট এ যেহেতু প্রশ্ন উত্তর দুটাই আছে, তাই সেখান থেকে এরর কন্সিডার করে করে এবং সেই অনুযায়ী সব ভ্যালু অ্যাডজাস্ট করে করে ফাইনালি এরকম স্ট্যাবল একটা স্টেজে আসে। এরর এর উপর ভিত্তি করে ভ্যালু অ্যাডজাস্ট করা নির্ভর করে Gradient Descent এরউপর। এ সম্পর্কে বাংলায় পড়তে চাইলে এখানে ক্লিক করুন

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

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

বিভিন্ন ডিপ লার্নিং লাইব্রেরীর ব্যবহার
আর্টিফিশিয়াল নিউরাল নেটওয়ার্কের গভীরের কর্মকাণ্ড গুলোর উপর যথেষ্ট পরিমাণ স্বচ্ছ ধারনা থাকার পরেই কেবল এরকম কিছু লাইব্রেরীর ব্যবহার করা উচিৎ হবে। TensorFlow বা সিমিলার লাইব্রেরী গুলো আসলে কি করে? আপনি ম্যানুয়ালি হয়ত Matrix Multiplication, Activation Function, Cost Function বা Gradient Descent করার জন্য এবং নিউরাল নেটওয়ার্কের লেয়ার বা নিউরন গুলো ডিফাইন করার জন্য এক গাদা কোড লিখবেন। যেভাবে এখন পর্যন্ত আমরা করেছি। আবার হয়ত, ইমেজ বা সাইন্ড নিয়ে কাজ করার সময় প্রাথমিক স্টেজে ইমেজ/সাউন্ড ডাটা ম্যানিপুলেট করার জন্যও কিছু কোড লিখবেন, যেমনইমেজকে গ্রেস্কেলে কনভার্ট করা, চ্যানেল আলাদা করা, ডাইমেনশন ঠিক ঠাক করা ইত্যাদি। মেশিন লার্নিং এবং ডিপ লার্নিং লাইব্রেরী গুলো বস্তুত এই ম্যানুয়াল কাজ গুলোর জন্যই কিছু রেডিমেড ফাংশন বা মেথড বানিয়ে রেখেছে। অর্থাৎ যে কাজ গুলো সবসময়ই করতে হয় যেকোনো মডেল নিয়ে কাজ করার সময়, সেগুলোর জন্য বিভিন্ন হেল্পার ফাংশন এবং আরও কিছু উপকারী ও গুরুত্বপূর্ণ ফিচার নিয়েই এরকম লাইব্রেরী গুলো তৈরি।

এগুলোকে হাই লেভেল বলতে হবে কারন আপনি অনেক ফাংশনের শুধু নাম ব্যবহার করেই সেটার ইমপ্লিমেন্টেশন করে ফেলতে পারেন। সেগুলোর গভীরে আসলেই কি ম্যাথ বা লজিক কাজ করছে তা জানা লাগবে না। এমনকি TensorFlow, Theano টাইপের হাই লেভেল লাইব্রেরীর উপর ভিত্তি করেও আরও হাই লেভেল লাইব্রেরী তৈরি হচ্ছে, যেমন – Keras. যত হাই লেভেল, তত বেশি অ্যাবসট্র্যাক্ট লেয়ার অর্থাৎ আপনার কাছ থেকে তত বেশি কর্মকাণ্ড হাইড করে রাখা। তাই, সবসময় হাই লেভেল লাইব্রেরী ব্যবহারে অভ্যস্ত হওয়া উচিৎ নয়। এটা সব রকম কন্টেক্সট এর জন্যই মেনে চলা উচিৎ। সেটা মেশিন লার্নিং হোক বা সাধারণ প্রোগ্রামিং বা ডেভেলপমেন্ট হোক।

যাই হোক TensorFlow কিন্তু Google এর ডেভেলপ করা লাইব্রেরী আর তাই আমি অন্তত এটাকে সুদূরপ্রসারী মনে করি। C/C++ আছে এই লাইব্রেরীর ব্যাকএন্ডে আর ফ্রন্টএন্ড ইন্টারফেইস আছে পাইথন এবং অন্য ল্যাঙ্গুয়েজের জন্য। জটিল নিউমেরিক্যাল ক্যালকুলেশন সম্পন্ন টাস্কগুলোকে সহজ এবং টাইম ইফিসিয়েন্ট করার জন্যই এই লাইব্রেরীর আবির্ভাব। ন্যাটিভ পাইথনে যার একটু ল্যাগ ছিল। আর এই লাইব্রেরী কাজ করে Data Flow Graph স্টাইলে অর্থাৎ ম্যাথেম্যাটিক্যাল অপারেশন নিয়ে নোড (Node) এবং মাল্টিডাইমেনশনাল অ্যারে নিয়ে এইজ (Edge) -এর সমন্বয়ে একটি ডাটা ফ্লো গ্রাফ তৈরি হয়।

আপনি কি আগে জানতেন – বিশেষ ধরনের মাল্টিডাইমেনশনাল অ্যারে টাইপের ডাটা স্ট্রাকচারকেই Tensor বলে? 🙂

নিচের ফিগার দুটো দেখলে আর সাধারণ জ্যামিতির ধারনা থাকলেই বুঝতে পারবেন Tensor মানে কোন ধরনের স্পেশাল ডাটা অবজেক্ট।

0 ডাইমেনশন মানে কোন ভ্যলুর একটাই অবস্থা/অস্তিত্ব যেমন একটা বিন্দু। 1 ডাইমেনশন মানে শুধু একদিকে গমন করে এরকম কিছু ডাটা পয়েন্ট। যেমন আমাদের অতি পরিচিত সাধারণ একটি 1D অ্যারে – [5, 10, 15, 20] এরকম. 2D ডাইমেনশনের উদাহরণ হতে পারে একটি ম্যাট্রিক্স, যেমন – একটা গ্রে-স্কেল ইমেজের পিক্সেল রিপ্রেজেন্টেশন। সেটা আমরা যেকোনো প্রোগ্রামিং ল্যাঙ্গুয়েজেই মাঝে মধ্যে ইমপ্লিমেন্ট করে থাকি এভাবে – [[210 100 255], [200 150 160], [210 0 100]]. 3D এর উদাহরণ হতে পারে একটি কালার ফটোর ম্যাট্রিক্স রিপ্রেজেন্টশন যেখানে Red, Green, Blue প্রত্যেকটি কালারের জন্য তিনটি আলাদা আলাদা 2D ম্যাট্রিক্স থাকে এবং সেগুলো একটার উপর আরেকটা বসিয়ে একটি অবস্থানের তিনটি আলাদা ম্যাট্রিক্সের সেল ভ্যালু হিসাব করে কালার তৈরি করে (নিচের মত),

4D এর উদাহরণ হতে পারে যখন একটি 3D ডাটা অবজেক্ট সময়ের সাথে পরিবর্তন হয়। সেই ডাইমেনশনটাকে TimeSpace ডাইমেনশনও বলা হয়ে থাকে।

আমরা TensorFlow দিয়ে উপরে আলোচিত কয়েকটি ডাইমেনশনের ডাটা অবজেক্টকে তৈরি করতে পারি (কোড এখন না বুঝলেও একটু পরেই বুঝতে পারবেন),

  
import tensorflow as tf

scalar = tf.constant([2])
vector = tf.constant([3, 4, 5])
matrix = tf.constant([[6, 7, 8], [9, 10, 11], [12, 13, 14]])
tensor = tf.constant([ [[6, 7, 8], [9, 10, 11], [12, 13, 14]], [[15, 16, 17], [18, 19, 20], [21, 22, 23]] , [[15, 16, 17], [18, 19, 20], [21, 22, 23]] ])

with tf.Session() as session:
    result = session.run(scalar)
    print("Scalar Data Example:\n", result)
    
    result = session.run(vector)
    print("\nVector Data:\n", result)    
    
    result = session.run(matrix)
    print("\nMatrix:\n", result)        
    
    result = session.run(tensor)
    print("\nTensor:\n", result)            

আউটপুট,

  
Scalar Data Example:
 [2]

Vector Data:
 [3 4 5]

Matrix:
 [[ 6  7  8]
 [ 9 10 11]
 [12 13 14]]

Tensor:
 [[[ 6  7  8]
  [ 9 10 11]
  [12 13 14]]

 [[15 16 17]
  [18 19 20]
  [21 22 23]]

 [[15 16 17]
  [18 19 20]
  [21 22 23]]]

যা হোক, TensorFlow নিয়ে কাজ করার ধাপ দুইটা – উপরে উল্লেখিত স্টাইলে গ্রাফ তৈরি এবং তারপর সেই গ্রাফকে রান বা এক্সিকিউট করা। আবার বলি, গ্রাফের মধ্যে থাকে কিছু ডিফাইন করা অপারেশন।

হ্যালো ওয়ার্ল্ড
যেহেতু এটা পাইথন লাইব্রেরী ব্যতীত আর কিছুই না। তাই এর ইন্সটলেশন আর দশটা স্বাভাবিক পাইথন লাইব্রেরীর মতই। অর্থাৎ, আপনার পছন্দের মেশিনে বা পাইথন রিয়েল/ভার্চুয়াল এনভায়রনমেন্টে pip ইন্সটলার দিয়ে সহজেই ইন্সটল করে নিতে পারেন নিচের কমান্ড ইস্যু। করে।

pip3 install --upgrade tensorflow #I only know what modern Python is. No idea what 2 vs 3 means. 

এর ইন্সটলেশন নিয়ে অযথাই প্যাঁচানোর মানে হয় না। যেখানে ইচ্ছা এই লাইব্রেরী ইন্সটল দিবেন। Anaconda, Miniconda হাবিযাবি আপাতত ভুলে জান। আপনার কম্পিউটার আছে, সেই কম্পিউটারে পাইথন ইন্সটলড অবস্থায় আছে। সাথে ধরে নিচ্ছি pip ইন্সটল্ড আছে। ব্যস pip দিয়ে TensorFlow ইন্সটল করে নিবেন আর নিচের মত প্রোগ্রাম লিখে রান করতে থাকবেন স্ক্রিপ্ট (বা মডিউল) মুডে।

নিচের প্রোগ্রামে আমরা TensorFlow দিয়ে একটি খুব সহজ কম্পিউটেশন করেছি যাতে আমরা ব্যাসিক অপারেশন এর ধাপটা সম্বন্ধে পরিষ্কার ধারনা পাই।

  
import tensorflow as tf

a = tf.constant([2])
b = tf.constant([3])

c = tf.add(a,b)

session = tf.Session()

result = session.run(c)
print(result)

session.close()

প্রথমেই লাইব্রেরীকে ইম্পরট করা হয়েছে। তারপর দুটো Source Operation (যে অপারেশনের বাইরে থেকে ইনপুট দরকার নাই বা Source Ops) ডিফাইন করা হয়েছে। এই ধরনের সোর্স অপ্স, অন্য অপারেশনের কাছে তাদের তথ্য পাঠায় যেখানে মুল কম্পিউটেশনটা ঘটে। এখানে a, b তে দুটো সোর্স অপ্স tf.constant([2]) এবং tf.constant([3]) এর আউটপুট জমা হচ্ছে। এরপরে লাইনে আমরা আরেকটি কম্পিউটেশনাল অপারেশন tf.add(a,b) ডিফাইন করেছি (এটা কিন্তু ইনপুট পায়)।

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

বার বার সেশন তৈরি করা এবং কাজ শেষে সেশন ক্লোজ করার ঝামেলা থেকে মুক্তি পেতে আমরা পাইথনের with ব্লকের সাহায্য নিতে পারি নিচের মত,

  
import tensorflow as tf

a = tf.constant([2])
b = tf.constant([3])

c = tf.add(a,b)

with tf.Session() as session:
    result = session.run(c)
    print(result)

দুটো প্রোগ্রামের আউটপুট একই আসবে [5]. এ অবস্থায় হয়ত মনে হচ্ছে নর্মাল একটা যোগ করতে এতো কাহিনী? আসলে এটার মাধ্যমে আপনি বুঝতে পারলেন TensorFlow কিভাবে কাজ করে। কিন্তু এই লেভেলের সস্থা কাজ নিশ্চয়ই আপনি TensorFlow দিয়ে করাবেন না, তাই না? অতি জটিল কম্পিউটেশন সহজ করার সাথে সাথে এই লাইব্রেরীর আরও কিছু সুবিধার মধ্যে আছে – আপনি একই গ্রাফ যেকোনো রকম হার্ডওয়্যার প্ল্যাটফর্মে রান করাতে পারবেন। CPU, GPU, Cluster বা Android, iOS. যাই হোক।
বলে নেয়া ভালো Google I/O 17 এ Google কিন্তু নতুন এক ধরনের হার্ডওয়্যার TPU (Tensor Processing Unit) রিলিজ দিয়েছে যা স্পেশালি Tensor ভিত্তিক কম্পিউটেশনের জন্য ইফেক্টিভলি ডিজাইন করা।

আরেকবার আমরা TensoFlow  এর একটা এক লাইনের সংজ্ঞা লিখে ফেলি – “একটি কম্পিউটেশন গ্রাফে বিভিন্ন অপারেশনের মধ্যে টেনসর ফর্মে ডাটা আদান প্রদান করে একবারে পুরো কম্পিউটেশন যেকোনো হার্ডওয়্যারে সম্পন্ন করার জন্য একটি মডেল বা লাইব্রেরী হচ্ছে TensorFlow.” আর এতো লম্বা মনে না থাকলে শুধু এটুকু মনে রাখুন এটা একটা “কম্পিউটেশনাল লাইব্রেরী” 😀

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

নিচের প্রোগ্রামটি খেয়াল করি,

  
import tensorflow as tf

state = tf.Variable(0)

one = tf.constant(1)
new_value = tf.add(state, one)
update = tf.assign(state, new_value)

init_op = tf.global_variables_initializer()

with tf.Session() as session:
    session.run(init_op)
    print(session.run(state))
    for _ in range(3):
        session.run(update)
        print(session.run(state))

উপরের প্রোগ্রামে, প্রথমেই tensorflow ইম্পোরট করে নেয়া হয়েছে। এরপর একটি ভ্যারিয়েবল state, ডিফাইন এবং ইনিসিয়ালাইজ করা হয়েছে 0 ভ্যালু নিয়ে। এরপর একটি source ops ডিফাইন করা হয়েছে। এরপর একটি কম্পিউটেশনাল অপারেশন, add এর ব্যবহার করা হয়েছে যা মূলত state ভ্যারিয়েবলের সাথে 1 যোগ করে। কিন্তু যেহেতু state ভ্যারিয়েবলের মান এখনো পরিবর্তন (update) হয় নি, তাই সেটা করার জন্য একটি assign অপারশন ডিফাইন করতে হচ্ছে। এরপরের লাইনে, উপরোক্ত ভ্যারিয়েবলকে ইনিসিয়ালাইজ করা হয়েছে কম্পিউটেশন গ্রাফে সেগুলো ব্যবহার করার জন্য।
অতঃপর একটি with ব্লকের মধ্যে, সেশন অবজেক্টের মাধ্যমে, প্রথমে ভ্যারিয়েবল ইনিসিয়ালাইজার অপারেশনকে রান করা হয়েছে। এবং state ভ্যারিয়েবলের শুরুর মান প্রিন্ট করা হয়েছে। এটার জন্য স্ক্রিনে প্রথম প্রিন্ট ভ্যালু 0 আসছে। এরপর একটি ফর লুপ চালিয়ে update অপারেশনকে রান করানো হচ্ছে এবং প্রত্যেকবার আপডেট অপারেশনের পর state ভ্যারিয়েবলের মান প্রিন্ট করা হচ্ছে।

আউটপুট,

  
0
1
2
3

এবার আসি প্লেস হোল্ডারের প্রসঙ্গে। যদি আপনি TensorFlow মডেলের বাইরে থেকে এটাকে ডাটা ইনপুট/ফিড করাতে চান তাহলে দরকার পরে এই প্লেসহোল্ডার। প্লেস হোল্ডার একরকম ভ্যারিয়েবল যেটাতে আসলে নির্দিষ্ট একটি সময় পর্যন্ত এর আসল কোন ভ্যালু থাকে না শুধু স্ট্রাকচার থাকে। একটু অন্যভাবে বলতে গেলে, প্লেসহোল্ডার মানে আপনার মডেলের কিছু গর্ত, যে গর্ত গুলোতে আপনি কিছু পরে ডাটা ঢুকাবেন। প্লেসহোল্ডার তৈরি করতে placeholder মেথড ব্যবহার করতে হয়। তৈরির সময় ডাটা টাইপ এবং এর প্রেসিশন ভ্যালুও ডিফাইন করতে হবে। নিচের টেবিলে প্রত্যেকটি ডাটাটাইপ এবং সে অনুযায়ী সিনট্যাক্স দেয়া আছে,

এবার নিচের প্রোগ্রামটি দেখি,

  
import tensorflow as tf

a = tf.placeholder(tf.float32)
b = a * 2

with tf.Session() as session:
    result = session.run(b)
    print(result)

এখানে প্রথমে একটি প্লেসহোল্ডার ডিফাইন করা হয়েছে float টাইপের। অতঃপর সেই প্লেসহোল্ডার ভ্যারিয়েবলের সাথে 2 গুন করার অপারশন ডিফাইন করা হয়েছে b তে (স্বাভাবিক যোগ বিয়োগের ক্ষেত্রে tf এর মেথড ব্যবহার না করে, স্বাভাবিক অপারেটর ব্যবহার করলেও চলে)। এবং স্বাভাবিক ভাবে session এর রান মেথডের মধ্যে b কে চালিয়ে দিয়ে এই অপারশণকে রান করার কথা বলা হচ্ছে। সাথে result প্রিন্ট এর কথা বলা হচ্ছে।
কিন্তু এই প্রোগ্রাম এরর থ্রো করবে (যেমন- You must feed a value for placeholder tensor), কারন প্লেসহোল্ডার ডিফাইন করলেও গ্রাফ রান করানোর সময় আমরা সেই প্লেসহোল্ডারের জন্য আসল কোন ভ্যালু গ্রাফ/মডেলের মধ্যে পাঠাই নি। পাঠানোর কাজটা খুবি সহজ, run মেথডের আরেকটি আর্গুমেন্ট হিসেবে আমরা প্লেসহোল্ডারের আসল ভ্যালু পাস করে দিতে পারি নিচের মত। পাস করার সময় প্লেসহোল্ডারের নাম এবং করেস্পন্ডীং ভ্যালুকে পাইথন ডিকশনারি ফরম্যাটে পাঠাতে হবে।

  
import tensorflow as tf

a = tf.placeholder(tf.float32)
b = a * 2

with tf.Session() as session:
    result = session.run(b, feed_dict={a:3.5})
    print(result)

আউটপুট আসবে 7.0

যেহেতু TensorFlow তে আমরা মাল্টি ডাইমেনশনাল ডাটা পাস করতে পারি। তাই চাইলে আমরা a এর ভ্যালু হিসেবে একটি Tensor -ও পাঠিয়ে দেখতে পারি। সেই টেনসরের উপর আমাদের ডিফাইন করা গুন a*2 -ই অ্যাপ্লাই হবে। নিচের প্রোগ্রাম দেখুন,

import tensorflow as tf

a = tf.placeholder(tf.float32)
b = a * 2

with tf.Session() as session:
    result = session.run(b, feed_dict={a:[ [[6, 7, 8], [9, 10, 11], [12, 13, 14]], [[15, 16, 17], [18, 19, 20], [21, 22, 23]] , [[15, 16, 17], [18, 19, 20], [21, 22, 23]] ]})
    print(result)

আউটপুট,

[[[ 12.  14.  16.]
  [ 18.  20.  22.]
  [ 24.  26.  28.]]

 [[ 30.  32.  34.]
  [ 36.  38.  40.]
  [ 42.  44.  46.]]

 [[ 30.  32.  34.]
  [ 36.  38.  40.]
  [ 42.  44.  46.]]]


আসছে …

TensorFlow দিয়ে ইমেজ ক্লাসিফিকেশনের উপযোগী একটি CNN তৈরি

ডিপ লার্নিং প্ল্যাটফর্ম

এই পোস্টের স্বয়ংক্রিয় আপডেট পেতে ব্লগে সাবস্ক্রাইব করে রাখতে পারেন। বলে নেই – সাবস্ক্রাইব মানে আমি টাকা পয়সা পাবো এমন কিচ্ছু না। এটা অ্যাড ফ্রি ব্লগ 🙂

ম্যাক এর জন্য ডেভেলপার বা প্রো-ইউজারদের প্রয়োজনীয় ৩০টি অ্যাপ সাজেশন

Standard
  1. Xcode যারা iOS, watchOS বা macOS এর জন্য অ্যাপ্লিকেশন ডেভেলপ করতে চান তাদের জন্য একান্ত প্রয়োজনীয় একটি IDE যার সাথে বিল্ট ইন আছে ইমুলেটর গুলোও। ম্যাক ইউজাররা ফ্রি তেই ডাউনলোড করতে পারবেন।
  2. chrome বর্তমান ওয়েব দুনিয়ায়, সব ব্রাউজারের ব্যবহার জরিপ অনুযায়ী শতকরা ৭০ ভাগেরও বেশি ব্যবহৃত হয় গুগলের তৈরি এই ব্রাউজারটি। বিশাল এক্সটেনশন এবং অ্যাপ মার্কেটপ্লেস এই ব্রাউজারকে করেছে আরও সমৃদ্ধ। এই ব্রাউজারে যেমন ক্লায়েন্ট সাইড ডিবাগিং, ইন্সপেকশন টুল বিল্ট আছে তেমনি এর জন্য এক্সটেনশন বা প্লাগিন তৈরি করাও বেশ সহজ। সবার জন্য ফ্রি।
  3. PhpStorm জেট ব্রেইন্স এর তৈরি সবচেয়ে পপুলার একটি IDE যার মাধ্যমে PHP -তে ওয়েব অ্যাপ ডেভেলপমেন্ট হতে পারে খুবি প্রোডাক্টিভ। স্টুডেন্টদের জন্য ফ্রি। এছাড়াও স্টার্ট আপ, ট্রেনিং সেন্টার বা ওপেন সোর্স প্রোডাক্ট ডেভেলপারদের জন্যও ফ্রি/ছাড়।
  4. PyCharm জেট ব্রেইন্স এর তৈরি আরেকটি বহুল পরিচিত পাইথন IDE যার একটি কমিউনিটি এডিশন আছে যেটি সবসময় বিনামূল্যে পাওয়া যায়। পাইথন অ্যাপ ডেভেলপার বা পাইথন স্ট্যাকে কাজ করেন এমন ইউজারদের জন্য খুবি প্রোডাক্টিভ একটি টুল। যারা Anaconda এর মত রেডি মেড প্ল্যাটফর্ম এর জন্য বাধ্য না, সেরকম ডাটা সায়েন্স ইঞ্জিনিয়াররাও এটায় কাজ করতে পারেন স্বাচ্ছন্দ্যে. এর প্রফেশনাল এডিশনটি স্টুডেন্টদের জন্য ফ্রি। এছাড়াও স্টার্ট আপ, ট্রেনিং সেন্টার বা ওপেন সোর্স প্রোডাক্ট ডেভেলপারদের জন্যও ফ্রি/ছাড়।
  5. Webstorm যাদের জাভাস্ক্রিপ্ট স্ট্যাক খুব পছন্দ এবং ক্লায়েন্ট সাইড অ্যাপ ডেভেলপমেন্টে ফোকাসড তাঁরা ব্যবহার করতে পারেন এই IDE টি. এমনকি MEAN স্ট্যাকে ডেভেলপমেন্ট করতে চাইলেও এই IDE হতে পারে প্রথম পছন্দ। স্টুডেন্টদের জন্য ফ্রি।
  6. IntelliJ IDEA জাভা ডেভেলপারদের জন্য অত্যন্ত চমৎকার ফিচার সমৃদ্ধ একটি IDE. স্কালা, গ্রুভি, কটলিন ল্যাঙ্গুয়েজের সাপোর্ট থেকে শুরু করে গিট সাপোর্ট এবং স্প্রিং এর মত ফ্রেমওয়ার্ক সাপোর্ট সবই আছে এতে। Android অ্যাপ ডেভেলপমেন্ট থেকে শুরু করে ওয়েব অ্যাপ ডেভেলপমেন্ট, সবই সম্ভব এই প্রোডাক্টিভ টুলটি ব্যবহারের মাধ্যমে। স্টুডেন্টদের জন্য ফ্রি।
  7. Android Studio অ্যান্ড্রয়েড অ্যাপ ডেভেলপমেন্ট এর জন্য একমাত্র অফিসিয়াল IDE. কোড এডিটিং, ডিবাগিং থেকে শুরু করে পারফরমেন্স টেস্টিং, ডিপ্লয়েমেন্ট, ইনস্ট্যান্ট বিল্ড ও অনেক অনেক ফিচার সমৃদ্ধ IDE টি অ্যান্ড্রয়েড অ্যাপ ডেভেলপারদের প্রথম পছন্দ। ফ্রি।
  8. Visual Studio Code মাইক্রোসফট এর তৈরি ফ্রি, ওপেন সোর্স এবং সুন্দর ইন্টারফেইস সমৃদ্ধ এই মাল্টি প্ল্যাটফর্ম কোড এডিটরটি লাইট ওয়েট এবং সাথে গিট ও ডিবাগিং ফিচার বিল্ট ইন। আরও আছে কমিউনিটির ডেভেলপ করা মারাত্মক সব এক্সটেনশন। ফ্রি.
  9. Docker এটি বর্তমানের সব চেয়ে পপুলার সফটওয়্যার কন্টেইনার প্ল্যাটফর্ম। মাল্টি প্ল্যাটফর্মে ডেভেলপমেন্ট, ফুল ডেভেলপমেন্ট এনভায়রনমেন্ট পোর্ট, অতঃপর দ্রুত ডেপ্লয়মেন্ট এবং সহজ স্কেল্যাব্লিটির জন্য সবাই এখন ব্যবহার করছে এই টুলটিকে। কমিউনিটি এডিশন ফ্রি।
  10. VirtualBox ম্যাকের মধ্যেই Windows বা Ubuntu বা অন্য কোন OS ইন্সটল দিতে চাইলে ভার্চুয়াল বক্স হতে পারে সলিড একটি সমাধান। এছাড়া ম্যাকে Vagrant ব্যবহার করতে হলেও এটি আগে ইন্সটল থাকতে হবে। ফ্রি তেই পাওয়া যাবে এই সফটওয়্যারটি।
  11. Vagrant ভার্চুয়াল বক্স ইউজ করে অন্য OS ইন্সটল দেয়ার পরেও কিছু সীমাবদ্ধতা থেকে যায় যেগুলো দূর করতে পারে এই কমান্ড লাইন অ্যাপটি। এটি ব্যবহার করে খুব দ্রুত যেকোনো হেড লেস OS ইন্সটল দেয়া এবং সাথে সাথে IP, Memory, Sync Folder, SSH ইত্যাদি কনফিগার করা যায় সহজেই। ফ্রি.
  12. Sequel Pro গ্র্যাফিক্যালি MySQL ডাটাবেজ ম্যানেজমেন্টের জন্য ম্যাকের উপযোগী খুব সুন্দর একটি অ্যাপ। ম্যাকের জন্য ফ্রিতেই পাওয়া যায়।
  13. Robomongo ক্রস প্ল্যাটফর্ম এবং ন্যাটিভ একটি গ্রাফিক্যাল টুল যা দিয়ে সহজেই MongoDB ম্যানেজ করতে পারেন।
  14. iTerm2 ম্যাকের বিল্ট ইন টার্মিনাল অ্যাপ এর চেয়ে অনেক বেশি কনফিগারেবল এবং অনেক অনেক ফিচার সমৃদ্ধ একটি টার্মিনাল ক্লায়েন্ট। ওপেন সোর্স এবং সম্পূর্ণ ফ্রি।
  15. Postman বর্তমানে সফটওয়্যার ডেভেলপমেন্ট এবং API ডেভেলপেমণ্ট প্রায় ওতপ্রোতভাবে জড়িত। আর পোষ্টম্যান হচ্ছে সেখানে অবশ্য প্রয়োজনীয় একটি অ্যাপ যার মাধ্যমে আপনার ডেভেলপ করা API এন্ডপয়েন্ট গুলোকে টেস্ট করতে পারবেন সহজেই।
  16. Homebrew এক কথায় একে বলা হয় The missing package manager for macOS. অর্থাৎ, যারা উবুন্টু বা এরকম ইউনিক্স সিস্টেমের বিল্ট ইন প্যাকেজ ম্যানেজার গুলোকে পছন্দ করেন এবং ম্যাকে এরকম একটি টুলকে মিস করেন তাদের জন্য লাইফ সেভার একটি টুল এটি। মজার বিষয় হচ্ছে, এটি কোন টুল ইন্সটল করার সময় এর নিজের একটি আলাদা লোকেশন ইন্সটল করে এবং সেটির একটি সিম্বোলিক লিঙ্ক ম্যাকের /usr/local ডিরেক্টরিতে তৈরি করে. আর তাই আপনার সিস্টেম ক্লিন থাকে।
  17. Github Desktop যদি আপনি একজন ওপেন সোর্স কন্ট্রিবিউটর হয়ে থাকেন এবং বিভিন্ন github রিপজিটরিতে খুব দ্রুত একটি গ্রাফিক্যাল টুল ইউজ করে কোলাবরেট করতে চান তাহলে এটি আপনার জন্য। এটি ফ্রি। Tower হচ্ছে এরকমই আরেকটি অ্যাপ যা আপনার সব গিট রিপজিটরির জন্য কিন্তু এটি পেইড অ্যাপ।
  18. FileZilla নানা কারণেই আপনার একটি FTP ক্লায়েন্ট দরকার হতে পারে যে ক্ষেত্রে এই ফ্রি, ওপেন সোর্স এবং ক্রস প্ল্যাটফর্ম অ্যাপটি হতে পারে প্রথম পছন্দের। FTP, SFPT সাপোর্ট রয়েছে এতে।
  19. Caffeine ছোট একটি টুলবার অ্যাপ যার মাধ্যমে নির্দিষ্ট সময়ের জন্য আপনার ম্যাককে স্লিপ মুডে যাওয়া থেকে বিরত রাখতে পারেন. ফ্রি।
  20. Spectacle ম্যাক ইউজারদের কাছে অনেক সময় বিরক্তির কারণ হয়ে দাড়ায় বিভিন্ন অ্যাপ উইন্ডোর সাইজকে ঠিক ঠাক করা। এই টুলবার অ্যাপ এবং এর কিবোর্ড শর্ট কাট এর মাধ্যমে খুব সহজেই কোন রানিং অ্যাপকে ফুল সাইজ করা, অর্ধেক ডানে বা অর্ধেক বামে করা ইত্যাদি নানা রকম প্লেসমেন্ট করা যায়। ফ্রি।
  21. Skype নতুন করে বলার কিছু নাই স্কাইপি নিয়ে। মার্কেটে অনেক সময় অনেক রকম কমিউনিকেশন টুল আসলেও এর অবস্থান অনড়। এখনও অনেক ইউজাররা মিটিং, স্ক্রিন শেয়ারিং, গ্রুপ কনভারসেশন এমনকি কলিং এর জন্য এর উপরেই ভরশা করে থাকেন. ফ্রি.
  22. Slack এটি আধুনিক একটি যোগাযোগের মাধ্যম যা চ্যাটিং ইন্টাফেইসকে ঘিরেই তৈরি। এটি বিশেষ করে ব্যবহৃত হয় অফিস বা টিমের মধ্যে। বিভিন্ন গ্রুপ বা চ্যানেল তৈরির মাধ্যমে মেম্বাররা নিজেদের মধ্যে চ্যাট, মেনশন, ফাইল শেয়ারিং ইত্যাদি করতে পারেন। এর জন্য বিভিন্ন বট তৈরি করেও একে আরও বেশি প্রয়োজনীয় এবং উপযোগী করে নিতে পারেন যে কেউ। ফ্রি.
  23. Dropbox ক্লাউড স্টোরেজের জন্য অত্যন্ত নির্ভরযোগ্য একটি প্ল্যাটফর্ম। এর ম্যাক অ্যাপটি টুলবারে থেকে খুব সহজেই আপনার প্রয়োজনীয় ফাইলকে ক্লাউডে সিঙ্ক করে নেয়। ম্যাক যেকোনো ফাইল তৈরি করার পর শুধু সেভ করার লোকেশনটি দেখিয়ে দিবেন Dropbox এর সিঙ্ক করা যেকোনো একটি ফোল্ডারে। সাথে সাথে এটি ক্লাউডে আপলোড হয়ে যাবে। অন্য ইউজারদের সাথে ফাইল শেয়ার করতেও ব্যবহার করা যায় এদের সার্ভিসকে। নির্দিষ্ট জায়গা পর্যন্ত ফ্রি।
  24. Office 365 যে যাই বলুক, মাইক্রোসফট এর তৈরি এই অফিস স্যুটটির ভাল কোন বিকল্প এখনও নেই। এর মধ্যে থাকে MS Word, MS Excel, MS Power Point এবং আরও কয়েকটি অত্যন্ত দরকারি অ্যাপ যা একাধারে ছাত্র, শিক্ষক, লেখক, হিসাবরক্ষক, চাকুরীজীবী সবার কাছেই গুরুত্বপূর্ণ। ছাত্রদের জন্য ফ্রি।
  25. Sketch অ্যাপ, ওয়েব পেইজ বা লে-আউট ডিজাইনাদের জন্য Photoshop এর বিকল্প এবং ম্যাকের জন্য বহুল ব্যবহৃত একটি অ্যাপ। যাদের Photoshop এর সব ফিচার দরকার নাই বা শুধুমাত্র অ্যাপ ডিজাইন নিয়েই ফোকাস করতে চান তাদের জন্য। এটি একটি পেইড অ্যাপ।
  26. VLC Media Player সবার অত্যন্ত পরিচিত একটি মিডিয়া প্লেয়ার। এটি ফ্রি এবং ওপেন সোর্স।
  27. uTorrent ম্যাকের জন্য একটি টরেন্ট ক্লায়েন্ট দরকার হলে এটি হতে পারে পছন্দের। যদিও অনেকে এই পারপাজে Transmission ব্যবহার করে থাকেন।
  28. Dash লিস্টের শেষের দিকে লিখছি মানেই যে এটি কম গুরুত্বপূর্ণ একটি অ্যাপ, বিষয়টি তা নয়। বরং, এটি লিস্টের শুরুতেও থাকতে পারতো। আপনার মাথায় যতরকম প্রোগ্রামিং ল্যাঙ্গুয়েজ, ফ্রেমওয়ার্ক বা ডেভেলপমেন্ট টুল এর নাম থাকতে পারে- প্রায় সবগুলোর ডকুমেন্টেশন অফলাইনেই ব্রাউজ করতে চাইলে এই অ্যাপের কোন বিকল্প নাই। এছাড়াও এতে আছে সুন্দর একটি snippet ম্যানেজার। ব্যাসিক ভার্সন ফ্রি.
  29. Dr. Cleaner ম্যাকের জন্য প্রয়োজনীয় একটি ইউটিলিটি অ্যাপ। এর মাধ্যমে একাধারে ডিস্ক ক্লিন আপ, মেমরি ক্লিনআপ এবং সিস্টেম অপটিমাইজেশনের মত কাজ গুলো সহজেই করা যায়। এর মাধ্যমে- সাইজ মোতাবেক পুরো ম্যাকের সব ফাইলকে লিস্ট করা যায় যাতে করে কোন ফাইল বা অ্যাপ কেমন জায়গা নিচ্ছে তার একটা আইডিয়া পাওয়া যায় এবং প্রয়োজনে সেটা ডিলিট বা রিমুভ করা যায়.
  30. AppCleaner ম্যাক থেকে যেকোনো রকম অ্যাপ, উইজেট বা প্লাগিন পুরোপুরি আনইন্সটল করতে চাইলে এই ছোট্ট অ্যাপটি আপনাকে সলিড কাজ করে দেখাবে।
বিঃ দ্রঃ এই লিস্টের বাইরেও আরও অনেক প্রয়োজনীয় এবং গুরুত্বপূর্ণ অ্যাপ/টুল আছে যেগুলো নির্দিষ্ট কাজের জন্য নির্দিষ্ট ইউজারের কাছে দরকারি।

macOS -এ আপনি কি কি অ্যাপ ব্যবহার করে থাকেন এবং কোন সাজেশন থাকলে কমেন্ট করুন নিচে

৫ টি পাইথন কথন

Standard

পাইথন কথন ১ঃ

#! /usr/bin/env python

এটা কি?

অনেক পাইথন স্ক্রিপ্ট এর শুরুতেই এরকম একটা লাইন দেখতে পাওয়া যায়। আসলে এর মাধ্যমে নির্দিষ্ট করে এই স্ক্রিপ্টটির ডিফল্ট ইন্টারপ্রেটার কোনটা হবে সেটা ডিফাইন করে দেয়া হয়।
অর্থাৎ টার্মিনালে chmod +x file.py কমান্ড দিয়ে file.py কে এক্সিউকিউটেবল বানিয়ে অতঃপর ./file.py কমান্ড দিয়ে সেটাকে এক্সিকিউট করতে চাইলে তার জন্য কোন ইন্টারপ্রেটার ব্যবহার হবে সেটা নির্ধারণ করে দেয়া হয়। এখানে Unix টাইপ সিস্টেমের ডিফল্ট পাইথনকে উক্ত স্ক্রিপ্ট বা ফাইলের ইন্টারপ্রেটার হিসেবে উল্লেখ্য করে দেয়া হচ্ছে। কিন্তু কিভাবে?
env হচ্ছে Unix সিস্টেমের মধ্যে থাকা একটা এক্সিকিউটেবল বাইনারি যে কিনা উক্ত সিস্টেমের সব এনভ্যায়রনমেন্ট ভ্যারিয়েবল গুলোকে খুঁজে নিতে পারে। তাই এর মাধ্যমে বস্তুত Python এর এক্সিকিউটেবল python -কে এই স্ক্রিপ্ট এর জন্য ব্যবহার করতে বলা হচ্ছে।
যেহেতু এই লাইনটির উদ্দেশ্য হচ্ছে Python কে চিনিয়ে দেয়া। তাই নিচের মত করেও এটা ডিফাইন করা যায়।

#! /usr/bin/python</code>

ধরে নিচ্ছি এটাই ওই সিস্টেমের python এর পাথ। কিন্তু এটা অ্যাবস্যুলেট পাথ। এক এক সিস্টেমে এক এক পাথে python থাকতে পারে। আমি আমার সিস্টেমে which python কমান্ড ইস্যু করে এটা পেয়েছি তাই এটা লিখলাম। এই অ্যাবস্যুলেট পাথের ঝামেলা মেটাতেই /usr/bin/env ব্যবহার করে python কে খুঁজে (যেখানেই থাকুক) সেটাকে ব্যবহার করতে বলা হয়।
এতক্ষণে বুঝে ফেলার কথা কিভাবে আমার এক্সিকিউটেবল পাইথন স্ক্রিপ্ট গুলোকে আমি Python 3 দিয়ে সবসময় রান করাতে পারবো। আমি স্ক্রিপ্টের শুরুতে নিচের মত করে Shebang লিখবো,

#! /usr/bin/env python3

পাইথন কথন ২ঃ
অনেকেই অফিসিয়াল ডকুমেন্টেশন থেকে বিভিন্ন ফাংশনের Signature পড়ার সময় বুঝে উঠতে পারে না আসলে এর প্যারামিটার গুলো কি। যেমন – round(number[, ndigits])
https://docs.python.org/3/library/functions.html#round

এটাকে বলে ফাংশন সিগনেচার। এর মাধ্যমে বুঝে নিতে হয় এই ফাংশনের প্যারামিটার গুলো কি এবং কেমন। যেমন এই ফাংশনের প্রথম প্যারামিটার ‘number’ অবশ্যই দিতে হবে অর্থাৎ Compulsory. আবার [, ] দিয়ে বোঝানো হয় এই প্যারামিটার গুলো Optional. আর তাই, [ ] এর বাইরে যেগুলো থাকবে সেগুলো অবশ্যই দিতে হবে আর ভিতরে যেগুলো থাকবে সেগুলো না দিলেও ওই ফাংশন কাজ করবে। কিন্তু,
[ ] এর মধ্যে থাকা অপশনাল প্যারামিটার গুলোর মধ্যে কিছু ডিপেন্ডেন্সিও থাকতে পারে। যেমন – RegexObject.match(string[, pos[, endpos]])
এখানে বোঝানো হয়েছে ‘endpos’ পাস করলে অবশ্যই ‘pos’ -ও পাস করতে হবে। তাই এগুলো একটা নেস্টেড ব্র্যাকেটের মধ্যে নির্দেশ করা হয়েছে। আবার শুধু ‘pos’ দিয়ে ‘endpos’ না দিলেও চলবে।

পাইথন কথন ৩ঃ
Python প্রোগ্রাম বলতে আমরা যা ব্যবহার করি তা হচ্ছে CPython. এই, CPython হচ্ছে আসলে Python এর একটা ডিফল্ট এবং বহুল ব্যবহৃত ইমপ্লিমেন্টেশন। এই ইমপ্লিমেন্টেশন জিনিষটা কি?
Python বা অন্য প্রোগ্রামিং ল্যাঙ্গুয়েজ গুলো হচ্ছে ফর্মাল ল্যাঙ্গুয়েজ অর্থাৎ একটু এদিক সেদিক করে এসব ভাষা ব্যবহার করলে কাজ হবে না। এটা বাংলা বা ইংলিশ এর মত ইনফর্মাল না যে – মুরাদ টাকলাদের ভাষাতেও কিছু লিখলে বুঝে নেয়া যায়।
যাই হোক সিমপ্লি, ল্যাঙ্গুয়েজ রেফারেন্স হিসেবে চিন্তা করলে Python -কে একটা ইন্টারফেসও বলা যেতে পারে। যারা প্রোগ্রামিং করেন তারা এই টার্ম সম্পর্কে জানেন – ইন্টারফেস হচ্ছে এক ধরণের অ্যাবসট্র্যাকশন যার মাধ্যমে নির্ধারণ করে দেয়া হয় একটা নির্দিষ্ট কাজ কিভাবে হবে কিন্তু ইমপ্লিমেন্টেশনটা যার যেমন ইচ্ছা সেভাবে করবে। তাই, CPython বস্তুত Python এর Language Reference মেনে C দিয়ে করা একটা ইমপ্লিমেন্টেশন। আবার, CPython -ই হচ্ছে Python প্রোগ্রামের ইন্টারপ্রেটার 😛

একটা পাইথন প্রোগ্রামের এক্সিকিউশনের ধাপ গুলো এরকমঃ

Python Source Code (.py) -> Compiler -> Bytecode (.pyc) -> Interpreter (VM/CPython) -> Output (Hello World!)

যখন নির্দিষ্ট কোন কাজের সাপেক্ষে বলা হয় Python স্লো বা ফাস্ট তখন আসলে দোষ বা বাহবা যেটাই দেয়া হোক, দিতে হবে CPython কে অথবা ওই নির্দিষ্ট ইমপ্লিমেন্টেশনকে 🙂
Python এর এরকম আরও অনেক ইমপ্লিমেন্টেশন আছে। যেমন- Jython, IronPython, PyPy ইত্যাদি। Jython এর ক্ষেত্রেও বিষয়টা একই। অর্থাৎ – Python নামক ফর্মাল ল্যাঙ্গুয়েজের ইমপ্লিমেন্টেশন করা হয়েছে Java তে। তাই Python এর এই ভার্সনেও স্বাভাবিক Python এর সিনট্যাক্স মোতাবেকই প্রোগ্রাম লেখা যাবে এবং প্রোগ্রাম রান করালে এর পিছনে আসলে কলকাঠি নাড়বে Java.
অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজের ক্ষেত্রেও বিষয়টা এরকম। যেমন, যদি বলা হয়ঃ C++ is implemented in C. এর মানে সহজ ভাবে বলতে গেলেঃ C++ এর কম্পাইলার C দিয়ে তৈরি 🙂
আরেকটা কথা, উপরের এক্সিকিউশনের ধাপ অনুযায়ী Python কে ইন্টারপ্রেটেড বা কম্পাইল্ড ল্যাঙ্গুয়েজ কোনটাই বলা যাবে না (সিরিয়াসলি?)। আসলে Python কিন্তু ইন্টারপ্রেটেড বা কম্পাইল্ড না। যদি এই বৈশিষ্ট্য কাউকে দিতেই হয় তাহলে CPython কে দিতে হবে।
CPython ইন্টারপ্রেটেড কিন্তু (আবার কি?) তার আগে একটা কম্পাইলেশন স্টেপ আছে 😛 যেটা [প্রোগ্রাম টু প্রসেসর] কনসেপ্ট অনুযায়ী এখানে অগ্রাহ্য)

পাইথন কথন ৪ঃ

# -*- coding: utf-8 -*-

এই কমেন্ট লাইনটাকে অনেক পাইথন স্ক্রিপ্টের শুরুতেই দেখা যায়। একটু একটু বোঝা যায় যে এখানে এনকোডিং ডিফাইন করে দেয়া হয়েছে। কিন্তু কিসের এবং কেন? কার জন্যই বা দরকার এটা?
প্রথমেই জানতে হবে কম্পিউটারের সাথে টেক্সট নিয়ে কাজ করতে হলে তাকে টেক্সট গুলো চেনাতে হয়, আর আমরা সবাই জানি কম্পিউটার 1, 0 ছাড়া আর কাউকেই চেনে না। তো এনকোডিং এর সহজ মানে হচ্ছে একটা ম্যাপিং টেবিল যেখানে বলা আছে A এর মানে 01000001 (এটা ASCII এনকোডিং/টেবিল)। কিন্তু এই টেবিলে দুনিয়ার সব ভাষার সব ক্যারেক্টার এর সাপেক্ষে এরকম কম্পিউটার উপযোগী কোড নাই। এদিকে আমাদের প্রোগ্রাম লিখতে বা টেক্সট ফাইল লিখতে সেই ক্যারেক্টার গুলো লাগতেই পারে। তাই এরকম আরও একটা বিশাল লম্বা টেবিল আছে, utf-8 এনকোডিং/টেবিল। এই টেবিলে বাংলা “ক” সাপেক্ষেও একটা বাইনারি পাওয়ার ব্যবস্থা আছে।
তো আমাদের পাইথন প্রোগ্রামে যদি এরকম ASCII এর বাইরের ক্যারেক্টার থাকে তাকে চেনাতে হলে ফাইলের শুরুতে বলে দিতে হবে যে – ভাই পাইথন তুমি আমার এই সোর্স ফাইলকে দয়া করে utf-8 টেবিল/এনকোডিং মোতাবেক পার্স করিয়ো নাহলে বুঝবা না আমি ফাইলে কি লিখছি 🙂
নিচের প্রোগ্রামটা যদি একটা Test.py ফাইলে লিখে পাইথন ২ দিয়ে রান করাই,

name = "নুহিল"
print(name)

তাহলে আউটপুট আসবে,

File "Test.py", line 3
SyntaxError: Non-ASCII character '\xe0' in file Test.py on line 3

তাই ওই Test.py কে আপডেট করে নিচের মত করতে হবে,

# -*- coding: utf-8 -*-
name = "নুহিল"
print(name)

এবার ঠিকঠাক রান করবে। আর হ্যা, ঠিক # -*- coding: utf-8 -*- এভাবেই যে সোর্স ফাইলের এনকোডিং ডিফাইন করতে হবে তাও কিন্তু না। # Please encoding: utf-8 (সত্যি) এরকম লিখলেও পাইথন বুঝে যাবে 🙂
শেষ কথা, এই ঝক্কি ঝামেলা কিন্তু Python 3 তে করতে হবে না কারন পাইথন ৩ ডিফল্ট এনকোডিং হিসেবে utf-8 কেই ধরে নেয় 😀

পাইথন কথন ৫ঃ

if __name__ == "__main__":

এই লাইনটা অনেক পাইথন ফাইলে দেখে ঘাবড়ে যাবার কিছু নাই। আমরা বোঝার চেষ্টা করি কেন লোকজন এই অদ্ভুত if কন্ডিশনটাকে তাদের পাইথন স্ক্রিপ্টে লিখে।
পাইথন ইন্টারপ্রেটার একটি প্রোগ্রামের এক্সিকিউশনের আগে যখন একটি সোর্স ফাইলকে পার্স (পড়ে) করে তখন সে এর জন্য কিছু স্পেশাল ভ্যারিয়েবল সেট করে। যখন স্বাধীনভাবে কোন পাইথন স্ক্রিপ্টকে রান করানো হয় তখন স্বয়ংক্রিয়ভাবে এর জন্য একটি __name__ নামের ভ্যারিয়েবল তৈরি হয় যার ভ্যালু সেট করা হয় স্ট্রিং “__main__” .
তাই আমরা যদি চাই আমাদের স্ক্রিপ্ট এর মধ্যেকার কিছু স্টেটমেন্ট শুধুমাত্র তখনি কাজ করুক যখন এটা একটা স্ট্যান্ডঅ্যালোণ স্ক্রিপ্ট হিসেবে রান করবে তখন বুদ্ধি করে এরকম একটা if কন্ডিশন লিখে তার মধ্যে ওগুলো লিখবো। কারন আমরা তো জানিই যে এই if কন্ডিশন তখনি সত্য হবে যখন এই স্ক্রিপ্টটা শুধু স্ক্রিপ্ট হিসেবেই রান হবে।
যেমন আমাদের যদি নিচের মত একটা প্রোগ্রাম থাকে Nuhil.py ফাইলে,

def my_module_func():
    print("Nuhil Mehdy")

if __name__ == "__main__":
    print("Nuhil")

তাহলে আমরা যখন python Nuhil.py এভাবে একে রান করাবো তখন আউটপুট আসবে,
Nuhil
কিন্তু (আবার কি হল?),
যদি এই Nuhil.py কে আরেকটি পাইথন ফাইল যেমন Mehdy.py এর মধ্যে মডিউল হিসেবে import করি তখন কিন্তু পাইথন এই Nuhil.py ফাইল পার্স (পড়ার সময়) করার সময় __name__ নামের ভ্যারিয়েবলের জন্য “__main__” ভ্যালু সেট করবে না। আর তাই if কন্ডিশনটা মিথ্যা হবে। তো, Mehdy.py এর কোড যদি হয় নিচের মত,

import Nuhil
Nuhil.my_module_func()

তাহলে আউটপুট আসবে,

Nuhil Mehdy

এবং সুন্দর মত print("Nuhil") স্টেটমেন্টটি গু(?)পনেই থেকে যাবে

এঞ্জিনএক্স, পিএইচপি, মাইএসকিউএল এর ইনস্টলেশন, কনফিগারেশন এবং সার্ভার ব্লক (ভার্চুয়াল হোস্ট) তৈরি

Standard

সবার জন্য প্রোগ্রামিং

সার্ভারের প্রাথমিক এবং ব্যাসিক কনফিগারেশন

1. নতুন তৈরি হওয়া সার্ভারে root ইউজার হিসেবে লগইন করুন নিচের কমান্ড দিয়ে

2. নতুন একটি ইউজার তৈরি করতে কমান্ড দিন নিচের মত। এখানে নতুন ইউজারের নাম demo

3. নতুন ইউজারকে root ইউজারের সমতুল্য অধিকার দিতে তাকে sudo গ্রুপে যুক্ত করুন

4. পাসওয়ার্ডের পরিবর্তে পাবলিক কি দিয়ে অথেনটিকেশন এর ব্যবস্থা

  • আপনার লোকাল মেশিনে এক জোড়া কি তৈরি করতে কমান্ড দিন (~/.ssh ডিরেক্টরির মধ্যে তৈরি করা ভালো)
  • পাবলিক কি এর কন্টেন্টকে রিমোট সার্ভারে কপি করতে প্রথম এর কন্টেন্ট প্রিন্ট করতে কমান্ড দিন

    এরপর স্বাভাবিকভাবে পুরো আউটপুট সিলেক্ট করে কপি করুন

  • সার্ভারে root ইউজার হিসেবে লগডইন থাকা অবস্থায় নিচের কমান্ড দিয়ে নতুন ইউজার হিসেবে লগইন করুন

    এ অবস্থায় আপনি demo ইউজারের home ডিরেক্টরিতে থাকবেন

  • demo ইউজারের home ডিরেক্টরিতে .ssh নামের একটি ডিরেক্টরি তৈরি করতে এবং সেটার যথাযথ পারমিশন সেট করতে নিচের দুটো কমান্ড পর পর দিন:

  • ওই ডিরেক্টরির মধ্যে authorized_keys নামের ফাইল তৈরি/এডিট করুন

    এবার লোকাল মেশিনের…

View original post 591 more words

রাস্পবেরি পাই পরিচিতি ও প্রথম বুট – ভিডিও

Standard

সবার জন্য প্রোগ্রামিং

Photo Sep 28, 11 54 16 AM
রাস্পবেরি পাই বি+ মডেলের পরিচিত, হার্ডওয়্যার রিভিউ, এর জন্য অপারেটিং সিস্টেম রেডি করা, প্রথম বুট এবং রাস্পবিয়ান এর ব্যাসিক পরিচিত

View original post