Chapter 6 of 28
Convolution, padding, stride, and the formulas behind them
এতক্ষণ পর্যন্ত আমরা যে সমস্ত সহজাত ধারণাগুলো বা intuitions অর্জন করেছি — যেমন "ফিল্টারগুলো ছবির ওপর দিয়ে স্লাইড করে যায়," "পুলিং ফিচার ম্যাপকে ছোট করে দেয়," "গভীর লেয়ারগুলো আরও বিমূর্ত বা অ্যাবস্ট্রাক্ট প্যাটার্ন দেখে" — এগুলোর প্রতিটির নিচেই আসলে নিখুঁত ও সুনির্দিষ্ট গাণিতিক হিসাব বা পাটিগণিত কাজ করে চলেছে। পরীক্ষায় কোনো আউটপুট সাইজ হিসাব করতে না পারার কারণে নম্বর কাটা গেলে, অথবা কোনো ইন্টারভিউতে প্যারামিটার কাউন্টের গণ্ডগোল পাকিয়ে ফেললে তার মূল কারণ হলো পেছনের গাণিতিক হিসাবগুলো ঠিকঠাক মুখস্থ বা আড়ালে না থাকা। এই চ্যাপ্টারটি হলো মূলত সেই কাজের ফর্মুলা শিট: একটি CNN বাস্তবে যে প্রতিটি সমীকরণ চালায়, এখানে তার প্রতিটি সংজ্ঞায়িত করা হয়েছে এবং খুব সহজ ভাষায় ব্যাখ্যা করা হয়েছে, যাতে এখানের কোনো কিছু আর আপনার কাছে রহস্যময় না থাকে।
ভাবুন তো, আপনি একটি টেকনিক্যাল ইন্টারভিউতে বসে আছেন। ইন্টারভিউয়ার বোর্ডে একটি গ্রে-স্কেল ছবি এঁকে বললেন, "আমরা একটি ফিল্টার প্রয়োগ করছি, কোনো প্যাডিং নেই (no padding), স্ট্রাইড ১," এবং জিজ্ঞেস করলেন: "আউটপুটের আকার বা সাইজ কত হবে?" সেখানে কোনো কিছু গুগলে সার্চ করার বা বই খোলার সময় নেই — হয় আপনি ফর্মুলাটি খুব ভালোভাবে জানেন, নয়তো আন্দাজে ঢিল মারবেন। এই চ্যাপ্টারটি ঠিক এজন্যই যাতে এ ধরনের প্রশ্ন (এবং এর সাথে সম্পর্কিত অন্য বিষয়গুলো: এই লেয়ারে কতগুলো প্যারামিটার আছে, পুলিং ইমেজের শেপের কী পরিবর্তন করে, লজিটগুলোর ওপর সফটম্যাক্স বসানোর পর কোন লস ফাংশন জোড়া দেওয়া হয়) আপনাকে আর কখনোই অপ্রস্তুত অবস্থায় ধরতে না পারে।
যেখানে: হলো ইনপুট ইমেজ (একটি ম্যাট্রিক্স), হলো কার্নেল/ফিল্টার (একটি ছোট ম্যাট্রিক্স), হলো প্রাপ্ত আউটপুট ফিচার ম্যাপ, হলো ক্যালকুলেট করা আউটপুটের পজিশন, এবং হলো কার্নেলের নিজস্ব ইনডেক্স বা সীমা।
সহজ কথা: প্রতিটি আউটপুট পিজিশন -তে, ছবির সংশ্লিষ্ট অঞ্চলের ওপর কার্নেলটি স্থাপন করুন, একে অপরের ওপর ওভারল্যাপ বা উপরিপাতন হওয়া প্রতিটি জোড়া মানকে গুণ করুন, এবং গুণফলগুলোকে যোগ করে একটিমাত্র সংখ্যায় নিয়ে আসুন। সেই একক সংখ্যাটি এই প্রশ্নের উত্তর দেয়: "ছবির এই ছোট লোকাল প্যাচটি কার্নেলে থাকা ডিজাইন বা প্যাটার্নটির সাথে ঠিক কতটা মিলছে?"
এটি কেন প্রয়োজন: এটিই নেটওয়ার্কটিকে ছবির যেকোনো জায়গায় একটি নির্দিষ্ট লোকাল প্যাটার্ন — যেমন একটি কিনারা, একটি কোণ, একটি বিন্দু — ঠিক একই ছোট ওয়েটের সেট ব্যবহার করে সনাক্ত করতে সাহায্য করে। এই ওজনের বারবার ব্যবহারকেই বলা হয় ওয়েট শেয়ারিং (weight sharing), যা মূলত CNN-কে কম্পিউটেশনাল দিক থেকে সম্ভব করে তোলে।
ব্যবহারিক ব্যাখ্যা: আউটপুট ফিচার ম্যাপের পজিশনে একটি বড় মানের অর্থ হলো কার্নেলের প্যাটার্নটি ছবির ওই অঞ্চলের সাথে খুব জোরালোভাবে মিলে গেছে; আর একটি ছোট বা ঋণাত্মক মানের অর্থ হলো এটি মেলেনি।
কনভোলিউশনকে একটা ছোট্ট স্টেনসিল বা রাবার স্ট্যাম্পের মতো ভাবুন, যেটাতে একটা নির্দিষ্ট প্যাটার্ন খোদাই করা আছে (ধরুন, একটা কোণা বা edge)। এই স্ট্যাম্পটা আপনি ছবির ওপর বাম-ওপর কোণা থেকে শুরু করে ধীরে ধীরে ডানে, তারপর এক লাইন নিচে নামিয়ে আবার বাম থেকে ডানে — এভাবে সরাতে থাকেন। প্রতিটা জায়গায় স্ট্যাম্প বসিয়ে আপনি প্রশ্ন করছেন: "এই জায়গার ছবির অংশটা কি আমার স্ট্যাম্পের প্যাটার্নের মতো দেখতে?" মিলে গেলে বড় সংখ্যা পাবেন, না মিললে ছোট বা negative সংখ্যা। পুরো ছবি জুড়ে এই "মিল খোঁজার" ফলাফলগুলো একসাথে করলেই feature map তৈরি হয়।
গাণিতিকভাবে, "আসল" কনভোলিউশন অপারেশনে ইনপুটের ওপর দিয়ে স্লাইড করার আগে কার্নেলটিকে উল্টে বা ফ্লিপ করে (flip) নিতে হয়। তবে প্রায় প্রতিটি ডিপ লার্নিং ফ্রেমওয়ার্কই (যেমন PyTorch, TensorFlow) বাস্তবে কোনো ফ্লিপিং ছাড়াই কাজ করে — যাকে মূলত ক্রস-কোরিলেশন (cross-correlation) বলা হয় — কিন্তু diplomas বা তবুও এদের নাম দিয়ে রেখেছে "কনভোলিউশন।" বাস্তবে এই পার্থক্যে কোনো এসে যায় না, কারণ নেটওয়ার্কটি লস কমানোর জন্য ফিল্টারের উল্টানো সংস্করণটি নিজে থেকেই শিখে নেয়। তবে এটি পরীক্ষার ভাইভা বোর্ডে ট্রিক করার জন্য অন্যতম একটি প্রিয় প্রশ্ন।
সংখ্যা দিয়ে সরাসরি দেখলে ব্যাপারটা আরো পরিষ্কার হয়। ধরুন একটা ছোট্ট ইনপুট আর একটা কার্নেল আছে:
কার্নেলটাকে ইনপুটের বাম-ওপর কোণায় বসিয়ে element-wise গুণ করে যোগ করুন: । এখন কার্নেলটা এক ঘর ডানে সরিয়ে একই কাজ করুন: । এভাবে কার্নেলটা প্রতিটা সম্ভাব্য অবস্থানে বসিয়ে (stride 1, no padding হলে মোট টা অবস্থান) একটা ছোট আউটপুট ম্যাট্রিক্স পাওয়া যায়:
লক্ষ্য করুন — পুরো প্রক্রিয়াটা আসলে শুধু "গুণ করে যোগ করা"-কেই বারবার, ভিন্ন ভিন্ন জায়গায় প্রয়োগ করা। কোনো জাদু নেই, শুধু repetitive arithmetic — আর এই সরল repetition-টাই কম্পিউটারের জন্য অত্যন্ত দ্রুত করা সম্ভব, যেটা CNN-কে বাস্তবে কাজ করার মতো দ্রুত বানায়।
ফিচার ম্যাপ হলো পুরো ইনপুটের ওপর একটি ফিল্টার কনভলভ (convolve) বা স্লাইড করার পর প্রাপ্ত 2D (অথবা একাধিক ফিল্টারের ক্ষেত্রে 3D) অ্যারে বা ম্যাট্রিক্স। প্রতিটি ফিল্টার ঠিক একটিমাত্র ফিচার ম্যাপ তৈরি করে — যাকে লেয়ারের আউটপুটের একটি চ্যানেলও (channel) বলা হয়।
সহজ কথা: কোনো লেয়ার যদি সংখ্যক ফিল্টার ব্যবহার করে, তবে এর আউটপুট হবে সংখ্যক আলাদা আলাদা ফিচার ম্যাপের একটি স্তুপ, যা মূলত আকারের একটি 3D টেন্সর। এই সংখ্যক চ্যানেলের প্রতিটি আসলে ছবির আলাদা আলাদা প্যাটার্ন "খুঁজছে।"
প্যাডিং হলো কনভোলিউশন প্রয়োগ করার আগে ইনপুটের সীমানার চারপাশ জুড়ে অতিরিক্ত পিক্সেল যোগ করা — সাধারণত শূন্য (0) ব্যবহার করে, যাকে "জিরো-প্যাডিং (zero-padding)" বলা হয়।
যেখানে: দুটি বা বহুল প্রচলিত প্যাডিং নিয়ম হলো valid padding (, কোনো প্যাডিং ছাড়াই — যার ফলে প্রতি কনভোলিউশন ধাপে আউটপুট ছোট হতে বাধ্য) এবং same padding (এমনভাবে প্যাডিং বেছে নেওয়া যাতে স্ট্রাইড ১ হলে আউটপুটের আকার ইনপুটের সমান থাকে)।
এটি কেন প্রয়োজন: প্যাডিং না থাকলে নেটওয়ার্ক যত গভীরে যায় দুটি বড় সমস্যা দেখা দেয় — প্রথমত ফিচার ম্যাপ অনবরত ছোট হতে থাকে, যা আপনি ঠিক কতগুলো লেয়ার স্তুপ করতে পারবেন তার সীমা নির্ধারণ করে দেয়, এবং দ্বিতীয়ত সীমানা ও কোণায় থাকা পিক্সেলগুলো মাঝের পিক্সেলগুলোর তুলনায় অনেক কম কনভোলিউশন উইন্ডোতে ব্যবহৃত হয়, যার ফলে সীমানার তথ্যগুলো ঠিকমতো রিপ্রেজেন্ট হতে পারে না।
একটা ছবিকে ফ্রেমে বাঁধানোর কথা ভাবুন — ফ্রেমের কারণে ছবির কোণার অংশটাও মাঝের অংশের মতোই সুন্দরভাবে দেখা যায়, কিছু বাদ পড়ে যায় না। Zero-padding ঠিক এই কাজটাই করে: ছবির চারপাশে কাল্পনিক শূন্য-মূল্যের পিক্সেল যোগ করে দেয়, যাতে কোণার আসল পিক্সেলগুলোও কেন্দ্রের পিক্সেলের মতো সমান সংখ্যক বার কার্নেলের নিচে পড়ে। এটা ছাড়া ছবির কিনারার তথ্য বারবার "কম গুরুত্ব" পেয়ে হারিয়ে যেতে থাকে।
স্ট্রাইড হলো ইনপুটের ওপর দিয়ে স্লাইড করার সময় কার্নেলটি প্রতি ধাপে ঠিক কত পিক্সেল করে সরবে বা লাফাবে তার সংখ্যা।
সহজ কথা: স্ট্রাইড বড় হওয়ার অর্থ হলো ফিল্টারটি কম জায়গায় বসবে, যার ফলে একটি ছোট আউটপুট তৈরি হবে এবং কম্পিউটেশনাল খরচ কমবে — তবে এটি ফিচার ম্যাপকে বেশ স্থূল বা coarse করে তুলতে পারে যার ফলে ছবির সূক্ষ্ম ডিটেইলস হারিয়ে যেতে পারে। স্ট্রাইড ১ হলো "সব জায়গায় নিখুঁতভাবে দেখা" সেটিং; আর বড় স্ট্রাইড মূলত গতির জন্য ডিটেইলসের আপস বা কোয়ালিটি ত্যাগ করা।
ছবি স্ক্যান করাকে হাঁটার সাথে তুলনা করা যায়। Stride ১ মানে প্রতি পায়ে মাত্র এক ঘর করে এগোনো — ধীর কিন্তু কোনো জায়গা বাদ পড়ে না। Stride ২ মানে প্রতি পায়ে দুই ঘর করে লাফানো — দ্রুত পৌঁছানো যায়, কিন্তু মাঝের কিছু জায়গা না দেখেই টপকে যাওয়া হয়। CNN-এ শুরুর দিকের layer-এ সাধারণত ছোট stride রাখা হয় (সূক্ষ্ম detail ধরার জন্য), গভীর layer-এ কখনো কখনো বড় stride ব্যবহার করে দ্রুত downsample করা হয়।
যেখানে: হলো ইনপুটের সাইজ (উচ্চতা বা প্রস্থ), হলো ফিল্টার/কার্নেলের সাইজ, হলো প্যাডিং, হলো স্ট্রাইড, এবং হলো ওই একই ডাইমেনশন বা মাত্রা বরাবর প্রাপ্ত আউটপুটের সাইজ।
সহজ কথা: লব বা numerator, , নির্দেশ করে প্যাডিং যোগ করার পর ফিল্টারটি স্লাইড করার জন্য ছবিতে ঠিক কতটা "জায়গা" আছে; স্ট্রাইড দিয়ে ভাগ করার অর্থ হলো ওই জায়গায় ঠিক কতগুলো আলাদা পদক্ষেপ নেওয়া যাবে; ফ্লোর ফাংশন বা floor function () হিসাবের অবশিষ্ট বা ভগ্নাংশ অংশকে বাদ দেয়; আর শেষের হিসাব করে ফিল্টারটি কোনো পদক্ষেপ নেওয়ার আগেই যে একদম প্রথম পজিশনে বসে ছিল সেই জায়গাটি।
ব্যবহারিক ব্যাখ্যা: এই ফর্মুলাটি উচ্চতা এবং প্রস্থের জন্য আলাদা আলাদাভাবে প্রয়োগ করুন — কারণ ছবির উচ্চতা ও প্রস্থ অথবা ফিল্টারের উচ্চতা ও প্রস্থ আলাদা হতে পারে, যা সাধারণত নন-স্কয়ার বা আয়তাকার ইমেজের ক্ষেত্রে ঘটে।
বাস্তব উদাহরণ: , , , হলে:
অর্থাৎ ইনপুটের ওপর ফিল্টার, কোনো প্যাডিং ছাড়া এবং স্ট্রাইড ১ হলে একটি আউটপুট পাওয়া যায়।
এটি একদম নিখুঁতভাবে মুখস্থ রাখুন — ফ্লোর ফাংশন এবং শেষের অংশটি সহ। পরীক্ষার হলের উত্তেজনায় শেষের বাদ দিয়ে ভুল উত্তর দিয়ে আসা খুবই কমন একটি ভুল।
যেখানে: হলো কার্নেলের উচ্চতা ও প্রস্থ, হলো ইনপুট চ্যানেলের সংখ্যা, হলো ফিল্টারের সংখ্যা (বা আউটপুট চ্যানেলের সংখ্যা), এবং অংশটি প্রতি ফিল্টারে একটি করে বায়াস (bias) নির্দেশ করে।
সহজ কথা: প্রতিটি ফিল্টারকে একই সাথে ইনপুটের সবগুলো চ্যানেলের ওপর দিয়ে কাজ করতে হয়, তাই একটিমাত্র ফিল্টারের ওয়েট সংখ্যা হলো , সাথে একটি বায়াস। যেহেতু মোট সংখ্যক স্বাধীন ফিল্টার আছে এবং প্রতিটি আলাদা আলাদা প্যাটার্ন শেখে, তাই পুরো সংখ্যাটিকে দিয়ে গুণ করা হয়।
যেখানে: হলো ইনপুট ফিচার ম্যাপ, এবং "window" হলো প্রতি ধাপে পুল করার জন্য বেছে নেওয়া ছোট লোকাল অঞ্চল (যেমন উইন্ডো)।
সহজ কথা: একটি ছোট উইন্ডোর ভেতরের সব মান রেখে দেওয়ার বদলে, Max Pooling শুধুমাত্র সবচেয়ে বড় বা শক্তিশালী মানটি ধরে রাখে — যার যুক্তি হলো "এই উইন্ডোর যেকোনো জায়গায় কি ফিচারটি উপস্থিত ছিল?" — আর Average Pooling ওই উইন্ডোর সব মানের গড় বা মিন (mean) ধরে রাখে — যার যুক্তি হলো "এই উইন্ডো জুড়ে ফিচারের সামগ্রিক সক্রিয়তার মাত্রা কেমন?"
এটি কেন প্রয়োজন: পুলিং স্থানিক বা স্পেশাল আকার কমিয়ে দেয় (যার ফলে পরবর্তী কম্পিউটেশনাল খরচ ও প্যারামিটার সংখ্যা কমে), ওভারফিটিং নিয়ন্ত্রণে সাহায্য করে, এবং ছবিকে সামান্য এদিক-ওদিক সরালেও (translation invariance) সনাক্ত করতে সাহায্য করে, কারণ পিক্সেল ১-২ ঘর সরলেও তা সাধারণত একই পুলিং উইন্ডোর ভেতরেই অবস্থান করে।
কনভোলিউশনের ক্ষেত্রে আমরা যে আউটপুট সাইজের ফর্মুলাটি দেখেছি, পুলিংয়ের ক্ষেত্রেও হুবহু সেটিই প্রযোজ্য — শুধু ফিল্টার সাইজ -এর জায়গায় পুলিং উইন্ডো এবং স্ট্রাইড -এর জায়গায় পুলিংয়ের স্ট্রাইড বসাতে হবে (পুলিংয়ের ক্ষেত্রে সাধারণত প্যাডিং ০ হয়)।
৪ জনের একটা দলের মধ্যে "কে সবচেয়ে লম্বা" জিজ্ঞেস করলে, বাকি তিনজনের সঠিক উচ্চতা না জেনেও শুধু সবচেয়ে লম্বা জনের নামটা মনে রাখলেই চলে — এটাই Max Pooling। আর প্রশ্ন যদি হয় "দলের গড় উচ্চতা কত", তাহলে সবার উচ্চতা যোগ করে ভাগ করতে হয় — এটাই Average Pooling। দুটো ক্ষেত্রেই ৪ জনের তথ্যকে ১টা সংখ্যায় সংক্ষিপ্ত করা হচ্ছে, শুধু "কোন তথ্যটা রাখা হচ্ছে" তার নিয়ম আলাদা।
সহজ কথা: positive বা ধনাত্মক মানগুলো কোনো পরিবর্তন ছাড়াই সম্পূর্ণভাবে পার হয়ে যায়; আর negative বা ঋণাত্মক মানগুলো কেটে ঠিক শূন্য (0) করে দেওয়া হয়।
এটি কেন প্রয়োজন: ReLU অত্যন্ত সস্তা বা কম খরচে নন-লিনিয়ারিটি যোগ করে — এখানে শুধু একটি কম্প্যারিসন বা তুলনা করতে হয় — এবং সিগময়েড বা tanh-এর মতো এটি খুব বড় পজিটিভ মানের জন্য স্যাচুরেট বা ফ্ল্যাট হয়ে যায় না। ঠিক এই কারণে এটি ডিপ নেটওয়ার্কের ভ্যানিশিং-গ্রেডিয়েন্ট সমস্যা এড়াতে সাহায্য করে।

