TinyML: नन्हीं चिप्स पर AIमध्यमपाठ 2785 मिनट का पाठ

फ़िट करने के लिए इसे छोटा करना

int8 quantisation हर वज़न (weight) को चार बाइट्स के बजाय एक बाइट में स्टोर करता है। इसे खुद numpy में करके देखें, और मापें कि आपने कितना साइज़ बचाया और कितनी एक्यूरेसी खोई।

पाठ वीडियो में

60 सेकंड में

फ़िट करने के लिए इसे छोटा करना

int8 quantisation हर वज़न (weight) को चार बाइट्स के बजाय एक बाइट में स्टोर करता है। इसे खुद numpy में करके देखें, और मापें कि आपने कितना साइज़ बचाया और कितनी एक्यूरेसी खोई।

1/5
आसान शब्दों में
कल्पना करें कि हर छात्र की लंबाई मिलीमीटर के दसवें हिस्से तक नापी जा रही है। यह बहुत ज़्यादा लिखना पड़ेगा, और किसी को इसकी ज़रूरत भी नहीं है। यदि आप इसे निकटतम सेंटीमीटर में राउंड कर देते हैं, तो हर संख्या छोटी हो जाती है, और फिर भी आप सभी को सही क्रम में खड़ा कर सकते हैं। Quantisation किसी मॉडल की संख्याओं को राउंड करता है ताकि वे कम जगह लें, जबकि मॉडल ज़्यादातर समय वही सही जवाब देता रहता है।
किसी ट्रेंड मॉडल के weights आमतौर पर float32 संख्याएँ होते हैं: प्रत्येक 4 बाइट्स का। int8 प्रत्येक weight को −128 से 127 तक की एक पूर्ण संख्या (whole number) के रूप में, 1 बाइट में स्टोर करता है। इससे weights चार गुना छोटे हो जाते हैं। कई microcontrollers पर, int8 मैथ्स तेज़ भी होता है और कम ऊर्जा का उपयोग करता है।

सिमेट्रिक int8 quantisation, सिलसिलेवार तरीके से

  1. 1

    सबसे बड़ा weight खोजें

    लेयर में सबसे बड़ा absolute मान लें, उदाहरण के लिए 1.3।
  2. 2

    एक scale चुनें

    scale = सबसे बड़ा ÷ 127। अब int8 में 127 का मतलब सबसे बड़ा weight है।
  3. 3

    भाग दें और राउंड करें

    q = round(weight ÷ scale), जिसे −127 … 127 तक क्लिप किया गया है, int8 के रूप में स्टोर करें।
  4. 4

    इसका उपयोग करें

    लगभग वैसा ही weight वापस पाने के लिए: weight ≈ q × scale। इसमें एरर ज़्यादा से ज़्यादा आधे स्टेप (step) की होती है।
Python: quantise six weights and check the errorpython
import numpy as np

w = np.array([0.83, -0.312, 0.051, -1.3, 0.644, 0.002])
scale = np.abs(w).max() / 127          # one float for the whole layer
q = np.round(w / scale).astype(np.int8)
back = q * scale

print("scale:", round(scale, 5))
print("int8: ", q)
print("back: ", back.round(4))
print("error:", np.abs(w - back).round(4))
प्रत्येक weight ज़्यादा से ज़्यादा आधे scale जितना बदला। अपने आकार के अनुपात में, सबसे छोटे weights को सबसे ज़्यादा नुकसान होता है। आखिरी weight, 0.002, 0 बन गया: यह आधे स्टेप से छोटा था।

असली TinyML quantisation कुछ और भी चीज़ें करता है

  • Activations भी। चिप पर, इनपुट्स और बीच के मान भी int8 होते हैं, ताकि पूरा मॉडल integer मैथ्स में चले। कन्वर्टर को उनके लिए scales चुनने के लिए असली उदाहरण इनपुट्स के एक छोटे सेट की ज़रूरत होती है, जिसे अक्सर representative dataset कहा जाता है।
  • Zero points। जो मान शून्य पर केन्द्रित नहीं होते (उदाहरण के लिए, सभी पॉज़िटिव), वे zero point नामक एक अतिरिक्त ऑफ़सेट का उपयोग करते हैं, ताकि int8 रेंज बेकार न जाए।
  • Per-channel scales। किसी लेयर का प्रत्येक आउटपुट चैनल अपना खुद का scale प्राप्त कर सकता है, जिससे आमतौर पर पूरी लेयर के लिए एक scale रखने की तुलना में कम एक्यूरेसी खोती है।
  • Biases को अक्सर उच्च प्रिसिजन (उदाहरण के लिए int32) पर रखा जाता है, क्योंकि वे कम होते हैं और बहुत मायने रखते हैं।
  • Quantisation-aware training मॉडल को ट्रेनिंग के दौरान राउंडिंग के साथ अभ्यास करने देती है, जो ट्रेनिंग के बाद साधारण राउंडिंग से होने वाले भारी एक्यूरेसी नुकसान की भरपाई कर सकती है।
