paint-brush
उत्पाद-संचालित ट्विस्ट के साथ एक मशीन लर्निंग टेक्स्ट वर्गीकरण केस स्टडीद्वारा@bemorelavender
29,438 रीडिंग
29,438 रीडिंग

उत्पाद-संचालित ट्विस्ट के साथ एक मशीन लर्निंग टेक्स्ट वर्गीकरण केस स्टडी

द्वारा Maria K17m2024/03/12
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

यह उत्पाद-संचालित मोड़ के साथ एक मशीन लर्निंग केस स्टडी है: हम दिखावा करने जा रहे हैं कि हमारे पास एक वास्तविक उत्पाद है जिसे हमें सुधारने की आवश्यकता है। हम एक डेटासेट का पता लगाएंगे और लॉजिस्टिक रिग्रेशन, आवर्ती तंत्रिका नेटवर्क और ट्रांसफार्मर जैसे विभिन्न मॉडलों को आज़माएंगे, यह देखेंगे कि वे कितने सटीक हैं, वे उत्पाद को कैसे बेहतर बनाने जा रहे हैं, वे कितनी तेजी से काम करते हैं, और क्या उन्हें डीबग करना आसान है और स्केल करें।
featured image - उत्पाद-संचालित ट्विस्ट के साथ एक मशीन लर्निंग टेक्स्ट वर्गीकरण केस स्टडी
Maria K HackerNoon profile picture


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


आप GitHub पर पूरा केस स्टडी कोड पढ़ सकते हैं और ज्यूपिटर नोटबुक व्यूअर में इंटरैक्टिव चार्ट के साथ विश्लेषण नोटबुक देख सकते हैं।


उत्साहित? चलो उसे करें!

कार्य सेटिंग

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


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


इस केस स्टडी के लिए, हम इसका उपयोग करेंगे ज़ेनोडो ई-कॉमर्स टेक्स्ट डेटासेट , जिसमें आइटम विवरण और श्रेणियां शामिल हैं।


अच्छा या बुरा? सबसे अच्छा मॉडल कैसे चुनें

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


जाहिर है, हमारे पास विभिन्न मॉडलों की ऑफ़लाइन तुलना करने के लिए एक तकनीकी गुणवत्ता मीट्रिक होगी। इस मामले में, हमारे पास एक बहु-वर्ग वर्गीकरण कार्य है, तो आइए एक संतुलित सटीकता स्कोर का उपयोग करें, जो असंतुलित लेबल को अच्छी तरह से संभालता है।


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


एबी-परीक्षण के लिए किसी उम्मीदवार को आगे बढ़ाने से पहले हमें और क्या विचार करना चाहिए? ऑफ़लाइन चरण के दौरान हम ऑनलाइन परीक्षण का कुछ समय बचाने के लिए क्या सोच सकते हैं और यह सुनिश्चित कर सकते हैं कि हम वास्तव में सर्वोत्तम संभव समाधान का परीक्षण कर रहे हैं?


तकनीकी मेट्रिक्स को प्रभाव-उन्मुख मेट्रिक्स में बदलना

संतुलित सटीकता बढ़िया है, लेकिन यह स्कोर इस सवाल का जवाब नहीं देता है कि "मॉडल वास्तव में उत्पाद को कैसे प्रभावित करेगा?"। अधिक उत्पाद-उन्मुख स्कोर खोजने के लिए हमें यह समझना होगा कि हम मॉडल का उपयोग कैसे करने जा रहे हैं।


हमारी सेटिंग में, गलती करना कोई उत्तर न देने से भी बदतर है, क्योंकि विक्रेता को गलती पर ध्यान देना होगा और श्रेणी को मैन्युअल रूप से बदलना होगा। एक अनजानी गलती से बिक्री कम हो जाएगी और विक्रेता का उपयोगकर्ता अनुभव खराब हो जाएगा, हम ग्राहकों को खोने का जोखिम उठाते हैं।