যেখানে: হলো ক্লাসের জন্য প্রাপ্ত raw স্কোর (logit), এবং হলো মোট ক্লাসের সংখ্যা।
সহজ কথা: সফটম্যাক্স যেকোনো raw স্কোরের ভেক্টরকে একটি বৈধ প্রোবাবিলিটি ডিস্ট্রিবিউশনে বা সম্ভাবনার বিন্যাসে রূপান্তর করে — যেখানে প্রতিটি আউটপুটের মান ০ থেকে ১-এর মধ্যে থাকে এবং ভেক্টরের সবগুলোর যোগফল ঠিক ১ হয়।
এটি কেন প্রয়োজন: এটি মাল্টি-ক্লাস ক্লাসিফায়ারের একদম শেষ লেয়ারে ব্যবহার করা হয় যাতে মডেলের প্রেডিকশনগুলোকে সরাসরি ক্লাস প্রোবাবিলিটি বা সম্ভাবনা হিসেবে সহজে পড়া যায়, raw বিভ্রান্তিকর স্কোরের বদলে।
যেখানে: হলো ওয়ান-হট আকারে থাকা আসল লেবেল (সঠিক ক্লাসের জন্য ১, অন্য সবার জন্য ০), এবং হলো সফটম্যাক্স থেকে পাওয়া মডেলের প্রেডিক্টেড প্রোবাবিলিটি।
সহজ কথা: যেহেতু আসল লেবেল সঠিক ক্লাস ছাড়া অন্য সব জায়গায় ০, তাই এই সম্পূর্ণ যোগফলটি শেষমেশ একটিমাত্র পদে নেমে আসে: । সঠিক ক্লাসের জন্য মডেলের প্রেডিক্টেড প্রোবাবিলিটি যত শূন্যের দিকে নামবে, -এর মান তত অবাস্তবভাবে বড় হতে থাকবে — অর্থাৎ ভুল উত্তরের ক্ষেত্রে মডেল যত বেশি আত্মবিশ্বাসী হবে, তাকে তত বেশি লস বা শাস্তি দেওয়া হবে।
এটি কেন প্রয়োজন: ক্রস-এন্ট্রপি ক্লাসিফিকেশনের জন্য স্ট্যান্ডার্ড লস ফাংশন কারণ এর ডেরিভেটিভ সফটম্যাক্সের সাথে মিলে অত্যন্ত সহজ ও স্থিতিশীল রূপে পরিণত হয়।
যেখানে: হলো ধাপে থাকা কোনো একটি ওয়েট, হলো লার্নিং রেট, এবং হলো ওই ওয়েটের সাপেক্ষে লসের গ্রেডিয়েন্ট।
সহজ কথা: গ্রেডিয়েন্ট নির্দেশ করে লস সবচেয়ে দ্রুত কোন দিকে বাড়ে, তাই তার বিপরীত বা opposite দিকে সামান্য সরে যাওয়াটাই হলো লস কমানোর সবচেয়ে সরাসরি রাস্তা। নিয়ন্ত্রণ করে সেই সরে যাওয়ার পদক্ষেপটি ঠিক কত বড় হবে।
এটি কেন প্রয়োজন: নেটওয়ার্কের প্রতিটি ওয়েটের ওপর প্রয়োগ করা এই একটিমাত্র আপডেট নিয়মই মূলত একটি CNN-কে "শিখতে" সাহায্য করে — যা কোটি কোটি ওজনকে ধীরে ধীরে এমন মানে নিয়ে যায় যেখানে ট্রেনিং লস সবচেয়ে কম হয়।
সহজ কথা: আউটপুটে পরিমাপ করা লস বা ত্রুটিকে চেইন রুল (chain rule) প্রয়োগ করে এক লেয়ার থেকে আরেক লেয়ারে পেছনের দিকে প্রবাহিত করা হয়। এটি নেটওয়ার্কটিকে হিসাব করতে সাহায্য করে যে আউটপুট থেকে যত দূরেই থাকুক না কেন, প্রতিটি একক ওয়েট চূড়ান্ত লসের ক্ষেত্রে ঠিক কতটা ভূমিকা রেখেছিল, নিজে হাতে আলাদা আলাদা সমীকরণ না লিখেই।
এটি চ্যাপ্টারে আপনার শুধু এটি মনে রাখাই যথেষ্ট যে চেইন রুলই মূলত ব্যাকপ্রোপাগেশন পরিচালনা করে। তবে কনভোলিউশন ও পুলিং লেয়ারের ভেতর দিয়ে গ্রেডিয়েন্ট কীভাবে পেছনের দিকে প্রবাহিত হয় — যা ডেন্স লেয়ারের চেয়ে কিছুটা আলাদা — সে সম্পর্কে আমরা ব্যাকপ্রোপাগেশন চ্যাপ্টারে সম্পূর্ণ গাণিতিক ব্যাখ্যা সহ বিস্তারিত জানব।
শুধু সমষ্টির (summation) সমীকরণের দিকে তাকিয়ে থাকার চেয়ে, ফর্মুলাটা চলমান কোড হিসেবে দেখলে জিনিসটা মাথায় অনেক দ্রুত গেঁথে যায়।
import numpy as np
def conv2d_single_channel(image, kernel, stride=1, padding=0):
"""একটি একক চ্যানেলের জন্য সাধারণ 2D কনভোলিউশন (ক্রস-কোরিলেশন)।"""
if padding > 0:
image = np.pad(image, padding, mode="constant")
n = image.shape[0]
f = kernel.shape[0]
out_size = (n - f) // stride + 1
output = np.zeros((out_size, out_size))
for i in range(out_size):
for j in range(out_size):
row, col = i * stride, j * stride
patch = image[row:row + f, col:col + f]
output[i, j] = np.sum(patch * kernel) # উপাদান-ভিত্তিক গুণ, তারপর সমষ্টি
return output
image = np.arange(49).reshape(7, 7).astype(float)
edge_kernel = np.array([[1, 0, -1],
[1, 0, -1],
[1, 0, -1]])
result = conv2d_single_channel(image, edge_kernel, stride=1, padding=0)
print("আউটপুট সাইজ বা Shape:", result.shape) # (5, 5), যা ওপরে আলোচনা করা বাস্তব উদাহরণের সাথে মিলে যায়এখানের out_size lineটি হলো আগে আলোচনা করা আউটপুট সাইজের গাণিতিক ফর্মুলা, এবং নেস্টেড লুপের ভেতরের np.sum(patch * kernel) হলো ডিসক্রিট কনভোলিউশন অপারেশনের কোড রূপ।
ওপরের প্রধান আটটি সমীকরণ — Convolution, Output Size, Conv Parameter Count, Max/Average Pooling, ReLU, Softmax, Cross-Entropy, Gradient Descent Update — এক পাতায় লিখে রাখুন। পরীক্ষায় বা ইন্টারভিউতে আসা CNN গাণিতিক প্রশ্নগুলোর প্রায় ৮০% এই সমীকরণগুলো দিয়েই সমাধান করা যায়।
সমীকরণের শেষের বাদ দিয়ে ফেলা খুবই কমন একটি অফ-বাই-ওয়ান (off-by-one) ভুল — সবসময় ফিল্টারের কোনো পদক্ষেপ নেওয়ার আগের প্রথম পজিশনটি হিসেবের মধ্যে রাখতে হবে।
শুধু হিসাব করে ফেলা এবং প্রতি ফিল্টারে একটি করে অতিরিক্ত বায়াস যোগ করতে ভুলে যাওয়া আরেকটি বড় ভুল। বড় হলে এটি সামগ্রিক হিসাবে অমিল তৈরি করতে পারে।
যেকোনো ফ্রেমওয়ার্কের Conv2d লেয়ার, MaxPool2d বা CrossEntropyLoss কল করার অর্থই হলো মূলত এই চ্যাপ্টারের আলোচনা করা সমীকরণগুলোর কোনো একটিকে সচল করা — এখানে কোনো কিছুই কেবল তাত্ত্বিক সাজসজ্জা নয়। এই ফর্মুলা শিটটি মাথায় রেখে, আমরা পরবর্তী চ্যাপ্টারে একটি raw ছবিকে একদম প্রথম পিক্সেল থেকে শুরু করে শেষ পর্যন্ত প্রতিটি সমীকরণ প্রয়োগ করে একটি বাস্তব উদাহরণের সাহায্যে ট্রেস করে দেখব।