नोट
पिछला पाठ व्यवहार में Quantisation फ़ोन और लैपटॉप पर बड़े मॉडलों को quantise करने के बारे में बताता है। विचार वही है। एक microcontroller पर, मेमोरी की कमी और कई चिप्स के फ्लोटिंग पॉइंट में धीमे होने के कारण, पूर्ण int8 आमतौर पर एक विकल्प नहीं, बल्कि एक ज़रूरत होता है।
लापरवाही से छोटा करना
  • बिना मापे quantise करना और डिप्लॉय कर देना
  • केवल कुल एक्यूरेसी जाँचना
  • कुछ रैंडम इनपुट्स को representative dataset के रूप में उपयोग करना
  • मान लेना कि Python और बोर्ड एक ही जवाब देंगे
सावधानीपूर्वक छोटा करना
  • पहले और बाद के साइज़ तथा हेल्ड-आउट डेटा पर एक्यूरेसी को मापना
  • प्रत्येक क्लास को जाँचना, खासकर दुर्लभ (rare) वाली
  • ऐसे वास्तविक इनपुट्स का उपयोग करना जो उन सभी स्थितियों को कवर करते हैं जो डिवाइस देखेगा
  • समान इनपुट्स पर बोर्ड के आउटपुट्स की तुलना Python के आउटपुट्स से करना
सावधान रहें
यदि quantisation के बाद एक्यूरेसी बहुत गिर जाती है, तो इसे यूँ ही स्वीकार न करें। ऐसी लेयर की जाँच करें जिसमें कुछ बहुत बड़े weights हों (एक भी आउटलायर scale को बड़ा और बाकी सभी weights को रफ बना देता है), per-channel scales आज़माएँ, या quantisation-aware training आज़माएँ। अपने टूल के मौजूदा दस्तावेज़ों में देखें कि वह किन विकल्पों का समर्थन करता है।
इसे आज़माएँ। ऊपर दिए गए कोड में, 1.3 को 13.0 में बदलें। राउंडिंग के बाद अन्य weights का क्या होता है? यही कारण है कि एक आउटलायर पूरी लेयर को नुकसान पहुँचा सकता है।

और देखें और पढ़ें

लैब

आपके अपने int8 quantise और dequantise फ़ंक्शन्स, जिसमें बचाए गए साइज़ और एक्यूरेसी में हुए बदलाव को मापा गया हो।

~25 min

समस्या

स्टार्टर कोड scikit-learn के इन-बिल्ट 8×8 हस्तलिखित अंकों पर एक छोटा न्यूरल नेटवर्क ट्रेन करता है: एक मीटर डिस्प्ले को पढ़ने वाले छोटे कैमरे का विकल्प।

  1. quantise(w) लिखें: scale = सबसे बड़ा absolute weight ÷ 127; q = round(w ÷ scale), जिसे np.int8 के रूप में −127 … 127 तक क्लिप किया गया हो। (q, scale) रिटर्न करें।
  2. dequantise(q, scale) लिखें: floats के रूप में q × scale रिटर्न करें।
  3. इसे रन करें। पहले और बाद के weights का साइज़ बाइट्स में, और पहले और बाद की एक्यूरेसी लिखें।
  4. यहाँ केवल weights को quantise किया गया है; biases float ही रहते हैं। एक वाक्य लिखें कि एक वास्तविक बोर्ड activations को भी quantise क्यों करेगा।

प्रैक्टिस लैब

कोड में बदलाव करें और इसे रन करें। Python आपके ब्राउज़र में चलता है — हमारे सर्वर पर कुछ नहीं भेजा जाता।

आउटपुट

कोई आउटपुट नहीं। वैल्यूज़ देखने के लिए print(...) जोड़ें।

आपका काम तब पूरा होगा जब

कठिन सवाल

उत्तर देखने से पहले ख़ुद जवाब देने की कोशिश करें। अगर आप इनके जवाब दे सकते हैं, तो आप पाठ समझ गए हैं।

Q1हम केवल दशमलव हटाने (कट ऑफ़ करने) के बजाय राउंड क्यों करते हैं?दिखाएं

राउंडिंग निकटतम int8 मान चुनती है, इसलिए एरर ज़्यादा से ज़्यादा आधा स्टेप होती है। कट ऑफ़ (ट्रंकेट) करने से मान हमेशा शून्य की ओर चले जाते हैं, इसलिए एरर लगभग एक पूरा स्टेप हो सकती है और एक ही दिशा में बायस्ड हो सकती है। वह बायस कई weights में जुड़ता जाता है और एक्यूरेसी को अधिक नुकसान पहुँचाता है।

Q2आपका quantised मॉडल Python में सटीक है, लेकिन बोर्ड के जवाब अलग हैं। इसका क्या कारण हो सकता है?दिखाएं

हो सकता है कि बोर्ड इनपुट को अलग तरीके से quantise करता हो: एक अलग scale या zero point, या इनपुट को उसी तरह int8 में न बदला गया हो। रनटाइम लेयर्स के बीच activations को भी राउंड करता है, जो Python में केवल-weights वाला टेस्ट नहीं दिखाता है। दोनों में समान इनपुट दें, और कदम दर कदम इनपुट टेन्सर और आउटपुट्स की तुलना करें। कन्वर्टर के अपने टूल्स अक्सर इस तुलना के लिए आपके कंप्यूटर पर quantised मॉडल चला सकते हैं।

जारी रखने के लिए कृपया साइन इन करें।

अक्सर पूछे जाने वाले सवाल

क्या quantisation से हमेशा एक्यूरेसी कम होती है?

लगभग हमेशा थोड़ी बहुत, कभी-कभी इतनी कम कि आप माप भी नहीं सकते, और कभी-कभी बहुत ज़्यादा। यह मॉडल और डेटा पर निर्भर करता है। इसीलिए आप पहले और बाद में हेल्ड-आउट डेटा पर मापते हैं।

−127 से 127 ही क्यों, −128 से 127 क्यों नहीं?

सिमेट्रिक स्कीम्स अक्सर −127 से 127 का उपयोग करती हैं ताकि पॉज़िटिव और नेगेटिव मानों की रेंज समान हो और शून्य पूरी तरह से शून्य रहे। कुछ टूल्स विशेष मामलों के लिए −128 का उपयोग करते हैं। चाहे जो भी हो, आपका रनटाइम जो अपेक्षा करता है उसका पालन करें।

क्या मैं int8 से भी छोटा कर सकता हूँ?

कुछ रिसर्च और कुछ टूल्स प्रति weight 4-बिट या उससे भी कम बिट्स का उपयोग करते हैं, और कुछ चिप्स विशेष फ़ॉर्मेट्स का समर्थन करते हैं। यह अधिक जगह बचाता है लेकिन अधिक एक्यूरेसी खो देता है और microcontrollers पर इसका समर्थन कम है। int8 आज का सामान्य और अच्छी तरह से समर्थित विकल्प है; अपने टूल के दस्तावेज़ देखें।

quantisation के अलावा मॉडल को और क्या छोटा करता है?

कम या छोटी लेयर्स का उपयोग करना, कम इनपुट फ़ीचर्स, प्रूनिंग (कम महत्व वाले weights को हटाना) और डिस्टिलेशन (एक बड़े मॉडल की नकल करने के लिए एक छोटे मॉडल को ट्रेन करना)। TinyML के लिए, एक छोटे डिज़ाइन से शुरुआत करना आमतौर पर सबसे बड़ा फ़ायदा होता है।

पाठ का टेस्ट

5 सवाल। पास होने और इस पाठ को पूरा करने के लिए 3 सही होने चाहिए (60%)।

टेस्ट देने और अपनी प्रोग्रेस सेव करने के लिए साइन इन करें