इससे बचने के लिए, हम मॉडल के स्कोर के लिए सीमाएं चुनेंगे ताकि हम केवल 1% गलतियों की अनुमति दें। उत्पाद-उन्मुख मीट्रिक को निम्नानुसार सेट किया जा सकता है:


यदि हमारी त्रुटि सहनशीलता केवल 1% है तो हम कितने प्रतिशत वस्तुओं को स्वचालित रूप से वर्गीकृत कर सकते हैं?


सर्वोत्तम मॉडल का चयन करते समय हम इसे नीचे Automatic categorisation percentage के रूप में संदर्भित करेंगे। पूर्ण सीमा चयन कोड यहां पाएं।


अनुमान का समय

एक मॉडल को एक अनुरोध को संसाधित करने में कितना समय लगता है?


यह मोटे तौर पर हमें यह तुलना करने की अनुमति देगा कि यदि एक मॉडल को दूसरे मॉडल के मुकाबले चुना जाता है तो कार्य भार को संभालने के लिए हमें सेवा के लिए कितने अधिक संसाधनों को बनाए रखना होगा।


अनुमापकता

जब हमारा उत्पाद बढ़ने वाला है, तो दिए गए आर्किटेक्चर का उपयोग करके विकास को प्रबंधित करना कितना आसान होगा?


विकास से हमारा तात्पर्य यह हो सकता है:

  • अधिक श्रेणियाँ, श्रेणियों की उच्च विस्तृतता
  • लंबा विवरण
  • बड़े डेटासेट
  • वगैरह

क्या हमें विकास को संभालने के लिए एक मॉडल विकल्प पर पुनर्विचार करना होगा या एक साधारण पुनर्प्रशिक्षण पर्याप्त होगा?


विवेचनीयता

प्रशिक्षण के दौरान और तैनाती के बाद मॉडल की त्रुटियों को डीबग करना कितना आसान होगा?


मॉडल का आकार

मॉडल का आकार मायने रखता है यदि:

  • हम चाहते हैं कि हमारे मॉडल का ग्राहक पक्ष पर मूल्यांकन किया जाए
  • यह इतना बड़ा है कि यह रैम में फिट नहीं हो सकता


हम बाद में देखेंगे कि उपरोक्त दोनों चीजें प्रासंगिक नहीं हैं, लेकिन यह अभी भी संक्षेप में विचार करने लायक है।

डेटासेट अन्वेषण एवं सफ़ाई

हम किसके साथ काम कर रहे हैं? आइए डेटा देखें और देखें कि क्या इसे साफ़ करने की ज़रूरत है!


डेटासेट में 2 कॉलम हैं: आइटम विवरण और श्रेणी, कुल 50.5k पंक्तियाँ।

 file_name = "ecommerceDataset.csv" data = pd.read_csv(file_name, header=None) data.columns = ["category", "description"] print("Rows, cols:", data.shape) # >>> Rows, cols: (50425, 2)


प्रत्येक आइटम को उपलब्ध 4 श्रेणियों में से 1 सौंपा गया है: Household , Books , Electronics या Clothing & Accessories । यहां प्रति श्रेणी 1 आइटम विवरण उदाहरण दिया गया है:


  • घरेलू एसपीके होम डेकोर क्ले हस्तनिर्मित वॉल हैंगिंग फेस (मल्टी कलर, H35xW12cm) इस हस्तनिर्मित टेराकोटा इंडियन फेस मास्क वॉल हैंगिंग के साथ अपने घर को और अधिक सुंदर बनाएं, इससे पहले कि आप बाजार में इस हस्तनिर्मित चीज को नहीं देख सकें। आप इसे अपने लिविंग रूम/प्रवेश लॉबी में जोड़ सकते हैं।


  • पुस्तकें BEGF101/FEG1-अंग्रेजी में फाउंडेशन कोर्स-1 (नीरज प्रकाशन 2018 संस्करण) BEGF101/FEG1-अंग्रेजी में फाउंडेशन कोर्स-1


  • कपड़े और सहायक उपकरण ब्रॉडस्टार महिला डेनिम डंगरी, ब्रॉडस्टार द्वारा डंगरी पहनकर ऑल-एक्सेस पास अर्जित करें। डेनिम से बनी ये डंगरी आपको आरामदायक रखेंगी। अपने कैज़ुअल लुक को पूरा करने के लिए इन्हें सफ़ेद या काले रंग के टॉप के साथ पहनें।


  • इलेक्ट्रॉनिक्स कैप्रिगो हैवी ड्यूटी - 2 फीट प्रीमियम प्रोजेक्टर सीलिंग माउंट स्टैंड ब्रैकेट (एडजस्टेबल - सफेद - वजन क्षमता 15 किलोग्राम)


