मुख्य सामग्री पर जाएँ

LSTM मॉडल: लॉन्ग शॉर्ट-टर्म मेमोरी नेटवर्क्स की संपूर्ण मार्गदर्शिका

LSTM नेटवर्क्स के भीतर के कामकाज में महारत हासिल करें, जो आधुनिक LLMs की नींव हैं। गेटिंग मैकेनिज़्म, ग्रेडिएंट्स का अन्वेषण करें, और PyTorch के साथ एक सेंटिमेंट क्लासिफायर बनाएँ।
· 15 मि॰ पढ़ें

AI के साथ खोजें

मानक रिकरंट न्यूरल नेटवर्क्स को मेमोरी के साथ दिक्कत होती है। जैसे-जैसे अनुक्रमs 20-30 टाइमस्टेप्स से आगे बढ़ते हैं, ग्रेडिएंट्स बैकप्रोपेगेशन के दौरान या तो शून्य की ओर सिकुड़ते हैं या बहुत बढ़ जाते हैं, और नेटवर्क इनपुट के दूरस्थ हिस्सों को जोड़ने की क्षमता खो देता है। Hochreiter और Schmidhuber ने इस समस्या को अपने 1997 के पेपर में Long Short-Term Memory नेटवर्क्स पेश करके सुलझाया।

इस गाइड में, मैं Python में व्यावहारिक इम्प्लीमेंटेशन से पहले LSTM के आंतरिक हिस्सों से होकर चलूँगा। अंतिम अनुभागों में LSTM और Transformers की तुलना है ताकि आप अपने उपयोग के मामले के लिए सही आर्किटेक्चर चुन सकें।

मैं हमारी Introduction to Deep Learning in PyTorch कोर्स की कड़ी सिफारिश करता हूँ ताकि आपको PyTorch का उपयोग करके न्यूरल नेटवर्क्स ट्रेन करने का हैंड्स-ऑन अनुभव मिल सके, जो LSTM मॉडल्स का आधार हैं।

LSTM मॉडल क्या है?

LSTM का अर्थ Long Short-Term Memory है, जो एक प्रकार का रिकरंट न्यूरल नेटवर्क (RNN) है, जिसे ऐसे अनुक्रमों को संभालने के लिए डिज़ाइन किया गया है जहाँ इनपुट में काफी पहले आया संदर्भ भी मायने रखता है।

LSTM के पीछे मुख्य विचार एक गेटिंग मैकेनिज़्म है जो नेटवर्क के भीतर सूचना के प्रवाह को नियंत्रित करता है। सभी संकेतों को समान रूप से गुजरने देने के बजाय, गेट्स सीखते हैं कि कब संदर्भ को बनाए रखना है और कब उसे छोड़ देना है। 

यह चयनात्मक मेमोरी LSTM को सैकड़ों टाइमस्टेप्स में निर्भरताओं को ट्रैक करने देती है, जो भाषा मॉडलिंग, स्पीच रिकग्निशन और टाइम सीरीज़ फोरकास्टिंग के लिए उपयोगी साबित हुई। यह समझने के लिए कि यह आर्किटेक्चर क्यों मौजूद है, यह देखना मददगार है कि मानक RNNs में क्या टूटता है।

RNNs में वैनिशिंग ग्रेडिएंट समस्या

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

यह फोटोकोपी की फोटोकोपी बनाने जैसा है। कुछ बार करें, और कॉपी ठीक दिखती है। पचास बार करें, और आप पाठ मुश्किल से पढ़ पाएँगे। RNNs यह दीवार लगभग 20-30 टाइमस्टेप्स पर टकराते हैं, इसलिए वे लंबे अनुक्रमों के साथ संघर्ष करते हैं।

LSTM लंबे-अवधि की निर्भरताएँ कैसे सुलझाते हैं

LSTM एक अलग मेमोरी ट्रैक जोड़ते हैं, जिसे सेल स्टेट कहते हैं, जो मानक हिडन स्टेट के समानांतर चलता है। फर्क संरचनात्मक है: सेल स्टेट में सूचना गुणा के बजाय जोड़ के माध्यम से बहती है, इसलिए यह वैसा ही क्षय नहीं करती।

यह तय करने के लिए कि इस मेमोरी में क्या अंदर और बाहर जाए, LSTM गेट्स का उपयोग करते हैं। प्रत्येक गेट एक छोटा न्यूरल नेटवर्क है जो 0 और 1 के बीच मान आउटपुट करना सीखता है, एक फ़िल्टर की तरह कार्य करता है। 0 के पास का मान सूचना को रोकता है; 1 के पास का मान उसे गुजरने देता है। प्रशिक्षण के दौरान नेटवर्क सीखता है कि कौन-से पैटर्न लंबी अनुक्रमों में याद रखने लायक हैं और किन्हें छोड़ दिया जा सकता है।

यही गेटिंग मैकेनिज़्म LSTM को साधारण RNNs से अलग करता है। सभी जानकारी को एक ही रास्ते से गुजरने के लिए मजबूर करने के बजाय, LSTM सैकड़ों टाइमस्टेप्स में चयनात्मक रूप से संदर्भ को संरक्षित कर सकते हैं। अगला अनुभाग ठीक-ठीक बताता है कि ये गेट्स कैसे काम करते हैं और कैसे मिलकर सेल स्टेट को अपडेट करते हैं।

LSTM मॉडल के उपयोग के मामले

जहाँ भी क्रमिक डेटा मायने रखता है, वहाँ LSTM दिखते हैं। सामान्य NLP और फोरकास्टिंग एप्लिकेशंस से परे कुछ उदाहरण:

  • बैंक, रूल-बेस्ड सिस्टम्स से छूट जाने वाले फ्रॉड पैटर्न पकड़ने के लिए ट्रांज़ैक्शन अनुक्रमों को LSTM के माध्यम से चलाते हैं
  • अस्पताल द्विदिश LSTM के साथ ECG स्ट्रीम्स की निगरानी करते हैं, थ्रेशहोल्ड अलर्ट्स से तेज़ हृदय संबंधी विसंगतियों को पकड़ते हैं
  • स्मार्ट सिटी प्लेटफ़ॉर्म सेंसर फीड्स से ट्रैफ़िक और ऊर्जा मांग की भविष्यवाणी करते हैं, स्पाइक्स आने से पहले संसाधनों को समायोजित करते हैं
  • फैक्ट्रियाँ उपकरणों के वाइब्रेशन को समय के साथ ट्रैक करती हैं ताकि कुछ टूटने से पहले मेंटेनेंस शेड्यूल किया जा सके

LSTM आर्किटेक्चर: गेट्स और मेमोरी सेल्स

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

यह समझने के लिए कि LSTM कैसे काम करते हैं, हम एक ठोस उदाहरण ट्रेस करेंगे: "The clouds are dark..." अनुक्रम को प्रोसेस करना ताकि अगला शब्द अनुमान लगाया जा सके। जब आप देखते हैं कि प्रत्येक घटक वास्तविक डेटा के साथ क्या करता है, तो सब कुछ अधिक समझ में आता है।

LSTM में सेल स्टेट और हिडन स्टेट

एक LSTM नेटवर्क के माध्यम से दो अलग-अलग वेक्टर बनाए रखता है: सेल स्टेट और हिडन स्टेट।

सेल स्टेट लंबे-अवधि के भंडारण की तरह कार्य करता है। यह प्रत्येक चरण में नियंत्रित संशोधनों के साथ टाइमस्टेप्स में जानकारी ले जाता है। हमारे अनुक्रम को प्रोसेस करते समय, "clouds" देखने के बाद सेल स्टेट "मौसम-संबंधी संज्ञा आई" जैसी चीज़ स्टोर कर सकता है और उस संदर्भ को "are" के पार संरक्षित कर सकता है, जब तक कि "dark" उस पैटर्न को और मज़बूत न कर दे।

हिडन स्टेट प्रत्येक टाइमस्टेप पर सेल का आउटपुट होता है। यह प्रेडिक्शंस और अगले टाइमस्टेप की गणनाओं में फीड होता है। "dark" को प्रोसेस करने के बाद, हिडन स्टेट कुछ ऐसा एन्कोड करता है जैसे "मौसम की स्थिति बताने वाला विशेषण" जिसे एक प्रेडिक्शन लेयर उपयोग कर सकती है।

LSTM Cell

दो अलग-अलग ट्रैक्स क्यों? एकल स्टेट को एक साथ लंबे-अवधि के संदर्भ को भी धारण करना होगा और उपयोगी आउटपुट भी उत्पन्न करना होगा। ये लक्ष्य टकराते हैं: स्थिर मेमोरी के लिए न्यूनतम बदलाव चाहिए, जबकि उपयोगी आउटपुट के लिए रूपांतरण चाहिए। उन्हें अलग करने से प्रत्येक ट्रैक अपने उद्देश्य के लिए अनुकूलित हो सकता है।

प्रत्येक टाइमस्टेप पर, सेल तीन इनपुट लेता है और दो आउटपुट देता है:

इनपुट:

  • पिछला सेल स्टेट (C_{t-1}): अब तक नेटवर्क क्या याद रखता है

  • पिछला हिडन स्टेट (h_{t-1}): पिछले टाइमस्टेप का आउटपुट

  • वर्तमान इनपुट (x_t): नया टोकन, जैसे "clouds" या "dark"

आउटपुट:

  • अपडेटेड सेल स्टेट (C_t): इस टोकन को प्रोसेस करने के बाद की मेमोरी

  • नया हिडन स्टेट (h_t): इस टाइमस्टेप का आउटपुट

LSTM गेट्स कैसे गणना करते हैं

चार घटक तय करते हैं कि सेल के अंदर क्या होता है। इनमें से तीन गेट्स हैं जो 0 और 1 के बीच मान आउटपुट करते हैं, फ़िल्टर की तरह कार्य करते हैं। चौथा कैंडिडेट है, जो नया कंटेंट प्रस्तावित करता है।

जब "clouds" के बाद "are" आता है, तो प्रत्येक घटक का एक काम होता है:

  • फॉरगेट गेट (f_t): क्या हमें "clouds" का संदर्भ बनाए रखना चाहिए? लिंकिंग वर्ब के बाद आने वाली मौसम-संबंधी संज्ञाएँ आमतौर पर मायने रखती हैं, इसलिए फॉरगेट गेट अधिकतर सेल स्टेट को संरक्षित करने के लिए 1 के पास के मान आउटपुट करता है।

  • इनपुट गेट (i_t): "are" को मेमोरी में कितना योगदान देना चाहिए? लिंकिंग वर्ब में भविष्यवाणी के लिए कम संकेत होते हैं, इसलिए इनपुट गेट कम मान आउटपुट करता है।

  • कैंडिडेट (C̃_t): "are" कौन-सी नई जानकारी जोड़ सकता है? कैंडिडेट कंटेंट प्रस्तावित करता है, लेकिन इनपुट गेट उसे स्केल डाउन कर देता है।

  • आउटपुट गेट (o_t): हिडन स्टेट में क्या दिखना चाहिए? आउटपुट गेट सेल स्टेट को फ़िल्टर करके h_t बनाता है।

How LSTM gates compute

प्रत्येक घटक अपना आउटपुट एक ही तरह से गणना करता है:

  1. h_{t-1} और x_t को जोड़कर एक वेक्टर बनाएँ

  2. सीखे गए वेट मैट्रिक्स से गुणा करें

  3. एक बायस टर्म जोड़ें

  4. एक एक्टिवेशन फ़ंक्शन लागू करें

गेट्स सिग्मॉइड एक्टिवेशन का उपयोग करते हैं, जो मानों को 0-1 रेंज में दबा देता है। कैंडिडेट tanh का उपयोग करता है, आउटपुट vैल्यूज -1 और 1 के बीच देता है, ताकि वह सेल स्टेट में वृद्धि और कमी दोनों प्रस्तावित कर सके।

समीकरण

फॉरगेट गेट (सिग्मॉइड → 0 से 1):

इनपुट गेट (सिग्मॉइड → 0 से 1):

आउटपुट गेट (सिग्मॉइड → 0 से 1):

कैंडिडेट (tanh → -1 से +1):

प्रत्येक घटक का अपना वेट मैट्रिक्स होता है (W_f, W_i, W_c, W_o), इसलिए वे इनपुट में अलग-अलग पैटर्न पर प्रतिक्रिया देना सीखते हैं।

फ़िल्टरिंग कैसे काम करती है

गेट आउटपुट्स वेक्टरों के साथ पोज़िशन-बाय-पोज़िशन गुणा करते हैं (एलिमेंट-वाइज़ मल्टिप्लिकेशन, जिसे ⊙ के रूप में लिखा जाता है)। प्रत्येक डायमेंशन स्वतंत्र रूप से फ़िल्टर होता है।

यदि कोई गेट पोज़िशन 1 के लिए 0.9 आउटपुट करता है, तो वह डायमेंशन अपने मान का 90% रखता है। यदि वह पोज़िशन 4 के लिए 0.0 आउटपुट करता है, तो वह डायमेंशन मिट जाता है। "clouds are" के बाद "dark" को प्रोसेस करते हुए, फॉरगेट गेट उन डायमेंशनों के लिए उच्च मान आउटपुट कर सकता है जो संज्ञा/मौसम संदर्भ स्टोर करते हैं और उन डायमेंशनों के लिए कम मान जो अप्रासंगिक पहले के संदर्भ रखते हैं।

फॉरगेट, ऐड और आउटपुट गेट्स के बीच सूचना प्रवाह

घटक तीन चरणों में मिलकर सेल स्टेट को अपडेट करते हैं और हिडन स्टेट उत्पन्न करते हैं।

चरण 1: भूलना

फॉरगेट गेट पिछले सेल स्टेट को फ़िल्टर करता है:

"dark" को प्रोसेस करते हुए, फॉरगेट गेट "clouds" से मौसम संदर्भ को संरक्षित करता है जबकि उन डायमेंशनों को साफ़ करता है जो आर्टिकल "The" को ट्रैक कर रहे थे।

चरण 2: जोड़ना

इनपुट गेट कैंडिडेट के प्रस्ताव को स्केल करता है, फिर उसे फ़िल्टर्ड सेल स्टेट में जोड़ देता है:

कैंडिडेट "मौसम-संबंधी संज्ञा को संशोधित करने वाला विशेषण" जैसा कुछ प्रस्तावित कर सकता है, और इनपुट गेट तय करता है कि उसे मेमोरी में कितना मज़बूती से लिखना है। यही एडिटिव अपडेट (मल्टिप्लिकेटिव नहीं) प्रशिक्षण के दौरान ग्रेडिएंट्स के प्रवाह में मदद करता है।

चरण 3: आउटपुट

सेल स्टेट tanh से होकर गुजरता है, फिर आउटपुट गेट फ़िल्टर करता है कि हिडन स्टेट क्या बनेगा:

tanh मानों को सीमित रखता है। आउटपुट गेट यह चुनता है कि संचित मेमोरी के कौन-से पहलू इस टाइमस्टेप पर प्रेडिक्शंस के लिए दिखाई देने चाहिए।

पूरी शृंखला:

यहाँ 4-डाईमेंशनल सेल स्टेट के साथ एक सरल ट्रेस है:

चरण

इनपुट

सेल स्टेट (सरलीकृत)

क्या होता है

1

"The"

[0.1, 0.0, 0.2, 0.0]

न्यूनतम भंडारण; आर्टिकल्स में कम भविष्यसूचक संकेत होते हैं

2

"clouds"

[0.1, 0.7, 0.2, 0.3]

इनपुट गेट डायमेंशंस 2,4 के लिए खुलता है; संज्ञा पैटर्न स्टोर करता है

3

"are"

[0.1, 0.6, 0.2, 0.3]

फॉरगेट गेट ≈ 0.9 संदर्भ संरक्षित करता है; लिंकिंग वर्ब कम जोड़ता है

4

"dark"

[0.1, 0.8, 0.5, 0.6]

विशेषण, डायमेंशंस 2,3,4 में सिग्नल को मज़बूत करता है

टाइमस्टेप 4 तक, डायमेंशंस 2-4 ने एक पैटर्न जमा कर लिया है। हिडन स्टेट h_4 एक प्रेडिक्शन लेयर (LSTM का भाग नहीं) में फीड होता है, जो शब्दावली संभावनाएँ निकालती है। वह संचित पैटर्न मॉडल को "rain" या "sky" जैसे शब्दों को वरीयता देने में मदद करता है।

नेटवर्क मौसम को नहीं समझता। यह सांख्यिकीय सह-संबंध सीखता है: कुछ इनपुट अनुक्रमों के बाद अक्सर कुछ आउटपुट आते हैं।

प्रशिक्षण के दौरान ग्रेडिएंट प्रवाह

सेल स्टेट की एडिटिव संरचना मानक RNNs की तुलना में अधिक प्रत्यक्ष ग्रेडिएंट पाथ प्रदान करती है। यदि आप यह नहीं जानते कि ग्रेडिएंट्स न्यूरल नेटवर्क्स के माध्यम से कैसे फैलते हैं, तो बैकप्रोपेगेशन ट्यूटोरियल बुनियादी बातें कवर करता है।

मानक RNNs में, ग्रेडिएंट्स प्रत्येक चरण पर वेट मैट्रिक्स के माध्यम से बहते हैं। बार-बार गुणा होने से असर जुड़ता है: 100 चरणों के बाद यदि वेट्स औसतन 0.9 हैं, तो ग्रेडिएंट 0.9^100 ≈ 0.00003 तक सिमट जाता है।

LSTM सेल स्टेट के साथ एक वैकल्पिक पाथ प्रदान करते हैं। C_t का C_{t-1} के सापेक्ष डेरिवेटिव:

∂C_t/∂C_{t-1} = f_t

यह फॉरगेट गेट का मान है, कोई वेट मैट्रिक्स नहीं। जब फॉरगेट गेट्स 1 के पास रहते हैं, तो ग्रेडिएंट्स कम क्षय के साथ पास होते हैं। यदि गेट्स औसतन 0.95 हों, तो 100 चरणों के बाद: 0.95^100 ≈ 0.006। अभी भी घटा हुआ, पर उपयोगी।

पहलू

RNN

LSTM

ग्रेडिएंट पाथ

केवल वेट मैट्रिक्स

सेल स्टेट के साथ अतिरिक्त पाथ

100-स्टेप ग्रेडिएंट

~10^-5 (गायब)

~10^-2 से 10^-1 (उपयोगी)

व्यावहारिक मेमोरी

~10-20 टाइमस्टेप्स

~50-200 टाइमस्टेप्स

प्रैक्टिकाल नोट: फॉरगेट गेट बायसेज़ को अक्सर 1.0 या उससे अधिक पर इनिशियलाइज़ किया जाता है, जिससे शुरुआती आउटपुट "सब कुछ याद रखो" की ओर झुकता है। यह नेटवर्क को प्रशिक्षण के शुरुआती चरण में लंबे-अवधि के पैटर्न सीखने में मदद करता है।

LSTM वैनिशिंग ग्रेडिएंट समस्या को समाप्त नहीं करते, बल्कि कम करते हैं। सुधार एडिटिव सेल-स्टेट अपडेट से आता है, जो मानक पाथ्स के साथ एक ग्रेडिएंट हाईवे प्रदान करता है।

Python में LSTM मॉडल कैसे इम्प्लीमेंट करें

पिछले अनुभाग में देखा कि LSTM सेल के अंदर क्या होता है: सूचना को फ़िल्टर करते गेट्स, संदर्भ को संरक्षित करता सेल स्टेट, और आउटपुट उत्पन्न करता हिडन स्टेट। अब हम देखेंगे कि PyTorch का nn.LSTM कैसे इन सबको एक ही मॉड्यूल में पैक करता है और इसका उपयोग मूवी रिव्यूज़ को सकारात्मक या नकारात्मक के रूप में वर्गीकृत करने में करता है।

कोड चलाने के लिए टिप: CPU पर 50 एपॉक्स तक प्रशिक्षण में बहुत समय लगता है। यूज़ करें Google Colab या Kaggle Notebooks GPU एक्सेलेरेशन के साथ, ताकि तेज़ परिणाम मिलें। पूरा स्क्रिप्ट GitHub Gist पर उपलब्ध है।

PyTorch के साथ एक LSTM क्लासिफायर बनाना

LSTM के साथ टेक्स्ट वर्गीकरण का एक पैटर्न है: शब्दों को वेक्टर में बदलें, LSTM को उन्हें क्रमवार प्रोसेस करने दें, फिर प्रेडिक्शन के लिए अंतिम आउटपुट का उपयोग करें।

शब्दों को वेक्टर में एम्बेड करना

न्यूरल नेटवर्क्स निरंतर संख्याओं पर काम करते हैं, लेकिन शब्द डिस्क्रीट प्रतीक हैं। हम "terrible" को सीधे मैट्रिक्स गुणा में नहीं दे सकते। सुझाव है एम्बेडिंग लेयर: एक लुकअप टेबल जहाँ प्रत्येक शब्द एक सीखने योग्य वेक्टर से मैप होता है।

self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=padding_idx)

यदि आप embedding_dim=32 चुनते हैं, तो हर शब्द 32-डायमेंशनल वेक्टर बन जाता है। प्रशिक्षण के शुरुआती चरण में, ये वेक्टर रैंडम होते हैं। जैसे-जैसे मॉडल सीखता है, समान सेंटिमेंट वाले शब्द इस वेक्टर स्पेस में एक-दूसरे के करीब आते जाते हैं। "Terrible," "awful," और "boring" एक-दूसरे के पास हो सकते हैं, जबकि "excellent" और "amazing" कहीं और क्लस्टर करते हैं।

padding_idx आर्गुमेंट लेयर को बताता है कि पैडिंग टोकन को ज़ीरो वेक्टर्स पर रखें, ताकि वे मॉडल को प्रभावित न करें।

LSTM आर्किटेक्चर परिभाषित करना

self.lstm = nn.LSTM(
	input_size=embedding_dim,
	hidden_size=hidden_size,
	num_layers=num_layers,
	batch_first=True,
	dropout=dropout if num_layers > 1 else 0,
	bidirectional=bidirectional,
)

यह एक पंक्ति पिछले सेक्शन की पूरी गेट मशीनरी बनाती है। hidden_size तय करता है कि सेल स्टेट और हिडन स्टेट कितनी जानकारी वहन कर सकते हैं। बड़े मान मॉडल को अधिक पैटर्न ट्रैक करने देते हैं लेकिन अधिक गणना माँगते हैं।

batch_first=True सेट करने का अर्थ है कि इनपुट का आकार (batch, sequence_length, embedding_dim) होगा। LSTM प्रत्येक पोज़िशन को बाएँ से दाएँ प्रोसेस करता है, हर चरण पर अपनी आंतरिक अवस्थाएँ अपडेट करता है।

अनुक्रम को प्रोसेस करना

"This movie was absolutely terrible" को प्रोसेस करने के बाद, LSTM ने हर शब्द देख लिया होता है। इसका अंतिम हिडन स्टेट उस अनुक्रम से जो भी निकालना मॉडल ने सीखा है, उसे संचित कर चुका होता है। सेंटिमेंट के लिए, यह कुछ ऐसा एन्कोड कर सकता है जैसे "अंत में मज़बूत नकारात्मक विशेषण, जो पहले के न्यूट्रल कंटेंट को नकार देता है।"

def forward(self, x):
	embedded = self.embedding(x)
	lstm_out, (h_n, c_n) = self.lstm(embedded)
	h_final = h_n[-1]
	return self.fc(h_final)

LSTM प्रति-टाइमस्टेप आउटपुट्स (lstm_out) और अंतिम स्टेट्स (h_n, c_n) दोनों लौटाता है। क्लासिफिकेशन के लिए, हमें सिर्फ h_n[-1] चाहिए, यानी अंतिम टोकन के बाद का हिडन स्टेट। फिर एक लीनियर लेयर इसे क्लास स्कोर्स में मैप करती है।

रिव्यू को मॉडल से ट्रेस करना

जब "This movie was terrible" क्लासिफायर में जाता है:

  1. प्रत्येक शब्द का एम्बेडिंग मिलता है: आकार (32,) के चार वेक्टर

  2. LSTM उन्हें क्रमवार प्रोसेस करता है। "This" कुछ सेल स्टेट इनिशियलाइज़ करता है। "Movie" उसे थोड़ा अपडेट करता है। "Was" न्यूट्रल है और कम बदलता है। "Terrible" फॉरगेट गेट को अप्रासंगिक संदर्भ साफ़ करने और इनपुट गेट को मज़बूत नकारात्मक संकेत लिखने को ट्रिगर करता है।

  3. अंतिम हिडन स्टेट संचित पैटर्न को कैप्चर करता है।

  4. लीनियर लेयर इसे दो स्कोर्स में मैप करती है: एक पॉज़िटिव के लिए, एक नेगेटिव के लिए

मॉडल भाषा को नहीं समझता। यह सांख्यिकीय पैटर्न सीखता है: कुछ शब्द अनुक्रम विशेष लेबल्स से सहसंबद्ध होते हैं।

पूरा मॉडल क्लास

नीचे आप पूरा LSTMClassifier क्लास देख सकते हैं जिसे हमने चरण दर चरण बनाया:

import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
from datasets import load_dataset
from collections import Counter
import numpy as np
 
torch.manual_seed(42)
np.random.seed(42)
 
 
class LSTMClassifier(nn.Module):
    def __init__(
        Self,
        Vocab_size,
        Embedding_dim,
        Hidden_size,
        Output_size,
        num_layers=1,
        dropout=0.0,
        bidirectional=False,
        padding_idx=0,
    ):
        super().__init__()
        self.hidden_size = hidden_size
    	self.num_layers = num_layers
    	self.bidirectional = bidirectional
 
    	self.embedding = nn.Embedding(
	    vocab_size, embedding_dim, padding_idx=padding_idx
        )
    	self.lstm = nn.LSTM(
            input_size=embedding_dim,
            hidden_size=hidden_size,
            num_layers=num_layers,
            batch_first=True,
            dropout=dropout if num_layers > 1 else 0,
            bidirectional=bidirectional,
    	)	
 
    	fc_input_size = hidden_size * 2 if bidirectional else hidden_size
    	self.fc = nn.Linear(fc_input_size, output_size)
 
    def forward(self, x):
    	embedded = self.embedding(x)
    	lstm_out, (h_n, c_n) = self.lstm(embedded)
 
    	if self.bidirectional:
            h_final = torch.cat([h_n[-2], h_n[-1]], dim=1)
    	else:
            h_final = h_n[-1]
 
    	return self.fc(h_final)

बिडायरेक्शनल विकल्प दो LSTM चलाता है: एक बाएँ-से-दाएँ, एक दाएँ-से-बाएँ। उनके अंतिम हिडन स्टेट्स को जोड़ा जाता है, जिससे मॉडल को दोनों दिशाओं से संदर्भ मिलता है। यह तब मदद करता है जब अर्थ इस पर निर्भर करता है कि आगे क्या आता है, जैसे "not bad," जहाँ "not" का मतलब तभी बनता है जब "bad" मौजूद हो।

मॉडल के लिए टेक्स्ट तैयार करना

LSTM को स्ट्रिंग्स नहीं, पूर्णांकों के अनुक्रम चाहिए। प्रीप्रोसेसिंग कच्चे टेक्स्ट को तीन चरणों से गुज़ारता है: 

  1. शब्दों को इंडेक्स से मैप करने वाली शब्दावली बनाना
  2. हर रिव्यू को इंडेक्स के अनुक्रम में बदलना
  3. अनुक्रमों को एक समान लंबाई तक पैड करना
def build_vocab(texts, max_vocab_size=10000):
	counter = Counter()
	for text in texts:
    		counter.update(text.lower().split())
 
	vocab = {"<pad>": 0, "<unk>": 1}
	for word, _ in counter.most_common(max_vocab_size - 2):
    		vocab[word] = len(vocab)
	return vocab

हम पैडिंग के लिए इंडेक्स 0 और अनजान शब्दों के लिए इंडेक्स 1 आरक्षित रखते हैं। शब्दावली आकार को सीमित करना दुर्लभ शब्दों को फ़िल्टर करता है, जिनके सीखने योग्य एम्बेडिंग के लिए पर्याप्त उदाहरण नहीं होते।

def tokenize_and_pad(texts, vocab, max_length=200):
	sequences = []
	for text in texts:
    		tokens = text.lower().split()
    		ids = [vocab.get(t, vocab["<unk>"]) for t in tokens[:max_length]]
    		ids = ids + [vocab["<pad>"]] * (max_length - len(ids))
    		sequences.append(ids)
	return torch.tensor(sequences, dtype=torch.long)

max_length तक ट्रंकेट करना यह सीमित करता है कि LSTM को कितनी दूर तक याद रखना होगा। लंबे अनुक्रम अधिक संदर्भ संरक्षित करते हैं लेकिन गणना और मेमोरी लागत बढ़ाते हैं। मूवी रिव्यूज़ के लिए, 100-200 टोकन आमतौर पर प्रमुख सेंटिमेंट संकेतों को कैप्चर कर लेते हैं।

पैडिंग सुनिश्चित करता है कि हर अनुक्रम एक ही लंबाई का हो, जिससे PyTorch उन्हें एक टेन्सर में बैच कर सके। एम्बेडिंग के बाद पैडिंग टोकन ज़ीरो वेक्टर बन जाते हैं और अंतिम स्टेट पर कम असर डालते हैं।

def load_imdb_data(max_samples=10000, max_length=200, max_vocab=10000):
	dataset = load_dataset("imdb")
 
	train_data = dataset["train"].shuffle(seed=42)
	test_data = dataset["test"].shuffle(seed=42)
 
	train_texts = train_data["text"][:max_samples]
	train_labels = train_data["label"][:max_samples]
	test_texts = test_data["text"][: max_samples // 4]
	test_labels = test_data["label"][: max_samples // 4]
 
	vocab = build_vocab(train_texts, max_vocab)
 
	X_train = tokenize_and_pad(train_texts, vocab, max_length)
	X_test = tokenize_and_pad(test_texts, vocab, max_length)
	y_train = torch.tensor(train_labels, dtype=torch.long)
	y_test = torch.tensor(test_labels, dtype=torch.long)
 
	return X_train, y_train, X_test, y_test, vocab

केवल प्रशिक्षण डेटा से शब्दावली बनाना सूचना लीक होने से रोकता है। यदि कोई दुर्लभ शब्द केवल टेस्ट रिव्यूज़ में आता है, तो मॉडल को उसे अनजान की तरह ट्रीट करना चाहिए, न कि प्रशिक्षण के दौरान उसका एम्बेडिंग सीख लेना चाहिए।

LSTM प्रशिक्षण और हाइपरपैरामीटर्स

ट्रेनिंग लूप मॉडल के वेट्स को इस आधार पर अपडेट करता है कि उसकी भविष्यवाणियाँ सही मानों से कितनी दूर हैं। LSTM के लिए, एक विवरण सामान्य से अधिक मायने रखता है: ग्रेडिएंट क्लिपिंग।

def train_model(model, train_loader, test_loader, n_epochs=5, lr=0.001):
	criterion = nn.CrossEntropyLoss()
	optimizer = torch.optim.Adam(model.parameters(), lr=lr)
 
	for epoch in range(n_epochs):
    		model.train()
    		total_loss, correct, total = 0, 0, 0
 
    		for batch_texts, batch_labels in train_loader:
        		optimizer.zero_grad()
        		outputs = model(batch_texts)
        		loss = criterion(outputs, batch_labels)
        		loss.backward()
            		torch.nn.utils.clip_grad_norm_(
	model.parameters(), 
	max_norm=5.0)
        		optimizer.step()
 
        		total_loss += loss.item()
        		_, predicted = outputs.max(1)
        		correct += (predicted == batch_labels).sum().item()
        		total += batch_labels.size(0)

LSTM के लिए ग्रेडिएंट क्लिपिंग क्यों मायने रखता है

पहले हमने समझाया कि LSTM सेल स्टेट में एडिटिव अपडेट्स के जरिए वैनिशिंग ग्रेडिएंट्स को कैसे कम करते हैं। लेकिन एक्सप्लोडिंग ग्रेडिएंट्स का जोखिम बना रहता है। जब ग्रेडिएंट्स बहुत बड़े हो जाते हैं, तो वेट अपडेट्स बहुत आगे निकल जाते हैं और ट्रेनिंग अस्थिर हो जाती है।

clip_grad_norm_ कुल ग्रेडिएंट परिमाण को कैप करता है। यदि ग्रेडिएंट्स max_norm=5.0 से अधिक होंगे, तो उन्हें आनुपातिक रूप से घटा दिया जाता है। यह अपडेट्स को स्थिर रखता है बिना ग्रेडिएंट सिग्नल को पूरी तरह खत्म किए।

    	model.eval()
    	test_correct, test_total = 0, 0
    	with torch.no_grad():
        	for batch_texts, batch_labels in test_loader:
            		outputs = model(batch_texts)
            		_, predicted = outputs.max(1)
            		test_correct += (predicted == batch_labels).sum().item()
            		test_total += batch_labels.size(0)
 
    	test_acc = test_correct / test_total
    	print(f"Epoch {epoch+1}: Loss={total_loss/len(train_loader):.4f}, "
          	f"Train={correct/total:.3f}, Test={test_acc:.3f}")
 
    return test_acc

model.eval() इवैल्यूएशन के दौरान ड्रॉपआउट को अक्षम करता है। torch.no_grad() ग्रेडिएंट गणना को छोड़ देता है क्योंकि हम वेट्स अपडेट नहीं कर रहे हैं, जिससे मेमोरी बचती है और इंफरेंस तेज़ होता है।

हाइपरपैरामीटर्स चुनना

X_train, y_train, X_test, y_test, vocab = load_imdb_data(
	max_samples=10000, max_length=100, max_vocab=5000
)
 
train_loader = DataLoader(TensorDataset(X_train, y_train), batch_size=64, shuffle=True)
test_loader = DataLoader(TensorDataset(X_test, y_test), batch_size=64)
 
model = LSTMClassifier(
	vocab_size=len(vocab),
	embedding_dim=32,
	hidden_size=32,
	output_size=2,
	padding_idx=vocab["<pad>"],
)
 
final_acc = train_model(model, train_loader, test_loader, n_epochs=50, lr=0.001)

ये मान ट्रेड-ऑफ़्स दर्शाते हैं:

  • hidden_size=32: तेज़ इटरेशन के लिए पर्याप्त छोटा। प्रोडक्शन मॉडल्स अक्सर 128-512 का उपयोग करते हैं, लेकिन आकार बढ़ने के साथ लाभ घटते हैं और ट्रेनिंग धीमी होती है।

  • embedding_dim=32: हिडन साइज से मिलाना आम है पर आवश्यक नहीं। बड़े एम्बेडिंग्स अधिक सूक्ष्म शब्द भिन्नताएँ कैप्चर करते हैं पर पैरामीटर्स बढ़ाते हैं।

  • max_length=100: अधिकांश सेंटिमेंट संकेत रिव्यूज़ की शुरुआत में आते हैं। लंबे अनुक्रम सूक्ष्म मामलों में मदद करते हैं, लेकिन दोगुने max_length के लिए मेमोरी उपयोग चार गुना कर देते हैं।

  • batch_size=64: बड़े बैच अधिक स्थिर ग्रेडिएंट आकलन देते हैं। छोटे बैच लोकल मिनिमा से निकलने में मदद कर सकते हैं। 32-128 सामान्य है।

  • lr=0.001: Adam का डिफ़ॉल्ट अधिकांश LSTM कार्यों के लिए काम करता है। यदि लॉस डगमगाता है, तो 0.0001 आज़माएँ। यदि सीखना रुक जाए, तो 0.01 आज़माएँ।

  • n_epochs=50: मॉडल को कन्वर्ज होने के लिए पर्याप्त। इस पर नज़र रखें कि टेस्ट एक्युरेसी कब पठार बनाती या गिरती है जबकि ट्रेन एक्युरेसी बढ़ती रहती है—यह ओवरफिटिंग का संकेत है।

मॉडल क्या सीखता है

यह कॉन्फ़िगरेशन चलाने पर ऐसा आउटपुट मिलता है:

...
Epoch 46: Loss=0.4126, Train=0.812, Test=0.789
Epoch 47: Loss=0.4054, Train=0.815, Test=0.791
Epoch 48: Loss=0.3998, Train=0.818, Test=0.788
Epoch 49: Loss=0.3921, Train=0.821, Test=0.793
Epoch 50: Loss=0.3867, Train=0.824, Test=0.795

ट्रेनिंग एक्युरेसी लगभग 82% तक पहुँचती है जबकि टेस्ट एक्युरेसी लगभग 80% पर स्थिर हो जाती है। मॉडल सीखता है कि कौन-से शब्द पैटर्न सेंटिमेंट की भविष्यवाणी करते हैं। अंत के पास मज़बूत विशेषण का वजन अधिक होता है। "not" जैसी नकारात्मकताएँ ध्रुवीयता पलट देती हैं। कुछ वाक्यांश ("waste of time," "highly recommend") मज़बूत संकेत बन जाते हैं। इनमें से कुछ भी प्रोग्राम नहीं किया गया; यह सब प्रशिक्षण डेटा के सह-संबंधों से उभरता है।

न्यूनतम ट्यूनिंग और छोटे मॉडल के साथ, 80% एक्युरेसी उचित है। ट्रेन और टेस्ट एक्युरेसी के बीच का छोटा अंतर दिखाता है कि मॉडल बिना गंभीर ओवरफिटिंग के अच्छी तरह जेनरलाइज़ करता है। ड्रॉपआउट जोड़ना, GloVe जैसे प्रीट्रेन एम्बेडिंग्स का उपयोग करना, या अधिक डेटा पर प्रशिक्षण देना एक्युरेसी को उच्च 80s तक ले जा सकता है।

LSTM मॉडल प्रदर्शन में सुधार

पिछले अनुभागों की बुनियादी LSTM आर्किटेक्चर काम करती है, लेकिन कई तकनीकें बिना किसी अलग मॉडल परिवार पर स्विच किए एक्युरेसी बढ़ा सकती हैं। इन तरीकों को हजारों प्रोडक्शन डिप्लॉयमेंट्स और शोध पत्रों में मान्य किया गया है।

बिडायरेक्शनल LSTM

मानक LSTM अनुक्रमों को बाएँ-से-दाएँ प्रोसेस करते हैं, केवल पिछले टोकनों से संदर्भ बनाते हैं। बिडायरेक्शनल LSTM (BiLSTM) दो समानांतर पास चलाते हैं: एक फॉरवर्ड, एक बैकवर्ड। प्रत्येक टाइमस्टेप पर अंतिम अभिव्यक्ति में पहले क्या आया और बाद में क्या आता है, दोनों शामिल होते हैं।

self.lstm = nn.LSTM(
	input_size=embedding_dim,
	hidden_size=hidden_size,
	bidirectional=True,  # Run both directions
	batch_first=True,
)
# Output size doubles: hidden_size * 2

सेंटिमेंट विश्लेषण के लिए, यह तब मायने रखता है जब नकारात्मकता उस शब्द के बाद आती है जिसे वह संशोधित करती है: "the movie was not bad" में "bad" के अस्तित्व को जानने के लिए फॉरवर्ड संदर्भ चाहिए, और यह जानने के लिए बैकवर्ड संदर्भ कि "not" उससे पहले आता है। 

BiLSTM नेम्ड एंटिटी रिकग्निशन (NER) पर सेंटीमेंट क्लासिफिकेशन और स्पीच रिकग्निशन में लगातार यूनिडायरेक्शनल मॉडेल्स से बेहतर प्रदर्शन करते हैं, सामान्यतः 5-15% के लाभ के साथ।

ट्रेड-ऑफ़: इन्फरेंस के समय आपको पूरी शृंखला चाहिए। स्ट्रीमिंग एप्लिकेशंस जो टोकन एक-एक करके प्राप्त करते हैं, बिडायरेक्शनल प्रोसेसिंग का उपयोग नहीं कर सकते।

अटेंशन जोड़ना

अटेंशन मॉडल को यह वज़न देने देता है कि किसी प्रेडिक्शन के लिए कौन-से टाइमस्टेप्स सबसे ज्यादा मायने रखते हैं। पूरी शृंखला को एक अंतिम हिडन स्टेट में दबाने के बजाय, अटेंशन सभी हिडन स्टेट्स का वेटेड संयोजन गणना करता है।

class AttentionLayer(nn.Module):
	def __init__(self, hidden_size):
    		super().__init__()
    		self.attention = nn.Linear(hidden_size, 1)
	
	def forward(self, lstm_outputs):
    	# lstm_outputs: (batch, seq_len, hidden_size)
    		scores = self.attention(lstm_outputs)  # (batch, seq_len, 1)
    		weights = torch.softmax(scores, dim=1)
    		context = torch.sum(weights * lstm_outputs, dim=1)
    		return context

"The acting was wooden, the plot made no sense, but the cinematography was stunning" जैसे रिव्यू में, अटेंशन सेंटिमेंट-धारक वाक्यांशों पर फोकस करना सीखता है, सभी शब्दों को समान रूप से ट्रीट करने के बजाय। मॉडल "wooden," "no sense," और "stunning" को उच्च वेट देता है जबकि "the" और "was" का वेट घटा देता है।

अटेंशन न्यूनतम कम्प्यूटेशनल ओवरहेड जोड़ता है और अक्सर क्लासिफिकेशन कार्यों पर 2-5% एक्युरेसी में सुधार देता है। ट्रांसलेशन जैसे सीक्वेंस-टू-सीक्वेंस समस्याओं के लिए, एन्कोडर और डिकोडर के बीच अटेंशन अच्छी परफ़ॉर्मेंस के लिए लगभग अनिवार्य है।

LSTM लेयर स्टैक करना

एक अकेली LSTM लेयर एक स्तर के एब्स्ट्रैक्शन पर पैटर्न पकड़ती है। कई लेयर स्टैक करने से नेटवर्क को श्रेणीबद्ध फीचर्स सीखने मिलते हैं: पहली लेयर लोकल फ्रेज़ पैटर्न्स पकड़ सकती है, जबकि ऊपरी लेयर इन्हें डॉक्यूमेंट-स्तरीय समझ में जोड़ती हैं।

self.lstm = nn.LSTM(
	input_size=embedding_dim,
	hidden_size=hidden_size,
	num_layers=3,  # Stack three layers
	dropout=0.3,   # Dropout between layers (not within)
	batch_first=True,
)

गहराई के लिए दिशानिर्देश:

  •  1 लेयर: सरल कार्य, छोटे डेटासेट, तेज़ इटरेशन
  • 2 लेयर: अधिकांश प्रोडक्शन एप्लिकेशंस
  • 3-4 लेयर: जटिल समय-निर्भरताएँ, बड़े डेटासेट
  • 4 से आगे: घटती वापसी, ट्रेनिंग अस्थिरता

प्रत्येक अतिरिक्त लेयर लगभग ट्रेनिंग समय दोगुना करती है। उथला शुरू करें और केवल तभी गहराई बढ़ाएँ जब वैलिडेशन मेट्रिक्स पठार बन जाएँ।

रेग्युलराइज़ेशन तकनीकें

LSTM आसानी से ओवरफिट हो जाते हैं, खासकर छोटे डेटासेट्स पर। तीन रेग्युलराइज़ेशन तकनीकें साथ में अच्छा काम करती हैं:

  • ड्रॉपआउट
  • ग्रेडिएंट क्लिपिंग
  • अर्ली स्टॉपिंग

ड्रॉपआउट

ड्रॉपआउट ट्रेनिंग के दौरान यादृच्छिक रूप से न्यूरॉनों को ज़ीरो कर देता है, जिससे नेटवर्क को सीखने को कई पाथवेज़ में वितरित करने के लिए मजबूर किया जाता है। ड्रॉपआउट को LSTM लेयर्स के बीच लागू करें, रिकरंट कनेक्शंस के भीतर नहीं (जो समयगत सीखने को बाधित कर सकता है)।

# PyTorch applies dropout between stacked layers automatically
self.lstm = nn.LSTM(..., num_layers=2, dropout=0.3)
 
# For single-layer LSTMs, add dropout after
self.dropout = nn.Dropout(0.3)

0.2-0.5 के ड्रॉपआउट रेट अधिकांश कार्यों के लिए काम करते हैं। उच्च मान गंभीर ओवरफिटिंग में मदद करते हैं लेकिन कन्वर्जेन्स धीमा कर देते हैं।

ग्रेडिएंट क्लिपिंग

ग्रेडिएंट क्लिपिंग बैकप्रोपेगेशन के दौरान ग्रेडिएंट्स की परिमाण को कैप करता है। जबकि LSTM वैनिशिंग ग्रेडिएंट्स को कम करते हैं, एक्सप्लोडिंग ग्रेडिएंट्स अभी भी होते हैं, खासकर लंबे अनुक्रमों या गहरे नेटवर्क्स के साथ।

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0)

1.0 से 5.0 के बीच मान सामान्य हैं। यदि ट्रेनिंग लॉस स्पाइक करता है या NaN वैल्यूज़ देता है, तो थ्रेशहोल्ड कम करें।

अर्ली स्टॉपिंग

अर्ली स्टॉपिंग वैलिडेशन लॉस की निगरानी करता है और जब यह सुधारना बंद कर देता है तो ट्रेनिंग रोक देता है। यह मॉडल को जनरलाइज़ेशन की कीमत पर ट्रेनिंग डेटा याद करने से रोकता है।

patience = 5
best_val_loss = float('inf')
epochs_without_improvement = 0
 
for epoch in range(max_epochs):
	train_loss = train_one_epoch(model, train_loader)
	val_loss = evaluate(model, val_loader)
	
	if val_loss < best_val_loss:
    		best_val_loss = val_loss
    		epochs_without_improvement = 0
    		torch.save(model.state_dict(), 'best_model.pt')
	else:
    		epochs_without_improvement += 1
	if epochs_without_improvement >= patience:
        	break

LSTM में ट्रेनिंग लूप्स, इवैल्यूएशन मेट्रिक्स और सामान्य समस्याओं को डीबग करने की पूरी वॉकथ्रू के लिए, देखें NLP with PyTorch गाइड।

प्रीट्रेन एम्बेडिंग्स

रैंडम एम्बेडिंग इनिशियलाइज़ेशन काम करता है, लेकिन GloVe या Word2Vec जैसी प्रीट्रेन एम्बेडिंग्स मॉडल को शुरुआती बढ़त देती हैं। ये एम्बेडिंग्स अरबों शब्दों से सीखे गए अर्थ-संबंध एन्कोड करती हैं: "king" और "queen" एक-दूसरे के पास आते हैं, जैसे "terrible" और "awful"।

import numpy as np
 
def load_glove_embeddings(glove_path, vocab, embedding_dim):
	embeddings = np.random.randn(len(vocab), embedding_dim) * 0.01
	
	with open(glove_path, 'r') as f:
    	for line in f:
        	parts = line.split()
        	word = parts[0]
        	if word in vocab:
            		embeddings[vocab[word]] = np.array(parts[1:], dtype=np.float32)
	
	return torch.tensor(embeddings, dtype=torch.float32)
 
# Load and freeze or fine-tune
pretrained = load_glove_embeddings('glove.6B.100d.txt', vocab, 100)
model.embedding.weight.data.copy_(pretrained)
model.embedding.weight.requires_grad = True  # Fine-tune during training

प्रीट्रेन एम्बेडिंग्स तब सबसे अधिक मदद करती हैं जब प्रशिक्षण डेटा सीमित हो। लाखों उदाहरणों के साथ, रैंडम इनिशियलाइज़्ड एम्बेडिंग्स अंततः पकड़ लेती हैं। अधिकांश व्यावहारिक एप्लिकेशंस (10k-100k सैंपल्स) के लिए, प्रीट्रेन इनिशियलाइज़ेशन से 3-8% एक्युरेसी गेन की अपेक्षा करें।

तकनीकों का संयोजन

ये तरीके स्टैक होते हैं। एक प्रोडक्शन-ग्रेड टेक्स्ट क्लासिफायर इस्तेमाल कर सकता है:

  • बिडायरेक्शनल संदर्भ के लिए BiLSTM
  • श्रेणीबद्ध फीचर्स के लिए 2 स्टैक्ड लेयर्स
  • अंतिम हिडन स्टेट के बजाय अटेंशन पूलिंग
  • ट्रेनिंग के दौरान फाइन-ट्यून की गई GloVe एम्बेडिंग्स
  • लेयर्स के बीच 0.3 का ड्रॉपआउट
  • 5.0 पर ग्रेडिएंट क्लिपिंग
  • 5 एपॉक्स की पेशेंस के साथ अर्ली स्टॉपिंग

प्रत्येक जोड़ जटिलता और ट्रेनिंग समय बढ़ाता है। पहले एक बेसलाइन सिंगल-लेयर LSTM आज़माएँ, परफॉर्मेंस मापें, फिर एक-एक करके तकनीकें जोड़ें ताकि देखें कि आपके विशेष कार्य पर क्या लाभ देता है।

LSTM बनाम Transformers: सही आर्किटेक्चर चुनना

1990 के दशक के अंत से लेकर 2010 के मध्य तक सीक्वेंस मॉडलिंग के लिए LSTM प्रमुख रहे। 2017 के "Attention Is All You Need" पेपर ने यह बदल दिया। अब Transformers अधिकांश बड़े भाषा मॉडलों को शक्ति देते हैं, लेकिन LSTM गायब नहीं हुए। वे अलग-अलग खाँचों को भरते हैं।

LSTM की सीमाएँ

पहले के अनुभागों में देखा कि LSTM अनुक्रमों को एक-एक टोकन करके प्रोसेस करते हैं और वह गेटिंग मैकेनिज़्म क्यों काम करता है। स्केल पर, यही क्रमिक निर्भरता बाधा बन जाती है। आपके GPU में हज़ारों कोर हो सकते हैं, लेकिन हिडन स्टेट की चेन ख़त्म होने तक ज्यादातर निष्क्रिय रहते हैं। 500-टोकन इनपुट का मतलब 500 क्रमिक ऑपरेशंस है।

Transformers पर यह बाधा नहीं होती। सेल्फ-अटेंशन सभी पोज़िशनों के बीच संबंधों को एक साथ गणना करता है, इसलिए वही 500-टोकन अनुक्रम समानांतर में प्रोसेस होता है। आधुनिक हार्डवेयर पर बड़े बैच आकारों के साथ, यह 10-100x ट्रेनिंग स्पीडअप में बदलता है।

सीक्वेंस लंबाई की सीमा भी मायने रखती है। हमने देखा कि LSTM वैनिला RNNs की तुलना में ग्रेडिएंट्स को बेहतर संरक्षित करते हैं, लेकिन "बेहतर" का मतलब "परफेक्ट" नहीं है। प्रदर्शन अभी भी लगभग 200-500 टोकन्स के आसपास गिरता है, कार्य पर निर्भर करता है। 

Transformers हर जोड़ी पोज़िशन के बीच सीधे अटेंशन गणना करते हैं, इसलिए टोकन 1 समान आसानी से टोकन 1000 पर ध्यान देता है। ट्रेड-ऑफ़ मेमोरी है: अटेंशन मैट्रिसेस अनुक्रम लंबाई के साथ वर्गानुपाती रूप से बढ़ती हैं।

गेट एक्टिवेशंस की वजह से व्याख्या भी कठिन हो जाती है। मान 0 से 1 के बीच होते हैं, स्पष्ट सीमाओं के बिना। Transformers में अटेंशन वेट्स भी परफेक्ट व्याख्या नहीं हैं, लेकिन वे यह बताने में अधिक स्पष्ट संकेत देते हैं कि किस आउटपुट के लिए कौन-से इनपुट टोकन मायने रखते थे।

LSTM कब उपयोग करें बनाम Transformers

Transformers तब समझ में आते हैं जब:

  • ट्रेनिंग डेटा 100K उदाहरणों से अधिक हो, और आपके पास GPU एक्सेस हो
  • कार्य में सैकड़ों टोकनों तक फैली निर्भरताएँ शामिल हों
  • इटरेशन चक्रों के लिए ट्रेनिंग स्पीड मायने रखती हो
  • GPT जैसे प्रीट्रेन मॉडल्स को आपके उपयोग के मामले के लिए फाइन-ट्यून किया जा सके

LSTM अब भी उपयुक्त हैं जब:

  • लक्ष्य डिवाइस पर मेमोरी की कड़ी पाबंदियाँ हों (एज, एम्बेडेड, मोबाइल)
  • डेटा कम हो (10K उदाहरणों से कम), और Transformer ओवरफिटिंग की चिंता हो
  • पूरी इनपुट आने से पहले आंशिक अनुक्रमों पर प्रेडिक्शंस चाहिए हों
  • लेटेंसी बजट हल्के-फुल्के मॉडल्स की माँग करते हों

टाइम सीरीज़ फोरकास्टिंग बीच का मामला है। हालिया बेंचमार्क दिखाते हैं कि एक-वेरिएट डेटा पर, जहाँ पैटर्न सुसंगत हैं, दोनों आर्किटेक्चर समान प्रदर्शन करते हैं। जब कई फीचर्स जटिल तरीकों से इंटरेक्ट करते हैं तो Transformers आगे निकलते हैं, लेकिन जब डेटा कम हो या कम्प्यूट कसा हुआ हो तो LSTM टिके रहते हैं।

हाइब्रिड डिज़ाइन्स दोनों तरीकों को मिलाते हैं। कुछ आर्किटेक्चर LSTM लेयर्स को अटेंशन मैकेनिज़्म के साथ स्टैक करते हैं। 2024 में प्रकाशित xLSTM ने मूल डिज़ाइन पर फिर से विचार किया, एक्सपोनेंशियल गेटिंग और मैट्रिक्स मेमोरी के साथ, छोटे स्केल पर Transformers के साथ प्रतिस्पर्धी परिणाम दिखाए।

पहलू

LSTM

Transformer

प्रोसेसिंग

क्रमिक (टोकन दर टोकन)

पैरेलल (सभी पोज़िशन एक साथ)

ट्रेनिंग स्पीड

धीमी (सीमित पैरललाइज़ेशन)

GPU पर तेज़

लंबी-दूरी निर्भरताएँ

200-500 टोकन्स के बाद गिरावट

हज़ारों टोकन्स संभालता है

मेमोरी स्केलिंग

O(n) अनुक्रम लंबाई के साथ

अटेंशन मैट्रिसेस के लिए O(n²)

कम डेटा पर प्रदर्शन

अच्छा (कम पैरामीटर्स)

ओवरफिटिंग की प्रवृत्ति

एज डिप्लॉयमेंट

उपयुक्त (कम मेमोरी फुटप्रिंट)

चुनौतीपूर्ण (बड़े मॉडल)

स्ट्रीमिंग/रीयल-टाइम

मूल समर्थन

पूरी शृंखला चाहिए

प्रीट्रेन इकोसिस्टम

सीमित

विस्तृत (BERT, GPT, आदि)

निर्णय आम तौर पर पाबंदियों पर निर्भर करता है। असीमित कम्प्यूट और डेटा? अधिकांश NLP कार्यों पर Transformers जीतते हैं। 10K प्रशिक्षण उदाहरणों वाला माइक्रोकंट्रोलर? LSTM व्यावहारिक रहते हैं।

निष्कर्ष

1997 में आने पर LSTM ने वास्तविक समस्या सुलझाई। Hochreiter और Schmidhuber द्वारा पेश किया गया गेटिंग मैकेनिज़्म नेटवर्क्स को अंततः कुछ दर्जन टोकन्स से लंबे अनुक्रमों से सीखने में सक्षम बनाता है। इस आर्किटेक्चर ने लगभग दो दशकों तक मशीन ट्रांसलेशन, स्पीच रिकग्निशन और टाइम सीरीज़ फोरकास्टिंग को शक्ति दी।

अब Transformers अधिकांश बड़े पैमाने के NLP कार्यों को संभालते हैं, लेकिन LSTM अप्रचलित नहीं हुए। वे अभी भी एज डिप्लॉयमेंट, स्ट्रीमिंग एप्लिकेशंस, और ऐसी स्थितियों में समझ आते हैं जहाँ प्रशिक्षण डेटा सीमित हो।

यदि आप कोई नया सीक्वेंस मॉडलिंग प्रोजेक्ट शुरू कर रहे हैं, तो पहले एक सरल LSTM आज़माएँ। इसकी परफॉर्मेंस मापें, इसकी विफलता मोड्स समझें, फिर तय करें कि क्या वास्तव में समस्या को Transformer चाहिए। इस गाइड की अवधारणाएँ (गेटिंग, सेल स्टेट, ग्रेडिएंट फ्लो) सीधे अधिक जटिल आर्किटेक्चर्स को समझने में ट्रांसफ़र होती हैं।

हैंड्स-ऑन अभ्यास के लिए, मैं हमारे Recurrent Neural Networks कोर्स लेने की सलाह देता हूँ, जो अतिरिक्त LSTM अनुप्रयोगों को गाइडेड अभ्यासों के साथ कवर करता है।

LSTM FAQs

LSTM और साधारण RNN में क्या अंतर है?

साधारण RNNs लंबी शृंखलाओं के साथ संघर्ष करते हैं क्योंकि बैकप्रोपेगेशन के दौरान ग्रेडिएंट्स सिकुड़ जाते हैं, जिससे दूरस्थ संदर्भ से सीखने की क्षमता खो जाती है। LSTM एक सेल स्टेट और गेटिंग मैकेनिज़्म जोड़ते हैं जो सूचना प्रवाह को नियंत्रित करते हैं, जिससे नेटवर्क 20-30 के बजाय सैकड़ों टाइमस्टेप्स तक प्रासंगिक संदर्भ को संरक्षित कर पाता है।

मुझे Transformers के बजाय LSTM कब उपयोग करना चाहिए?

जब आपके पास सीमित प्रशिक्षण डेटा (10K उदाहरणों से कम) हो, मेमोरी-सीमित डिवाइसों जैसे मोबाइल या एम्बेडेड सिस्टम पर चलाना हो, पूरी शृंखला आने से पहले स्ट्रीमिंग डेटा पर रीयल-टाइम प्रेडिक्शंस चाहिए हों, या कड़े लेटेंसी आवश्यकताएँ बड़े मॉडलों को बाहर कर दें—तब LSTM बेहतर काम करते हैं।

PyTorch LSTM में hidden_size का क्या अर्थ है?

PyTorch LSTM में hidden_size पैरामीटर हिडन स्टेट और सेल स्टेट वेक्टर, दोनों की डायमेंशनलिटी निर्धारित करता है। बड़े मान मॉडल को अधिक पैटर्न ट्रैक करने देते हैं, लेकिन गणना और मेमोरी उपयोग बढ़ाते हैं। 32-512 के मान सामान्य हैं, प्रोडक्शन टेक्स्ट एप्लिकेशंस के लिए 128-256 सामान्यतः प्रयुक्त होते हैं।

मैं अपने LSTM को ओवरफिटिंग से कैसे बचाऊँ?

LSTM लेयर्स के बीच ड्रॉपआउट (0.2-0.5 रेट) का उपयोग करें, एक्सप्लोडिंग ग्रेडिएंट्स से बचाने के लिए ग्रेडिएंट क्लिपिंग लागू करें, वैलिडेशन लॉस में सुधार रुकने पर प्रशिक्षण रोकने के लिए अर्ली स्टॉपिंग करें, और यदि आपका डेटासेट छोटा है तो GloVe जैसी प्रीट्रेन एम्बेडिंग्स पर विचार करें।

बिडायरेक्शनल LSTM क्या है, और मुझे इसे कब उपयोग करना चाहिए?

एक बिडायरेक्शनल LSTM शृंखला पर दो पास चलाता है: एक फॉरवर्ड और एक बैकवर्ड। इससे हर पोज़िशन को दोनों दिशाओं से संदर्भ मिलता है, जो तब मदद करता है जब अर्थ भविष्य के टोकनों पर निर्भर करता है (जैसे "not bad" जहाँ "not" को "bad" देखना ज़रूरी है)। इसे तब उपयोग करें जब आपके पास इन्फरेंस समय पर पूरी शृंखला हो (क्लासिफिकेशन और टैगिंग कार्य), लेकिन स्ट्रीमिंग एप्लिकेशंस के लिए इससे बचें।

Bexruz (Bex) Tuychiev

लेखक

Bexruz (Bex) Tuychiev

मैं 2 से अधिक वर्षों के अनुभव वाला डेटा साइंस कंटेंट क्रिएटर हूँ और Medium पर सबसे बड़े फॉलोइंग्स में से एक रखता हूँ। मुझे एआई और एमएल पर विस्तार से लेख लिखना पसंद है, जिसमें हल्का-सा व्यंग्यात्मक अंदाज रहता है—क्योंकि कुछ तो करना पड़ता है ताकि वे कम उबाऊ लगें। मैंने 130 से अधिक लेख और एक DataCamp कोर्स तैयार किया है, और एक और बन रहा है। मेरा कंटेंट 50 लाख से अधिक लोगों ने देखा है, जिनमें से 20 हज़ार लोग Medium और LinkedIn पर फॉलोअर्स बन गए। 

विषय