कोर्स
टोकनाइज़ेशन HuggingFace Transformer स्टैक का वह हिस्सा है जिस पर हम आमतौर पर ध्यान नहीं देते—जब तक कि वह आपके आउटपुट में लीक न होने लगे। एक मामूली व्हाइटस्पेस क्विर्क टोकन सीमाएँ बदल सकता है, डिकोडिंग अप्रत्याशित स्ट्रिंग्स दे सकती है, और टेम्पलेटिंग के दौरान चैट प्रॉम्प्ट चुपचाप टूट सकते हैं।
Transformers v5 इन समस्याओं को एक ऐसे टोकनाइज़ेशन रीडिज़ाइन से हल करता है जो अलग-अलग इम्प्लीमेंटेशंस में व्यवहार को मानकीकृत करता है, API सतह को सरल बनाता है, और जब डिबगिंग की ज़रूरत हो तो टोकनाइज़र के आंतरिक हिस्सों का निरीक्षण करना आसान बनाता है।
इस ट्यूटोरियल में, मैं पहले बताऊँगा कि टोकनाइज़ेशन क्या उत्पन्न करता है और पाइपलाइन कैसे काम करती है, फिर व्यावहारिक, माइग्रेशन-केंद्रित दृष्टिकोण से v5 में वास्तव में क्या बदलता है। आप एन्कोडिंग, डिकोडिंग, चैट टेम्पलेट्स और सीरियलाइज़ेशन के लिए v4 बनाम v5 कोड पैटर्न साथ-साथ देखेंगे ताकि आप अपने कोडबेस अपडेट कर सकें।
यदि आप टोकनाइज़ेशन में नए हैं, तो मैं सलाह दूँगा कि आप Introduction to Natural Language Processing in Python कोर्स देखें।
Tokenization क्या है?
टोकनाइज़ेशन की एक बहुत आम परिभाषा है कि यह पाठ को टोकन IDs में बदलता है—जो सही है, लेकिन अधूरी। प्रोडक्शन में, टोकनाइज़ेशन को एक अनुबंध के रूप में बेहतर समझा जाता है। कच्चे टेक्स्ट को देखते हुए, टोकनाइज़र को एक संरचित एन्कोडिंग उत्पन्न करनी चाहिए जिसे मॉडल सुरक्षित रूप से उपभोग कर सके।
न्यूनतम रूप से, इस अनुबंध में शामिल हैं:
input_ids, जो पूर्णांक टोकन IDs हैं जो मॉडल की एम्बेडिंग टेबल में इंडेक्स करते हैं।- इसमें
attention_maskभी शामिल है, जो दर्शाता है कि कौन-सी पोज़िशन वास्तविक टोकन से मेल खाती हैं और कौन-सी पैडिंग से। - ऑफसेट/अलाइनमेंट (यदि उपलब्ध) मूल टेक्स्ट में टोकन स्पैन को कैरेक्टर या शब्द-स्तरीय स्पैन से मैप करते हैं, जो हाइलाइटिंग, NER, और एट्रिब्यूशन के लिए आवश्यक है।
- विशेष टोकन सिमेंटिक्स संरक्षित रहनी चाहिए; अर्थात्
BOS/EOS/PAD/UNKका स्थान और IDs मॉडल के प्रशिक्षण के दौरान उपयोग की गई परंपराओं से मेल खाने चाहिए। - चैट मॉडलों के लिए, चैट फ़ॉर्मेटिंग अनुबंध का हिस्सा है, इसलिए हम आमतौर पर टोकनाइज़ेशन चलाने से पहले मॉडल का चैट टेम्पलेट लागू करते हैं।
Transformers में, ये ज़िम्मेदारियाँ टोकनाइज़र लेयर पर होती हैं (मॉडल के फॉरवर्ड पास के अंदर नहीं), यही कारण है कि AutoTokenizer स्टैंडर्ड एंट्री पॉइंट है। यह एक सरल उदाहरण है:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM3-3B")
enc = tokenizer("Hello world")
print(enc["input_ids"])
print(tokenizer.convert_ids_to_tokens(enc["input_ids"]))
यह अपेक्षित आउटपुट है:
[9906, 1917]
['Hello', 'Ġworld']
यहाँ, enc एक BatchEncoding ऑब्जेक्ट है (डिक्ट-जैसा कंटेनर) जो टोकनाइज़र द्वारा उत्पन्न मॉडल-तैयार फ़ील्ड्स रखता है (जैसे input_ids और अक्सर attention_mask)। आउटपुट [9906, 1917] देता है, जो इनपुट स्ट्रिंग के लिए पूर्णांक टोकन IDs हैं, साथ ही ['Hello', 'Ġworld'], जो संबंधित टोकन स्ट्रिंग्स दिखाता है।
नोट: Ġ प्रीफिक्स एक सामान्य परंपरा है जो दर्शाता है कि टोकन में अग्रणी स्पेस शामिल है, इसलिए Ġworld का अर्थ " world" है, न कि बिना व्हाइटस्पेस के "world"।
एक पाइपलाइन के रूप में टोकनाइज़ेशन: v5 इसे कैसे डिबग करने योग्य बनाता है
टोकनाइज़ेशन की समस्याएँ अक्सर छोटे मुद्दों के रूप में सामने आती हैं—अतिरिक्त स्पेस, अजीब यूनिकोड स्प्लिट, टोकन काउंट में अचानक उछाल, या चैट प्रॉम्प्ट जो रोल्स का सही तरह पालन नहीं करते।
इन समस्याओं को डिबग करने का सबसे सरल तरीका है टोकनाइज़ेशन को चरणों की एक पाइपलाइन के रूप में देखना। एक बार जब आपको पता चल जाए कि कौन-सा चरण किसकी ज़िम्मेदारी लेता है, तो आप अनुमान लगाने के बजाय जल्दी से मुद्दों को अलग कर सकते हैं। ध्यान रखने के लिए कुछ संकेतक:
टोकनाइज़ेशन एक कंपोज़ेबल पाइपलाइन है
पहला लक्ष्य यह आम भ्रांति तोड़ना है कि टोकनाइज़र बस एक WordPiece है। इसके बजाय, यह विशिष्ट ट्रांसफॉर्मेशन चरणों का अनुक्रम है, जिसमें नॉर्मलाइज़ेशन, प्री-टोकनाइज़ेशन, सबवर्ड मॉडलिंग, पोस्ट-प्रोसेसिंग और डिकोडिंग शामिल हैं। हर चरण अंतिम व्यवहार के अलग हिस्से को नियंत्रित करता है।
डिबग करने योग्य मेंटल मॉडल
टोकनाइज़ेशन को चरणों में तोड़ना हमें एक भरोसेमंद ट्रबलशूटिंग मानचित्र देता है:
- व्हाइटस्पेस की गड़बड़ियाँ आमतौर पर प्री-टोकनाइज़र या डिकोडर से आती हैं
- यूनिकोड से जुड़ी बातें प्रायः नॉर्मलाइज़र से उत्पन्न होती हैं।
- टोकन विस्फोट अक्सर सबवर्ड मॉडल और उसके शब्दभंडार/मर्जेस से होते हैं
- चैट-फ़ॉर्मेटिंग की गलतियाँ मुख्यतः टेम्पलेट्स या पोस्ट-प्रोसेसिंग से आती हैं
डिज़ाइन द्वारा स्पष्ट और निरीक्षण योग्य
Transformers v5 टोकनाइज़र का निरीक्षण करना आसान बनाता है, खासकर उन टोकनाइज़र्स के लिए जो Rust tokenizers इंजन द्वारा समर्थित हैं।
जब Rust बैकएंड उपयोग होता है, तो हम अंतर्निहित घटकों का tokenizer._tokenizer (नॉर्मलाइज़र, प्री-टोकनाइज़र, मॉडल, पोस्ट-प्रोसेसर, डिकोडर) के माध्यम से निरीक्षण कर सकते हैं। हम रोज़ _tokenizer का उपयोग नहीं करते, लेकिन v5 रिलीज़ के साथ यह उपयोगी है, जो जरूरत पड़ने पर आंतरिक हिस्सों को दृश्य बनाता है।
यह स्वाभाविक रूप से इंजन बनाम रैपर के अंतर की ओर ले जाता है:
- इंजन (
tokenizers): लो-लेवल Rust इम्प्लीमेंटेशन जो नॉर्मलाइज़ेशन, स्प्लिटिंग, सबवर्ड सेगमेंटेशन, और टोकन IDs (और उपलब्ध होने पर ऑफसेट्स) बनाने जैसी मूल यांत्रिकी करता है। - रैपर (
transformers): यह मॉडल-फेसिंग लेयर है जो उन यांत्रिकियों को मॉडल-तैयार इनपुट में बदलती है, विशेष-टोकन हैंडलिंग, चैट टेम्पलेट्स, पैडिंग/ट्रंकेशन नियम, और फ्रेमवर्क-विशिष्ट टेंसर आउटपुट जैसी परंपराएँ लागू करके।
Transformers v5 में क्या बदला?
Transformers v5 एक प्रमुख मानकीकृत रिलीज़ है, और टोकनाइज़ेशन उन क्षेत्रों में से है जहाँ उपयोगकर्ता-दृश्य बदलाव हैं। यह रिलीज़ डुप्लिकेट इम्प्लीमेंटेशंस को कम करता है, टोकनाइज़र व्यवहार को मॉडलों में अधिक सुसंगत बनाता है, और टोकनाइज़र को निरीक्षण (और कुछ मामलों में) शून्य से ट्रेन करना आसान बनाता है। नीचे वे बदलाव हैं जो दिन-प्रतिदिन के उपयोगकर्ताओं को सबसे अधिक प्रभावित करते हैं।
प्रति मॉडल एक टोकनाइज़र इम्प्लीमेंटेशन
पिछली रिलीज़ में, कई मॉडलों में थे:
- एक धीमा Python टोकनाइज़र
- एक तेज़ Rust-समर्थित टोकनाइज़र इम्प्लीमेंटेशन
v5 में, Transformers प्रति मॉडल एक ही टोकनाइज़र फ़ाइल में समेकित करता है और Rust-समर्थित मार्ग को प्राथमिकता देता है। यह इसलिए काम करता है क्योंकि:
- धीमे बनाम तेज़ इम्प्लीमेंटेशंस के डुप्लिकेशन को हटाता है।
- उन इम्प्लीमेंटेशंस के बीच सूक्ष्म व्यवहार-असंगतियों से उत्पन्न पैरिटी बग्स को कम करता है।
- यह टोकनाइज़र इम्प्लीमेंटेशन टेस्ट सतह को छोटा और सरल बनाता है, क्योंकि सत्यापित करने के लिए केवल एक प्राथमिक कोड पाथ है।
- यह मॉडलों में टोकनाइज़र व्यवहार के लिए एकल “स्रोत-ऑफ-ट्रुथ” स्थापित भी करता है।
एन्कोडिंग API माइग्रेशन
v4 का encode_plus() API अब डिप्रिकेटेड है और इसके स्थान पर सीधे टोकनाइज़र को कॉल करना चाहिए। यहाँ v4 और v5 के बीच का अंतर है:
v4 संस्करण
enc = tokenizer.encode_plus(
text,
truncation=True,
padding="max_length",
max_length=128,
return_tensors="pt",
)
v5 संस्करण
enc = tokenizer(
text,
truncation=True,
padding="max_length",
max_length=128,
return_tensors="pt",
)
encode_plus() से एकल tokenizer() एंट्री पॉइंट पर जाना वास्तविक फेल्योर मोड्स को कम करता है जो प्रोडक्शन कोड में दिखते हैं।
v4 में, कई एन्कोडिंग विधियाँ होने का मतलब था कि पैडिंग, ट्रंकेशन, बैचिंग, या टेंसर कन्वर्ज़न में सूक्ष्म अंतर इस पर निर्भर कर सकते थे कि आपने कौन-सा पाथ चुना, और यह अक्सर तब सामने आता था जब आप सिंगल इनपुट से बैच्ड वर्कलोड्स में स्विच करते थे।
v5 सब कुछ एक एन्कोडिंग पाथ पर मानकीकृत करता है जो हमेशा एक BatchEncoding लौटाता है, जिससे व्यवहार अधिक पूर्वानुमेय बनता है और एज-केस बग्स तथा टोकनाइज़ेशन पाइपलाइनों को सुसंगत रखने के लिए आवश्यक कोड दोनों कम होते हैं।
डिकोडिंग API माइग्रेशन
v5 डिकोडिंग को एकीकृत करता है ताकि decode() सिंगल और बैच्ड दोनों इनपुट संभाल सके, और डिकोड का व्यवहार एन्कोड के अनुरूप रहे।
v4 संस्करण
texts = tokenizer.batch_decode(batch_ids, skip_special_tokens=True)
v5 संस्करण
texts = tokenizer.decode(batch_ids, skip_special_tokens=True)
v5 में, डिकोडिंग को एन्कोडिंग की तरह डिज़ाइन किया गया है। जैसे tokenizer() एक सिंगल स्ट्रिंग या स्ट्रिंग्स के बैच को स्वीकार कर सकता है, वैसे ही decode() टोकन IDs के एक सिंगल सीक्वेंस या सीक्वेंस के बैच को स्वीकार कर सकता है।
मुख्य बात यहाँ रिटर्न टाइप है; यानी, यदि आप एक सीक्वेंस पास करते हैं, तो एक सिंगल स्ट्रिंग वापस मिलेगी, लेकिन यदि आप बैच पास करते हैं (जैसे list[list[int]]), तो स्ट्रिंग्स की एक सूची मिलेगी। यह API को समग्र रूप से साफ़ बनाता है, लेकिन इसका मतलब यह भी है कि कोई भी कोड जो मानता है कि decode() हमेशा एक स्ट्रिंग लौटाता है, उसे दोनों स्थितियों को संभालने के लिए अपडेट करना चाहिए।
चैट टेम्पलेट्स
v4 में, apply_chat_template बैकवर्ड कम्पैटिबिलिटी के लिए कच्चे input_ids लौटाता था। v5 में, यह अन्य टोकनाइज़र मेथड्स की तरह BatchEncoding लौटाता है।
v4 संस्करण
input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt")
v5 संस्करण
enc = tokenizer.apply_chat_template(messages, return_tensors="pt")
input_ids = enc["input_ids"]
attention_mask = enc["attention_mask"]
v5 में, apply_chat_template() को एक विशेष-केस हेल्पर के बजाय एक सही टोकनाइज़र एंट्री पॉइंट की तरह माना जाता है। केवल input_ids लौटाने के बजाय यह पूर्ण BatchEncoding ऑब्जेक्ट देता है (जैसे input_ids और attention_mask वाले फ़ील्ड्स के साथ)।
यह इसलिए मायने रखता है क्योंकि चैट-फ़ॉर्मेटेड इनपुट अब नियमित टोकनाइज़ेशन की तरह ही बैचिंग, पैडिंग, ट्रंकेशन और टेंसर-रिटर्न वर्कफ़्लो में प्लग हो जाते हैं। इसलिए हमें मास्क फिर से बनाने या मॉडल को भेजने से पहले फ़ॉर्मैट्स को मैन्युअली अलाइन करने के लिए अतिरिक्त कोड की ज़रूरत नहीं होती।
टोकनाइज़र सीरियलाइज़ेशन
v5 में, टोकनाइज़र सीरियलाइज़ेशन को सरल बनाया गया है—विशेष-टोकन और जोड़े गए टोकन के मेटाडेटा को कम आर्टिफैक्ट्स में समेकित करके—जबकि बैकवर्ड कम्पैटिबिलिटी के लिए लेगसी फ़ाइलों का समर्थन बना रहता है। इससे कई “स्रोत-ऑफ-ट्रुथ” फ़ाइलों के असंगत होने का जोखिम घटता है और टोकनाइज़र एसेट्स को Transformers लाइब्रेरी के बाहर काम करने वाले डाउनस्ट्रीम टूल्स में लोड और दोबारा इस्तेमाल करना आसान होता है।
कॉन्फिगरेबल आर्किटेक्चर के रूप में टोकनाइज़र
v5 में मूल परिवर्तन यह है कि टोकनाइज़र को सिर्फ सीरियलाइज़्ड फ़ाइलों से लोड की जाने वाली चीज़ नहीं, बल्कि एक परिभाषित पाइपलाइन और सीखे गए आर्टिफैक्ट्स के रूप में देखा जाता है।
- टोकनाइज़र क्लास यह निर्दिष्ट करती है कि टेक्स्ट को कैसे नॉर्मलाइज़ किया जाता है, टुकड़ों में बाँटा जाता है, सबवर्ड टोकन में बदला जाता है और अंत में फिर टेक्स्ट में डिकोड किया जाता है।
- वोकैब्युलरी और मर्ज रूल्स सीखे हुए आर्टिफैक्ट्स हैं, यानी वे प्रशिक्षित हिस्से हैं जो यह निर्धारित करते हैं कि कौन-से टोकन मौजूद हैं और टेक्स्ट को टोकन IDs में कैसे संपीड़ित किया जाता है।
- यह पृथक्करण आर्किटेक्चर-फर्स्ट वर्कफ़्लोज़ सक्षम करता है। समर्थित टोकनाइज़र्स के लिए, आप किसी मॉडल के डिज़ाइन का पालन करने वाला टोकनाइज़र इंस्टैंशिएट कर सकते हैं और फिर वोकैब/मर्जेस अलग से लोड या ट्रेन कर सकते हैं, जिससे कस्टमाइज़ेशन और री-ट्रेनिंग कहीं अधिक सरल हो जाता है।
अंतिम विचार
Transformers v5 टोकनाइज़ेशन मानकीकरण और सरलीकरण की ओर एक बड़ा कदम है। अब एक अधिक कैनॉनिकल व्यवहार पाथ है (धीमे/तेज़ विचलन घटता है), एक सरल API सतह, चैट टेम्पलेटिंग जो सामान्य टोकनाइज़ेशन की तरह ही संरचित BatchEncoding ऑब्जेक्ट लौटाती है, और समेकित सीरियलाइज़ेशन जो नाज़ुक फ़ाइल-स्तरीय अनुमानों को कम करता है।
यह एक आर्किटेक्चर-फर्स्ट मेंटल मॉडल को भी बढ़ावा देता है जहाँ टोकनाइज़र का निरीक्षण करना और, समर्थित मामलों में, शून्य से ट्रेन करना आसान है। v4 से स्मूथ माइग्रेशन के लिए, encode_plus() को tokenizer() से बदलें, batch_decode() को decode() से बदलें, apply_chat_template() कॉल साइट्स को BatchEncoding के साथ काम करने के लिए अपडेट करें, सेव करते समय लेगसी टोकनाइज़र फ़ाइलनाम हार्डकोड करने से बचें, और अपेक्षा करें कि किसी भी धीमे टोकनाइज़र की गड़बड़ियाँ tokenizers-समर्थित व्यवहार की ओर अभिसृत हों।
यदि आप हालिया रिलीज़ के बारे में और सीखना चाहते हैं, तो यहाँ रिलीज़ नोट्स हैं। मैं Hugging Face Fundamentals स्किल ट्रैक की भी सिफारिश करता/करती हूँ ताकि आप हैंड्स-ऑन प्रैक्टिस कर सकें।
Tokenization v5 FAQs
क्या अब भी मुझे "Fast" (Rust) और "Slow" (Python) टोकनाइज़र क्लासेज़ के बीच चुनना होगा?
नहीं। Transformers v5 इन्हें प्रति मॉडल एक इम्प्लीमेंटेशन में समेकित करता है। अब लाइब्रेरी सभी समर्थित मॉडलों के लिए डिफ़ॉल्ट रूप से अत्यधिक अनुकूलित Rust बैकएंड (tokenizers लाइब्रेरी) का उपयोग करती है, जिससे LlamaTokenizerFast बनाम LlamaTokenizer को मैन्युअली चुनने की ज़रूरत समाप्त हो जाती है।
क्या मेरा मौजूदा encode_plus कोड तुरंत काम करना बंद कर देगा?
तुरंत नहीं, लेकिन यह डिप्रिकेटेड है। भले ही v5 वर्तमान में चेतावनी के साथ encode_plus को सपोर्ट करे, दृढ़ता से सलाह दी जाती है कि आप सीधे tokenizer(__call__) मेथड पर स्विच करें। इससे आपको नई एकीकृत बैचिंग बिहेवियर मिलते हैं और आपका कोडबेस भविष्य-प्रूफ रहता है।
अब apply_chat_template स्ट्रिंग के बजाय BatchEncoding डिक्ट क्यों लौटाता है?
चैट इनपुट्स को किसी अन्य मॉडल इनपुट की तरह ट्रीट करने के लिए। एक डिक्शनरी लौटाकर (जिसमें input_ids और attention_mask शामिल हैं), v5 चैट-फॉर्मेटेड डेटा को बिना किसी दूसरी टोकनाइज़ेशन स्टेप की आवश्यकता के तुरंत बैच, पैड और ट्रंकेट करने देता है।
क्या मैं अब भी return_tensors="tf" या return_tensors="jax" उपयोग कर सकता/सकती हूँ?
नहीं। v5 आर्किटेक्चर बदलावों के हिस्से के रूप में, Transformers ने TensorFlow और Flax/JAX बैकएंड्स के लिए आधिकारिक समर्थन हटा दिया है ताकि पूरी तरह PyTorch पर ध्यान केंद्रित किया जा सके। आपको PyTorch बैकएंड पर निर्भर रहना होगा या अन्य फ़्रेमवर्क्स के लिए मॉडलों को ONNX/GGUF जैसे फ़ॉर्मेट्स में एक्सपोर्ट करना होगा।
v5 में "साइलेंट" टोकनाइज़ेशन एरर्स को कैसे डिबग करें?
निरीक्षण योग्य आंतरिक हिस्सों का उपयोग करें। v5 में, आप tokenizer._tokenizer के ज़रिए अंतर्निहित Rust पाइपलाइन तक पहुँच सकते हैं। यह आपको विशेष चरणों—जैसे Normalizer या Pre-tokenizer—को अलग-थलग जाँचने देता है ताकि आप ठीक-ठीक देख सकें कि कोई स्ट्रिंग कहाँ अनपेक्षित रूप से स्प्लिट या मॉडिफ़ाई हो रही है।
मैं एमएल (Gen AI) में Google Developers Expert, Kaggle 3x Expert, और Women Techmakers एंबेसडर हूँ, तथा तकनीक क्षेत्र में 3+ वर्षों का अनुभव रखती हूँ। मैंने 2020 में एक हेल्थ-टेक स्टार्टअप की सह-स्थापना की और वर्तमान में Georgia Tech से कंप्यूटर विज्ञान में मास्टर कर रही हूँ, जिसमें मेरा विशेषज्ञता क्षेत्र मशीन लर्निंग है।