लापता मूल्य

डेटासेट में केवल एक खाली मान है, जिसे हम हटाने जा रहे हैं।

 print(data.info()) # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 50425 entries, 0 to 50424 # Data columns (total 2 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 category 50425 non-null object # 1 description 50424 non-null object # dtypes: object(2) # memory usage: 788.0+ KB data.dropna(inplace=True)


डुप्लिकेट

हालाँकि, बहुत सारे दोहराए गए विवरण हैं। सौभाग्य से सभी डुप्लिकेट एक ही श्रेणी के हैं, इसलिए हम उन्हें सुरक्षित रूप से हटा सकते हैं।

 repeated_messages = data \ .groupby("description", as_index=False) \ .agg( n_repeats=("category", "count"), n_unique_categories=("category", lambda x: len(np.unique(x))) ) repeated_messages = repeated_messages[repeated_messages["n_repeats"] > 1] print(f"Count of repeated messages (unique): {repeated_messages.shape[0]}") print(f"Total number: {repeated_messages['n_repeats'].sum()} out of {data.shape[0]}") # >>> Count of repeated messages (unique): 13979 # >>> Total number: 36601 out of 50424


डुप्लिकेट को हटाने के बाद हमारे पास 55% मूल डेटासेट बचता है। डेटासेट अच्छी तरह से संतुलित है.

 data.drop_duplicates(inplace=True) print(f"New dataset size: {data.shape}") print(data["category"].value_counts()) # New dataset size: (27802, 2) # Household 10564 # Books 6256 # Clothing & Accessories 5674 # Electronics 5308 # Name: category, dtype: int64


विवरण भाषा

ध्यान दें, डेटासेट विवरण के अनुसार,

डेटासेट को भारतीय ई-कॉमर्स प्लेटफॉर्म से हटा दिया गया है।


विवरण आवश्यक रूप से अंग्रेजी में नहीं लिखे गए हैं। उनमें से कुछ गैर-ASCII प्रतीकों का उपयोग करके हिंदी या अन्य भाषाओं में लिखे गए हैं या लैटिन वर्णमाला में लिप्यंतरित हैं, या भाषाओं के मिश्रण का उपयोग करते हैं। Books श्रेणी से उदाहरण:


  • यू जी सी – नेट जूनियर रिसर्च फैलोशिप एवं सहायक प्रोफेसर योग्यता …
  • Prarambhik Bhartiy Itihas
  • History of NORTH INDIA/வட இந்திய வரலாறு/ …


विवरण में गैर-अंग्रेजी शब्दों की उपस्थिति का मूल्यांकन करने के लिए, आइए 2 अंकों की गणना करें:


  • ASCII-स्कोर: विवरण में गैर-ASCII प्रतीकों का प्रतिशत
  • मान्य अंग्रेजी शब्द स्कोर: यदि हम केवल लैटिन अक्षरों पर विचार करते हैं, तो विवरण में कितने प्रतिशत शब्द अंग्रेजी में मान्य हैं? मान लीजिए कि वैध अंग्रेजी शब्द वे हैं जो Word2Vec-300 में अंग्रेजी कॉर्पस पर प्रशिक्षित हैं।


ASCII-स्कोर का उपयोग करके हम सीखते हैं कि केवल 2.3% विवरणों में 1% से अधिक गैर-ASCII प्रतीक शामिल हैं।

 def get_ascii_score(description): total_sym_cnt = 0 ascii_sym_cnt = 0 for sym in description: total_sym_cnt += 1 if sym.isascii(): ascii_sym_cnt += 1 return ascii_sym_cnt / total_sym_cnt data["ascii_score"] = data["description"].apply(get_ascii_score) data[data["ascii_score"] < 0.99].shape[0] / data.shape[0] # >>> 0.023


वैध अंग्रेजी शब्दों के स्कोर से पता चलता है कि केवल 1.5% विवरणों में ASCII शब्दों के बीच 70% से कम वैध अंग्रेजी शब्द हैं।

 w2v_eng = gensim.models.KeyedVectors.load_word2vec_format(w2v_path, binary=True) def get_valid_eng_score(description): description = re.sub("[^az \t]+", " ", description.lower()) total_word_cnt = 0 eng_word_cnt = 0 for word in description.split(): total_word_cnt += 1 if word.lower() in w2v_eng: eng_word_cnt += 1 return eng_word_cnt / total_word_cnt data["eng_score"] = data["description"].apply(get_valid_eng_score) data[data["eng_score"] < 0.7].shape[0] / data.shape[0] # >>> 0.015


इसलिए अधिकांश विवरण (लगभग 96%) अंग्रेजी में या अधिकतर अंग्रेजी में हैं। हम अन्य सभी विवरण हटा सकते हैं, लेकिन इसके बजाय, आइए उन्हें वैसे ही छोड़ दें और फिर देखें कि प्रत्येक मॉडल उन्हें कैसे संभालता है।

मोडलिंग

आइए अपने डेटासेट को 3 समूहों में विभाजित करें:

  • प्रशिक्षण 70% - मॉडलों के प्रशिक्षण के लिए (19 हजार संदेश)

  • परीक्षण 15% - पैरामीटर और थ्रेशोल्ड चयन के लिए (4.1k संदेश)

  • मूल्यांकन 15% - अंतिम मॉडल चुनने के लिए (4.1k संदेश)


 from sklearn.model_selection import train_test_split data_train, data_test = train_test_split(data, test_size=0.3) data_test, data_eval = train_test_split(data_test, test_size=0.5) data_train.shape, data_test.shape, data_eval.shape # >>> ((19461, 3), (4170, 3), (4171, 3))


बेसलाइन मॉडल: शब्दों का थैला + लॉजिस्टिक रिग्रेशन

एक अच्छी आधार रेखा प्राप्त करने के लिए शुरुआत में कुछ सीधा और तुच्छ कार्य करना सहायक होता है। आइए आधार रेखा के रूप में ट्रेन डेटासेट के आधार पर शब्दों की संरचना का एक बैग बनाएं।


आइए शब्दकोश का आकार भी 100 शब्दों तक सीमित रखें।

 count_vectorizer = CountVectorizer(max_features=100, stop_words="english") x_train_baseline = count_vectorizer.fit_transform(data_train["description"]) y_train_baseline = data_train["category"] x_test_baseline = count_vectorizer.transform(data_test["description"]) y_test_baseline = data_test["category"] x_train_baseline = x_train_baseline.toarray() x_test_baseline = x_test_baseline.toarray()


मैं एक मॉडल के रूप में लॉजिस्टिक रिग्रेशन का उपयोग करने की योजना बना रहा हूं, इसलिए मुझे प्रशिक्षण से पहले काउंटर सुविधाओं को सामान्य करने की आवश्यकता है।

 ss = StandardScaler() x_train_baseline = ss.fit_transform(x_train_baseline) x_test_baseline = ss.transform(x_test_baseline) lr = LogisticRegression() lr.fit(x_train_baseline, y_train_baseline) balanced_accuracy_score(y_test_baseline, lr.predict(x_test_baseline)) # >>> 0.752


मल्टी-क्लास लॉजिस्टिक रिग्रेशन ने 75.2% संतुलित सटीकता दिखाई। यह एक महान आधार रेखा है!


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


आधारभूत समाधान के लिए भ्रम मैट्रिक्स।


उदाहरण के लिए, Electronics अक्सर Household समझ लिया जाता है। लेकिन यह साधारण मॉडल भी Clothing & Accessories काफी सटीकता से कैप्चर कर सकता है।


Clothing & Accessories श्रेणी की भविष्यवाणी करते समय यहां फीचर महत्व दिए गए हैं:

'कपड़े और सहायक उपकरण' लेबल के लिए आधारभूत समाधान के लिए फीचर महत्व


Clothing & Accessories श्रेणी के पक्ष और विपक्ष में शीर्ष-6 सर्वाधिक योगदान देने वाले शब्द:

 women 1.49 book -2.03 men 0.93 table -1.47 cotton 0.92 author -1.11 wear 0.69 books -1.10 fit 0.40 led -0.90 stainless 0.36 cable -0.85


आरएनएन

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


हम विवरणों को टोकनाइज़ करने और एक मॉडल बनाने और प्रशिक्षित करने के लिए pytorch लाइब्रेरी का उपयोग करेंगे।


सबसे पहले, हमें टेक्स्ट को संख्याओं में बदलना होगा:

  1. विवरण को शब्दों में विभाजित करें
  2. प्रशिक्षण डेटासेट के आधार पर कॉर्पस में प्रत्येक शब्द के लिए एक इंडेक्स निर्दिष्ट करें
  3. अज्ञात शब्दों और पैडिंग के लिए विशेष सूचकांक आरक्षित करें
  4. ट्रेन और परीक्षण डेटासेट में प्रत्येक विवरण को सूचकांकों के वैक्टर में बदलें।


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

(पूर्ण CorpusDictionary कार्यान्वयन यहां पाएं)


 corpus_dict = util.CorpusDictionary(data_train["description"]) corpus_dict.truncate_dictionary(min_frequency=0.03) data_train["vector"] = corpus_dict.transform(data_train["description"]) data_test["vector"] = corpus_dict.transform(data_test["description"]) print(data_train["vector"].head()) # 28453 [1, 1, 1, 1, 12, 1, 2, 1, 6, 1, 1, 1, 1, 1, 6,... # 48884 [1, 1, 13, 34, 3, 1, 1, 38, 12, 21, 2, 1, 37, ... # 36550 [1, 60, 61, 1, 62, 60, 61, 1, 1, 1, 1, 10, 1, ... # 34999 [1, 34, 1, 1, 75, 60, 61, 1, 1, 72, 1, 1, 67, ... # 19183 [1, 83, 1, 1, 87, 1, 1, 1, 12, 21, 42, 1, 2, 1... # Name: vector, dtype: object


अगली चीज़ जो हमें तय करने की ज़रूरत है वह वेक्टर की सामान्य लंबाई है जिसे हम आरएनएन में इनपुट के रूप में फीड करने जा रहे हैं। हम पूर्ण वैक्टर का उपयोग नहीं करना चाहते, क्योंकि सबसे लंबे विवरण में 9.4k टोकन हैं।


हालाँकि, ट्रेन डेटासेट में 95% विवरण अब 352 टोकन से अधिक नहीं हैं - यह ट्रिमिंग के लिए एक अच्छी लंबाई है। छोटे विवरणों से क्या होगा?


वे सामान्य लंबाई तक पैडिंग इंडेक्स के साथ गद्देदार होने जा रहे हैं।

 print(max(data_train["vector"].apply(len))) # >>> 9388 print(int(np.quantile(data_train["vector"].apply(len), q=0.95))) # >>> 352


अगला - हमें नुकसान की गणना करने और प्रत्येक प्रशिक्षण चरण पर बैक-प्रचार करने के लिए लक्ष्य श्रेणियों को 0-1 वैक्टर में बदलने की आवश्यकता है।

 def get_target(label, total_labels=4): target = [0] * total_labels target[label_2_idx.get(label)] = 1 return target data_train["target"] = data_train["category"].apply(get_target) data_test["target"] = data_test["category"].apply(get_target)


अब हम मॉडल में फीड करने के लिए एक कस्टम pytorch डेटासेट और डेटालोडर बनाने के लिए तैयार हैं। पूर्ण PaddedTextVectorDataset कार्यान्वयन यहां पाएं।

 ds_train = util.PaddedTextVectorDataset( data_train["description"], data_train["target"], corpus_dict, max_vector_len=352, ) ds_test = util.PaddedTextVectorDataset( data_test["description"], data_test["target"], corpus_dict, max_vector_len=352, ) train_dl = DataLoader(ds_train, batch_size=512, shuffle=True) test_dl = DataLoader(ds_test, batch_size=512, shuffle=False)


अंत में, चलिए एक मॉडल बनाते हैं।


न्यूनतम वास्तुकला है:

  • एम्बेडिंग परत
  • आरएनएन परत
  • रैखिक परत
  • सक्रियण परत


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


 class GRU(nn.Module): def __init__(self, vocab_size, embedding_dim, n_hidden, n_out): super().__init__() self.vocab_size = vocab_size self.embedding_dim = embedding_dim self.n_hidden = n_hidden self.n_out = n_out self.emb = nn.Embedding(self.vocab_size, self.embedding_dim) self.gru = nn.GRU(self.embedding_dim, self.n_hidden) self.dropout = nn.Dropout(0.3) self.out = nn.Linear(self.n_hidden, self.n_out) def forward(self, sequence, lengths): batch_size = sequence.size(1) self.hidden = self._init_hidden(batch_size) embs = self.emb(sequence) embs = pack_padded_sequence(embs, lengths, enforce_sorted=True) gru_out, self.hidden = self.gru(embs, self.hidden) gru_out, lengths = pad_packed_sequence(gru_out) dropout = self.dropout(self.hidden[-1]) output = self.out(dropout) return F.log_softmax(output, dim=-1) def _init_hidden(self, batch_size): return Variable(torch.zeros((1, batch_size, self.n_hidden)))


हम हानि फ़ंक्शन के रूप में Adam ऑप्टिमाइज़र और cross_entropy उपयोग करेंगे।


 vocab_size = len(corpus_dict.word_to_idx) emb_dim = 4 n_hidden = 15 n_out = len(label_2_idx) model = GRU(vocab_size, emb_dim, n_hidden, n_out) opt = optim.Adam(model.parameters(), 1e-2) util.fit( model=model, train_dl=train_dl, test_dl=test_dl, loss_fn=F.cross_entropy, opt=opt, epochs=35 ) # >>> Train loss: 0.3783 # >>> Val loss: 0.4730 

प्रति युग ट्रेन एवं परीक्षण हानि, आरएनएन मॉडल

इस मॉडल ने इवल डेटासेट पर 84.3% संतुलित सटीकता दिखाई। वाह, क्या प्रगति है!


पूर्व-प्रशिक्षित एम्बेडिंग का परिचय

आरएनएन मॉडल को शुरू से प्रशिक्षित करने का प्रमुख नकारात्मक पक्ष यह है कि इसमें शब्दों का अर्थ स्वयं सीखना पड़ता है - यही एम्बेडिंग परत का काम है। पूर्व-प्रशिक्षित word2vec मॉडल रेडी-मेड एम्बेडिंग परत के रूप में उपयोग करने के लिए उपलब्ध हैं, जो मापदंडों की संख्या को कम करता है और टोकन में बहुत अधिक अर्थ जोड़ता है। आइए pytorch में उपलब्ध word2vec मॉडलों में से एक का उपयोग करें - glove, dim=300


हमें डेटासेट निर्माण में केवल मामूली बदलाव करने की आवश्यकता है - अब हम प्रत्येक विवरण और मॉडल आर्किटेक्चर glove लिए पूर्व-परिभाषित इंडेक्स का एक वेक्टर बनाना चाहते हैं।

 ds_emb_train = util.PaddedTextVectorDataset( data_train["description"], data_train["target"], emb=glove, max_vector_len=max_len, ) ds_emb_test = util.PaddedTextVectorDataset( data_test["description"], data_test["target"], emb=glove, max_vector_len=max_len, ) dl_emb_train = DataLoader(ds_emb_train, batch_size=512, shuffle=True) dl_emb_test = DataLoader(ds_emb_test, batch_size=512, shuffle=False)
 import torchtext.vocab as vocab glove = vocab.GloVe(name='6B', dim=300) class LSTMPretrained(nn.Module): def __init__(self, n_hidden, n_out): super().__init__() self.emb = nn.Embedding.from_pretrained(glove.vectors) self.emb.requires_grad_ = False self.embedding_dim = 300 self.n_hidden = n_hidden self.n_out = n_out self.lstm = nn.LSTM(self.embedding_dim, self.n_hidden, num_layers=1) self.dropout = nn.Dropout(0.5) self.out = nn.Linear(self.n_hidden, self.n_out) def forward(self, sequence, lengths): batch_size = sequence.size(1) self.hidden = self.init_hidden(batch_size) embs = self.emb(sequence) embs = pack_padded_sequence(embs, lengths, enforce_sorted=True) lstm_out, (self.hidden, _) = self.lstm(embs) lstm_out, lengths = pad_packed_sequence(lstm_out) dropout = self.dropout(self.hidden[-1]) output = self.out(dropout) return F.log_softmax(output, dim=-1) def init_hidden(self, batch_size): return Variable(torch.zeros((1, batch_size, self.n_hidden)))


और हम प्रशिक्षण के लिए तैयार हैं!

 n_hidden = 50 n_out = len(label_2_idx) emb_model = LSTMPretrained(n_hidden, n_out) opt = optim.Adam(emb_model.parameters(), 1e-2) util.fit(model=emb_model, train_dl=dl_emb_train, test_dl=dl_emb_test, loss_fn=F.cross_entropy, opt=opt, epochs=11) 

प्रति युग ट्रेन और परीक्षण हानि, आरएनएन मॉडल + पूर्व-प्रशिक्षित एम्बेडिंग

अब हमें eval डेटासेट पर 93.7% संतुलित सटीकता मिल रही है। वाह!


बर्ट

अनुक्रमों के साथ काम करने के लिए आधुनिक अत्याधुनिक मॉडल ट्रांसफार्मर हैं। हालाँकि, एक ट्रांसफार्मर को शुरू से प्रशिक्षित करने के लिए, हमें भारी मात्रा में डेटा और कम्प्यूटेशनल संसाधनों की आवश्यकता होगी। हम यहां जो प्रयास कर सकते हैं - वह है अपने उद्देश्य की पूर्ति के लिए पूर्व-प्रशिक्षित मॉडलों में से एक को बेहतर बनाना। ऐसा करने के लिए हमें एक पूर्व-प्रशिक्षित BERT मॉडल डाउनलोड करना होगा और अंतिम भविष्यवाणी प्राप्त करने के लिए ड्रॉपआउट और रैखिक परत जोड़ना होगा। 4 युगों के लिए एक ट्यून किए गए मॉडल को प्रशिक्षित करने की अनुशंसा की जाती है। मैंने समय बचाने के लिए केवल 2 अतिरिक्त युगों का प्रशिक्षण लिया - ऐसा करने में मुझे 40 मिनट लगे।


 from transformers import BertModel class BERTModel(nn.Module): def __init__(self, n_out=12): super(BERTModel, self).__init__() self.l1 = BertModel.from_pretrained('bert-base-uncased') self.l2 = nn.Dropout(0.3) self.l3 = nn.Linear(768, n_out) def forward(self, ids, mask, token_type_ids): output_1 = self.l1(ids, attention_mask = mask, token_type_ids = token_type_ids) output_2 = self.l2(output_1.pooler_output) output = self.l3(output_2) return output


 ds_train_bert = bert.get_dataset( list(data_train["description"]), list(data_train["target"]), max_vector_len=64 ) ds_test_bert = bert.get_dataset( list(data_test["description"]), list(data_test["target"]), max_vector_len=64 ) dl_train_bert = DataLoader(ds_train_bert, sampler=RandomSampler(ds_train_bert), batch_size=batch_size) dl_test_bert = DataLoader(ds_test_bert, sampler=SequentialSampler(ds_test_bert), batch_size=batch_size)


 b_model = bert.BERTModel(n_out=4) b_model.to(torch.device("cpu")) def loss_fn(outputs, targets): return torch.nn.BCEWithLogitsLoss()(outputs, targets) optimizer = optim.AdamW(b_model.parameters(), lr=2e-5, eps=1e-8) epochs = 2 scheduler = get_linear_schedule_with_warmup( optimizer, num_warmup_steps=0, num_training_steps=total_steps ) bert.fit(b_model, dl_train_bert, dl_test_bert, optimizer, scheduler, loss_fn, device, epochs=epochs) torch.save(b_model, "models/bert_fine_tuned")


