Chapter 8 of 18
Forward pass, backpropagation through time, and weight updates — by hand
"Mathematics of LSTM" চ্যাপ্টারে আমরা প্রতিটি গ্রেডিয়েন্ট সমীকরণ হাতে-কলমে বের করেছিলাম। এই চ্যাপ্টারে আমরা সেই সমীকরণগুলোকে লাইন বাই লাইন কোডে রূপান্তর করবো — যেখানে কোনো মেশিন লার্নিং ফ্রেমওয়ার্ক ছাড়া সম্পূর্ণ স্ক্র্যাচ থেকে একটি কার্যকর ও ট্রেইনেবল LSTM মডেল তৈরি করা হবে NumPy ব্যবহার করে। আমাদের মূল লক্ষ্য কিন্তু কোনো প্রোডাকশন-গ্রেড কোড লেখা নয়; বরং সমীকরণ এবং কোডের মধ্যকার মিলগুলোকে এত স্পষ্টভাবে তুলে ধরা যাতে আপনি কোড দেখলেই সমীকরণ এবং সমীকরণ দেখলেই কোড মেলাতে পারেন।
ইনপুট -এর জন্য আলাদা ওয়েট ম্যাট্রিক্স এবং হিডেন স্টেট -এর জন্য আলাদা ওয়েট ম্যাট্রিক্স ব্যবহার করার বদলে, আমরা এই দুটি ওয়েট ম্যাট্রিক্সকে একসাথে জুড়ে দিয়ে শেপের একটি একক ম্যাট্রিক্স তৈরি করি। একই সাথে ও -কে উলম্বভাবে জুড়ে (concatenate) দিয়ে শেপের একটি একক ভেক্টর তৈরি করি। এর ফলে প্রতি গেটের জন্য দুটি আলাদা ম্যাট্রিক্স গুণের বদলে কেবল একটি ম্যাট্রিক্স গুণ করলেই চলে — যা গাণিতিকভাবে সম্পূর্ণ এক হলেও Keras-এর ভেতরে ঠিক এভাবেই এটি ইমপ্লিমেন্ট করা হয়:
প্রতিটি ওয়েট ম্যাট্রিক্সকে * scale দিয়ে গুণ করে ইনিশিয়ালাইজ করা হয়েছে — যেখানে scale = 1/sqrt(hidden_size)। ট্রেনিংয়ের শুরুতে ওয়েট খুব বেশি বড় রাখলে গেটের প্রি-অ্যাক্টিভেশনগুলো সরাসরি সিগময়েড/tanh-এর স্যাচুরেটেড অঞ্চলে (যেখানে গ্রেডিয়েন্ট শূন্যের কাছাকাছি থাকে) চলে যাবে, যার ফলে শুরুতেই লার্নিং বা ট্রেনিং থমকে যাবে।
কোডের dC_next = dC * f লাইনটিই হলো LSTM পেপারের সেই বিখ্যাত কনস্ট্যান্ট এরর ক্যারোসেল (constant error carousel)। আগের টাইম স্টেপের সেল স্টেটে ফিরে যাওয়া গ্রেডিয়েন্টটি হলো কেবল বর্তমান সেল-স্টেটের গ্রেডিয়েন্টের সাথে ফরগেট গেটের উপাদান-ভিত্তিক গুণ। এখানে কোনো ওয়েট ম্যাট্রিক্সের জটিল গুণফল নেই, কোনো অ্যাক্টিভেশন ডেরিভেটিভের তীব্র সংকোচন নেই। কোডের এই একটি মাত্র লাইনই বাস্তবায়ন করে কেন LSTM দীর্ঘ সিকোয়েন্স জুড়ে গ্রেডিয়েন্ট ধরে রাখতে পারে।
আপনি দেখতে পাবেন যে ৩০০টি এপক (epoch) চলার পর লস ক্রমাগত কমছে। শেষ ৩০টি এপকের গড় লস প্রথম দিকের চেয়ে উল্লেখযোগ্যভাবে কম হবে — যা প্রমাণ করে সম্পূর্ণ হাতে তৈরি এই LSTM সফলভাবে শিখতে পারছে।
forward() মেথডের প্রতিটি গেটের লাইন আমাদের শেখা ৬টি গাণিতিক সূত্রের সাথে হুবহু মিলে যায়। দুজনকে পাশাপাশি রেখে মিলিয়ে দেখুন।C = f * C + i * c_tilde সমীকরণে প্লাস + চিহ্ন ব্যবহৃত হয়েছে, স্টার * নয়। এটি স্ক্র্যাচ থেকে তৈরি করার সময় নতুনদের সবচেয়ে বেশি করা ভুল।backward() মেথডের reversed() লুপটি — BPTT মূলত সময়ের উল্টো দিকে হেঁটে কাজ করে।dWf, dWi, ইত্যাদি) লুপের শুরুতে শূন্যে সেট করা হয় এবং প্রতিটি টাইম স্টেপের গ্রেডিয়েন্ট এর সাথে যোগ করা হয়, এবং সব শেষে একবার আপডেট করা হয়। এটি BPTT-এর শেয়ার্ড ওয়েট নিয়মের প্র্যাকটিক্যাল রূপ।[x_t; h_{t-1}] কে একসাথে জুড়ে দেওয়া) ব্যবহার করা গাণিতিকভাবে আলাদা W ও U ম্যাট্রিক্স ব্যবহারের সমান, তবে এটি প্রতি গেটের জন্য দুটি ম্যাট্রিক্স গুণের বদলে মাত্র একটি গুনেই কাজ সম্পন্ন করে।dC_next = dC * f দিয়ে dC-কে পেছনে পাঠানো।dC_next = dC * f — কনস্ট্যান্ট এরর ক্যারোসেল বাস্তবায়ন করে: আগের সেল স্টেটে ফেরত যাওয়া গ্রেডিয়েন্টে কোনো ম্যাট্রিক্স গুণ বা স্যাচুরেশন থাকে না।1/sqrt(hidden_size) দিয়ে স্কেল করে নেওয়া অত্যন্ত জরুরি।স্ক্র্যাচ থেকে তৈরি এই ইমপ্লিমেন্টেশনটি মূলত একটি ডায়াগনস্টিক টুল। Keras-এ ট্রেন করা কোনো প্রোডাকশন মডেল যদি অদ্ভুত আচরণ করে — যেমন গেট সব স্যাচুরেটেড হয়ে যাওয়া, গ্রেডিয়েন্ট এক্সপ্লোড করা বা লস আটকে থাকা — তখন এই কোডটিই আপনাকে স্পষ্টভাবে বুঝিয়ে দেয় যে কোথায় ভুল হচ্ছে। এটি আপনাকে যেকোনো ফ্রেমওয়ার্কের সোর্স কোড সহজে পড়তে এবং প্রয়োজনে কাস্টম গেটিং মেকানিজম বা কাস্টম সেল তৈরি করতে প্রস্তুত করে তুলবে।