{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# പുനരാവർത്തിത ന്യൂറൽ നെറ്റ്‌വർക്കുകൾ\n", "\n", "മുൻ മോഡ്യൂളിൽ, നാം വാചകത്തിന്റെ സമൃദ്ധമായ സാംവേദനാത്മക പ്രതിനിധാനങ്ങൾ പഠിച്ചു. നാം ഉപയോഗിച്ച ആർക്കിടെക്ചർ വാചകത്തിലെ വാക്കുകളുടെ സംയുക്ത അർത്ഥം പിടിച്ചുപറ്റുന്നു, പക്ഷേ വാക്കുകളുടെ **ക്രമം** പരിഗണിക്കുന്നില്ല, കാരണം എംബെഡിംഗുകൾക്ക് ശേഷം നടക്കുന്ന സംയോജനം ഈ വിവരങ്ങൾ മൊഴിയുടെ യഥാർത്ഥ രൂപത്തിൽ നിന്ന് നീക്കം ചെയ്യുന്നു. ഈ മോഡലുകൾ വാക്കുകളുടെ ക്രമീകരണം പ്രതിനിധാനം ചെയ്യാൻ കഴിയാത്തതിനാൽ, വാചക സൃഷ്ടി അല്ലെങ്കിൽ ചോദ്യോത്തരങ്ങൾ പോലുള്ള കൂടുതൽ സങ്കീർണ്ണമായ അല്ലെങ്കിൽ സംശയാസ്പദമായ പ്രവർത്തനങ്ങൾ പരിഹരിക്കാൻ കഴിയില്ല.\n", "\n", "ഒരു വാചക ശ്രേണിയുടെ അർത്ഥം പിടിച്ചുപറ്റാൻ, നാം **പുനരാവർത്തിത ന്യൂറൽ നെറ്റ്‌വർക്ക്** എന്നറിയപ്പെടുന്ന ഒരു ന്യൂറൽ നെറ്റ്‌വർക്ക് ആർക്കിടെക്ചർ ഉപയോഗിക്കും, അതായത് RNN. RNN ഉപയോഗിക്കുമ്പോൾ, നാം വാചകം ഓരോ ടോക്കണും ഒരിക്കൽ씩 നെറ്റ്‌വർക്കിലൂടെ കടത്തുന്നു, നെറ്റ്‌വർക്ക് ചില **സ്റ്റേറ്റ്** ഉൽപ്പാദിപ്പിക്കുന്നു, അത് പിന്നീട് അടുത്ത ടോക്കണുമായി വീണ്ടും നെറ്റ്‌വർക്കിലേക്ക് നൽകുന്നു.\n", "\n", "![പുനരാവർത്തിത ന്യൂറൽ നെറ്റ്‌വർക്ക് ഉദാഹരണ സൃഷ്ടി കാണിക്കുന്ന ചിത്രം.](../../../../../translated_images/ml/rnn.27f5c29c53d727b5.webp)\n", "\n", "ഇൻപുട്ട് ടോക്കൺ ശ്രേണി $X_0,\\dots,X_n$ നൽകിയാൽ, RNN ന്യൂറൽ നെറ്റ്‌വർക്ക് ബ്ലോക്കുകളുടെ ഒരു ശ്രേണി സൃഷ്ടിക്കുന്നു, ഈ ശ്രേണി ബാക്ക്‌പ്രൊപ്പഗേഷൻ ഉപയോഗിച്ച് എന്റു-ടു-എൻഡ് പരിശീലിപ്പിക്കുന്നു. ഓരോ നെറ്റ്‌വർക്ക് ബ്ലോക്കും $(X_i,S_i)$ എന്ന ജോഡി ഇൻപുട്ടായി സ്വീകരിച്ച് $S_{i+1}$ എന്ന ഔട്ട്പുട്ട് നൽകുന്നു. അവസാന സ്റ്റേറ്റ് $S_n$ അല്ലെങ്കിൽ ഔട്ട്പുട്ട് $Y_n$ ഒരു ലീനിയർ ക്ലാസിഫയറിലേക്ക് പോകുന്നു ഫലം ഉൽപ്പാദിപ്പിക്കാൻ. എല്ലാ നെറ്റ്‌വർക്ക് ബ്ലോക്കുകളും ഒരേ ഭാരങ്ങൾ പങ്കുവെക്കുന്നു, ഒറ്റ ബാക്ക്‌പ്രൊപ്പഗേഷൻ പാസിലൂടെ എന്റു-ടു-എൻഡ് പരിശീലിപ്പിക്കുന്നു.\n", "\n", "> മുകളിൽ കാണുന്ന ചിത്രം പുനരാവർത്തിത ന്യൂറൽ നെറ്റ്‌വർക്ക് അനറോൾഡ് രൂപത്തിൽ (ഇടത്തരം) കൂടാതെ കൂടുതൽ സംക്ഷിപ്തമായ പുനരാവർത്തിത പ്രതിനിധാനത്തിൽ (വലത്തരം) കാണിക്കുന്നു. എല്ലാ RNN സെല്ലുകൾക്കും ഒരേ **പങ്കിടാവുന്ന ഭാരങ്ങൾ** ഉണ്ടെന്ന് മനസ്സിലാക്കുന്നത് പ്രധാനമാണ്.\n", "\n", "സ്റ്റേറ്റ് വെക്ടറുകൾ $S_0,\\dots,S_n$ നെറ്റ്‌വർക്കിലൂടെ കടത്തപ്പെടുന്നതിനാൽ, RNN വാക്കുകൾ തമ്മിലുള്ള അനുക്രമപരമായ ആശ്രിതത്വങ്ങൾ പഠിക്കാൻ കഴിയും. ഉദാഹരണത്തിന്, *not* എന്ന വാക്ക് ശ്രേണിയിൽ എവിടെയെങ്കിലും വന്നാൽ, അത് സ്റ്റേറ്റ് വെക്ടറിലെ ചില ഘടകങ്ങളെ നിഷേധിക്കാൻ പഠിക്കാം.\n", "\n", "ഓരോ RNN സെല്ലിനുള്ളിൽ രണ്ട് ഭാര മാട്രിസുകൾ ഉണ്ട്: $W_H$യും $W_I$യും, കൂടാതെ ബയാസ് $b$. ഓരോ RNN ഘട്ടത്തിലും, ഇൻപുട്ട് $X_i$യും ഇൻപുട്ട് സ്റ്റേറ്റ് $S_i$യും നൽകിയാൽ, ഔട്ട്പുട്ട് സ്റ്റേറ്റ് $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$ എന്നിങ്ങനെ കണക്കാക്കുന്നു, ഇവിടെ $f$ ഒരു ആക്ടിവേഷൻ ഫംഗ്ഷനാണ് (സാധാരണയായി $\\tanh$).\n", "\n", "> വാചക സൃഷ്ടി പോലുള്ള പ്രശ്നങ്ങൾക്കായി (അടുത്ത യൂണിറ്റിൽ നാം പഠിക്കും) അല്ലെങ്കിൽ മെഷീൻ വിവർത്തനത്തിനായി, ഓരോ RNN ഘട്ടത്തിലും ചില ഔട്ട്പുട്ട് മൂല്യവും ലഭിക്കണം. ഈ സാഹചര്യത്തിൽ, മറ്റൊരു മാട്രിക്സ് $W_O$ ഉണ്ട്, ഔട്ട്പുട്ട് $Y_i=f(W_O\\times S_i+b_O)$ എന്നിങ്ങനെ കണക്കാക്കുന്നു.\n", "\n", "പുനരാവർത്തിത ന്യൂറൽ നെറ്റ്‌വർക്കുകൾ നമ്മുടെ വാർത്താ ഡാറ്റാസെറ്റ് ക്ലാസിഫൈ ചെയ്യുന്നതിൽ എങ്ങനെ സഹായിക്കാമെന്ന് നോക്കാം.\n", "\n", "> സാൻഡ്‌ബോക്സ് പരിസ്ഥിതിക്കായി, ആവശ്യമായ ലൈബ്രറി ഇൻസ്റ്റാൾ ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കാനും ഡാറ്റ പ്രിഫെച്ച് ചെയ്യാനും താഴെ കാണുന്ന സെൽ പ്രവർത്തിപ്പിക്കേണ്ടതാണ്. നിങ്ങൾ ലോക്കലായി പ്രവർത്തിപ്പിക്കുന്നുവെങ്കിൽ, താഴെ കാണുന്ന സെൽ ഒഴിവാക്കാം.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sys\n", "!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0\n", "!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", "import tensorflow_datasets as tfds\n", "import numpy as np\n", "\n", "# We are going to be training pretty large models. In order not to face errors, we need\n", "# to set tensorflow option to grow GPU memory allocation when required\n", "physical_devices = tf.config.list_physical_devices('GPU') \n", "if len(physical_devices)>0:\n", " tf.config.experimental.set_memory_growth(physical_devices[0], True)\n", "\n", "ds_train, ds_test = tfds.load('ag_news_subset').values()" ] }, { "cell_type": "markdown", "metadata": { "nteract": { "transient": { "deleting": false } } }, "source": [ "വലിയ മോഡലുകൾ പരിശീലിപ്പിക്കുമ്പോൾ, GPU മെമ്മറി അലോക്കേഷൻ പ്രശ്നമായി മാറാം. ഡാറ്റ GPU മെമ്മറിയിൽ ഫിറ്റ് ആകുകയും പരിശീലനം വേഗത്തിൽ നടക്കുകയും ചെയ്യാൻ, വ്യത്യസ്ത മിനിബാച്ച് വലുപ്പങ്ങൾ പരീക്ഷിക്കേണ്ടതുണ്ടാകാം. നിങ്ങൾ ഈ കോഡ് നിങ്ങളുടെ സ്വന്തം GPU യന്ത്രത്തിൽ ഓടിക്കുന്നുവെങ്കിൽ, പരിശീലനം വേഗത്തിലാക്കാൻ മിനിബാച്ച് വലുപ്പം ക്രമീകരിച്ച് പരീക്ഷിക്കാം.\n", "\n", "> **Note**: NVidia ഡ്രൈവർസിന്റെ ചില പതിപ്പുകൾ മോഡൽ പരിശീലനത്തിന് ശേഷം മെമ്മറി റിലീസ് ചെയ്യാത്തതായി അറിയപ്പെടുന്നു. ഈ നോട്ട്‌ബുക്കിൽ നാം പല ഉദാഹരണങ്ങളും ഓടിക്കുന്നതിനാൽ, പ്രത്യേകിച്ച് നിങ്ങൾ ഈ നോട്ട്‌ബുക്കിന്റെ ഭാഗമായുള്ള പരീക്ഷണങ്ങൾ നടത്തുമ്പോൾ, ചില സജ്ജീകരണങ്ങളിൽ മെമ്മറി തീരാൻ സാധ്യതയുണ്ട്. മോഡൽ പരിശീലനം ആരംഭിക്കുമ്പോൾ ചില അസാധാരണ പിശകുകൾ നേരിടുകയാണെങ്കിൽ, നോട്ട്‌ബുക്ക് കർണൽ പുനരാരംഭിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കാം.\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": false, "source_hidden": false }, "nteract": { "transient": { "deleting": false } } }, "outputs": [], "source": [ "batch_size = 16\n", "embed_size = 64" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ലളിതമായ RNN ക്ലാസിഫയർ\n", "\n", "ലളിതമായ RNN-ന്റെ കാര്യത്തിൽ, ഓരോ റിക്കറന്റ് യൂണിറ്റും ഒരു ലളിതമായ ലീനിയർ നെറ്റ്‌വർക്കാണ്, ഇത് ഒരു ഇൻപുട്ട് വെക്ടറും സ്റ്റേറ്റ് വെക്ടറും സ്വീകരിച്ച് പുതിയ സ്റ്റേറ്റ് വെക്ടർ ഉത്പാദിപ്പിക്കുന്നു. Keras-ൽ ഇത് `SimpleRNN` ലെയർ ഉപയോഗിച്ച് പ്രതിനിധീകരിക്കാം.\n", "\n", "RNN ലെയറിലേക്ക് നേരിട്ട് വൺ-ഹോട്ട് എൻകോഡഡ് ടോക്കണുകൾ നൽകാമെങ്കിലും, അവയുടെ ഉയർന്ന ഡൈമെൻഷണാലിറ്റിയുടെ കാരണം ഇത് നല്ല ആശയമല്ല. അതിനാൽ, വാക്കുകളുടെ വെക്ടറുകളുടെ ഡൈമെൻഷണാലിറ്റി കുറയ്ക്കാൻ ഒരു എംബെഡ്ഡിംഗ് ലെയർ ഉപയോഗിച്ച്, തുടർന്ന് RNN ലെയർ, ഒടുവിൽ `Dense` ക്ലാസിഫയർ ഉപയോഗിക്കും.\n", "\n", "> **Note**: ഡൈമെൻഷണാലിറ്റി അത്ര ഉയർന്നതല്ലാത്ത സാഹചര്യങ്ങളിൽ, ഉദാഹരണത്തിന് കറക്റ്റർ-ലെവൽ ടോക്കണൈസേഷൻ ഉപയോഗിക്കുമ്പോൾ, വൺ-ഹോട്ട് എൻകോഡഡ് ടോക്കണുകൾ നേരിട്ട് RNN സെല്ലിലേക്ക് നൽകുന്നത് യുക്തിയുള്ളതായിരിക്കാം.\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential\"\n", "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "text_vectorization (TextVect (None, None) 0 \n", "_________________________________________________________________\n", "embedding (Embedding) (None, None, 64) 1280000 \n", "_________________________________________________________________\n", "simple_rnn (SimpleRNN) (None, 16) 1296 \n", "_________________________________________________________________\n", "dense (Dense) (None, 4) 68 \n", "=================================================================\n", "Total params: 1,281,364\n", "Trainable params: 1,281,364\n", "Non-trainable params: 0\n", "_________________________________________________________________\n" ] } ], "source": [ "vocab_size = 20000\n", "\n", "vectorizer = keras.layers.experimental.preprocessing.TextVectorization(\n", " max_tokens=vocab_size,\n", " input_shape=(1,))\n", "\n", "model = keras.models.Sequential([\n", " vectorizer,\n", " keras.layers.Embedding(vocab_size, embed_size),\n", " keras.layers.SimpleRNN(16),\n", " keras.layers.Dense(4,activation='softmax')\n", "])\n", "\n", "model.summary()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **കുറിപ്പ്:** എളുപ്പത്തിനായി ഇവിടെ ഒരു പരിശീലനമില്ലാത്ത എംബെഡിംഗ് ലെയർ ഉപയോഗിക്കുന്നു, പക്ഷേ മുൻവശം യൂണിറ്റിൽ വിവരിച്ച പോലെ Word2Vec ഉപയോഗിച്ച് പരിശീലനമേറ്റ എംബെഡിംഗ് ലെയർ ഉപയോഗിക്കുന്നത് മികച്ച ഫലങ്ങൾ നൽകും. ഈ കോഡ് pretrained embeddings ഉപയോഗിച്ച് പ്രവർത്തിക്കാൻ നിങ്ങൾക്ക് മാറ്റി ഉപയോഗിക്കുന്നത് നല്ല അഭ്യാസമായിരിക്കും.\n", "\n", "ഇപ്പോൾ നമുക്ക് RNN പരിശീലിപ്പിക്കാം. സാധാരണയായി RNNകൾ പരിശീലിപ്പിക്കുന്നത് വളരെ ബുദ്ധിമുട്ടാണ്, കാരണം RNN സെല്ലുകൾ സീക്വൻസ് നീളത്തിന് അനുസരിച്ച് അനറോൾ ചെയ്താൽ, ബാക്ക്‌പ്രൊപ്പഗേഷനിൽ ഉൾപ്പെടുന്ന ലെയറുകളുടെ എണ്ണം വളരെ കൂടുതലാകും. അതിനാൽ ചെറിയ ലേണിംഗ് റേറ്റ് തിരഞ്ഞെടുക്കുകയും നല്ല ഫലങ്ങൾ ലഭിക്കാൻ വലിയ ഡാറ്റാസെറ്റിൽ നെറ്റ്‌വർക്ക് പരിശീലിപ്പിക്കേണ്ടതുണ്ട്. ഇത് വളരെ സമയം എടുക്കാം, അതിനാൽ GPU ഉപയോഗിക്കുന്നത് മുൻഗണനയുള്ളതാണ്.\n", "\n", "വേഗത വർദ്ധിപ്പിക്കാൻ, നാം RNN മോഡൽ വാർത്താ തലക്കെട്ടുകളിൽ മാത്രം പരിശീലിപ്പിക്കും, വിവരണം ഒഴിവാക്കും. നിങ്ങൾ വിവരണത്തോടെ പരിശീലിപ്പിക്കാൻ ശ്രമിച്ച് മോഡൽ പരിശീലിപ്പിക്കാൻ കഴിയുന്നുണ്ടോ എന്ന് നോക്കാം.\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Training vectorizer\n" ] } ], "source": [ "def extract_title(x):\n", " return x['title']\n", "\n", "def tupelize_title(x):\n", " return (extract_title(x),x['label'])\n", "\n", "print('Training vectorizer')\n", "vectorizer.adapt(ds_train.take(2000).map(extract_title))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7500/7500 [==============================] - 82s 11ms/step - loss: 0.6629 - acc: 0.7623 - val_loss: 0.5559 - val_acc: 0.7995\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n", "model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))" ] }, { "cell_type": "markdown", "metadata": { "nteract": { "transient": { "deleting": false } } }, "source": [ "> **കുറിപ്പ്** ഇവിടെ കൃത്യത കുറവായിരിക്കാം, കാരണം നാം വാർത്താ തലക്കെട്ടുകളിൽ മാത്രമേ പരിശീലനം നടത്തുകയുള്ളൂ.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## വ്യത്യസ്ത നീളമുള്ള സീക്വൻസുകൾ വീണ്ടും പരിശോധിക്കൽ\n", "\n", "`TextVectorization` ലെയർ സ്വയം മിനിബാച്ചിലെ വ്യത്യസ്ത നീളമുള്ള സീക്വൻസുകൾ പാഡ് ടോക്കണുകളാൽ പാഡ് ചെയ്യുമെന്ന് ഓർക്കുക. ആ ടോക്കണുകളും പരിശീലനത്തിൽ പങ്കാളികളാകുന്നു, അതിനാൽ മോഡലിന്റെ കോൺവെർജൻസ് സങ്കീർണ്ണമാക്കാം.\n", "\n", "പാഡിംഗിന്റെ അളവ് കുറയ്ക്കാൻ നാം പല മാർഗ്ഗങ്ങളും സ്വീകരിക്കാം. അവയിൽ ഒന്നാണ് ഡാറ്റാസെറ്റ് സീക്വൻസ് നീളത്തിന്റെ അടിസ്ഥാനത്തിൽ പുനഃക്രമീകരിച്ച് എല്ലാ സീക്വൻസുകളും വലുപ്പം അനുസരിച്ച് ഗ്രൂപ്പുചെയ്യുക. ഇത് `tf.data.experimental.bucket_by_sequence_length` ഫംഗ്ഷൻ ഉപയോഗിച്ച് ചെയ്യാം (കാണുക [ഡോക്യുമെന്റേഷൻ](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length)).\n", "\n", "മറ്റൊരു മാർഗ്ഗം **മാസ്കിംഗ്** ഉപയോഗിക്കുകയാണ്. Keras-ൽ ചില ലെയറുകൾ പരിശീലനത്തിൽ ഏത് ടോക്കണുകൾ പരിഗണിക്കണമെന്ന് കാണിക്കുന്ന അധിക ഇൻപുട്ട് പിന്തുണയ്ക്കുന്നു. മാസ്കിംഗ് നമ്മുടെ മോഡലിൽ ഉൾപ്പെടുത്താൻ, നാം വേർതിരിച്ച `Masking` ലെയർ ([ഡോക്സ്](https://keras.io/api/layers/core_layers/masking/)) ചേർക്കാം, അല്ലെങ്കിൽ `Embedding` ലെയറിന്റെ `mask_zero=True` പാരാമീറ്റർ നിർദ്ദേശിക്കാം.\n", "\n", "> **Note**: ഈ പരിശീലനം മുഴുവൻ ഡാറ്റാസെറ്റിൽ ഒരു എപ്പോക്ക് പൂർത്തിയാക്കാൻ ഏകദേശം 5 മിനിറ്റ് എടുക്കും. ക്ഷമത കുറഞ്ഞാൽ 언제든 പരിശീലനം നിർത്താം. നിങ്ങൾക്ക് ചെയ്യാവുന്നത് `.take(...)` ക്ലോസ് `ds_train` ഉം `ds_test` datasets-ഉം ശേഷം ചേർത്ത് പരിശീലനത്തിനുള്ള ഡാറ്റയുടെ അളവ് പരിമിതപ്പെടുത്തലും ആണ്.\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7500/7500 [==============================] - 371s 49ms/step - loss: 0.5401 - acc: 0.8079 - val_loss: 0.3780 - val_acc: 0.8822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def extract_text(x):\n", " return x['title']+' '+x['description']\n", "\n", "def tupelize(x):\n", " return (extract_text(x),x['label'])\n", "\n", "model = keras.models.Sequential([\n", " vectorizer,\n", " keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),\n", " keras.layers.SimpleRNN(16),\n", " keras.layers.Dense(4,activation='softmax')\n", "])\n", "\n", "model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n", "model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ഇപ്പോൾ നാം മാസ്കിംഗ് ഉപയോഗിക്കുന്നതിനാൽ, തലക്കെട്ടുകളും വിവരണങ്ങളും ഉൾപ്പെടുന്ന മുഴുവൻ ഡാറ്റാസെറ്റിലും മോഡൽ പരിശീലിപ്പിക്കാം.\n", "\n", "> **Note**: നാം വാർത്താ തലക്കെട്ടുകളിൽ പരിശീലിപ്പിച്ച വെക്ടറൈസർ ഉപയോഗിക്കുന്നുണ്ടെന്ന് നിങ്ങൾ ശ്രദ്ധിച്ചിട്ടുണ്ടോ, ലേഖനത്തിന്റെ മുഴുവൻ ഉള്ളടക്കമല്ല? ഇതു ചില ടോക്കണുകൾ അവഗണിക്കപ്പെടാൻ കാരണമാകാം, അതിനാൽ വെക്ടറൈസർ വീണ്ടും പരിശീലിപ്പിക്കുന്നത് നല്ലതാണ്. എങ്കിലും, ഇതിന് വളരെ ചെറിയ ഫലമുണ്ടാകാമെന്ന് തോന്നുന്നു, അതുകൊണ്ട് ലളിതത്വത്തിനായി മുമ്പത്തെ പ്രീ-ട്രെയിൻ ചെയ്ത വെക്ടറൈസറിനോടെയാണ് നാം തുടരുന്നത്.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## LSTM: ദീർഘകാല ചെറുകാല സ്മൃതി\n", "\n", "RNN-കളുടെ പ്രധാന പ്രശ്നങ്ങളിൽ ഒന്നാണ് **വാനിഷിംഗ് ഗ്രേഡിയന്റുകൾ**. RNN-കൾ വളരെ ദൈർഘ്യമേറിയതായിരിക്കാം, ബാക്ക്‌പ്രൊപ്പഗേഷൻ സമയത്ത് ഗ്രേഡിയന്റുകൾ നെറ്റ്വർക്കിന്റെ ആദ്യ ലെയറിലേക്ക് പൂർണ്ണമായി പ്രചരിപ്പിക്കാൻ ബുദ്ധിമുട്ട് ഉണ്ടാകാം. ഇതു സംഭവിക്കുമ്പോൾ, നെറ്റ്വർക്ക് ദൂരെയുള്ള ടോക്കണുകൾ തമ്മിലുള്ള ബന്ധങ്ങൾ പഠിക്കാൻ കഴിയില്ല. ഈ പ്രശ്നം ഒഴിവാക്കാനുള്ള ഒരു മാർഗം **ഗേറ്റുകൾ** ഉപയോഗിച്ച് **സ്പഷ്ടമായ സ്റ്റേറ്റ് മാനേജ്മെന്റ്** പരിചയപ്പെടുത്തുകയാണ്. ഗേറ്റുകൾ പരിചയപ്പെടുത്തുന്ന രണ്ട് സാധാരണ ആർക്കിടെക്ചറുകൾ **ലോങ് ഷോർട്ട്-ടേം മെമ്മറി** (LSTM)യും **ഗേറ്റഡ് റീലേ യൂണിറ്റ്** (GRU)യും ആണ്. ഇവിടെ നാം LSTM-കളെ പരിചയപ്പെടും.\n", "\n", "![ദീർഘകാല ചെറുകാല സ്മൃതി സെല്ലിന്റെ ഉദാഹരണം കാണിക്കുന്ന ചിത്രം](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n", "\n", "LSTM നെറ്റ്വർക്ക് RNN-നെപ്പോലെ ക്രമീകരിച്ചിരിക്കുന്നു, പക്ഷേ ലെയർ മുതൽ ലെയർ വരെ രണ്ട് സ്റ്റേറ്റുകൾ കൈമാറുന്നു: യഥാർത്ഥ സ്റ്റേറ്റ് $c$, കൂടാതെ ഹിഡൻ വെക്ടർ $h$. ഓരോ യൂണിറ്റിലും, ഹിഡൻ വെക്ടർ $h_{t-1}$ ഇൻപുട്ട് $x_t$-നൊപ്പം ചേർത്ത്, **ഗേറ്റുകൾ** വഴി സ്റ്റേറ്റ് $c_t$-ക്കും ഔട്ട്പുട്ട് $h_t$-ക്കും എന്ത് സംഭവിക്കുമെന്ന് നിയന്ത്രിക്കുന്നു. ഓരോ ഗേറ്റിനും സിഗ്മോയിഡ് ആക്ടിവേഷൻ ഉണ്ട് (ഔട്ട്പുട്ട് $[0,1]$ പരിധിയിൽ), ഇത് സ്റ്റേറ്റ് വെക്ടറുമായി ഗുണിക്കുമ്പോൾ ബിറ്റ്‌വൈസ് മാസ്ക് പോലെ കരുതാം. LSTM-കൾക്ക് താഴെപ്പറയുന്ന ഗേറ്റുകൾ ഉണ്ട് (മുകളിൽ ചിത്രത്തിൽ ഇടത്തുനിന്ന് വലത്തേക്ക്):\n", "* **ഫോർഗറ്റ് ഗേറ്റ്**: വെക്ടർ $c_{t-1}$-ന്റെ ഏത് ഘടകങ്ങൾ മറക്കണം, ഏത് കടത്തിക്കളയണം എന്ന് നിർണ്ണയിക്കുന്നു.\n", "* **ഇൻപുട്ട് ഗേറ്റ്**: ഇൻപുട്ട് വെക്ടറും മുൻ ഹിഡൻ വെക്ടറും സ്റ്റേറ്റ് വെക്ടറിലേക്ക് എത്രമാത്രം വിവരങ്ങൾ ഉൾപ്പെടുത്തണം എന്ന് നിർണ്ണയിക്കുന്നു.\n", "* **ഔട്ട്പുട്ട് ഗേറ്റ്**: പുതിയ സ്റ്റേറ്റ് വെക്ടർ എടുത്ത് അതിന്റെ ഏത് ഘടകങ്ങൾ പുതിയ ഹിഡൻ വെക്ടർ $h_t$ സൃഷ്ടിക്കാൻ ഉപയോഗിക്കുമെന്ന് തീരുമാനിക്കുന്നു.\n", "\n", "സ്റ്റേറ്റ് $c$-യുടെ ഘടകങ്ങളെ ഓൺ-ഓഫ് ചെയ്യാവുന്ന ഫ്ലാഗുകളായി കരുതാം. ഉദാഹരണത്തിന്, സീക്വൻസിൽ *Alice* എന്ന പേര് കണ്ടപ്പോൾ, അത് ഒരു സ്ത്രീയെ സൂചിപ്പിക്കുന്നതായി നാം കരുതുകയും, വാചകത്തിൽ സ്ത്രീലിംഗ നാമം ഉണ്ടെന്ന് സൂചിപ്പിക്കുന്ന ഫ്ലാഗ് സ്റ്റേറ്റിൽ ഉയർത്തുകയും ചെയ്യും. പിന്നീട് *and Tom* എന്ന വാക്കുകൾ കണ്ടപ്പോൾ, ബഹുവചന നാമം ഉണ്ടെന്ന് സൂചിപ്പിക്കുന്ന ഫ്ലാഗ് ഉയർത്തും. ഇങ്ങനെ സ്റ്റേറ്റ് നിയന്ത്രിച്ച് വാചകത്തിന്റെ വ്യാകരണ ഗുണങ്ങൾ ട്രാക്ക് ചെയ്യാം.\n", "\n", "> **Note**: LSTM-കളുടെ ആന്തരിക ഘടന മനസ്സിലാക്കാൻ മികച്ച ഒരു വിഭവം: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ക്രിസ്റ്റഫർ ഒലാഹ് എഴുതിയത്.\n", "\n", "LSTM സെല്ലിന്റെ ആന്തരിക ഘടന സങ്കീർണ്ണമായിരിക്കാം, പക്ഷേ Keras ഈ നടപ്പാക്കൽ `LSTM` ലെയറിനുള്ളിൽ മറച്ചുവെക്കുന്നു, അതിനാൽ മുകളിൽ നൽകിയ ഉദാഹരണത്തിൽ നാം ചെയ്യേണ്ടത് റിക്കറന്റ് ലെയർ മാറ്റുക മാത്രമാണ്:\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "15000/15000 [==============================] - 188s 13ms/step - loss: 0.5692 - acc: 0.7916 - val_loss: 0.3441 - val_acc: 0.8870\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = keras.models.Sequential([\n", " vectorizer,\n", " keras.layers.Embedding(vocab_size, embed_size),\n", " keras.layers.LSTM(8),\n", " keras.layers.Dense(4,activation='softmax')\n", "])\n", "\n", "model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n", "model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **കുറിപ്പ്** LSTM-കൾ പരിശീലിപ്പിക്കുന്നത് വളരെ മന്ദഗതിയിലാണ്, പരിശീലനത്തിന്റെ തുടക്കത്തിൽ നിങ്ങൾക്ക് കൃത്യതയിൽ വലിയ വർദ്ധനവ് കാണാനാകില്ല. നല്ല കൃത്യത നേടാൻ കുറച്ച് സമയം പരിശീലനം തുടരേണ്ടതുണ്ടാകും.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ദ്വിദിശയും ബഹുസ്തര RNN-കളും\n", "\n", "ഇതുവരെ ഞങ്ങളുടെ ഉദാഹരണങ്ങളിൽ, റികറന്റ് നെറ്റ്വർക്കുകൾ ഒരു സീക്വൻസിന്റെ തുടക്കം മുതൽ അവസാനം വരെ പ്രവർത്തിക്കുന്നു. ഇത് നമുക്ക് സ്വാഭാവികമായി തോന്നുന്നത്, കാരണം നാം വായിക്കുന്നതോ സംസാരിക്കുന്നതോ ചെയ്യുന്ന ദിശയിലേയ്ക്ക് ഇത് പ്രവർത്തിക്കുന്നു. എന്നാൽ, ഇൻപുട്ട് സീക്വൻസിൽ യാദൃച്ഛിക ആക്‌സസ് ആവശ്യമായ സാഹചര്യങ്ങളിൽ, റികറന്റ് കണക്കുകൂട്ടൽ ഇരുവശത്തും നടത്തുന്നത് കൂടുതൽ യുക്തിസഹമാണ്. ഇരുവശത്തും കണക്കുകൂട്ടലുകൾ അനുവദിക്കുന്ന RNN-കൾ **ദ്വിദിശ RNN-കൾ** എന്ന് വിളിക്കപ്പെടുന്നു, ഇവ ഒരു പ്രത്യേക `Bidirectional` ലെയർ ഉപയോഗിച്ച് റികറന്റ് ലെയർ ചുറ്റിപ്പറ്റി സൃഷ്ടിക്കാം.\n", "\n", "> **Note**: `Bidirectional` ലെയർ അതിനുള്ളിൽ ലെയറിന്റെ രണ്ട് പകർപ്പുകൾ ഉണ്ടാക്കുന്നു, അവയിൽ ഒന്നിന്റെ `go_backwards` പ്രോപ്പർട്ടി `True` ആയി സജ്ജമാക്കി, സീക്വൻസിന്റെ വിരുദ്ധ ദിശയിൽ പ്രവർത്തിക്കാൻ അനുവദിക്കുന്നു.\n", "\n", "യൂണിഡിരക്ഷണോ ദ്വിദിശ RNN-കളോ സീക്വൻസിനുള്ളിൽ പാറ്റേണുകൾ പിടിച്ചുപറ്റി അവയെ സ്റ്റേറ്റ് വെക്ടറുകളിലോ ഔട്ട്പുട്ടിലോ സൂക്ഷിക്കുന്നു. കോൺവല്യൂഷണൽ നെറ്റ്വർക്കുകളെപ്പോലെ, ആദ്യ ലെയറിന്റെ താഴ്ന്ന തലത്തിലുള്ള പാറ്റേണുകൾ പിടിച്ചുപറ്റി ഉയർന്ന തലത്തിലുള്ള പാറ്റേണുകൾ പിടിക്കാൻ മറ്റൊരു റികറന്റ് ലെയർ ചേർക്കാം. ഇതാണ് **ബഹുസ്തര RNN** എന്ന ആശയം, ഇത് രണ്ട് അല്ലെങ്കിൽ അതിലധികം റികറന്റ് നെറ്റ്വർക്കുകൾ ഉൾക്കൊള്ളുന്നു, മുൻ ലെയറിന്റെ ഔട്ട്പുട്ട് അടുത്ത ലെയറിന്റെ ഇൻപുട്ടായി നൽകുന്നു.\n", "\n", "![ബഹുസ്തര ലോങ്-ഷോർട്ട്-ടേം-മെമ്മറി RNN-നെ കാണിക്കുന്ന ചിത്രം](../../../../../translated_images/ml/multi-layer-lstm.dd975e29bb2a59fe.webp)\n", "\n", "*ഫെർണാണ്ടോ ലോപ്പസ് എഴുതിയ [ഈ മനോഹരമായ പോസ്റ്റ്](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) നിന്നുള്ള ചിത്രം.*\n", "\n", "കേരാസ് ഈ നെറ്റ്വർക്കുകൾ നിർമ്മിക്കുന്നത് എളുപ്പമാക്കുന്നു, കാരണം നിങ്ങൾക്ക് മോഡലിൽ കൂടുതൽ റികറന്റ് ലെയറുകൾ ചേർക്കേണ്ടതുണ്ട്. അവസാന ലെയർ ഒഴികെയുള്ള എല്ലാ ലെയറുകൾക്കും `return_sequences=True` പാരാമീറ്റർ നൽകണം, കാരണം റികറന്റ് കണക്കുകൂട്ടലിന്റെ അവസാന സ്റ്റേറ്റ് മാത്രമല്ല, ഇടക്കാല സ്റ്റേറ്റുകളും ലെയർ തിരികെ നൽകണം.\n", "\n", "നമ്മുടെ ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിന് രണ്ട് ലെയർ ദ്വിദിശ LSTM നിർമ്മിക്കാം.\n", "\n", "> **Note** ഈ കോഡ് വീണ്ടും പൂർത്തിയാകാൻ കുറച്ച് സമയം എടുക്കും, പക്ഷേ ഇതുവരെ കണ്ട ഏറ്റവും ഉയർന്ന കൃത്യത നൽകുന്നു. അതിനാൽ ഫലം കാണാൻ കാത്തിരിക്കേണ്ടതുണ്ടെന്ന് തോന്നുന്നു.\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5044/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r5045/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706" ] } ], "source": [ "model = keras.models.Sequential([\n", " vectorizer,\n", " keras.layers.Embedding(vocab_size, 128, mask_zero=True),\n", " keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),\n", " keras.layers.Bidirectional(keras.layers.LSTM(64)), \n", " keras.layers.Dense(4,activation='softmax')\n", "])\n", "\n", "model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n", "model.fit(ds_train.map(tupelize).batch(batch_size),\n", " validation_data=ds_test.map(tupelize).batch(batch_size))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## മറ്റ് ജോലികൾക്കുള്ള RNNകൾ\n", "\n", "ഇതുവരെ, നാം RNNകൾ ഉപയോഗിച്ച് ടെക്സ്റ്റ് സീക്വൻസുകൾ വർഗ്ഗീകരിക്കുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിച്ചിരുന്നു. എന്നാൽ അവക്ക് ടെക്സ്റ്റ് ജനറേഷൻ, മെഷീൻ ട്രാൻസ്ലേഷൻ പോലുള്ള നിരവധി മറ്റ് ജോലികളും കൈകാര്യം ചെയ്യാൻ കഴിയും — ആ ജോലികൾ അടുത്ത യൂണിറ്റിൽ പരിഗണിക്കും.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n\n\n**അസൂയാ**: \nഈ രേഖ AI വിവർത്തന സേവനം [Co-op Translator](https://github.com/Azure/co-op-translator) ഉപയോഗിച്ച് വിവർത്തനം ചെയ്തതാണ്. നാം കൃത്യതയ്ക്ക് ശ്രമിച്ചിട്ടുണ്ടെങ്കിലും, സ്വയം പ്രവർത്തിക്കുന്ന വിവർത്തനങ്ങളിൽ പിശകുകൾ അല്ലെങ്കിൽ തെറ്റുകൾ ഉണ്ടാകാമെന്ന് ദയവായി ശ്രദ്ധിക്കുക. അതിന്റെ മാതൃഭാഷയിലുള്ള യഥാർത്ഥ രേഖ അധികാരപരമായ ഉറവിടമായി കണക്കാക്കപ്പെടണം. നിർണായക വിവരങ്ങൾക്ക്, പ്രൊഫഷണൽ മനുഷ്യ വിവർത്തനം ശുപാർശ ചെയ്യപ്പെടുന്നു. ഈ വിവർത്തനത്തിന്റെ ഉപയോഗത്തിൽ നിന്നുണ്ടാകുന്ന ഏതെങ്കിലും തെറ്റിദ്ധാരണകൾക്കോ തെറ്റായ വ്യാഖ്യാനങ്ങൾക്കോ ഞങ്ങൾ ഉത്തരവാദികളല്ല.\n\n" ] } ], "metadata": { "kernel_info": { "name": "conda-env-py37_tensorflow-py" }, "kernelspec": { "display_name": "py37_tensorflow", "language": "python", "name": "conda-env-py37_tensorflow-py" }, "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.7.9" }, "nteract": { "version": "nteract-front-end@1.0.0" }, "coopTranslator": { "original_hash": "81351e61f619b432ff51010a4f993194", "translation_date": "2025-11-26T02:07:11+00:00", "source_file": "lessons/5-NLP/16-RNN/RNNTF.ipynb", "language_code": "ml" } }, "nbformat": 4, "nbformat_minor": 4 }