प्रशिक्षण लॉग:

 2024-02-29 19:38:13.383953 Epoch 1 / 2 Training... 2024-02-29 19:40:39.303002 step 40 / 305 done 2024-02-29 19:43:04.482043 step 80 / 305 done 2024-02-29 19:45:27.767488 step 120 / 305 done 2024-02-29 19:47:53.156420 step 160 / 305 done 2024-02-29 19:50:20.117272 step 200 / 305 done 2024-02-29 19:52:47.988203 step 240 / 305 done 2024-02-29 19:55:16.812437 step 280 / 305 done 2024-02-29 19:56:46.990367 Average training loss: 0.18 2024-02-29 19:56:46.990932 Validating... 2024-02-29 19:57:51.182859 Average validation loss: 0.10 2024-02-29 19:57:51.182948 Epoch 2 / 2 Training... 2024-02-29 20:00:25.110818 step 40 / 305 done 2024-02-29 20:02:56.240693 step 80 / 305 done 2024-02-29 20:05:25.647311 step 120 / 305 done 2024-02-29 20:07:53.668489 step 160 / 305 done 2024-02-29 20:10:33.936778 step 200 / 305 done 2024-02-29 20:13:03.217450 step 240 / 305 done 2024-02-29 20:15:28.384958 step 280 / 305 done 2024-02-29 20:16:57.004078 Average training loss: 0.08 2024-02-29 20:16:57.004657 Validating... 2024-02-29 20:18:01.546235 Average validation loss: 0.09


अंत में, फाइन ट्यून किया गया BERT मॉडल ईवल डेटासेट पर 95.1% संतुलित सटीकता दिखाता है।


हमारा विजेता चुनना

अंतिम सुविज्ञ विकल्प चुनने के लिए हमने पहले ही विचार करने योग्य बातों की एक सूची बना ली है।

यहां मापने योग्य पैरामीटर दिखाने वाले चार्ट हैं:

मॉडलों के प्रदर्शन मेट्रिक्स


हालाँकि फाइन-ट्यून BERT गुणवत्ता में अग्रणी है, पूर्व-प्रशिक्षित एम्बेडिंग परत LSTM+EMB के साथ RNN दूसरे स्थान पर है, जो स्वचालित श्रेणी असाइनमेंट से केवल 3% पीछे है।


दूसरी ओर, फाइन-ट्यून किए गए BERT का अनुमान समय LSTM+EMB से 14 गुना अधिक है। इससे बैकएंड रखरखाव लागत में वृद्धि होगी जो संभवत LSTM+EMB तुलना में फाइन-ट्यून किए गए BERT मिलने वाले लाभों से अधिक होगी।


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


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


आशा है आपको यह केस स्टडी पसंद आयी होगी। आपने कौन सा मॉडल चुना होगा और क्यों?