{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# மீளும் நரம்பியல் வலைகள்\n", "\n", "முந்தைய தொகுதியில், நாங்கள் உரையின் செறிந்த அர்த்தமான பிரதிநிதிகளைப் பயன்படுத்தி, எம்பெடிங்க்களின் மேல் ஒரு எளிய நேரியல் வகைப்பாட்டாளரை பயன்படுத்தினோம். இந்த கட்டமைப்பு ஒரு வாக்கியத்தில் உள்ள சொற்களின் ஒருங்கிணைந்த அர்த்தத்தைப் பிடிக்கிறது, ஆனால் இது சொற்களின் **வரிசையை** கணக்கில் எடுத்துக்கொள்ளவில்லை, ஏனெனில் எம்பெடிங்க்களின் மேல் உள்ள ஒருங்கிணைப்பு செயல்பாடு மூல உரையில் இருந்து இந்த தகவலை நீக்கிவிடுகிறது. இந்த மாதிரிகள் சொற்களின் வரிசையை மாதிரி செய்ய முடியாததால், உரை உருவாக்கம் அல்லது கேள்வி பதில் போன்ற சிக்கலான அல்லது குழப்பமான பணிகளைத் தீர்க்க முடியாது.\n", "\n", "உரையின் வரிசை அர்த்தத்தைப் பிடிக்க, **மீளும் நரம்பியல் வலை**, அல்லது RNN எனப்படும் மற்றொரு நரம்பியல் வலை கட்டமைப்பைப் பயன்படுத்த வேண்டும். RNN இல், நாங்கள் எங்கள் வாக்கியத்தை ஒவ்வொரு சின்னத்தையும் ஒரே நேரத்தில் வலையமைப்பில் கடத்துகிறோம், மற்றும் வலையமைப்பு சில **நிலை** உருவாக்குகிறது, அதை அடுத்த சின்னத்துடன் மீண்டும் வலையமைப்பில் கடத்துகிறோம்.\n", "\n", "\"RNN\"\n", "\n", "உள்ளீட்டு டோக்கன்களின் வரிசை $X_0,\\dots,X_n$ கொடுக்கப்பட்டால், RNN நரம்பியல் வலைகள் வரிசையை உருவாக்குகிறது, மற்றும் இந்த வரிசையை முடிவு-to-end முறையில் பின்செலுத்தல் மூலம் பயிற்சி செய்கிறது. ஒவ்வொரு வலைகள் தொகுதியும் $(X_i,S_i)$ என்ற ஜோடியை உள்ளீடாக எடுத்து, $S_{i+1}$ என்ற முடிவை உருவாக்குகிறது. இறுதி நிலை $S_n$ அல்லது வெளியீடு $X_n$ ஒரு நேரியல் வகைப்பாட்டாளருக்குள் செலுத்தப்பட்டு முடிவை உருவாக்குகிறது. அனைத்து வலைகள் தொகுதிகளும் ஒரே எடைகளைப் பகிர்ந்து கொள்கின்றன, மற்றும் ஒரு பின்செலுத்தல் முறையில் முடிவு-to-end பயிற்சி செய்யப்படுகின்றன.\n", "\n", "நிலை வெக்டர்கள் $S_0,\\dots,S_n$ வலையமைப்பின் வழியாக கடத்தப்படுவதால், இது சொற்களுக்கிடையேயான வரிசை சார்ந்த சார்புகளை கற்றுக்கொள்ள முடியும். உதாரணமாக, *not* என்ற சொல் வரிசையில் எங்காவது தோன்றும்போது, இது நிலை வெக்டருக்குள் குறிப்பிட்ட கூறுகளை மறுப்பதற்கான திறனை கற்றுக்கொள்ள முடியும், இது மறுப்பு விளைவாக இருக்கும்.\n", "\n", "> RNN தொகுதிகளின் எடைகள் அனைத்தும் பகிரப்பட்டுள்ளதால், படத்தில் உள்ள அதே தொகுதியை ஒரு தொகுதி (வலது பக்கம்) மீளும் பின்னூட்டக் குரலுடன் பிரதிநிதியாகக் காட்டலாம், இது வலையமைப்பின் வெளியீட்டு நிலையை உள்ளீட்டிற்கு மீண்டும் கடத்துகிறது.\n", "\n", "நாம் எங்கள் செய்தி தரவுத்தொகுப்பை வகைப்படுத்த மீளும் நரம்பியல் வலைகள் எவ்வாறு உதவ முடியும் என்பதை பார்ப்போம்.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading dataset...\n", "Building vocab...\n" ] } ], "source": [ "import torch\n", "import torchtext\n", "from torchnlp import *\n", "train_dataset, test_dataset, classes, vocab = load_dataset()\n", "vocab_size = len(vocab)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## எளிய RNN வகைப்பாடு\n", "\n", "எளிய RNN இன் பட்சத்தில், ஒவ்வொரு மீள்நிலை அலகும் ஒரு எளிய நேரியல் நெட்வொர்க் ஆகும், இது இணைக்கப்பட்ட உள்ளீட்டு வெக்டர் மற்றும் நிலை வெக்டரை எடுத்து, புதிய நிலை வெக்டரை உருவாக்கும். PyTorch இந்த அலகை `RNNCell` வகுப்புடன் பிரதிநிதித்துவப்படுத்துகிறது, மற்றும் இவ்வகை செல்களின் நெட்வொர்க்குகளை `RNN` அடுக்கு எனக் குறிப்பிடுகிறது.\n", "\n", "ஒரு RNN வகைப்பாட்டை வரையறுக்க, முதலில் ஒரு எம்பெடிங் அடுக்கை பயன்படுத்தி உள்ளீட்டு சொற்கள்தொகுப்பின் பரிமாணத்தை குறைப்போம், அதன் மேல் RNN அடுக்கை அமைப்போம்:\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "class RNNClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.rnn = torch.nn.RNN(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " x,h = self.rnn(x)\n", " return self.fc(x.mean(dim=1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **குறிப்பு:** எளிமைக்காக, இங்கு பயிற்சி செய்யப்படாத embedding layer-ஐ பயன்படுத்துகிறோம், ஆனால் மேலும் சிறந்த முடிவுகளுக்காக, முந்தைய அலகில் விவரிக்கப்பட்ட Word2Vec அல்லது GloVe embeddings உடன் முன்பே பயிற்சி செய்யப்பட்ட embedding layer-ஐ பயன்படுத்தலாம். மேலும் விளக்கம் பெற, இந்தக் குறியீட்டை முன்பே பயிற்சி செய்யப்பட்ட embeddings உடன் வேலை செய்ய மாற்ற விரும்பலாம்.\n", "\n", "எங்கள் நிலைமையில், நாங்கள் padded data loader-ஐ பயன்படுத்துவோம், எனவே ஒவ்வொரு தொகுதியிலும் ஒரே நீளத்திலான pad செய்யப்பட்ட வரிசைகளின் எண்ணிக்கை இருக்கும். RNN layer embedding tensors வரிசையை எடுத்துக்கொண்டு இரண்டு output-களை உருவாக்கும்: \n", "* $x$ என்பது ஒவ்வொரு படியில் RNN cell output-களின் வரிசை \n", "* $h$ என்பது வரிசையின் கடைசி உருப்படியின் இறுதி மறைமாநிலம் \n", "\n", "பின்னர், வகுப்புகளின் எண்ணிக்கையை பெற ஒரு முழுமையாக இணைக்கப்பட்ட நேரியல் வகைப்பாட்டாளரை பயன்படுத்துகிறோம்.\n", "\n", "> **குறிப்பு:** RNN-களை பயிற்சி செய்வது மிகவும் கடினம், ஏனெனில் RNN cells வரிசை நீளத்துடன் unroll செய்யப்படும் போது, பின்னடைவு பரவலுக்குள் ஈடுபடும் அடுக்கு எண்ணிக்கை மிகவும் அதிகமாக இருக்கும். எனவே, சிறிய கற்றல் விகிதத்தைத் தேர்ந்தெடுக்கவும், நல்ல முடிவுகளை உருவாக்க பெரிய தரவுத்தொகுப்பில் நெட்வொர்க்கை பயிற்சி செய்யவும் வேண்டும். இது மிகவும் நீண்ட நேரம் எடுக்கக்கூடும், எனவே GPU-ஐ பயன்படுத்துவது விரும்பத்தக்கது.\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.3090625\n", "6400: acc=0.38921875\n", "9600: acc=0.4590625\n", "12800: acc=0.511953125\n", "16000: acc=0.5506875\n", "19200: acc=0.57921875\n", "22400: acc=0.6070089285714285\n", "25600: acc=0.6304296875\n", "28800: acc=0.6484027777777778\n", "32000: acc=0.66509375\n", "35200: acc=0.6790056818181818\n", "38400: acc=0.6929166666666666\n", "41600: acc=0.7035817307692308\n", "44800: acc=0.7137276785714286\n", "48000: acc=0.72225\n", "51200: acc=0.73001953125\n", "54400: acc=0.7372794117647059\n", "57600: acc=0.7436631944444444\n", "60800: acc=0.7503947368421052\n", "64000: acc=0.75634375\n", "67200: acc=0.7615773809523809\n", "70400: acc=0.7662642045454545\n", "73600: acc=0.7708423913043478\n", "76800: acc=0.7751822916666666\n", "80000: acc=0.7790625\n", "83200: acc=0.7825\n", "86400: acc=0.7858564814814815\n", "89600: acc=0.7890513392857142\n", "92800: acc=0.7920474137931034\n", "96000: acc=0.7952708333333334\n", "99200: acc=0.7982258064516129\n", "102400: acc=0.80099609375\n", "105600: acc=0.8037594696969697\n", "108800: acc=0.8060569852941176\n" ] } ], "source": [ "train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)\n", "net = RNNClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch(net,train_loader, lr=0.001)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## நீண்ட குறுகிய கால நினைவகம் (LSTM)\n", "\n", "சாதாரண RNNகளின் முக்கிய பிரச்சனைகளில் ஒன்று **மங்கும் சாய்வு** பிரச்சனை. RNNகள் ஒரே பின்செலுத்தல் செயல்முறையில் முடிவுக்கு முடிவு வரை பயிற்சி பெறுவதால், பிழையை நெடுவான அடுக்கு முதல் அடுக்கு வரை பரப்புவதில் சிரமம் ஏற்படுகிறது, இதனால் நெட்வொர்க் தூரமான டோக்கன்களுக்கிடையிலான தொடர்புகளை கற்றுக்கொள்ள முடியாது. இந்த பிரச்சனையை தவிர்க்க ஒரு வழி **வெளிப்படையான நிலை மேலாண்மை** அறிமுகப்படுத்துவது, அதாவது **கேடுகள்** பயன்படுத்துவது. இந்த வகை அமைப்புகளில் மிகவும் பிரபலமான இரண்டு வடிவமைப்புகள்: **நீண்ட குறுகிய கால நினைவகம்** (LSTM) மற்றும் **கேடட் ரிலே யூனிட்** (GRU).\n", "\n", "![நீண்ட குறுகிய கால நினைவக செலின் உதாரணத்தை காட்டும் படம்](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n", "\n", "LSTM நெட்வொர்க் RNN போலவே அமைக்கப்பட்டுள்ளது, ஆனால் இரண்டு நிலைகள் அடுக்கு முதல் அடுக்கு வரை அனுப்பப்படுகின்றன: உண்மையான நிலை $c$, மற்றும் மறைக்கப்பட்ட வெக்டர் $h$. ஒவ்வொரு யூனிடிலும், மறைக்கப்பட்ட வெக்டர் $h_i$ உள்ளீடு $x_i$ உடன் இணைக்கப்படுகிறது, மற்றும் அவை **கேடுகள்** மூலம் நிலை $c$ இல் என்ன நடக்கிறது என்பதை கட்டுப்படுத்துகின்றன. ஒவ்வொரு கேடும் சிக்மாய்டு செயல்பாட்டுடன் (வெளியீடு $[0,1]$ வரம்பில்) ஒரு நரம்பியல் நெட்வொர்க் ஆகும், இது நிலை வெக்டருடன் பெருக்கப்பட்டால் பிட்வைஸ் மாஸ்க் போல கருதலாம். மேலே உள்ள படத்தில் இடது பக்கம் முதல் வலது பக்கம் வரை உள்ள கேடுகள்:\n", "* **மறக்கும் கேடு** மறைக்கப்பட்ட வெக்டரை எடுத்து, வெக்டர் $c$ இன் எந்த கூறுகளை நாம் மறக்க வேண்டும், மற்றும் எவை வழியாக செல்ல வேண்டும் என்பதை தீர்மானிக்கிறது.\n", "* **உள்ளீட்டு கேடு** உள்ளீடு மற்றும் மறைக்கப்பட்ட வெக்டரிலிருந்து சில தகவல்களை எடுத்து, அதை நிலைக்கு சேர்க்கிறது.\n", "* **வெளியீட்டு கேடு** நிலையை $\\tanh$ செயல்பாட்டுடன் சில நேரியல் அடுக்கு மூலம் மாற்றி, அதன் சில கூறுகளை மறைக்கப்பட்ட வெக்டர் $h_i$ பயன்படுத்தி புதிய நிலை $c_{i+1}$ உருவாக்குகிறது.\n", "\n", "நிலை $c$ இன் கூறுகளை சில கொடிகள் (flags) போல கருதலாம், அவற்றை ஆன் அல்லது ஆஃப் செய்யலாம். உதாரணமாக, ஒரு வரிசையில் *Alice* என்ற பெயரை சந்திக்கும் போது, அது பெண் கதாபாத்திரத்தை குறிக்கிறது என்று கருதி, அந்த வாக்கியத்தில் பெண் பெயர்ச்சொல் உள்ளது என்பதை குறிக்கும் கொடியை நிலையில் உயர்த்தலாம். பின்னர் *and Tom* என்ற சொற்றொடரை சந்திக்கும் போது, பலவினை பெயர்ச்சொல் உள்ளது என்பதை குறிக்கும் கொடியை உயர்த்தலாம். இவ்வாறு நிலையை மாற்றுவதன் மூலம், வாக்கியத்தின் பகுதிகளின் இலக்கண பண்புகளை கண்காணிக்க முடியும்.\n", "\n", "> **குறிப்பு**: LSTM-களின் உள் அமைப்புகளை புரிந்துகொள்ள சிறந்த ஆதாரம், Christopher Olah எழுதிய [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) என்ற சிறந்த கட்டுரை.\n", "\n", "LSTM செலின் உள் அமைப்பு சிக்கலாக தோன்றினாலும், PyTorch இந்த செயல்பாட்டை `LSTMCell` வகுப்பில் மறைக்கிறது, மேலும் முழு LSTM அடுக்கை பிரதிநிதித்துவப்படுத்த `LSTM` பொருளை வழங்குகிறது. எனவே, LSTM வகைப்பாட்டாளரை செயல்படுத்துவது மேலே பார்த்த எளிய RNN போலவே இருக்கும்:\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class LSTMClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n", " self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " x,(h,c) = self.rnn(x)\n", " return self.fc(h[-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "இப்போது நமது நெட்வொர்க்கை பயிற்சி செய்யலாம். LSTM-ஐ பயிற்சி செய்வது மெல்லியதாக இருக்கும் என்பதை கவனிக்கவும், மேலும் பயிற்சியின் தொடக்கத்தில் துல்லியத்தில் அதிக உயர்வு தெரியாமல் இருக்கலாம். மேலும், `lr` எனும் கற்றல் வீதம் அளவுருவுடன் விளையாடி, நியாயமான பயிற்சி வேகத்தை வழங்கும் கற்றல் வீதத்தை கண்டறியவும், அதே நேரத்தில் நினைவகத்தை வீணாக்காமல் இருக்கவும் தேவைப்படலாம்.\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.259375\n", "6400: acc=0.25859375\n", "9600: acc=0.26177083333333334\n", "12800: acc=0.2784375\n", "16000: acc=0.313\n", "19200: acc=0.3528645833333333\n", "22400: acc=0.3965625\n", "25600: acc=0.4385546875\n", "28800: acc=0.4752777777777778\n", "32000: acc=0.505375\n", "35200: acc=0.5326704545454546\n", "38400: acc=0.5557552083333334\n", "41600: acc=0.5760817307692307\n", "44800: acc=0.5954910714285714\n", "48000: acc=0.6118333333333333\n", "51200: acc=0.62681640625\n", "54400: acc=0.6404779411764706\n", "57600: acc=0.6520138888888889\n", "60800: acc=0.662828947368421\n", "64000: acc=0.673546875\n", "67200: acc=0.6831547619047619\n", "70400: acc=0.6917897727272727\n", "73600: acc=0.6997146739130434\n", "76800: acc=0.707109375\n", "80000: acc=0.714075\n", "83200: acc=0.7209134615384616\n", "86400: acc=0.727037037037037\n", "89600: acc=0.7326674107142858\n", "92800: acc=0.7379633620689655\n", "96000: acc=0.7433645833333333\n", "99200: acc=0.7479032258064516\n", "102400: acc=0.752119140625\n", "105600: acc=0.7562405303030303\n", "108800: acc=0.76015625\n", "112000: acc=0.7641339285714286\n", "115200: acc=0.7677777777777778\n", "118400: acc=0.7711233108108108\n" ] }, { "data": { "text/plain": [ "(0.03487814127604167, 0.7728)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net = LSTMClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch(net,train_loader, lr=0.001)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## தொகுக்கப்பட்ட வரிசைகள்\n", "\n", "எங்கள் எடுத்துக்காட்டில், மினிபேச்சில் உள்ள அனைத்து வரிசைகளையும் பூஜ்ய வெக்டர்களுடன் நிரப்ப வேண்டியிருந்தது. இது நினைவகத்தை வீணாக்குவதற்கு வழிவகுக்கும், ஆனால் RNNகளுடன், நிரப்பப்பட்ட உள்ளீட்டு உருப்படிகளுக்காக கூடுதல் RNN செல்கள் உருவாக்கப்படுவது மிகவும் முக்கியமானது, அவை பயிற்சியில் பங்கேற்கின்றன, ஆனால் எந்த முக்கியமான உள்ளீட்டு தகவலையும் கொண்டிருக்கவில்லை. உண்மையான வரிசை அளவுக்கு மட்டுமே RNN-ஐ பயிற்சி செய்ய வேண்டும்.\n", "\n", "அதைச் செய்ய, PyTorch-ல் நிரப்பப்பட்ட வரிசை சேமிப்பு ஒரு சிறப்பு வடிவத்தில் அறிமுகப்படுத்தப்பட்டுள்ளது. நாம் இந்த மாதிரியான ஒரு நிரப்பப்பட்ட மினிபேச்சை வைத்திருக்கிறோம் என்று கருதுங்கள்:\n", "```\n", "[[1,2,3,4,5],\n", " [6,7,8,0,0],\n", " [9,0,0,0,0]]\n", "```\n", "இங்கு 0 நிரப்பப்பட்ட மதிப்புகளை குறிக்கிறது, மற்றும் உள்ளீட்டு வரிசைகளின் உண்மையான நீள வெக்டர் `[5,3,1]`.\n", "\n", "நிரப்பப்பட்ட வரிசையுடன் RNN-ஐ பயிற்சி செய்ய பயனுள்ளதாக, RNN செல்களின் முதல் குழுவை பெரிய மினிபேச்சுடன் (`[1,6,9]`) பயிற்சி செய்யத் தொடங்க விரும்புகிறோம், ஆனால் மூன்றாவது வரிசையின் செயல்பாட்டை முடித்து, குறுகிய மினிபேச்சுகளுடன் (`[2,7]`, `[3,8]`) பயிற்சியை தொடர வேண்டும், இப்படி. எனவே, தொகுக்கப்பட்ட வரிசை ஒரு வெக்டராக பிரதிநிதித்துவம் செய்யப்படுகிறது - எங்கள் வழக்கில் `[1,6,9,2,7,3,8,4,5]`, மற்றும் நீள வெக்டர் (`[5,3,1]`), இதிலிருந்து நாம் ஆரம்ப நிரப்பப்பட்ட மினிபேச்சை எளிதாக மீண்டும் உருவாக்கலாம்.\n", "\n", "தொகுக்கப்பட்ட வரிசையை உருவாக்க, `torch.nn.utils.rnn.pack_padded_sequence` செயல்பாட்டைப் பயன்படுத்தலாம். RNN, LSTM மற்றும் GRU உட்பட அனைத்து மறு நிகழ்வு அடுக்குகளும், உள்ளீடாக தொகுக்கப்பட்ட வரிசைகளை ஆதரிக்கின்றன, மற்றும் தொகுக்கப்பட்ட வெளியீட்டை உருவாக்குகின்றன, இது `torch.nn.utils.rnn.pad_packed_sequence` மூலம் டிகோடு செய்யலாம்.\n", "\n", "தொகுக்கப்பட்ட வரிசையை உருவாக்க முடியும், நெடுவரிசை வெக்டரை நெட்வொர்க்கிற்கு அனுப்ப வேண்டும், எனவே மினிபேச்சுகளைத் தயாரிக்க ஒரு வேறு செயல்பாட்டை தேவைப்படும்:\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def pad_length(b):\n", " # build vectorized sequence\n", " v = [encode(x[1]) for x in b]\n", " # compute max length of a sequence in this minibatch and length sequence itself\n", " len_seq = list(map(len,v))\n", " l = max(len_seq)\n", " return ( # tuple of three tensors - labels, padded features, length sequence\n", " torch.LongTensor([t[0]-1 for t in b]),\n", " torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v]),\n", " torch.tensor(len_seq)\n", " )\n", "\n", "train_loader_len = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=pad_length, shuffle=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "உண்மையான நெட்வொர்க் மேலே உள்ள `LSTMClassifier` போன்றதே இருக்கும், ஆனால் `forward` பாஸ் பேடட் மினிபேட்ச் மற்றும் வரிசை நீளங்களின் வெக்டரைப் பெறும். எம்பெடிங் கணக்கிடப்பட்ட பிறகு, நாங்கள் பேக்டு வரிசையை கணக்கிடுகிறோம், அதை LSTM லேயருக்கு அனுப்புகிறோம், பின்னர் முடிவை மீண்டும் அன்பேக் செய்கிறோம்.\n", "\n", "> **குறிப்பு**: நாங்கள் உண்மையில் அன்பேக் செய்யப்பட்ட முடிவான `x` ஐ பயன்படுத்தவில்லை, ஏனெனில் அடுத்த கணக்கீடுகளில் நாங்கள் மறைமுக லேயர்களின் அவுட்புட் ஐ பயன்படுத்துகிறோம். எனவே, இந்தக் குறியீட்டிலிருந்து அன்பேக்கிங் முற்றிலும் நீக்கலாம். நெட்வொர்க் அவுட்புட் ஐ மேலும் கணக்கீடுகளில் பயன்படுத்த வேண்டிய அவசியம் ஏற்பட்டால், நீங்கள் இந்தக் குறியீட்டை எளிதாக மாற்ற முடியும் என்பதற்காகவே இதை இங்கு வைத்துள்ளோம்.\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "class LSTMPackClassifier(torch.nn.Module):\n", " def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n", " super().__init__()\n", " self.hidden_dim = hidden_dim\n", " self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n", " self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n", " self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n", " self.fc = torch.nn.Linear(hidden_dim, num_class)\n", "\n", " def forward(self, x, lengths):\n", " batch_size = x.size(0)\n", " x = self.embedding(x)\n", " pad_x = torch.nn.utils.rnn.pack_padded_sequence(x,lengths,batch_first=True,enforce_sorted=False)\n", " pad_x,(h,c) = self.rnn(pad_x)\n", " x, _ = torch.nn.utils.rnn.pad_packed_sequence(pad_x,batch_first=True)\n", " return self.fc(h[-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "இப்போது பயிற்சியை செய்யலாம்:\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3200: acc=0.285625\n", "6400: acc=0.33359375\n", "9600: acc=0.3876041666666667\n", "12800: acc=0.44078125\n", "16000: acc=0.4825\n", "19200: acc=0.5235416666666667\n", "22400: acc=0.5559821428571429\n", "25600: acc=0.58609375\n", "28800: acc=0.6116666666666667\n", "32000: acc=0.63340625\n", "35200: acc=0.6525284090909091\n", "38400: acc=0.668515625\n", "41600: acc=0.6822596153846154\n", "44800: acc=0.6948214285714286\n", "48000: acc=0.7052708333333333\n", "51200: acc=0.71521484375\n", "54400: acc=0.7239889705882353\n", "57600: acc=0.7315277777777778\n", "60800: acc=0.7388486842105263\n", "64000: acc=0.74571875\n", "67200: acc=0.7518303571428572\n", "70400: acc=0.7576988636363636\n", "73600: acc=0.7628940217391305\n", "76800: acc=0.7681510416666667\n", "80000: acc=0.7728125\n", "83200: acc=0.7772235576923077\n", "86400: acc=0.7815393518518519\n", "89600: acc=0.7857700892857142\n", "92800: acc=0.7895043103448276\n", "96000: acc=0.7930520833333333\n", "99200: acc=0.7959072580645161\n", "102400: acc=0.798994140625\n", "105600: acc=0.802064393939394\n", "108800: acc=0.8051378676470589\n", "112000: acc=0.8077857142857143\n", "115200: acc=0.8104600694444445\n", "118400: acc=0.8128293918918919\n" ] }, { "data": { "text/plain": [ "(0.029785829671223958, 0.8138166666666666)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "net = LSTMPackClassifier(vocab_size,64,32,len(classes)).to(device)\n", "train_epoch_emb(net,train_loader_len, lr=0.001,use_pack_sequence=True)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **குறிப்பு:** நீங்கள் பயிற்சி செயல்பாட்டிற்கு `use_pack_sequence` என்ற அளவுருவை அனுப்புவதைக் கவனித்திருக்கலாம். தற்போது, `pack_padded_sequence` செயல்பாடு நீள வரிசை டென்சரை CPU சாதனத்தில் வைத்திருக்க வேண்டும், எனவே பயிற்சி செயல்பாடு பயிற்சியின் போது நீள வரிசை தரவுகளை GPU-க்கு நகர்த்துவதை தவிர்க்க வேண்டும். [`torchnlp.py`](../../../../../lessons/5-NLP/16-RNN/torchnlp.py) கோப்பில் உள்ள `train_emb` செயல்பாட்டின் செயல்பாட்டை நீங்கள் பார்க்கலாம்.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## இரு திசை மற்றும் பல அடுக்கு RNNகள்\n", "\n", "எங்கள் எடுத்துக்காட்டுகளில், அனைத்து மீளச்சுழற்சி நெட்வொர்க்குகளும் ஒரு திசையில் செயல்பட்டன, ஒரு வரிசையின் தொடக்கத்திலிருந்து முடிவுக்கு. இது இயல்பாகவே தெரிகிறது, ஏனெனில் இது நாம் படிக்கும் மற்றும் பேச்சை கேட்கும் முறையை ஒத்ததாக உள்ளது. ஆனால், பல நடைமுறை சந்தர்ப்பங்களில் நாங்கள் உள்ளீட்டு வரிசையை சீரற்ற அணுகலில் அணுக முடியும், எனவே மீளச்சுழற்சி கணக்கீட்டை இரு திசைகளிலும் இயக்குவது பொருத்தமாக இருக்கலாம். இத்தகைய நெட்வொர்க்குகள் **இரு திசை** RNNகள் என அழைக்கப்படுகின்றன, மேலும் RNN/LSTM/GRU கட்டமைப்பாளருக்கு `bidirectional=True` என்ற அளவுருவை வழங்குவதன் மூலம் அவற்றை உருவாக்கலாம்.\n", "\n", "இரு திசை நெட்வொர்க்குடன் செயல்படும்போது, ஒவ்வொரு திசைக்கும் ஒரு ஒளியக நிலை வெக்டரின் தேவை ஏற்படும். PyTorch இந்த வெக்டர்களை இரட்டிப்பு அளவுடைய ஒரு வெக்டராக குறியாக்குகிறது, இது மிகவும் வசதியாக உள்ளது, ஏனெனில் நீங்கள் பொதுவாக resulting hidden state-ஐ முழுமையாக இணைக்கப்பட்ட நேரியல் அடுக்கு (fully-connected linear layer)க்கு அனுப்புவீர்கள், மேலும் இந்த அளவின் அதிகரிப்பை அந்த அடுக்கை உருவாக்கும்போது கணக்கில் எடுத்துக்கொள்ள வேண்டும்.\n", "\n", "ஒரு திசை அல்லது இரு திசை மீளச்சுழற்சி நெட்வொர்க்கு, ஒரு வரிசையின் குறிப்பிட்ட முறைமைகளை பிடித்து, அவற்றை state வெக்டரில் சேமிக்க அல்லது output-க்கு அனுப்ப முடியும். குவால்வோல்யூஷனல் நெட்வொர்க்குகளின் (convolutional networks) போல, முதல் அடுக்கால் எடுக்கப்பட்ட குறைந்த நிலை முறைமைகளிலிருந்து உயர் நிலை முறைமைகளை பிடிக்க, முதல் அடுக்கின் மேல் மற்றொரு மீளச்சுழற்சி அடுக்கை கட்டமைக்கலாம். இது **பல அடுக்கு RNN** என்ற கருத்துக்கு வழிவகுக்கிறது, இது இரண்டு அல்லது அதற்கு மேற்பட்ட மீளச்சுழற்சி நெட்வொர்க்குகளை கொண்டுள்ளது, இதில் முந்தைய அடுக்கின் output அடுத்த அடுக்கிற்கு input ஆக அனுப்பப்படுகிறது.\n", "\n", "![பல அடுக்கு நீண்ட-குறுகிய-கால நினைவக RNN-ஐ காட்டும் படம்](../../../../../translated_images/ta/multi-layer-lstm.dd975e29bb2a59fe.webp)\n", "\n", "*Fernando López எழுதிய [இந்த அற்புதமான பதிவிலிருந்து](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) படம்*\n", "\n", "PyTorch இத்தகைய நெட்வொர்க்குகளை உருவாக்குவதை எளிதாக்குகிறது, ஏனெனில் RNN/LSTM/GRU கட்டமைப்பாளருக்கு `num_layers` என்ற அளவுருவை வழங்குவதன் மூலம் மீளச்சுழற்சி அடுக்குகளை தானாகவே உருவாக்க முடியும். இது hidden/state வெக்டரின் அளவு சீராக அதிகரிக்கும் என்பதையும் பொருள் படுத்தும், மேலும் மீளச்சுழற்சி அடுக்குகளின் output-ஐ கையாளும்போது இதை கணக்கில் எடுத்துக்கொள்ள வேண்டும்.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## RNNகள் மற்ற பணிகளுக்கு\n", "\n", "இந்த பிரிவில், RNNகள் வரிசை வகைப்படுத்தலுக்கு பயன்படுத்தப்படலாம் என்பதை நாம் பார்த்தோம், ஆனால் உண்மையில், அவை மேலும் பல பணிகளைச் செய்ய முடியும், உதாரணமாக உரை உருவாக்கல், இயந்திர மொழிபெயர்ப்பு மற்றும் பல. அடுத்த பிரிவில் நாம் அந்த பணிகளைப் பரிசீலிக்கப் போகிறோம்.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**குறிப்பு**: \nஇந்த ஆவணம் [Co-op Translator](https://github.com/Azure/co-op-translator) என்ற AI மொழிபெயர்ப்பு சேவையைப் பயன்படுத்தி மொழிபெயர்க்கப்பட்டுள்ளது. நாங்கள் துல்லியத்திற்காக முயற்சிக்கிறோம், ஆனால் தானியங்கி மொழிபெயர்ப்புகளில் பிழைகள் அல்லது தவறான தகவல்கள் இருக்கக்கூடும் என்பதை தயவுசெய்து கவனத்தில் கொள்ளுங்கள். அதன் தாய்மொழியில் உள்ள மூல ஆவணம் அதிகாரப்பூர்வ ஆதாரமாக கருதப்பட வேண்டும். முக்கியமான தகவல்களுக்கு, தொழில்முறை மனித மொழிபெயர்ப்பு பரிந்துரைக்கப்படுகிறது. இந்த மொழிபெயர்ப்பைப் பயன்படுத்துவதால் ஏற்படும் எந்த தவறான புரிதல்கள் அல்லது தவறான விளக்கங்களுக்கு நாங்கள் பொறுப்பல்ல.\n" ] } ], "metadata": { "interpreter": { "hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f" }, "kernelspec": { "display_name": "Python 3.8.12 ('py38')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" }, "coopTranslator": { "original_hash": "522ee52ae3d5ae933e283286254e9a55", "translation_date": "2025-10-11T12:55:57+00:00", "source_file": "lessons/5-NLP/16-RNN/RNNPyTorch.ipynb", "language_code": "ta" } }, "nbformat": 4, "nbformat_minor": 2 }