462 lines
22 KiB
Plaintext
462 lines
22 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Korduvad närvivõrgud\n",
|
|
"\n",
|
|
"Eelmises moodulis käsitlesime teksti rikkalikke semantilisi esitusi. Kasutatud arhitektuur haarab lause sõnade koondatud tähenduse, kuid ei arvesta sõnade **järjekorda**, kuna koondamisoperatsioon, mis järgneb sisendite teisendamisele, eemaldab selle teabe algsest tekstist. Kuna need mudelid ei suuda esitada sõnade järjestust, ei saa nad lahendada keerukamaid või mitmetähenduslikke ülesandeid, nagu teksti genereerimine või küsimustele vastamine.\n",
|
|
"\n",
|
|
"Tekstijada tähenduse tabamiseks kasutame närvivõrgu arhitektuuri, mida nimetatakse **korduvaks närvivõrguks** ehk RNN-iks. RNN-i kasutamisel edastame oma lause võrgu kaudu ühe tokeni korraga, ja võrk toodab mingi **seisundi**, mille edastame võrku uuesti koos järgmise tokeniga.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Arvestades sisendjada tokenitest $X_0,\\dots,X_n$, loob RNN närvivõrgu plokkide jada ja treenib seda jada otsast lõpuni tagasileviku abil. Iga võrguplokk võtab sisendiks paari $(X_i,S_i)$ ja annab tulemuseks $S_{i+1}$. Lõplik seisund $S_n$ või väljund $Y_n$ suunatakse lineaarse klassifikaatori kaudu tulemuse saamiseks. Kõik võrguplokid jagavad samu kaale ja neid treenitakse otsast lõpuni ühe tagasileviku käigu abil.\n",
|
|
"\n",
|
|
"> Ülaltoodud joonis näitab korduvat närvivõrku lahtirullitud kujul (vasakul) ja kompaktsema korduva esitusena (paremal). Oluline on mõista, et kõik RNN-rakud jagavad samu **kaale**.\n",
|
|
"\n",
|
|
"Kuna seisundivektorid $S_0,\\dots,S_n$ edastatakse võrgu kaudu, suudab RNN õppida sõnade järjestuslikke sõltuvusi. Näiteks, kui sõna *mitte* ilmub kuskil jadas, suudab see õppida teatud elementide eitamist seisundivektoris.\n",
|
|
"\n",
|
|
"Iga RNN-raku sees on kaks kaalumatriitsi: $W_H$ ja $W_I$, ning nihe $b$. Iga RNN-sammu puhul arvutatakse sisendi $X_i$ ja sisendseisundi $S_i$ põhjal väljundseisund järgmiselt: $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$, kus $f$ on aktivatsioonifunktsioon (sageli $\\tanh$).\n",
|
|
"\n",
|
|
"> Probleemide puhul, nagu teksti genereerimine (mida käsitleme järgmises üksuses) või masintõlge, soovime saada väljundväärtust igal RNN-sammul. Sellisel juhul on olemas ka teine maatriks $W_O$, ja väljund arvutatakse järgmiselt: $Y_i=f(W_O\\times S_i+b_O)$.\n",
|
|
"\n",
|
|
"Vaatame, kuidas korduvad närvivõrgud aitavad meil klassifitseerida meie uudiste andmekogumit.\n",
|
|
"\n",
|
|
"> Liivakasti keskkonna jaoks peame käivitama järgmise lahtri, et veenduda vajaliku teegi installimises ja andmete eellaadimises. Kui töötate lokaalselt, võite järgmise lahtri vahele jätta.\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": [
|
|
"Suuremate mudelite treenimisel võib GPU mälu jaotamine muutuda probleemiks. Samuti võib olla vajalik katsetada erinevate minibatch'i suurustega, et andmed mahuksid GPU mällu, kuid treenimine oleks siiski piisavalt kiire. Kui käitate seda koodi oma GPU masinas, võite katsetada minibatch'i suuruse kohandamist, et treenimist kiirendada.\n",
|
|
"\n",
|
|
"> **Note**: Teatud NVidia draiverite versioonid on teadaolevalt sellised, mis ei vabasta mälu pärast mudeli treenimist. Me käitame selles märkmikus mitmeid näiteid, mis võib teatud seadistustes põhjustada mälu ammendumist, eriti kui teete oma eksperimente sama märkmiku raames. Kui mudeli treenimise alustamisel ilmnevad kummalised vead, võib olla vajalik märkmiku kerneli taaskäivitamine.\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": [
|
|
"## Lihtne RNN klassifikaator\n",
|
|
"\n",
|
|
"Lihtsa RNN-i puhul on iga korduvüksus lihtne lineaarne võrk, mis võtab sisendvektori ja olekuvektori ning toodab uue olekuvektori. Kerases saab seda esindada `SimpleRNN` kihiga.\n",
|
|
"\n",
|
|
"Kuigi me saame anda RNN-kihile otse ühekuumkooditud (one-hot encoded) tokenid, ei ole see hea mõte nende kõrge dimensioonilisuse tõttu. Seetõttu kasutame sõnavektorite dimensioonide vähendamiseks esmalt sisendkihina embedding-kihte, millele järgneb RNN-kiht ja lõpuks `Dense` klassifikaator.\n",
|
|
"\n",
|
|
"> **Märkus**: Juhtudel, kus dimensioonilisus ei ole nii kõrge, näiteks kui kasutatakse tähemärgitase tokeniseerimist, võib olla mõistlik anda ühekuumkooditud tokenid otse RNN-rakule.\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": [
|
|
"> **Märkus:** Siin kasutame lihtsuse huvides treenimata sisendkihti, kuid paremate tulemuste saavutamiseks võiks kasutada eeltreenitud sisendkihti, näiteks Word2Vec-i, nagu kirjeldatud eelmises osas. Hea harjutus oleks kohandada seda koodi töötama eeltreenitud sisenditega.\n",
|
|
"\n",
|
|
"Nüüd treenime oma RNN-i. Üldiselt on RNN-e üsna keeruline treenida, sest kui RNN-i rakud lahti rullitakse mööda järjestuse pikkust, on tagasipropagatsioonis osalevate kihtide arv üsna suur. Seetõttu peame valima väiksema õppemäära ja treenima võrku suurema andmekogumi peal, et saavutada häid tulemusi. See võib võtta üsna kaua aega, seega on eelistatud kasutada GPU-d.\n",
|
|
"\n",
|
|
"Kiiruse huvides treenime RNN-mudelit ainult uudiste pealkirjade põhjal, jättes kirjelduse välja. Võite proovida treenida koos kirjeldusega ja vaadata, kas mudel suudab treenida.\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": [
|
|
"<tensorflow.python.keras.callbacks.History at 0x7f3e0030d350>"
|
|
]
|
|
},
|
|
"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": [
|
|
"> **Märkus**: täpsus on siin tõenäoliselt madalam, kuna treenime ainult uudiste pealkirjade põhjal.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Muutuvate järjestuste uuesti vaatamine\n",
|
|
"\n",
|
|
"Pea meeles, et `TextVectorization` kiht lisab automaatselt pad-tokeneid muutuvate pikkustega järjestustele minibatchis. Selgub, et need tokenid osalevad samuti treeningus ja võivad mudeli koondumist keerulisemaks muuta.\n",
|
|
"\n",
|
|
"On mitmeid lähenemisi, mida saame kasutada, et vähendada pad-tokeneid. Üks neist on andmekogumi ümberjärjestamine järjestuse pikkuse järgi ja kõigi järjestuste rühmitamine suuruse alusel. Seda saab teha funktsiooni `tf.data.experimental.bucket_by_sequence_length` abil (vaata [dokumentatsiooni](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length)).\n",
|
|
"\n",
|
|
"Teine lähenemine on kasutada **maskimist**. Kerases toetavad mõned kihid täiendavat sisendit, mis näitab, milliseid tokeneid tuleks treeningu ajal arvesse võtta. Maskimise kaasamiseks oma mudelisse saame lisada eraldi `Masking` kihi ([dokumentatsioon](https://keras.io/api/layers/core_layers/masking/)) või määrata `Embedding` kihi parameetri `mask_zero=True`.\n",
|
|
"\n",
|
|
"> **Note**: Selle treeningu läbiviimine kogu andmekogumi ühe epohhi jaoks võtab umbes 5 minutit. Kui kaotate kannatuse, võite treeningu igal ajal katkestada. Samuti saate piirata treeninguks kasutatava andmekogumi mahtu, lisades `.take(...)` klausli pärast `ds_train` ja `ds_test` andmekogumeid.\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": [
|
|
"<tensorflow.python.keras.callbacks.History at 0x7f3dec118850>"
|
|
]
|
|
},
|
|
"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üüd, kui kasutame maskeerimist, saame mudelit treenida kogu pealkirjade ja kirjelduste andmestiku põhjal.\n",
|
|
"\n",
|
|
"> **Märkus**: Kas oled märganud, et oleme kasutanud vektoreerijat, mis on treenitud uudiste pealkirjade, mitte kogu artikli sisu põhjal? See võib potentsiaalselt põhjustada mõnede tokenite ignoreerimist, seega oleks parem vektoreerija uuesti treenida. Kuid selle mõju võib olla väga väike, nii et lihtsuse huvides jääme eelmise eeltreenitud vektoreerija juurde.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## LSTM: Pikaajaline lühimälu\n",
|
|
"\n",
|
|
"Üks peamisi RNN-ide probleeme on **kaduvad gradiendid**. RNN-id võivad olla üsna pikad ja neil võib olla raskusi gradientide tagasi esimese kihini edastamisega tagasilevi ajal. Kui see juhtub, ei suuda võrk õppida kaugemate tokenite vahelisi seoseid. Üks viis selle probleemi vältimiseks on **eksplitsiitne oleku haldamine** **väravate** abil. Kaks kõige levinumat arhitektuuri, mis kasutavad väravaid, on **pikaajaline lühimälu** (LSTM) ja **gated relay unit** (GRU). Siin käsitleme LSTM-e.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"LSTM-võrk on organiseeritud sarnaselt RNN-ile, kuid kihilt kihile edastatakse kaks olekut: tegelik olek $c$ ja peidetud vektor $h$. Igas üksuses kombineeritakse peidetud vektor $h_{t-1}$ sisendiga $x_t$, ja koos kontrollivad nad, mis juhtub olekuga $c_t$ ja väljundiga $h_{t}$ **väravate** kaudu. Igal väraval on sigmoidne aktivatsioon (väljund vahemikus $[0,1]$), mida võib mõelda kui bittmaski, kui see korrutatakse oleku vektoriga. LSTM-idel on järgmised väravad (vasakult paremale ülaloleval pildil):\n",
|
|
"* **unustamisvärav**, mis määrab, millised komponendid vektorist $c_{t-1}$ tuleb unustada ja millised edasi anda.\n",
|
|
"* **sisendvärav**, mis määrab, kui palju informatsiooni sisendvektorist ja eelmisest peidetud vektorist tuleks olekuvektorisse lisada.\n",
|
|
"* **väljundvärav**, mis võtab uue olekuvektori ja otsustab, milliseid selle komponente kasutatakse uue peidetud vektori $h_t$ loomiseks.\n",
|
|
"\n",
|
|
"Olekukomponente $c$ võib mõelda kui lippe, mida saab sisse ja välja lülitada. Näiteks, kui kohtame järjestuses nime *Alice*, arvame, et see viitab naisele, ja tõstame olekus lipu, mis ütleb, et lauses on naissoost nimisõna. Kui kohtame hiljem sõnu *ja Tom*, tõstame lipu, mis ütleb, et lauses on mitmuse nimisõna. Seega, manipuleerides olekuga, saame jälgida lause grammatilisi omadusi.\n",
|
|
"\n",
|
|
"> **Note**: Siin on suurepärane ressurss LSTM-ide sisemuse mõistmiseks: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) autorilt Christopher Olah.\n",
|
|
"\n",
|
|
"Kuigi LSTM-raku sisemine struktuur võib tunduda keeruline, peidab Keras selle implementatsiooni `LSTM` kihi sisse, nii et ainus asi, mida me peame ülaltoodud näites tegema, on asendada korduv kiht:\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": [
|
|
"<tensorflow.python.keras.callbacks.History at 0x7f3d6af5c350>"
|
|
]
|
|
},
|
|
"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": [
|
|
"> **Märkus**: LSTM-ide treenimine on samuti üsna aeglane ja treeningu alguses ei pruugi täpsus märkimisväärselt suureneda. Hea täpsuse saavutamiseks võib olla vajalik treenimist mõnda aega jätkata.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Kaksuunalised ja mitmekihilised RNN-id\n",
|
|
"\n",
|
|
"Meie senistes näidetes on korduvad närvivõrgud töötanud järjestuse algusest lõpuni. See tundub meile loomulik, kuna see järgib sama suunda, milles me loeme või kuulame kõnet. Kuid olukordades, kus on vaja sisendjärjestusele juhuslikult ligi pääseda, on mõistlikum käivitada korduv arvutus mõlemas suunas. RNN-e, mis võimaldavad arvutusi mõlemas suunas, nimetatakse **kaksuunalisteks** RNN-ideks ning neid saab luua, mähkides korduva kihi spetsiaalse `Bidirectional` kihi sisse.\n",
|
|
"\n",
|
|
"> **Note**: `Bidirectional` kiht teeb selle sees olevast kihist kaks koopiat ja seab ühe neist koopiatest omaduse `go_backwards` väärtuseks `True`, mis paneb selle liikuma järjestuses vastassuunas.\n",
|
|
"\n",
|
|
"Korduvad närvivõrgud, olgu need ühe- või kaksuunalised, püüavad kinni mustreid järjestuses ja salvestavad need olekuvektoritesse või tagastavad need väljundina. Nii nagu konvolutsioonivõrkude puhul, saame esimesele kihile lisada teise korduva kihi, et püüda kinni kõrgema taseme mustreid, mis on loodud esimese kihi poolt tuvastatud madalama taseme mustritest. See viib meid **mitmekihilise RNN-i** mõisteni, mis koosneb kahest või enamast korduvast võrgust, kus eelmise kihi väljund edastatakse järgmisele kihile sisendina.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"*Pilt [sellest suurepärasest postitusest](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3), autor Fernando López.*\n",
|
|
"\n",
|
|
"Keras muudab nende võrkude loomise lihtsaks ülesandeks, kuna peate mudelile lihtsalt lisama rohkem korduvaid kihte. Kõigi kihtide puhul, välja arvatud viimane, peame määrama parameetri `return_sequences=True`, kuna vajame, et kiht tagastaks kõik vahepealsed olekud, mitte ainult korduva arvutuse lõppoleku.\n",
|
|
"\n",
|
|
"Loome kahekihilise kaksuunalise LSTM-i meie klassifitseerimisülesande jaoks.\n",
|
|
"\n",
|
|
"> **Note** see kood võtab taas üsna kaua aega, et lõpule jõuda, kuid see annab meile seni nähtud kõrgeima täpsuse. Seega võib-olla tasub oodata ja tulemust näha.\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-id muudeks ülesanneteks\n",
|
|
"\n",
|
|
"Siiani oleme keskendunud RNN-ide kasutamisele tekstijadade klassifitseerimiseks. Kuid need suudavad toime tulla paljude teiste ülesannetega, nagu teksti genereerimine ja masintõlge — neid ülesandeid käsitleme järgmises üksuses.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Lahtiütlus**: \nSee dokument on tõlgitud AI tõlketeenuse [Co-op Translator](https://github.com/Azure/co-op-translator) abil. Kuigi püüame tagada täpsust, palume arvestada, et automaatsed tõlked võivad sisaldada vigu või ebatäpsusi. Algne dokument selle algses keeles tuleks pidada autoriteetseks allikaks. Olulise teabe puhul soovitame kasutada professionaalset inimtõlget. Me ei vastuta selle tõlke kasutamisest tulenevate arusaamatuste või valesti tõlgenduste eest.\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-10-11T12:55:01+00:00",
|
|
"source_file": "lessons/5-NLP/16-RNN/RNNTF.ipynb",
|
|
"language_code": "et"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |