ফোনে লার্জ ল্যাঙ্গুয়েজ মডেল (LLM) চালানো এখন আর কোনো গবেষণামূলক পরীক্ষা নয়। এটি এখন একটি বাস্তব পণ্য হিসেবে বাজারে আসার বাস্তবতা। তবুও, আপনি যখন একটি সাধারণ ডেমো থেকে একটি প্রকৃত পণ্যে উন্নীত হন, তখন ল্যাটেন্সি (latency) আবারও প্রকট হয়ে ওঠে। আপনি মডেলটি ট্রিম করেছেন, ওয়েটগুলো (weights) কোয়ান্টাইজ করেছেন, তবুও প্রিফিল (prefill) পর্যায়টি ধীর হয়ে যায়। টোকেনগুলো আটকে যায়। ইউআই (UI) ফ্রিজ হয়ে যায়। এর দোষ খুব কমই সেখানে দেওয়া হয় যেখানে আসলে দেওয়া উচিত।
অ্যান্ড্রয়েড ডিভাইসে, LLM প্রিফিলের সময় কম্পিউট (compute) প্রায় কখনোই বাধা (bottleneck) হয়ে দাঁড়ায় না। বাধা হয়ে দাঁড়ায় মেমরি ব্যান্ডউইথ (memory bandwidth)। আধুনিক ফ্ল্যাগশিপ SoC-গুলোতে শক্তিশালী GPU এবং NPU কোর থাকে যা মেমরি সাবসিস্টেম তাদের ডেটা সরবরাহ করার চেয়ে অনেক দ্রুত গাণিতিক কাজ সম্পন্ন করতে পারে। আপনি যখন একটি সাধারণ (naive) অ্যাটেনশন ইমপ্লিমেন্টেশন প্রোফাইল করেন, তখন দেখা যায় এক্সিকিউশন ইউনিটগুলো সম্পৃক্ত (saturated) হচ্ছে না। তারা অপেক্ষা করছে। DRAM-এর জন্য অপেক্ষা করছে।
কেন আপনার কোয়ান্টাইজড মডেলটি এখনও ধীর মনে হয়
অন-ডিভাইস ইনফারেন্সের (on-device inference) জন্য কোয়ান্টাইজেশন এখন ডিফল্ট প্রথম পদক্ষেপ হয়ে দাঁড়িয়েছে। FP16 থেকে INT8-এ ওয়েটগুলো ছোট করার ফলে মডেলের আকার অর্ধেক হয়ে যায় এবং স্টোরেজ কমে। এটি সাহায্য করে। কিন্তু এটি অ্যাটেনশন লেয়ারের ল্যাটেন্সি সমাধান করে না। কারণটি সহজ: কোয়ান্টাইজেশন আপনি যে পরিমাণ ডেটা সংরক্ষণ করেন তা কমিয়ে দেয়, কিন্তু এটি অ্যাটেনশন মেকানিজম কতবার মেমরি ট্রানজ্যাকশন করছে তা কমায় না।
পাঠ্যপুস্তকীয় পদ্ধতিতে ইমপ্লিমেন্ট করা একটি স্ট্যান্ডার্ড মাল্টি-হেড অ্যাটেনশন লেয়ার প্রতিটি লেয়ারের জন্য DRAM-এ তিনটি সম্পূর্ণ রাউন্ড ট্রিপ করে। Query, Key, এবং Value ম্যাট্রিক্সগুলো মেইন মেমরি থেকে পড়া হয়, স্কোর গণনা করা হয় এবং মধ্যবর্তী ফলাফলগুলো পুনরায় লিখে রাখা হয়। গাণিতিক কাজগুলো খুব সহজ। কিন্তু ডেটা মুভমেন্ট অত্যন্ত কঠিন। অ্যান্ড্রয়েডে, যেখানে পাওয়ার এবং থার্মাল বাজেট সীমিত, এই প্যাটার্নটি মেমরি বাসকে (memory bus) বিপর্যস্ত করে তোলে। প্রসেসরটি কার্যত একই ব্রিজ পার হওয়ার জন্য তিনবার টোল দিচ্ছে।
আপনি যদি INT8 মডেল শিপ করছেন এবং ভাবছেন কেন প্রম্পটের দৈর্ঘ্যের সাথে প্রিফিল ধাপটি এখনও কোয়াড্রাটিকভাবে (quadratically) বৃদ্ধি পাচ্ছে, তবে উত্তরটি এটিই। ওয়েটগুলো ছোট হলেও অ্যাক্টিভেশন ট্রাফিক (activation traffic) বিশাল থাকে।
বাধাটি মেমরিতে, গণিতে নয়
সমাধানটি বুঝতে হলে রুফলাইন (roofline) দেখুন। Snapdragon 8 Gen 3 এবং Dimensity 9300-এর মতো চিপের মোবাইল GPU এবং NPU-গুলোর তাত্ত্বিক কম্পিউট থ্রুপুট (compute throughput) তাদের LPDDR5X ইন্টারফেসের ধারণক্ষমতার চেয়ে অনেক বেশি। একটি সাধারণ অ্যাটেনশন কার্নেলে, প্রতিটি হেড Q এবং K-এর গুণফলের ওপর softmax গণনা করে, তারপর V দিয়ে গুণ করে। প্রতিটি মধ্যবর্তী স্কোর ম্যাট্রিক্স গ্লোবাল মেমরিতে materialize হয়। এর মানে হলো আপনার পিক DRAM রিড সিকোয়েন্স দৈর্ঘ্যের বর্গের সাথে বা O(n²) হারে বৃদ্ধি পায়। ১০২৪-টোকেন প্রম্পটের জন্য, মেমরি ট্রাফিক ইতিমধ্যেই এক্সিকিউশন টাইমকে প্রভাবিত করার মতো যথেষ্ট বড়।
কোরগুলো অপব্যবহার হচ্ছে (underutilized) কারণ তারা ল্যাটেন্সি লুকাতে পারে না। আধুনিক প্রসেসরগুলো পাইপলাইন পূর্ণ রাখতে ক্যাশ (cache)-এর ওপর নির্ভর করে। যখন একটি অ্যালগরিদম ক্রমাগত ক্যাশে মিস করে এবং DRAM থেকে ডেটা নিয়ে আসে, তখন এক্সিকিউশন ইউনিটগুলো অলস বসে থাকে। কোয়ান্টাইজেশনের মাধ্যমে কম্পিউট ক্ষমতা এবং মেমরি সরবরাহের মধ্যে এই কাঠামোগত অমিল দূর করা সম্ভব নয়।
কীভাবে টাইলিন (Tiling) ব্যান্ডউইথ পুনরুদ্ধার করে
সমাধান হলো একটি টাইলিন কৌশল যা মধ্যবর্তী স্কোরগুলোকে DRAM-এ পাঠানোর পরিবর্তে অন-চিপ SRAM-এ রাখে। এটি সেই একই ধারণা যা Flash Attention-কে চালিত করে, যা অ্যান্ড্রয়েডের কম্পিউট স্ট্যাকের জন্য অভিযোজিত। মেমরিতে একটি পূর্ণ n × n স্কোর ম্যাট্রিক্স তৈরি করার পরিবর্তে, আপনি গণনাটিকে ছোট ছোট টাইলে বিভক্ত করেন যা L1 ক্যাশের মধ্যে এঁটে যায়। আপনি লোকাল softmax পরিসংখ্যান গণনা করেন, চলমান ম্যাক্স ভ্যালু এবং নরমালাইজেশন সাম (normalization sums) জমা করেন এবং শুধুমাত্র চূড়ান্ত ওয়েটেড আউটপুটগুলো মেমরিতে ফেরত লেখেন।
এটি ব্যান্ডউইথ জটিলতা পরিবর্তন করে দেয়। পিক DRAM রিড O(n²) থেকে কমে O(n) হয়ে যায়, কারণ আপনাকে আর মেইন মেমরির মাধ্যমে পূর্ণ স্কোর ম্যাট্রিক্স আদান-প্রদান করতে হয় না। মূল কাজগুলো এক্সিকিউশন ইউনিটের ঠিক পাশেই SRAM-এর ভেতরে ঘটে।
একটি বাস্তব উদাহরণ হিসেবে, ৬৪ সাইজের একটি টাইল এবং ১২৮ সাইজের একটি হেড ডাইমেনশন বিবেচনা করুন। স্কোর টাইলটি ১৬ KB জায়গা নেয়। এই ফুটপ্রিন্টটি Snapdragon 8 Gen 3 এবং Dimensity 9300-এর মতো বর্তমান ফ্ল্যাগশিপ SoC-গুলোর L1 ক্যাশের মধ্যে অনায়াসেই এঁটে যায়। গাণিতিক কাজগুলো লোকাল থাকে। মেমরি বাস স্বাচ্ছন্দ্যে কাজ করতে পারে।
এটি অ্যান্ড্রয়েডে ইমপ্লিমেন্ট করা
অ্যালগরিদমিক স্কেচটি সহজ, যদিও খুঁটিনাটি বিষয়গুলো সঠিকভাবে করা গুরুত্বপূর্ণ।
আপনার Query, Key-কে বিভক্ত করুন
