├── LICENSE
├── README.md
├── char_rnns
├── README.md
├── dino_names.txt
├── notebooks
│ ├── Dino_Names_GRU.ipynb
│ ├── Dino_Names_LSTM.ipynb
│ ├── Dino_Names_RNN.ipynb
│ └── Dino_Names_Scratch.ipynb
└── plots
│ ├── Dino_Names_GRU.jpeg
│ ├── Dino_Names_LSTM.jpeg
│ ├── Dino_Names_RNN.jpeg
│ └── Dino_Names_Scratch.jpeg
├── neural_machine_translation
├── README.md
├── notebooks
│ ├── Attention_Is_All_You_Need.ipynb
│ ├── Conv_Seq2Seq.ipynb
│ ├── Seq2Seq.ipynb
│ └── Seq2Seq_with_Attention.ipynb
└── plots
│ ├── Conv_Seq2Seq.jpeg
│ ├── Seq2Seq.jpeg
│ ├── Seq2Seq_with_Attention.jpeg
│ └── Transformer.jpeg
├── text_classification
├── README.md
├── notebooks
│ ├── BERT.ipynb
│ ├── CNN.ipynb
│ ├── FastText.ipynb
│ └── LSTM.ipynb
└── plots
│ ├── BERT.png
│ ├── CNN.png
│ ├── FastText.png
│ └── LSTM.png
└── word_rnn
├── Book 1 - The Philosopher's Stone.txt
├── Main_Paragraph_generation_on_larger_dataset_lstm (1).ipynb
├── README.md
├── ezgif.com-gif-maker.gif
├── paragraph generation loss gru.png
├── paragraph generation loss lstm.png
├── paragraph generation loss rnn.png
├── wordRNN_paragraph_gru2.pth
├── wordRNN_paragraph_lstm2.pth
└── wordRNN_paragraph_rnn2.pth
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 IvLabs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Natural Language Processing
2 | This is the Natural Language Processing repository of IvLabs and contains implementation of various architectures, starting from Character Level RNN(s) built from scratch, up to and including the Transformer architecture.
3 | Further, we have also included a rough roadmap for enthusiasts with basic knowledge of Machine/Deep Learning.
4 |
5 | We have implemented and compared the following architectures:
6 | - [x] [Character Level RNN (Char RNN)](char_rnns)
7 | - [x] From scratch
8 | - [x] Vanilla RNN
9 | - [x] LSTM
10 | - [x] GRU
11 |
12 | - [x] [Language Models (Word RNN)](word_rnn)
13 | - [x] Vanilla RNN
14 | - [x] LSTM
15 | - [x] GRU
16 |
17 | - [x] [Neural Machine Translation](neural_machine_translation)\
18 | For Neural Machine Translation, we have implemented the following papers.
19 | - [x] [Sequence to Sequence Learning with Neural Networks](https://arxiv.org/abs/1409.3215)
20 | - [x] [Neural Machine Translation by Jointly Learning to Align and Translate](https://arxiv.org/abs/1409.0473)
21 | - [x] [Convolutional Sequence to Sequence Learning](https://arxiv.org/abs/1705.03122)
22 | - [x] [Attention Is All You Need](https://arxiv.org/abs/1706.03762)
23 |
24 |
25 |
26 |
27 | ### Contributors:
28 | * [Rishika Bhagwatkar](https://https//github.com/rishika2110)
29 | * [Khurshed P. Fitter](https://https//github.com/GlazeDonuts)
30 | * [Aneesh A. Shetye](https://https//github.com/aneesh-shetye)
31 | * [Diksha Bagade](https://github.com/Diksha942)
32 | * [Kshitij Ambilduke](https://github.com/Kshitij-Ambilduke)
33 | * [Ajinkya Deshpande](https://github.com/AjinkyaDeshpande39)
34 | * [Prayash Swain](https://github.com/SprayashB)
35 | * [Thanmay Jayakumar](https://github.com/ThanmayJ)
36 | * [Fauzan Farooqui](https://github.com/FauzanFarooqui)
37 |
38 |
--------------------------------------------------------------------------------
/char_rnns/README.md:
--------------------------------------------------------------------------------
1 | # Character Level RNN (Char RNN)
2 | The fundamental basis of any language is its alphabet. Hence character level RNN(s) are the most basic form of recurrent neural networks and we have implemented them from scratch. Also, we have used the RNN, LSTM and GRU layers available in PyTorch for comparison.
3 |
4 | All the models are trained on the [Dino Names](Dino_Names.txt) dataset which contains 1536 dinosaur names. Data splitting and training parameters are mentioned below.
5 |
6 |
7 | | Parameter | Value |
8 | | ----------------- |:------------------:|
9 | | Training Set | 95% (1460/1536) |
10 | | Testing Set | 3% (46/1536) |
11 | | Validation Set | 2% (30/1536) |
12 | | Number of Epochs | 40 |
13 | | Learning Rate | 4x10-4 |
14 | | Hidden Dimensions | 64 |
15 | | Loss Function | Cross Entropy Loss |
16 | | Optimizer | AdamW |
17 |
18 |
19 |
20 | ## General Pipeline
21 | 1. Every character in the vocabulary(including the delimiter ".") is embedded using One-Hot vector representation.
22 | 2. A sequence of embeddings is fed to the model. This typically contains embeddings of all the characters of a word, except the delimiter.
23 | 3. The output of the model is validated against the ground truth, i.e. a sequence of embeddings of all the characters of the word (including the delimiter) except the first.
24 | 4. The training and validation losses are calculated and stochastic optimization is applied.
25 | 5. This is repeated for every word in the corpus.
26 | 6. The cumilitive training and validation losses for each epoch are recorded and plotted.
27 |
28 |
29 |
30 | ## Architectures:
31 | ### 1. [Char RNN from Scratch](https://github.com/IvLabs/Natural-Language-Processing/blob/master/char_rnns/notebooks/Dino_Names_Scratch.ipynb) [](https://colab.research.google.com/drive/1N01IvqI0yxK1CAKi0cfwRTcgvR-_YukL?authuser=1#forceEdit=true&sandboxMode=true)
32 | This notebook implements a vanilla RNN, right from scratch using only basic linear layers and activation functions. This notebook aims at deepening the understanding and general implementation paradigm for recurrent nerual networks. It covers every step, right from data preprocessing to sampling from the trained model, using only basic Python and PyTorch functionalities.
33 |
34 | ### 2. [Char RNN using Vanilla RNN Layer](https://github.com/IvLabs/Natural-Language-Processing/blob/master/char_rnns/notebooks/Dino_Names_RNN.ipynb) [](https://colab.research.google.com/drive/1POL4Hjr-jATbmJLEhfGqcUhKNB6XYHHp?authuser=1#forceEdit=true&sandboxMode=true)
35 | This architecture employs the Vanilla RNN Layer available in PyTorch instead of writing the entire RNN model from scratch. This makes the model atleast 4 times faster owing to the optimized data-flow design of PyTorch's inbuilt layers. The increment in performance, is quite nominal due to the general drawbacks of Vanilla RNN models like vanishing gradients and short temporal memory spans.
36 |
37 | ### 3. [Char RNN using LSTM Layer](https://github.com/IvLabs/Natural-Language-Processing/blob/master/char_rnns/notebooks/Dino_Names_LSTM.ipynb) [](https://colab.research.google.com/drive/1lj7S2NaPa55rS-3X4yWlMj3-dy1EPEne?authuser=1#forceEdit=true&sandboxMode=true)
38 | In this notebook, we implement a single layered Long Short Term Memory (LSTM) network using PyTorch's inbuilt LSTM Layer. This network has more than 3 times more parameters than the Vanilla RNN. The final convergent loss does not change a lot but the results of sampling seem to make a lot more sense, i.e. appear to be closer to natural language and sound more sensible or natural.
39 |
40 | ### 4. [Char RNN using GRU Layer](https://github.com/IvLabs/Natural-Language-Processing/blob/master/char_rnns/notebooks/Dino_Names_GRU.ipynb) [](https://colab.research.google.com/drive/1KHngbDPUXEpSyl1HfbIFeNwkun5ssZsK?authuser=1#forceEdit=true&sandboxMode=true)
41 | The final notebook in the comparison, uses Gated Recurrent Units (GRU) which are a more computationally efficient version of the LSTM units. The number of trainable parameters is almost 2.5 times that of the equivalent Vanilla RNN, but the performance is often at par with the LSTM network. This makes them a friendlier choice for large scale deployment.
42 |
43 |
44 |
45 | ## Summary
46 | Below is a table, summarising the number of parameters and the convergent loss achieved by each model.
47 |
48 | | Architecture | No. of Learnable Parameters | Training Loss | Validation Loss | Test Loss |
49 | | ---------------- |:---------------------------:|:-------------:|:---------------:| :-------: |
50 | | RNN from scratch | 10856 | 2.0110 | 1.8492 | 1.7026 |
51 | | Vanilla RNN | 7707 | 1.8576 | 1.6835 | 1.5294 |
52 | | LSTM | 25563 | 1.7426 | 1.6065 | 1.4923 |
53 | | GRU | 19611 | 1.7202 | 1.5082 | 1.3935 |
54 |
55 |
56 |
57 |
58 | ## Plots
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | ### Note:
69 | In the notebooks (all except RNN from scratch), a parameter named "NUM_LAYERS" can be changed to change the number of stacked layers in the model. However, keeping in mind the miniscule amount of data available and the meagrely small objective at hand, using multi-layer architectures seems futile as the trade-off between performance and required computation, tilts more towards the computationally heavy side.
70 |
--------------------------------------------------------------------------------
/char_rnns/dino_names.txt:
--------------------------------------------------------------------------------
1 | Aachenosaurus
2 | Aardonyx
3 | Abdallahsaurus
4 | Abelisaurus
5 | Abrictosaurus
6 | Abrosaurus
7 | Abydosaurus
8 | Acanthopholis
9 | Achelousaurus
10 | Acheroraptor
11 | Achillesaurus
12 | Achillobator
13 | Acristavus
14 | Acrocanthosaurus
15 | Acrotholus
16 | Actiosaurus
17 | Adamantisaurus
18 | Adasaurus
19 | Adelolophus
20 | Adeopapposaurus
21 | Aegyptosaurus
22 | Aeolosaurus
23 | Aepisaurus
24 | Aepyornithomimus
25 | Aerosteon
26 | AetonyxAfromimus
27 | Afrovenator
28 | Agathaumas
29 | Aggiosaurus
30 | Agilisaurus
31 | Agnosphitys
32 | Agrosaurus
33 | Agujaceratops
34 | Agustinia
35 | Ahshislepelta
36 | Airakoraptor
37 | Ajancingenia
38 | Ajkaceratops
39 | Alamosaurus
40 | Alaskacephale
41 | Albalophosaurus
42 | Albertaceratops
43 | Albertadromeus
44 | Albertavenator
45 | Albertonykus
46 | Albertosaurus
47 | Albinykus
48 | Albisaurus
49 | Alcovasaurus
50 | Alectrosaurus
51 | Aletopelta
52 | Algoasaurus
53 | Alioramus
54 | Aliwalia
55 | Allosaurus
56 | Almas
57 | Alnashetri
58 | Alocodon
59 | Altirhinus
60 | Altispinax
61 | Alvarezsaurus
62 | Alwalkeria
63 | Alxasaurus
64 | Amargasaurus
65 | Amargastegos
66 | Amargatitanis
67 | Amazonsaurus
68 | Ammosaurus
69 | Ampelosaurus
70 | Amphicoelias
71 | Amphicoelicaudia
72 | Amphisaurus
73 | Amtocephale
74 | Amtosaurus
75 | Amurosaurus
76 | Amygdalodon
77 | Anabisetia
78 | Anasazisaurus
79 | Anatosaurus
80 | Anatotitan
81 | Anchiceratops
82 | Anchiornis
83 | Anchisaurus
84 | Andesaurus
85 | Andhrasaurus
86 | Angaturama
87 | Angloposeidon
88 | Angolatitan
89 | Angulomastacator
90 | Aniksosaurus
91 | Animantarx
92 | Ankistrodon
93 | Ankylosaurus
94 | Anodontosaurus
95 | Anoplosaurus
96 | Anserimimus
97 | Antarctopelta
98 | Antarctosaurus
99 | Antetonitrus
100 | Anthodon
101 | Antrodemus
102 | Anzu
103 | Aoniraptor
104 | Aorun
105 | Apatodon
106 | Apatoraptor
107 | Apatosaurus
108 | Appalachiosaurus
109 | Aquilops
110 | Aragosaurus
111 | Aralosaurus
112 | Araucanoraptor
113 | Archaeoceratops
114 | Archaeodontosaurus
115 | Archaeopteryx
116 | Archaeoraptor
117 | Archaeornis
118 | Archaeornithoides
119 | Archaeornithomimus
120 | Arcovenator
121 | Arctosaurus
122 | Arcusaurus
123 | Arenysaurus
124 | Argentinosaurus
125 | Argyrosaurus
126 | Aristosaurus
127 | Aristosuchus
128 | Arizonasaurus
129 | Arkansaurus
130 | Arkharavia
131 | Arrhinoceratops
132 | Arstanosaurus
133 | Asiaceratops
134 | Asiamericana
135 | Asiatosaurus
136 | Astrodon
137 | Astrodonius
138 | Astrodontaurus
139 | Astrophocaudia
140 | Asylosaurus
141 | Atacamatitan
142 | Atlantosaurus
143 | Atlasaurus
144 | Atlascopcosaurus
145 | Atrociraptor
146 | Atsinganosaurus
147 | Aublysodon
148 | Aucasaurus
149 | Augustia
150 | Augustynolophus
151 | Auroraceratops
152 | Aurornis
153 | Australodocus
154 | Australovenator
155 | Austrocheirus
156 | Austroposeidon
157 | Austroraptor
158 | Austrosaurus
159 | Avaceratops
160 | Avalonia
161 | Avalonianus
162 | Aviatyrannis
163 | Avimimus
164 | Avisaurus
165 | Avipes
166 | Azendohsaurus
167 | Bactrosaurus
168 | Bagaceratops
169 | Bagaraatan
170 | Bahariasaurus
171 | Bainoceratops
172 | Bakesaurus
173 | Balaur
174 | Balochisaurus
175 | Bambiraptor
176 | Banji
177 | Baotianmansaurus
178 | Barapasaurus
179 | Barilium
180 | Barosaurus
181 | Barrosasaurus
182 | Barsboldia
183 | Baryonyx
184 | Bashunosaurus
185 | Basutodon
186 | Bathygnathus
187 | Batyrosaurus
188 | Baurutitan
189 | Bayosaurus
190 | Becklespinax
191 | Beelemodon
192 | Beibeilong
193 | Beipiaognathus
194 | Beipiaosaurus
195 | Beishanlong
196 | Bellusaurus
197 | Belodon
198 | Berberosaurus
199 | Betasuchus
200 | Bicentenaria
201 | Bienosaurus
202 | Bihariosaurus
203 | Bilbeyhallorum
204 | Bissektipelta
205 | Bistahieversor
206 | Blancocerosaurus
207 | Blasisaurus
208 | Blikanasaurus
209 | Bolong
210 | Bonapartenykus
211 | Bonapartesaurus
212 | Bonatitan
213 | Bonitasaura
214 | Borealopelta
215 | Borealosaurus
216 | Boreonykus
217 | Borogovia
218 | Bothriospondylus
219 | Brachiosaurus
220 | Brachyceratops
221 | Brachylophosaurus
222 | Brachypodosaurus
223 | Brachyrophus
224 | Brachytaenius
225 | Brachytrachelopan
226 | Bradycneme
227 | Brasileosaurus
228 | Brasilotitan
229 | Bravoceratops
230 | Breviceratops
231 | Brohisaurus
232 | Brontomerus
233 | Brontoraptor
234 | Brontosaurus
235 | Bruhathkayosaurus
236 | Bugenasaura
237 | Buitreraptor
238 | Burianosaurus
239 | Buriolestes
240 | Byranjaffia
241 | Byronosaurus
242 | Caenagnathasia
243 | Caenagnathus
244 | Calamosaurus
245 | Calamospondylus
246 | Calamospondylus
247 | Callovosaurus
248 | Camarasaurus
249 | Camarillasaurus
250 | Camelotia
251 | Camposaurus
252 | Camptonotus
253 | Camptosaurus
254 | Campylodon
255 | Campylodoniscus
256 | Canardia
257 | Capitalsaurus
258 | Carcharodontosaurus
259 | Cardiodon
260 | Carnotaurus
261 | Caseosaurus
262 | Cathartesaura
263 | Cathetosaurus
264 | Caudipteryx
265 | Caudocoelus
266 | Caulodon
267 | Cedarosaurus
268 | Cedarpelta
269 | Cedrorestes
270 | Centemodon
271 | Centrosaurus
272 | Cerasinops
273 | Ceratonykus
274 | Ceratops
275 | Ceratosaurus
276 | Cetiosauriscus
277 | Cetiosaurus
278 | Changchunsaurus
279 | Changdusaurus
280 | Changyuraptor
281 | Chaoyangsaurus
282 | Charonosaurus
283 | Chasmosaurus
284 | Chassternbergia
285 | Chebsaurus
286 | Chenanisaurus
287 | Cheneosaurus
288 | Chialingosaurus
289 | Chiayusaurus
290 | Chienkosaurus
291 | Chihuahuasaurus
292 | Chilantaisaurus
293 | Chilesaurus
294 | Chindesaurus
295 | Chingkankousaurus
296 | Chinshakiangosaurus
297 | Chirostenotes
298 | Choconsaurus
299 | Chondrosteosaurus
300 | Chromogisaurus
301 | Chuandongocoelurus
302 | Chuanjiesaurus
303 | Chuanqilong
304 | Chubutisaurus
305 | Chungkingosaurus
306 | Chuxiongosaurus
307 | Cinizasaurus
308 | Cionodon
309 | Citipati
310 | Cladeiodon
311 | Claorhynchus
312 | Claosaurus
313 | Clarencea
314 | Clasmodosaurus
315 | Clepsysaurus
316 | Coahuilaceratops
317 | Coelophysis
318 | Coelosaurus
319 | Coeluroides
320 | Coelurosauravus
321 | Coelurus
322 | Colepiocephale
323 | Coloradia
324 | Coloradisaurus
325 | Colossosaurus
326 | Comahuesaurus
327 | Comanchesaurus
328 | Compsognathus
329 | Compsosuchus
330 | Concavenator
331 | Conchoraptor
332 | Condorraptor
333 | Coronosaurus
334 | Corythoraptor
335 | Corythosaurus
336 | Craspedodon
337 | Crataeomus
338 | Craterosaurus
339 | Creosaurus
340 | Crichtonpelta
341 | Crichtonsaurus
342 | Cristatusaurus
343 | Crosbysaurus
344 | Cruxicheiros
345 | Cryolophosaurus
346 | Cryptodraco
347 | Cryptoraptor
348 | Cryptosaurus
349 | Cryptovolans
350 | Cumnoria
351 | Daanosaurus
352 | Dacentrurus
353 | Dachongosaurus
354 | Daemonosaurus
355 | Dahalokely
356 | Dakosaurus
357 | Dakotadon
358 | Dakotaraptor
359 | Daliansaurus
360 | Damalasaurus
361 | Dandakosaurus
362 | Danubiosaurus
363 | Daptosaurus
364 | Darwinsaurus
365 | Dashanpusaurus
366 | Daspletosaurus
367 | Dasygnathoides
368 | Dasygnathus
369 | Datanglong
370 | Datonglong
371 | Datousaurus
372 | Daurosaurus
373 | Daxiatitan
374 | Deinocheirus
375 | Deinodon
376 | Deinonychus
377 | Delapparentia
378 | Deltadromeus
379 | Demandasaurus
380 | Denversaurus
381 | Deuterosaurus
382 | Diabloceratops
383 | Diamantinasaurus
384 | Dianchungosaurus
385 | Diceratops
386 | DiceratusDiclonius
387 | Dicraeosaurus
388 | DidanodonDilong
389 | Dilophosaurus
390 | Diluvicursor
391 | Dimodosaurus
392 | Dinheirosaurus
393 | Dinodocus
394 | Dinotyrannus
395 | Diplodocus
396 | Diplotomodon
397 | Diracodon
398 | Dolichosuchus
399 | Dollodon
400 | Domeykosaurus
401 | Dongbeititan
402 | Dongyangopelta
403 | Dongyangosaurus
404 | Doratodon
405 | Doryphorosaurus
406 | Draconyx
407 | Dracopelta
408 | Dracoraptor
409 | Dracorex
410 | Dracovenator
411 | Dravidosaurus
412 | Dreadnoughtus
413 | Drinker
414 | Dromaeosauroides
415 | Dromaeosaurus
416 | Dromiceiomimus
417 | Dromicosaurus
418 | Drusilasaura
419 | Dryosaurus
420 | Dryptosauroides
421 | Dryptosaurus
422 | Dubreuillosaurus
423 | Duriatitan
424 | Duriavenator
425 | Dynamosaurus
426 | Dyoplosaurus
427 | Dysalotosaurus
428 | Dysganus
429 | Dyslocosaurus
430 | Dystrophaeus
431 | Dystylosaurus
432 | Echinodon
433 | Edmarka
434 | Edmontonia
435 | Edmontosaurus
436 | Efraasia
437 | Einiosaurus
438 | Ekrixinatosaurus
439 | Elachistosuchus
440 | Elaltitan
441 | Elaphrosaurus
442 | Elmisaurus
443 | Elopteryx
444 | Elosaurus
445 | Elrhazosaurus
446 | Elvisaurus
447 | Emausaurus
448 | Embasaurus
449 | Enigmosaurus
450 | Eoabelisaurus
451 | Eobrontosaurus
452 | Eocarcharia
453 | Eoceratops
454 | Eocursor
455 | Eodromaeus
456 | Eohadrosaurus
457 | Eolambia
458 | Eomamenchisaurus
459 | Eoplophysis
460 | Eoraptor
461 | Eosinopteryx
462 | Eotrachodon
463 | Eotriceratops
464 | Eotyrannus
465 | Eousdryosaurus
466 | Epachthosaurus
467 | Epanterias
468 | Ephoenosaurus
469 | Epicampodon
470 | Epichirostenotes
471 | Epidendrosaurus
472 | Epidexipteryx
473 | Equijubus
474 | Erectopus
475 | Erketu
476 | Erliansaurus
477 | Erlikosaurus
478 | Eshanosaurus
479 | Euacanthus
480 | Eucamerotus
481 | Eucentrosaurus
482 | Eucercosaurus
483 | Eucnemesaurus
484 | Eucoelophysis
485 | Eugongbusaurus
486 | Euhelopus
487 | Euoplocephalus
488 | Eupodosaurus
489 | Eureodon
490 | Eurolimnornis
491 | Euronychodon
492 | Europasaurus
493 | Europatitan
494 | Europelta
495 | Euskelosaurus
496 | Eustreptospondylus
497 | Fabrosaurus
498 | Falcarius
499 | Fendusaurus
500 | Fenestrosaurus
501 | Ferganasaurus
502 | Ferganastegos
503 | Ferganocephale
504 | Foraminacephale
505 | Fosterovenator
506 | Frenguellisaurus
507 | Fruitadens
508 | Fukuiraptor
509 | Fukuisaurus
510 | Fukuititan
511 | Fukuivenator
512 | Fulengia
513 | Fulgurotherium
514 | Fusinasus
515 | Fusuisaurus
516 | Futabasaurus
517 | Futalognkosaurus
518 | Gadolosaurus
519 | Galeamopus
520 | Galesaurus
521 | Gallimimus
522 | Galtonia
523 | Galveosaurus
524 | Galvesaurus
525 | Gannansaurus
526 | Gansutitan
527 | Ganzhousaurus
528 | Gargoyleosaurus
529 | Garudimimus
530 | Gasosaurus
531 | Gasparinisaura
532 | Gastonia
533 | Gavinosaurus
534 | Geminiraptor
535 | Genusaurus
536 | Genyodectes
537 | Geranosaurus
538 | Gideonmantellia
539 | Giganotosaurus
540 | Gigantoraptor
541 | Gigantosaurus
542 | Gigantosaurus
543 | Gigantoscelus
544 | Gigantspinosaurus
545 | Gilmoreosaurus
546 | Ginnareemimus
547 | Giraffatitan
548 | Glacialisaurus
549 | Glishades
550 | Glyptodontopelta
551 | Skeleton
552 | Gobiceratops
553 | Gobisaurus
554 | Gobititan
555 | Gobivenator
556 | Godzillasaurus
557 | Gojirasaurus
558 | Gondwanatitan
559 | Gongbusaurus
560 | Gongpoquansaurus
561 | Gongxianosaurus
562 | Gorgosaurus
563 | Goyocephale
564 | Graciliceratops
565 | Graciliraptor
566 | Gracilisuchus
567 | Gravitholus
568 | Gresslyosaurus
569 | Griphornis
570 | Griphosaurus
571 | Gryphoceratops
572 | Gryponyx
573 | Gryposaurus
574 | Gspsaurus
575 | Guaibasaurus
576 | Gualicho
577 | Guanlong
578 | Gwyneddosaurus
579 | Gyposaurus
580 | Hadrosauravus
581 | Hadrosaurus
582 | Haestasaurus
583 | Hagryphus
584 | Hallopus
585 | Halszkaraptor
586 | Halticosaurus
587 | Hanssuesia
588 | Hanwulosaurus
589 | Haplocanthosaurus
590 | Haplocanthus
591 | Haplocheirus
592 | Harpymimus
593 | Haya
594 | Hecatasaurus
595 | Heilongjiangosaurus
596 | Heishansaurus
597 | Helioceratops
598 | Helopus
599 | Heptasteornis
600 | Herbstosaurus
601 | Herrerasaurus
602 | Hesperonychus
603 | Hesperosaurus
604 | Heterodontosaurus
605 | Heterosaurus
606 | Hexing
607 | Hexinlusaurus
608 | Heyuannia
609 | Hierosaurus
610 | Hippodraco
611 | Hironosaurus
612 | Hisanohamasaurus
613 | Histriasaurus
614 | Homalocephale
615 | Honghesaurus
616 | Hongshanosaurus
617 | Hoplitosaurus
618 | Hoplosaurus
619 | Horshamosaurus
620 | Hortalotarsus
621 | Huabeisaurus
622 | Hualianceratops
623 | Huanansaurus
624 | Huanghetitan
625 | Huangshanlong
626 | Huaxiagnathus
627 | Huaxiaosaurus
628 | Huaxiasaurus
629 | Huayangosaurus
630 | Hudiesaurus
631 | Huehuecanauhtlus
632 | Hulsanpes
633 | Hungarosaurus
634 | Huxleysaurus
635 | Hylaeosaurus
636 | HylosaurusHypacrosaurus
637 | Hypselorhachis
638 | Hypselosaurus
639 | Hypselospinus
640 | Hypsibema
641 | Hypsilophodon
642 | Hypsirhophus
643 | habodcraniosaurus
644 | Ichthyovenator
645 | Ignavusaurus
646 | Iguanacolossus
647 | Iguanodon
648 | Iguanoides
649 | Skeleton
650 | Iguanosaurus
651 | Iliosuchus
652 | Ilokelesia
653 | Incisivosaurus
654 | Indosaurus
655 | Indosuchus
656 | Ingenia
657 | Inosaurus
658 | Irritator
659 | Isaberrysaura
660 | Isanosaurus
661 | Ischioceratops
662 | Ischisaurus
663 | Ischyrosaurus
664 | Isisaurus
665 | Issasaurus
666 | Itemirus
667 | Iuticosaurus
668 | Jainosaurus
669 | Jaklapallisaurus
670 | Janenschia
671 | Jaxartosaurus
672 | Jeholosaurus
673 | Jenghizkhan
674 | Jensenosaurus
675 | Jeyawati
676 | Jianchangosaurus
677 | Jiangjunmiaosaurus
678 | Jiangjunosaurus
679 | Jiangshanosaurus
680 | Jiangxisaurus
681 | Jianianhualong
682 | Jinfengopteryx
683 | Jingshanosaurus
684 | Jintasaurus
685 | Jinzhousaurus
686 | Jiutaisaurus
687 | Jobaria
688 | Jubbulpuria
689 | Judiceratops
690 | Jurapteryx
691 | Jurassosaurus
692 | Juratyrant
693 | Juravenator
694 | Kagasaurus
695 | Kaijiangosaurus
696 | Kakuru
697 | Kangnasaurus
698 | Karongasaurus
699 | Katepensaurus
700 | Katsuyamasaurus
701 | Kayentavenator
702 | Kazaklambia
703 | Kelmayisaurus
704 | KemkemiaKentrosaurus
705 | Kentrurosaurus
706 | Kerberosaurus
707 | Kentrosaurus
708 | Khaan
709 | Khetranisaurus
710 | Kileskus
711 | Kinnareemimus
712 | Kitadanisaurus
713 | Kittysaurus
714 | KlamelisaurusKol
715 | Koparion
716 | Koreaceratops
717 | Koreanosaurus
718 | Koreanosaurus
719 | Koshisaurus
720 | Kosmoceratops
721 | Kotasaurus
722 | Koutalisaurus
723 | Kritosaurus
724 | Kryptops
725 | Krzyzanowskisaurus
726 | Kukufeldia
727 | Kulceratops
728 | Kulindadromeus
729 | Kulindapteryx
730 | Kunbarrasaurus
731 | Kundurosaurus
732 | Kunmingosaurus
733 | Kuszholia
734 | Labocania
735 | Labrosaurus
736 | Laelaps
737 | Laevisuchus
738 | Lagerpeton
739 | Lagosuchus
740 | Laiyangosaurus
741 | Lamaceratops
742 | Lambeosaurus
743 | Lametasaurus
744 | Lamplughsaura
745 | Lanasaurus
746 | Lancangosaurus
747 | Lancanjiangosaurus
748 | Lanzhousaurus
749 | Laosaurus
750 | Lapampasaurus
751 | Laplatasaurus
752 | Lapparentosaurus
753 | Laquintasaura
754 | Latenivenatrix
755 | Latirhinus
756 | Leaellynasaura
757 | Leinkupal
758 | Leipsanosaurus
759 | Lengosaurus
760 | Leonerasaurus
761 | Lepidocheirosaurus
762 | Lepidus
763 | Leptoceratops
764 | Leptorhynchos
765 | Leptospondylus
766 | Leshansaurus
767 | Lesothosaurus
768 | Lessemsaurus
769 | Levnesovia
770 | Lewisuchus
771 | Lexovisaurus
772 | Leyesaurus
773 | Liaoceratops
774 | Liaoningosaurus
775 | Liaoningtitan
776 | Liaoningvenator
777 | Liassaurus
778 | Libycosaurus
779 | Ligabueino
780 | Ligabuesaurus
781 | Ligomasaurus
782 | Likhoelesaurus
783 | Liliensternus
784 | Limaysaurus
785 | Limnornis
786 | Limnosaurus
787 | Limusaurus
788 | Linhenykus
789 | Linheraptor
790 | Linhevenator
791 | Lirainosaurus
792 | LisboasaurusLiubangosaurus
793 | Lohuecotitan
794 | Loncosaurus
795 | Longisquama
796 | Longosaurus
797 | Lophorhothon
798 | Lophostropheus
799 | Loricatosaurus
800 | Loricosaurus
801 | Losillasaurus
802 | Lourinhanosaurus
803 | Lourinhasaurus
804 | Luanchuanraptor
805 | Luanpingosaurus
806 | Lucianosaurus
807 | Lucianovenator
808 | Lufengosaurus
809 | Lukousaurus
810 | Luoyanggia
811 | Lurdusaurus
812 | Lusitanosaurus
813 | Lusotitan
814 | Lycorhinus
815 | Lythronax
816 | Macelognathus
817 | Machairasaurus
818 | Machairoceratops
819 | Macrodontophion
820 | Macrogryphosaurus
821 | Macrophalangia
822 | Macroscelosaurus
823 | Macrurosaurus
824 | Madsenius
825 | Magnapaulia
826 | Magnamanus
827 | Magnirostris
828 | Magnosaurus
829 | Magulodon
830 | Magyarosaurus
831 | Mahakala
832 | Maiasaura
833 | Majungasaurus
834 | Majungatholus
835 | Malarguesaurus
836 | Malawisaurus
837 | Maleevosaurus
838 | Maleevus
839 | Mamenchisaurus
840 | Manidens
841 | Mandschurosaurus
842 | Manospondylus
843 | Mantellisaurus
844 | Mantellodon
845 | Mapusaurus
846 | Marasuchus
847 | Marisaurus
848 | Marmarospondylus
849 | Marshosaurus
850 | Martharaptor
851 | Masiakasaurus
852 | Massospondylus
853 | Matheronodon
854 | Maxakalisaurus
855 | Medusaceratops
856 | Megacervixosaurus
857 | Megadactylus
858 | Megadontosaurus
859 | Megalosaurus
860 | Megapnosaurus
861 | Megaraptor
862 | Mei
863 | Melanorosaurus
864 | Mendozasaurus
865 | Mercuriceratops
866 | Meroktenos
867 | Metriacanthosaurus
868 | Microcephale
869 | Microceratops
870 | Microceratus
871 | Microcoelus
872 | Microdontosaurus
873 | Microhadrosaurus
874 | Micropachycephalosaurus
875 | Microraptor
876 | Microvenator
877 | Mierasaurus
878 | Mifunesaurus
879 | Minmi
880 | Minotaurasaurus
881 | Miragaia
882 | Mirischia
883 | Moabosaurus
884 | Mochlodon
885 | Mohammadisaurus
886 | Mojoceratops
887 | Mongolosaurus
888 | Monkonosaurus
889 | Monoclonius
890 | Monolophosaurus
891 | Mononychus
892 | Mononykus
893 | Montanoceratops
894 | Morelladon
895 | Morinosaurus
896 | Morosaurus
897 | Morrosaurus
898 | Mosaiceratops
899 | Moshisaurus
900 | Mtapaiasaurus
901 | Mtotosaurus
902 | Murusraptor
903 | Mussaurus
904 | Muttaburrasaurus
905 | Muyelensaurus
906 | Mymoorapelta
907 | Naashoibitosaurus
908 | Nambalia
909 | Nankangia
910 | Nanningosaurus
911 | Nanosaurus
912 | Nanotyrannus
913 | Nanshiungosaurus
914 | Nanuqsaurus
915 | Nanyangosaurus
916 | Narambuenatitan
917 | Nasutoceratops
918 | Natronasaurus
919 | Nebulasaurus
920 | Nectosaurus
921 | Nedcolbertia
922 | Nedoceratops
923 | Neimongosaurus
924 | Nemegtia
925 | Nemegtomaia
926 | Nemegtosaurus
927 | Neosaurus
928 | Neosodon
929 | Neovenator
930 | Neuquenraptor
931 | Neuquensaurus
932 | Newtonsaurus
933 | Ngexisaurus
934 | Nicksaurus
935 | Nigersaurus
936 | Ningyuansaurus
937 | Niobrarasaurus
938 | Nipponosaurus
939 | Noasaurus
940 | Nodocephalosaurus
941 | Nodosaurus
942 | Nomingia
943 | Nopcsaspondylus
944 | Normanniasaurus
945 | Nothronychus
946 | Notoceratops
947 | Notocolossus
948 | Notohypsilophodon
949 | Nqwebasaurus
950 | Nteregosaurus
951 | Nurosaurus
952 | Nuthetes
953 | Nyasasaurus
954 | Nyororosaurus
955 | Ohmdenosaurus
956 | Ojoceratops
957 | Ojoraptorsaurus
958 | Oligosaurus
959 | Olorotitan
960 | Omeisaurus
961 | Omosaurus
962 | Onychosaurus
963 | Oohkotokia
964 | Opisthocoelicaudia
965 | Oplosaurus
966 | Orcomimus
967 | OrinosaurusOrkoraptor
968 | OrnatotholusOrnithodesmus
969 | Ornithoides
970 | Ornitholestes
971 | Ornithomerus
972 | Ornithomimoides
973 | Ornithomimus
974 | Ornithopsis
975 | Ornithosuchus
976 | Ornithotarsus
977 | Orodromeus
978 | Orosaurus
979 | Orthogoniosaurus
980 | Orthomerus
981 | Oryctodromeus
982 | Oshanosaurus
983 | Osmakasaurus
984 | Ostafrikasaurus
985 | Ostromia
986 | Othnielia
987 | Othnielosaurus
988 | Otogosaurus
989 | Ouranosaurus
990 | Overosaurus
991 | Oviraptor
992 | Ovoraptor
993 | Owenodon
994 | Oxalaia
995 | Ozraptor
996 | Pachycephalosaurus
997 | Pachyrhinosaurus
998 | Pachysauriscus
999 | Pachysaurops
1000 | Pachysaurus
1001 | Pachyspondylus
1002 | Pachysuchus
1003 | Padillasaurus
1004 | Pakisaurus
1005 | Palaeoctonus
1006 | Palaeocursornis
1007 | Palaeolimnornis
1008 | Palaeopteryx
1009 | Palaeosauriscus
1010 | Palaeosaurus
1011 | Palaeosaurus
1012 | Palaeoscincus
1013 | Paleosaurus
1014 | Paludititan
1015 | Paluxysaurus
1016 | Pampadromaeus
1017 | Pamparaptor
1018 | Panamericansaurus
1019 | Pandoravenator
1020 | Panguraptor
1021 | Panoplosaurus
1022 | Panphagia
1023 | Pantydraco
1024 | Paraiguanodon
1025 | Paralititan
1026 | Paranthodon
1027 | Pararhabdodon
1028 | Parasaurolophus
1029 | Pareiasaurus
1030 | Parksosaurus
1031 | Paronychodon
1032 | Parrosaurus
1033 | Parvicursor
1034 | Patagonykus
1035 | Patagosaurus
1036 | Patagotitan
1037 | Pawpawsaurus
1038 | Pectinodon
1039 | Pedopenna
1040 | Pegomastax
1041 | Peishansaurus
1042 | Pekinosaurus
1043 | Pelecanimimus
1044 | Pellegrinisaurus
1045 | Peloroplites
1046 | Pelorosaurus
1047 | Peltosaurus
1048 | Penelopognathus
1049 | Pentaceratops
1050 | Petrobrasaurus
1051 | Phaedrolosaurus
1052 | Philovenator
1053 | Phuwiangosaurus
1054 | Phyllodon
1055 | Piatnitzkysaurus
1056 | Picrodon
1057 | Pinacosaurus
1058 | Pisanosaurus
1059 | Pitekunsaurus
1060 | Piveteausaurus
1061 | Planicoxa
1062 | Plateosauravus
1063 | Plateosaurus
1064 | Platyceratops
1065 | Plesiohadros
1066 | Pleurocoelus
1067 | Pleuropeltus
1068 | Pneumatoarthrus
1069 | Pneumatoraptor
1070 | Podokesaurus
1071 | Poekilopleuron
1072 | Polacanthoides
1073 | Polacanthus
1074 | Polyodontosaurus
1075 | Polyonax
1076 | Ponerosteus
1077 | Poposaurus
1078 | Parasaurolophus
1079 | Postosuchus
1080 | Powellvenator
1081 | Pradhania
1082 | Prenocephale
1083 | Prenoceratops
1084 | Priconodon
1085 | Priodontognathus
1086 | Proa
1087 | Probactrosaurus
1088 | Probrachylophosaurus
1089 | Proceratops
1090 | Proceratosaurus
1091 | Procerosaurus
1092 | Procerosaurus
1093 | Procheneosaurus
1094 | Procompsognathus
1095 | Prodeinodon
1096 | Proiguanodon
1097 | Propanoplosaurus
1098 | Proplanicoxa
1099 | Prosaurolophus
1100 | Protarchaeopteryx
1101 | Protecovasaurus
1102 | Protiguanodon
1103 | Protoavis
1104 | Protoceratops
1105 | Protognathosaurus
1106 | Protognathus
1107 | Protohadros
1108 | Protorosaurus
1109 | Protorosaurus
1110 | Protrachodon
1111 | Proyandusaurus
1112 | Pseudolagosuchus
1113 | Psittacosaurus
1114 | Pteropelyx
1115 | Pterospondylus
1116 | Puertasaurus
1117 | Pukyongosaurus
1118 | Pulanesaura
1119 | Pycnonemosaurus
1120 | Pyroraptor
1121 | Qantassaurus
1122 | Qianzhousaurus
1123 | Qiaowanlong
1124 | Qijianglong
1125 | Qinlingosaurus
1126 | Qingxiusaurus
1127 | Qiupalong
1128 | Quaesitosaurus
1129 | Quetecsaurus
1130 | Quilmesaurus
1131 | Rachitrema
1132 | Rahiolisaurus
1133 | Rahona
1134 | Rahonavis
1135 | Rajasaurus
1136 | Rapator
1137 | Rapetosaurus
1138 | Raptorex
1139 | Ratchasimasaurus
1140 | Rativates
1141 | Rayososaurus
1142 | Razanandrongobe
1143 | Rebbachisaurus
1144 | Regaliceratops
1145 | Regnosaurus
1146 | Revueltosaurus
1147 | Rhabdodon
1148 | Rhadinosaurus
1149 | Rhinorex
1150 | Rhodanosaurus
1151 | Rhoetosaurus
1152 | Rhopalodon
1153 | Riabininohadros
1154 | Richardoestesia
1155 | Rileya
1156 | Rileyasuchus
1157 | Rinchenia
1158 | Rinconsaurus
1159 | Rioarribasaurus
1160 | Riodevasaurus
1161 | Riojasaurus
1162 | Riojasuchus
1163 | Rocasaurus
1164 | Roccosaurus
1165 | Rubeosaurus
1166 | Ruehleia
1167 | Rugocaudia
1168 | Rugops
1169 | Rukwatitan
1170 | Ruyangosaurus
1171 | Sacisaurus
1172 | Sahaliyania
1173 | Saichania
1174 | Saldamosaurus
1175 | Salimosaurus
1176 | Saltasaurus
1177 | Saltopus
1178 | Saltriosaurus
1179 | Sanchusaurus
1180 | Sangonghesaurus
1181 | Sanjuansaurus
1182 | Sanpasaurus
1183 | Santanaraptor
1184 | Saraikimasoom
1185 | Sarahsaurus
1186 | Sarcolestes
1187 | Sarcosaurus
1188 | Sarmientosaurus
1189 | Saturnalia
1190 | Sauraechinodon
1191 | Saurolophus
1192 | Sauroniops
1193 | Sauropelta
1194 | Saurophaganax
1195 | Saurophagus
1196 | Sauroplites
1197 | Sauroposeidon
1198 | Saurornithoides
1199 | Saurornitholestes
1200 | Savannasaurus
1201 | Scansoriopteryx
1202 | Scaphonyx
1203 | Scelidosaurus
1204 | Scipionyx
1205 | Sciurumimus
1206 | Scleromochlus
1207 | Scolosaurus
1208 | Scutellosaurus
1209 | Secernosaurus
1210 | Sefapanosaurus
1211 | Segisaurus
1212 | Segnosaurus
1213 | Seismosaurus
1214 | Seitaad
1215 | Selimanosaurus
1216 | Sellacoxa
1217 | Sellosaurus
1218 | Serendipaceratops
1219 | Serikornis
1220 | Shamosaurus
1221 | Shanag
1222 | Shanshanosaurus
1223 | Shantungosaurus
1224 | Shanxia
1225 | Shanyangosaurus
1226 | Shaochilong
1227 | Shenzhousaurus
1228 | Shidaisaurus
1229 | Shingopana
1230 | Shixinggia
1231 | Shuangbaisaurus
1232 | Shuangmiaosaurus
1233 | Shunosaurus
1234 | Shuvosaurus
1235 | Shuvuuia
1236 | Siamodon
1237 | Siamodracon
1238 | Siamosaurus
1239 | Siamotyrannus
1240 | Siats
1241 | Sibirosaurus
1242 | Sibirotitan
1243 | Sidormimus
1244 | Sigilmassasaurus
1245 | Silesaurus
1246 | Siluosaurus
1247 | Silvisaurus
1248 | Similicaudipteryx
1249 | Sinocalliopteryx
1250 | Sinoceratops
1251 | Sinocoelurus
1252 | Sinopelta
1253 | Sinopeltosaurus
1254 | Sinornithoides
1255 | Sinornithomimus
1256 | Sinornithosaurus
1257 | Sinosauropteryx
1258 | Sinosaurus
1259 | Sinotyrannus
1260 | Sinovenator
1261 | Sinraptor
1262 | Sinusonasus
1263 | Sirindhorna
1264 | Skorpiovenator
1265 | Smilodon
1266 | Sonidosaurus
1267 | Sonorasaurus
1268 | Soriatitan
1269 | Sphaerotholus
1270 | Sphenosaurus
1271 | Sphenospondylus
1272 | Spiclypeus
1273 | Spinophorosaurus
1274 | Spinops
1275 | Spinosaurus
1276 | Spinostropheus
1277 | Spinosuchus
1278 | Spondylosoma
1279 | Squalodon
1280 | Staurikosaurus
1281 | Stegoceras
1282 | Stegopelta
1283 | Stegosaurides
1284 | Stegosaurus
1285 | Stenonychosaurus
1286 | Stenopelix
1287 | Stenotholus
1288 | Stephanosaurus
1289 | Stereocephalus
1290 | Sterrholophus
1291 | Stokesosaurus
1292 | Stormbergia
1293 | Strenusaurus
1294 | Streptospondylus
1295 | Struthiomimus
1296 | Struthiosaurus
1297 | Stygimoloch
1298 | Stygivenator
1299 | Styracosaurus
1300 | Succinodon
1301 | Suchomimus
1302 | Suchosaurus
1303 | Suchoprion
1304 | Sugiyamasaurus
1305 | Skeleton
1306 | Sulaimanisaurus
1307 | Supersaurus
1308 | Suuwassea
1309 | Suzhousaurus
1310 | Symphyrophus
1311 | Syngonosaurus
1312 | Syntarsus
1313 | Syrmosaurus
1314 | Szechuanosaurus
1315 | Tachiraptor
1316 | Talarurus
1317 | Talenkauen
1318 | Talos
1319 | Tambatitanis
1320 | Tangvayosaurus
1321 | Tanius
1322 | Tanycolagreus
1323 | Tanystropheus
1324 | Tanystrosuchus
1325 | Taohelong
1326 | Tapinocephalus
1327 | Tapuiasaurus
1328 | Tarascosaurus
1329 | Tarbosaurus
1330 | Tarchia
1331 | Tastavinsaurus
1332 | Tatankacephalus
1333 | Tatankaceratops
1334 | Tataouinea
1335 | Tatisaurus
1336 | Taurovenator
1337 | Taveirosaurus
1338 | Tawa
1339 | Tawasaurus
1340 | Tazoudasaurus
1341 | Technosaurus
1342 | Tecovasaurus
1343 | Tehuelchesaurus
1344 | Teihivenator
1345 | Teinurosaurus
1346 | Teleocrater
1347 | Telmatosaurus
1348 | Tenantosaurus
1349 | Tenchisaurus
1350 | Tendaguria
1351 | Tengrisaurus
1352 | Tenontosaurus
1353 | Teratophoneus
1354 | Teratosaurus
1355 | Termatosaurus
1356 | Tethyshadros
1357 | Tetragonosaurus
1358 | Texacephale
1359 | Texasetes
1360 | Teyuwasu
1361 | Thecocoelurus
1362 | Thecodontosaurus
1363 | Thecospondylus
1364 | Theiophytalia
1365 | Therizinosaurus
1366 | Therosaurus
1367 | Thescelosaurus
1368 | Thespesius
1369 | Thotobolosaurus
1370 | Tianchisaurus
1371 | Tianchungosaurus
1372 | Tianyulong
1373 | Tianyuraptor
1374 | Tianzhenosaurus
1375 | Tichosteus
1376 | Tienshanosaurus
1377 | Timimus
1378 | Timurlengia
1379 | Titanoceratops
1380 | Titanosaurus
1381 | Titanosaurus
1382 | Tochisaurus
1383 | Tomodon
1384 | Tonganosaurus
1385 | Tongtianlong
1386 | Tonouchisaurus
1387 | Torilion
1388 | Tornieria
1389 | Torosaurus
1390 | Torvosaurus
1391 | Tototlmimus
1392 | Trachodon
1393 | Traukutitan
1394 | Trialestes
1395 | Triassolestes
1396 | Tribelesodon
1397 | Triceratops
1398 | Trigonosaurus
1399 | Trimucrodon
1400 | Trinisaura
1401 | Triunfosaurus
1402 | Troodon
1403 | Tsaagan
1404 | Tsagantegia
1405 | Tsintaosaurus
1406 | Tugulusaurus
1407 | Tuojiangosaurus
1408 | Turanoceratops
1409 | Turiasaurus
1410 | Tylocephale
1411 | Tylosteus
1412 | Tyrannosaurus
1413 | Tyrannotitan
1414 | Illustration
1415 | Uberabatitan
1416 | Udanoceratops
1417 | Ugrosaurus
1418 | Ugrunaaluk
1419 | Uintasaurus
1420 | Ultrasauros
1421 | Ultrasaurus
1422 | Ultrasaurus
1423 | Umarsaurus
1424 | Unaysaurus
1425 | Unenlagia
1426 | Unescoceratops
1427 | Unicerosaurus
1428 | Unquillosaurus
1429 | Urbacodon
1430 | Utahceratops
1431 | Utahraptor
1432 | Uteodon
1433 | Vagaceratops
1434 | Vahiny
1435 | Valdoraptor
1436 | Valdosaurus
1437 | Variraptor
1438 | Velociraptor
1439 | Vectensia
1440 | Vectisaurus
1441 | Velafrons
1442 | Velocipes
1443 | Velociraptor
1444 | Velocisaurus
1445 | Venaticosuchus
1446 | Venenosaurus
1447 | Veterupristisaurus
1448 | Viavenator
1449 | Vitakridrinda
1450 | Vitakrisaurus
1451 | Volkheimeria
1452 | Vouivria
1453 | Vulcanodon
1454 | Wadhurstia
1455 | Wakinosaurus
1456 | Walgettosuchus
1457 | Walkeria
1458 | Walkersaurus
1459 | Wangonisaurus
1460 | Wannanosaurus
1461 | Wellnhoferia
1462 | Wendiceratops
1463 | Wiehenvenator
1464 | Willinakaqe
1465 | Wintonotitan
1466 | Wuerhosaurus
1467 | Wulagasaurus
1468 | Wulatelong
1469 | Wyleyia
1470 | Wyomingraptor
1471 | Xenoceratops
1472 | Xenoposeidon
1473 | Xenotarsosaurus
1474 | Xianshanosaurus
1475 | Xiaosaurus
1476 | Xingxiulong
1477 | Xinjiangovenator
1478 | Xinjiangtitan
1479 | Xiongguanlong
1480 | Xixianykus
1481 | Xixiasaurus
1482 | Xixiposaurus
1483 | Xuanhanosaurus
1484 | Xuanhuaceratops
1485 | Xuanhuasaurus
1486 | Xuwulong
1487 | Yaleosaurus
1488 | Yamaceratops
1489 | Yandusaurus
1490 | Yangchuanosaurus
1491 | Yaverlandia
1492 | Yehuecauhceratops
1493 | Yezosaurus
1494 | Yibinosaurus
1495 | Yimenosaurus
1496 | Yingshanosaurus
1497 | Yinlong
1498 | Yixianosaurus
1499 | Yizhousaurus
1500 | Yongjinglong
1501 | Yuanmouraptor
1502 | Yuanmousaurus
1503 | Yueosaurus
1504 | Yulong
1505 | Yunganglong
1506 | Yunmenglong
1507 | Yunnanosaurus
1508 | Yunxianosaurus
1509 | Yurgovuchia
1510 | Yutyrannus
1511 | Zanabazar
1512 | Zanclodon
1513 | Zapalasaurus
1514 | Zapsalis
1515 | Zaraapelta
1516 | ZatomusZby
1517 | Zephyrosaurus
1518 | Zhanghenglong
1519 | Zhejiangosaurus
1520 | Zhenyuanlong
1521 | Zhongornis
1522 | Zhongjianosaurus
1523 | Zhongyuansaurus
1524 | Zhuchengceratops
1525 | Zhuchengosaurus
1526 | Zhuchengtitan
1527 | Zhuchengtyrannus
1528 | Ziapelta
1529 | Zigongosaurus
1530 | Zizhongosaurus
1531 | Zuniceratops
1532 | Zunityrannus
1533 | Zuolong
1534 | Zuoyunlong
1535 | Zupaysaurus
1536 | Zuul
--------------------------------------------------------------------------------
/char_rnns/plots/Dino_Names_GRU.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/char_rnns/plots/Dino_Names_GRU.jpeg
--------------------------------------------------------------------------------
/char_rnns/plots/Dino_Names_LSTM.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/char_rnns/plots/Dino_Names_LSTM.jpeg
--------------------------------------------------------------------------------
/char_rnns/plots/Dino_Names_RNN.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/char_rnns/plots/Dino_Names_RNN.jpeg
--------------------------------------------------------------------------------
/char_rnns/plots/Dino_Names_Scratch.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/char_rnns/plots/Dino_Names_Scratch.jpeg
--------------------------------------------------------------------------------
/neural_machine_translation/README.md:
--------------------------------------------------------------------------------
1 | # Neural Machine Translation
2 |
3 | The machine translation task was traditionally performed using statistical methods. However, like most statistical paradigms, this Statistical Machine Translation (SMT) had large computational and memory overheads.
4 |
5 | With the popularization of neural networks and deep learning, heavy research into Neural Machine Translation (NMT) and its successful employment has largely replaced SMT. This section contains implementations of papers that introduced some of those ground-breaking architectures in NMT.
6 |
7 | All the models were trained on the [Multi30k](https://arxiv.org/abs/1605.00459) dataset which contains roughly 30 thousand English, German and French sentences, each sentence being 10-20 words long. We have trained and evaluated our models for translation from German to English.
8 |
9 | Below is a table addressing some common data and optimization related parameters.
10 |
11 | | Parameter | Value |
12 | | -------------- |:------------------:|
13 | | Training Set | 29000/31014 |
14 | | Testing Set | 1000/31014 |
15 | | Validation Set | 1014/31014 |
16 | | Loss Function | Cross Entropy Loss |
17 | | Optimizer | AdamW |
18 |
19 | ## Architectures
20 |
21 | ### 1. [Sequence to Sequence Learning with Neural Networks](https://github.com/IvLabs/Natural-Language-Processing/blob/master/neural_machine_translation/notebooks/Seq2Seq.ipynb) [](https://colab.research.google.com/drive/1QaoSKUbLy4ViHnJsl3m3H6xEemDdowkL?usp=sharing)
22 | This paper proposes the pioneering paradigm for neural machine translation using a simple yet applaudable encoder-decoder RNN pair. Although being the poorest of performers in this list, it earns a spot due to its novely.\
23 | **Note: ** A few changes have been made in order to improve performance.
24 | 1. Unlike the paper, reversing the input sequences resulted in a lower BLEU Score. Hence, the input sequences have not been reversed.
25 | 2. Further an additional parameter called ```teacher_forcing_ratio```, which is the probability of using the ground truth tokens as inputs while decoding has been introduced. It is usually set to 1 while training and 0 while sampling. However, setting it to 0.5 while training resulted in a better BLEU Score than setting it to 1.
26 |
27 | ### 2. [Neural Machine Translation by Jointly Learning to Align and Translate](https://github.com/IvLabs/Natural-Language-Processing/blob/master/neural_machine_translation/notebooks/Seq2Seq_with_Attention.ipynb) [](https://colab.research.google.com/drive/1hOd2JFafWgOvdbeXWoSm1gIiMEQ64KbM?usp=sharing)
28 | This paper presents a remarkable improvement in the Sequence to Sequence architecture by introducing a (soft)alignment metric called "attention". This metric induces a sense of similarity between tokens of the source and decoded sentences, which increases the BLEU score by almost 1.5 times and is much more robust with regards to the length of source and target sentences.\
29 | **Note: ** In this implementation, setting the ```teacher_forcing_ratio``` to 1 resulted in a better BLEU score (even with higher validation and test perplexities) than setting it to 0.5.
30 |
31 | ### 3. [Convolutional Sequence to Sequence Learning](https://github.com/IvLabs/Natural-Language-Processing/blob/master/neural_machine_translation/notebooks/Conv_Seq2Seq.ipynb) [](https://colab.research.google.com/drive/18uxa0ZMlck4f5fzTUdkze_cuKz-Hgx_o?usp=sharing)
32 | Unlike the previous papers, this paper is the first paper to tackle language modelling without using Recurrent Neural Networks. However, it does provide an attention mechanism and outperforms the sequential attention based architecture while having almost similar training times. The validation and test perplexities are quite low and the BLEU score is much better than that of the previous paper.
33 |
34 | ### 4. [Attention Is All You Need](https://github.com/IvLabs/Natural-Language-Processing/blob/master/neural_machine_translation/notebooks/Attention_Is_All_You_Need.ipynb) [](https://colab.research.google.com/drive/1RlDhclIlJWzcFC0iPqwbiFEuiCbYIJBG?usp=sharing)
35 | This paper can be said to have revolutionized almost all of Natural Language Processing, all owing to its tremendous simplicity and efficiency which makes it the backbone of almost all present State Of The Art architectures. The proposed *Transformer* architecture introduces a novel metric called *Self-Attention* which induces a sense of (soft)alignment amongst the source sentence tokens too. Additionally architecture uses simple feed-forward layers which makes it almost 4 times lighter than the Convolutional Sequence to Sequence architecture, while attaining the highest BLEU score amongst all the above mentioned architectures.
36 |
37 | ## Summary
38 | Below is a table, summarising the number of parameters and the BLEU scores achieved by each architecture.
39 |
40 | | Architecture | No. of Trainable Parameters | BLEU Score |
41 | | ----------------------------------- |:---------------------------:|:----------:|
42 | | Sequence to Sequence | 13,899,013 | 18.94 |
43 | | Sequence to Sequence with Attention | 20,518,917 | 31.24 |
44 | | Convolutional Sequence to Sequence | 37,351,685 | 36.53 |
45 | | Attention Is All You Need | 9,038,853 | 37.50 |
46 |
47 | **Note:**
48 | 1. The above BLEU scores may vary slightly upon training the models (even with fixed SEED).
49 | 2. The research paper notes for the above mentioned papers can be found [here](https://github.com/IvLabs/ResearchPaperNotes/tree/master/natural_language_processing).
50 |
51 |
52 | ### Reference(s):
53 | * [PyTorch Seq2Seq by Ben Trevett](https://github.com/bentrevett/pytorch-seq2seq)
54 |
--------------------------------------------------------------------------------
/neural_machine_translation/plots/Conv_Seq2Seq.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/neural_machine_translation/plots/Conv_Seq2Seq.jpeg
--------------------------------------------------------------------------------
/neural_machine_translation/plots/Seq2Seq.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/neural_machine_translation/plots/Seq2Seq.jpeg
--------------------------------------------------------------------------------
/neural_machine_translation/plots/Seq2Seq_with_Attention.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/neural_machine_translation/plots/Seq2Seq_with_Attention.jpeg
--------------------------------------------------------------------------------
/neural_machine_translation/plots/Transformer.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/neural_machine_translation/plots/Transformer.jpeg
--------------------------------------------------------------------------------
/text_classification/README.md:
--------------------------------------------------------------------------------
1 | # Sentiment Analysis and Text Classification
2 |
3 | With the advent rise of digitization, the need to automate the analysis of the predominant method of interacting with the digital world, i.e. text, has exponentially risen for a variety of reasons and purposes.
4 |
5 | Text classification is heavily used in tasks such as spam detection, news categorization, customer query tagging, and of course, sentiment analysis.
6 |
7 | Sentiment analysis is the automated process of determining the polarity of a topic, given an input sentence.
8 | It is used in tasks such as analyzing a product/company's public sentiment/word of mouth, customer feedback analysis, political analysis, etc.
9 |
10 | We experiment with 4 architectures on two datasets. The IMDb dataset was to used to train the model for predicting the polarity of movie reviews. For text classification, the TREC dataset was used to train the model to predict one of six classes - `['ENTY', 'HUM', 'DESC', 'NUM', 'LOC', 'ABBR']`.
11 |
12 |
13 | Below is a table addressing some common data and optimization related parameters.
14 |
15 | | Parameter | Value |
16 | | -------------- |:------------------:|
17 | | Training Set | 17500 |
18 | | Testing Set | 25000 |
19 | | Validation Set | 7500 |
20 | | Loss Function | Cross Entropy Loss |
21 | | Optimizer | Adam |
22 |
23 | ## Architectures
24 |
25 | ### [1. Long Short-Term Memory Networks](https://github.com/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/LSTM.ipynb) [](https://colab.research.google.com/github/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/LSTM.ipynb)
26 | RNNs were one of the first architectures for capturing sequential data on various tasks such as predicting parts of speech, sentiment analysis, text classification, etc. However, RNNs suffers from a vanishing gradient problem that make them unable to propagate useful gradient information, thereby causing the model not to learn from larger contexts. To overcome this problem, LSTMs were introduced, which are a modified form of the RNN.
27 |
28 | ### [2. Bag of Tricks for Efficient Text Classification](https://github.com/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/FastText.ipynb) [](https://colab.research.google.com/github/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/FastText.ipynb)
29 | This paper shows that tweaking baseline linear classifiers enables us to learn an efficient and accurate text classifier for a very large corpus with a large output space (whereas deep networks would be very slow). Sentences being represented by BoW and trained by improved linear models (like logistic regression or SVM) with a rank constraint and a fast loss approximation are shown to achieve performance on par with the state-of-the-art.
30 |
31 | ### [3. Convolutional Neural Networks for Sentence Classification](https://github.com/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/CNN.ipynb) [](https://colab.research.google.com/github/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/CNN.ipynb)
32 | CNNs trained on top of pre-trained word vectors for sentence-level classification tasks are shown to achieve excellent results on multiple benchmarks.
33 | The underlying idea strengthened here is that feature extractors obtained from a pre-
34 | trained deep learning model perform well on a variety of tasks—including tasks that are very different from the original task for which the feature extractors were trained.
35 |
36 | ### [4. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding](https://github.com/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/BERT.ipynb) [](https://colab.research.google.com/github/IvLabs/Natural-Language-Processing/blob/master/text_classification/notebooks/BERT.ipynb)
37 | BERT is designed to pre-train deep bidirectional representations from unlabeled text by jointly conditioning on both left and right context in all layers. As a result, the pre-trained BERT model can be fine-tuned with just one additional output layer to create state-of-the-art models for a wide range of tasks, without substantial task-specific architecture modifications.
38 |
39 | ## Summary
40 | Below is a table, summarising the number of parameters and the train, test, validation accuracies.
41 |
42 | | Architecture | No. of Learnable Parameters | Train Acc. (%) | Valid. Acc. (%) | Test Acc. (%) |
43 | | ------------ | --------------------------- | -------------- | --------------- | ------------- |
44 | | LSTM | 4,810,857 | 89.10 | 88.37 | 87.62 |
45 | | FastText | 2,500,301 | 88.35 | 86.67 | 86.28 |
46 | | CNN | 843,906 | 94.95 | 79.89 | 84.90 |
47 | | BERT | 110,468,609 | 91.04 | 91.04 | 91.44 |
48 |
49 | ## Plots
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ## Reference(s)
58 | * [PyTorch Sentiment Analysis by Ben Trevett](https://github.com/bentrevett/)
59 |
60 |
--------------------------------------------------------------------------------
/text_classification/notebooks/CNN.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "id": "-B_MqscXWGI4"
7 | },
8 | "source": [
9 | "# Installing Packages"
10 | ]
11 | },
12 | {
13 | "cell_type": "code",
14 | "execution_count": null,
15 | "metadata": {},
16 | "outputs": [],
17 | "source": [
18 | "!pip install -U torchtext==0.6.0"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {
24 | "id": "bbMNpP192mb2"
25 | },
26 | "source": [
27 | "# Importing Required Libraries"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 1,
33 | "metadata": {
34 | "id": "slw2Y5t3taWQ"
35 | },
36 | "outputs": [],
37 | "source": [
38 | "import torch\n",
39 | "from torchtext import data, datasets\n",
40 | "import torch.nn as nn\n",
41 | "import torch.optim as optim\n",
42 | "from torchtext.data import Field, LabelField, BucketIterator\n",
43 | "import torch.nn.functional as F\n",
44 | "\n",
45 | "import random\n",
46 | "\n",
47 | "import matplotlib.pyplot as plt"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "execution_count": 2,
53 | "metadata": {
54 | "colab": {
55 | "base_uri": "https://localhost:8080/"
56 | },
57 | "id": "7kAMYpKr2tJV",
58 | "outputId": "3ecc3577-55f7-4711-b775-7f5471892d0d"
59 | },
60 | "outputs": [
61 | {
62 | "name": "stdout",
63 | "output_type": "stream",
64 | "text": [
65 | "Notebook is running on cuda\n"
66 | ]
67 | }
68 | ],
69 | "source": [
70 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
71 | "print(\"Notebook is running on\", device)"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {
77 | "id": "8ZOcRV2w2vpH"
78 | },
79 | "source": [
80 | "Fixing SEED for reproducibility of results"
81 | ]
82 | },
83 | {
84 | "cell_type": "code",
85 | "execution_count": 3,
86 | "metadata": {
87 | "id": "N99mW-8XtnWr"
88 | },
89 | "outputs": [],
90 | "source": [
91 | "SEED = 4444\n",
92 | "\n",
93 | "random.seed(SEED)\n",
94 | "torch.manual_seed(SEED)\n",
95 | "torch.cuda.manual_seed(SEED)\n",
96 | "torch.backends.cudnn.deterministic = True"
97 | ]
98 | },
99 | {
100 | "cell_type": "code",
101 | "execution_count": 4,
102 | "metadata": {
103 | "id": "O5NaQke7touV"
104 | },
105 | "outputs": [],
106 | "source": [
107 | "FIELD = Field(tokenize = 'spacy', tokenizer_language = 'en_core_web_sm')\n",
108 | "\n",
109 | "LABEL = LabelField()"
110 | ]
111 | },
112 | {
113 | "cell_type": "markdown",
114 | "metadata": {
115 | "id": "RWXCd0V73YK7"
116 | },
117 | "source": [
118 | "# Splitting the data"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": 5,
124 | "metadata": {
125 | "colab": {
126 | "base_uri": "https://localhost:8080/"
127 | },
128 | "id": "79ih2w2sttNq",
129 | "outputId": "c4358b46-cc35-4382-a74c-bdc0118e067b"
130 | },
131 | "outputs": [],
132 | "source": [
133 | "train_data, test_data = datasets.TREC.splits(FIELD, LABEL, fine_grained=False)"
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": 6,
139 | "metadata": {
140 | "id": "nxpdowpRtwNQ"
141 | },
142 | "outputs": [],
143 | "source": [
144 | "train_data, valid_data = train_data.split(random_state = random.seed(SEED))"
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 7,
150 | "metadata": {
151 | "colab": {
152 | "base_uri": "https://localhost:8080/"
153 | },
154 | "id": "BSWt_wDwtzLt",
155 | "outputId": "548f8358-857e-454d-c80a-f8e320606108"
156 | },
157 | "outputs": [
158 | {
159 | "name": "stdout",
160 | "output_type": "stream",
161 | "text": [
162 | "Number of training examples: 3816\n",
163 | "Number of validation examples: 1636\n",
164 | "Number of testing examples: 500\n"
165 | ]
166 | }
167 | ],
168 | "source": [
169 | "print(f'Number of training examples: {len(train_data)}')\n",
170 | "print(f'Number of validation examples: {len(valid_data)}')\n",
171 | "print(f'Number of testing examples: {len(test_data)}')"
172 | ]
173 | },
174 | {
175 | "cell_type": "code",
176 | "execution_count": 8,
177 | "metadata": {
178 | "colab": {
179 | "base_uri": "https://localhost:8080/"
180 | },
181 | "id": "trFz-SmNt0fO",
182 | "outputId": "4d2dcf36-d394-40f5-c1b1-42bb09e00c6b"
183 | },
184 | "outputs": [],
185 | "source": [
186 | "MAX_VOCAB_SIZE = 25000 # excluding and token\n",
187 | "FIELD.build_vocab(train_data, max_size = MAX_VOCAB_SIZE, vectors=\"glove.6B.100d\", unk_init = torch.Tensor.normal_)\n",
188 | "LABEL.build_vocab(train_data)"
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": 9,
194 | "metadata": {
195 | "colab": {
196 | "base_uri": "https://localhost:8080/"
197 | },
198 | "id": "PQUUTTgat5hg",
199 | "outputId": "3703b174-a45b-4bb2-b5a7-65c7d123899e"
200 | },
201 | "outputs": [
202 | {
203 | "name": "stdout",
204 | "output_type": "stream",
205 | "text": [
206 | "Unique tokens in FIELD vocabulary: 7518\n",
207 | "Unique tokens in LABEL vocabulary: 6\n"
208 | ]
209 | }
210 | ],
211 | "source": [
212 | "print(f\"Unique tokens in FIELD vocabulary: {len(FIELD.vocab)}\")\n",
213 | "print(f\"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}\")"
214 | ]
215 | },
216 | {
217 | "cell_type": "markdown",
218 | "metadata": {
219 | "id": "BIZMVoIA4S2K"
220 | },
221 | "source": [
222 | "# Model Definition"
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": 10,
228 | "metadata": {
229 | "id": "egyx2GtzuEdP"
230 | },
231 | "outputs": [],
232 | "source": [
233 | "class CNN(nn.Module):\n",
234 | " def __init__(self, vocab_size, emb_dim, num_filters, filter_sizes, output_dim, pad_idx):\n",
235 | " super().__init__()\n",
236 | " self.embedding = nn.Embedding(vocab_size, emb_dim)\n",
237 | " self.convs = nn.ModuleList([nn.Conv2d(in_channels = 1, \n",
238 | " out_channels = num_filters, \n",
239 | " kernel_size = (fs, emb_dim)) \n",
240 | " for fs in filter_sizes])\n",
241 | " self.fc = nn.Linear(len(filter_sizes) * num_filters, output_dim)\n",
242 | " self.dropout = nn.Dropout(0.5)\n",
243 | " \n",
244 | " def forward(self, text): # [input] = [seq_len, batch_size]\n",
245 | " text = text.permute(1, 0) # [input] = [batch_size, seq_len]\n",
246 | " embedded = self.embedding(text) # [embedded] = [batch_size, seq_len, emb_dim]\n",
247 | " embedded = embedded.unsqueeze(1) # [embedded] = [batch_size, 1, seq_len, emb_dim]\n",
248 | " conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs] # [conv] = [batch_size, num_filters, seq_len - filter_sizes[n]]\n",
249 | " pooled = [F.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved] # [pooled] = [batch_size, num_filters]\n",
250 | " output = self.dropout(torch.cat(pooled, dim = 1)) # [output] = [batch_size, num_filters * len(filter_sizes)]\n",
251 | " return self.fc(output)"
252 | ]
253 | },
254 | {
255 | "cell_type": "code",
256 | "execution_count": 11,
257 | "metadata": {
258 | "id": "2PDdgoXiufHr"
259 | },
260 | "outputs": [],
261 | "source": [
262 | "def batch_accuracy(preds, y):\n",
263 | " top_pred = preds.argmax(1, keepdim = True)\n",
264 | " correct = top_pred.eq(y.view_as(top_pred)).sum()\n",
265 | " acc = correct.float() / y.shape[0]\n",
266 | " return acc"
267 | ]
268 | },
269 | {
270 | "cell_type": "markdown",
271 | "metadata": {
272 | "id": "OpnqXXA1uvuD"
273 | },
274 | "source": [
275 | "# Training and Evaluation Functions"
276 | ]
277 | },
278 | {
279 | "cell_type": "code",
280 | "execution_count": 12,
281 | "metadata": {
282 | "id": "gKSFO3hRutOc"
283 | },
284 | "outputs": [],
285 | "source": [
286 | "def Train(model, iterator, optimizer, criterion): \n",
287 | " epoch_loss = 0\n",
288 | " epoch_acc = 0\n",
289 | " model.train()\n",
290 | " for batch in iterator:\n",
291 | " optimizer.zero_grad()\n",
292 | " inp = batch.text\n",
293 | " label = batch.label \n",
294 | " predictions = model(inp)\n",
295 | " loss = criterion(predictions, label)\n",
296 | " acc = batch_accuracy(predictions, label)\n",
297 | " loss.backward()\n",
298 | " optimizer.step()\n",
299 | " epoch_loss += loss.item()\n",
300 | " epoch_acc += acc.item()\n",
301 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
302 | ]
303 | },
304 | {
305 | "cell_type": "code",
306 | "execution_count": 13,
307 | "metadata": {
308 | "id": "YqTp93Aruwoe"
309 | },
310 | "outputs": [],
311 | "source": [
312 | "def Evaluate(model, iterator, criterion):\n",
313 | " epoch_loss = 0\n",
314 | " epoch_acc = 0\n",
315 | " model.eval()\n",
316 | " with torch.no_grad():\n",
317 | " for batch in iterator:\n",
318 | " inp = batch.text\n",
319 | " label = batch.label \n",
320 | " predictions = model(inp).squeeze(1)\n",
321 | " loss = criterion(predictions, label)\n",
322 | " acc = batch_accuracy(predictions, label)\n",
323 | " epoch_loss += loss.item()\n",
324 | " epoch_acc += acc.item()\n",
325 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
326 | ]
327 | },
328 | {
329 | "cell_type": "markdown",
330 | "metadata": {
331 | "id": "v1_3yX3-42vO"
332 | },
333 | "source": [
334 | "# Data Iterators, Hyperparameters and Model Initialization"
335 | ]
336 | },
337 | {
338 | "cell_type": "code",
339 | "execution_count": 14,
340 | "metadata": {
341 | "id": "yIHX-jbs5ClS"
342 | },
343 | "outputs": [],
344 | "source": [
345 | "BATCH_SIZE = 64\n",
346 | "\n",
347 | "train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits((train_data, valid_data, test_data), batch_size = BATCH_SIZE, device = device)"
348 | ]
349 | },
350 | {
351 | "cell_type": "code",
352 | "execution_count": 15,
353 | "metadata": {
354 | "id": "o6c7ld9wuYh4"
355 | },
356 | "outputs": [],
357 | "source": [
358 | "VOCAB_SIZE = len(FIELD.vocab) # dimension of one-hot vector / vocabulary\n",
359 | "EMB_DIM = 100 # dimensions of word embeddings\n",
360 | "NUM_FILTERS = 100 # number of filters in CNN\n",
361 | "FILTER_SIZES = [2,3,4] # filter sizes of CNN\n",
362 | "OUTPUT_DIM = len(LABEL.vocab) # dimensions of output\n",
363 | "DROPOUT = 0.5 \n",
364 | "\n",
365 | "NUM_EPOCHS = 10\n",
366 | "LR = 0.001"
367 | ]
368 | },
369 | {
370 | "cell_type": "code",
371 | "execution_count": 16,
372 | "metadata": {
373 | "id": "j5U3vbZcwEgr"
374 | },
375 | "outputs": [],
376 | "source": [
377 | "model = CNN(VOCAB_SIZE, EMB_DIM, NUM_FILTERS, FILTER_SIZES, OUTPUT_DIM, FIELD.vocab.stoi[FIELD.pad_token])"
378 | ]
379 | },
380 | {
381 | "cell_type": "code",
382 | "execution_count": 17,
383 | "metadata": {
384 | "id": "ziglTF1D5voa"
385 | },
386 | "outputs": [],
387 | "source": [
388 | "optimizer = optim.Adam(model.parameters(), lr=LR)\n",
389 | "\n",
390 | "criterion = nn.CrossEntropyLoss()\n",
391 | "\n",
392 | "model = model.to(device)\n",
393 | "criterion = criterion.to(device)"
394 | ]
395 | },
396 | {
397 | "cell_type": "code",
398 | "execution_count": 18,
399 | "metadata": {
400 | "colab": {
401 | "base_uri": "https://localhost:8080/"
402 | },
403 | "id": "X7Mm3BnuuZ2F",
404 | "outputId": "e195ceb6-9a27-4359-8aae-c8777a5f7b1a"
405 | },
406 | "outputs": [
407 | {
408 | "name": "stdout",
409 | "output_type": "stream",
410 | "text": [
411 | "The model has 843,906 trainable parameters\n"
412 | ]
413 | }
414 | ],
415 | "source": [
416 | "def count_parameters(model):\n",
417 | " return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
418 | "\n",
419 | "print(f'The model has {count_parameters(model):,} trainable parameters')"
420 | ]
421 | },
422 | {
423 | "cell_type": "markdown",
424 | "metadata": {
425 | "id": "99qvK1qw5aAV"
426 | },
427 | "source": [
428 | "# Training"
429 | ]
430 | },
431 | {
432 | "cell_type": "code",
433 | "execution_count": 19,
434 | "metadata": {
435 | "id": "WT1J71IjuySn"
436 | },
437 | "outputs": [],
438 | "source": [
439 | "import time\n",
440 | "\n",
441 | "def Epoch_time(start_time, end_time):\n",
442 | " elapsed_time = end_time - start_time\n",
443 | " elapsed_mins = int(elapsed_time / 60)\n",
444 | " elapsed_secs = int(elapsed_time - (elapsed_mins * 60))\n",
445 | " return elapsed_mins, elapsed_secs"
446 | ]
447 | },
448 | {
449 | "cell_type": "code",
450 | "execution_count": 21,
451 | "metadata": {
452 | "colab": {
453 | "base_uri": "https://localhost:8080/"
454 | },
455 | "id": "TKDOAVH5uz2s",
456 | "outputId": "846b4443-f6d6-4519-fe6d-a70d4911f35d"
457 | },
458 | "outputs": [
459 | {
460 | "name": "stdout",
461 | "output_type": "stream",
462 | "text": [
463 | "Learning Rate: 0.001, Number of Filters: 100, Filter Sizes: [2, 3, 4]\n",
464 | "Time taken for epoch 1: 0m 17s\n",
465 | "Training Loss: 1.4261 | Validation Loss: 1.0630\n",
466 | "Training Accuracy: 43.17 %| Validation Accuracy: 62.21 %\n",
467 | "Time taken for epoch 2: 0m 14s\n",
468 | "Training Loss: 0.9428 | Validation Loss: 0.8337\n",
469 | "Training Accuracy: 64.54 %| Validation Accuracy: 70.10 %\n",
470 | "Time taken for epoch 3: 0m 14s\n",
471 | "Training Loss: 0.7243 | Validation Loss: 0.7207\n",
472 | "Training Accuracy: 73.87 %| Validation Accuracy: 74.49 %\n",
473 | "Time taken for epoch 4: 0m 14s\n",
474 | "Training Loss: 0.5866 | Validation Loss: 0.6712\n",
475 | "Training Accuracy: 79.45 %| Validation Accuracy: 74.23 %\n",
476 | "Time taken for epoch 5: 0m 15s\n",
477 | "Training Loss: 0.4986 | Validation Loss: 0.6235\n",
478 | "Training Accuracy: 83.14 %| Validation Accuracy: 76.77 %\n",
479 | "Time taken for epoch 6: 0m 14s\n",
480 | "Training Loss: 0.3997 | Validation Loss: 0.5953\n",
481 | "Training Accuracy: 87.04 %| Validation Accuracy: 77.98 %\n",
482 | "Time taken for epoch 7: 0m 14s\n",
483 | "Training Loss: 0.3328 | Validation Loss: 0.5735\n",
484 | "Training Accuracy: 89.69 %| Validation Accuracy: 78.20 %\n",
485 | "Time taken for epoch 8: 0m 14s\n",
486 | "Training Loss: 0.2581 | Validation Loss: 0.5676\n",
487 | "Training Accuracy: 92.07 %| Validation Accuracy: 79.17 %\n",
488 | "Time taken for epoch 9: 0m 15s\n",
489 | "Training Loss: 0.2212 | Validation Loss: 0.5526\n",
490 | "Training Accuracy: 93.41 %| Validation Accuracy: 79.92 %\n",
491 | "Time taken for epoch 10: 0m 14s\n",
492 | "Training Loss: 0.1761 | Validation Loss: 0.5503\n",
493 | "Training Accuracy: 94.95 %| Validation Accuracy: 79.89 %\n",
494 | "Model with Train Loss 0.1761, Validation Loss: 0.5503 was saved.\n"
495 | ]
496 | }
497 | ],
498 | "source": [
499 | "print(f\"Learning Rate: {LR}, Number of Filters: {NUM_FILTERS}, Filter Sizes: {FILTER_SIZES}\")\n",
500 | "train_losses = []\n",
501 | "valid_losses = []\n",
502 | "min_losses = [float('inf'), float('inf')]\n",
503 | "\n",
504 | "start_time = time.time()\n",
505 | "for epoch in range(1, NUM_EPOCHS+1):\n",
506 | " \n",
507 | " train_loss, train_acc = Train(model, train_iterator, optimizer, criterion)\n",
508 | " train_losses.append(train_loss)\n",
509 | " valid_loss, valid_acc = Evaluate(model, valid_iterator, criterion)\n",
510 | " valid_losses.append(valid_loss)\n",
511 | "\n",
512 | " if valid_loss < min_losses[0]:\n",
513 | " min_losses[0] = valid_loss\n",
514 | " min_losses[1] = train_loss\n",
515 | " torch.save(model.state_dict(), 'CNN.pt')\n",
516 | "\n",
517 | " elapsed_time = Epoch_time(start_time, time.time())\n",
518 | " print(f\"Time taken for epoch {epoch}: {elapsed_time[0]}m {elapsed_time[1]}s\")\n",
519 | " start_time = time.time()\n",
520 | " print(f\"Training Loss: {train_loss:.4f} | Validation Loss: {valid_loss:.4f}\")\n",
521 | " print(f\"Training Accuracy: {train_acc*100:.2f} %| Validation Accuracy: {valid_acc*100:.2f} %\")\n",
522 | "\n",
523 | "print(f\"Model with Train Loss {min_losses[1]:.4f}, Validation Loss: {min_losses[0]:.4f} was saved.\")"
524 | ]
525 | },
526 | {
527 | "cell_type": "code",
528 | "execution_count": 27,
529 | "metadata": {
530 | "id": "OkjBpvPt8BmJ"
531 | },
532 | "outputs": [
533 | {
534 | "data": {
535 | "image/png": "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",
536 | "text/plain": [
537 | ""
538 | ]
539 | },
540 | "metadata": {
541 | "needs_background": "light"
542 | },
543 | "output_type": "display_data"
544 | }
545 | ],
546 | "source": [
547 | "plt.title(\"Text Classification (CNN): Learning Curves\")\n",
548 | "plt.xlabel(\"Number of Epochs\")\n",
549 | "plt.ylabel(\"Cross Entropy Loss\")\n",
550 | "plt.plot(train_losses, label = \"Training Loss\")\n",
551 | "plt.plot(valid_losses, label= \"Validation Loss\")\n",
552 | "plt.legend()\n",
553 | "plt.show()"
554 | ]
555 | },
556 | {
557 | "cell_type": "markdown",
558 | "metadata": {},
559 | "source": [
560 | "# Testing"
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": 23,
566 | "metadata": {
567 | "id": "YLpKGbjyu2OK"
568 | },
569 | "outputs": [
570 | {
571 | "name": "stdout",
572 | "output_type": "stream",
573 | "text": [
574 | "Test Loss: 0.3947\n",
575 | "Test Accuracy: 84.90%\n"
576 | ]
577 | }
578 | ],
579 | "source": [
580 | "model.load_state_dict(torch.load('CNN.pt'))\n",
581 | "\n",
582 | "test_loss, test_acc = Evaluate(model, test_iterator, criterion)\n",
583 | "\n",
584 | "print(f'Test Loss: {test_loss:.4f}')\n",
585 | "print(f'Test Accuracy: {test_acc*100:.2f}%')"
586 | ]
587 | },
588 | {
589 | "cell_type": "markdown",
590 | "metadata": {
591 | "id": "o3vZ2NNn8sM6"
592 | },
593 | "source": [
594 | "# Sampling"
595 | ]
596 | },
597 | {
598 | "cell_type": "code",
599 | "execution_count": 24,
600 | "metadata": {
601 | "id": "e0hc5XtDsqIH"
602 | },
603 | "outputs": [],
604 | "source": [
605 | "import spacy\n",
606 | "nlp = spacy.load('en_core_web_sm')\n",
607 | "\n",
608 | "def predict_class(model, text, min_len = 4):\n",
609 | " model.eval()\n",
610 | " tokenized = [tok.text for tok in nlp.tokenizer(text)]\n",
611 | " if len(tokenized) < min_len:\n",
612 | " tokenized += [''] * (min_len - len(tokenized))\n",
613 | " indexed = [FIELD.vocab.stoi[t] for t in tokenized]\n",
614 | " tensor = torch.LongTensor(indexed).to(device)\n",
615 | " tensor = tensor.unsqueeze(1)\n",
616 | " preds = model(tensor)\n",
617 | " max_preds = preds.argmax(dim = 1)\n",
618 | " return max_preds.item()"
619 | ]
620 | },
621 | {
622 | "cell_type": "code",
623 | "execution_count": 42,
624 | "metadata": {},
625 | "outputs": [
626 | {
627 | "name": "stdout",
628 | "output_type": "stream",
629 | "text": [
630 | "['ENTY', 'HUM', 'DESC', 'NUM', 'LOC', 'ABBR']\n"
631 | ]
632 | }
633 | ],
634 | "source": [
635 | "print(LABEL.vocab.itos)"
636 | ]
637 | },
638 | {
639 | "cell_type": "code",
640 | "execution_count": 52,
641 | "metadata": {
642 | "id": "vc0zO3gTws-d"
643 | },
644 | "outputs": [
645 | {
646 | "name": "stdout",
647 | "output_type": "stream",
648 | "text": [
649 | "Predicted class is: ABBR\n"
650 | ]
651 | }
652 | ],
653 | "source": [
654 | "pred_class = predict_class(model, \"What does CNN stand for?\")\n",
655 | "print(f'Predicted class is: {LABEL.vocab.itos[pred_class]}')"
656 | ]
657 | },
658 | {
659 | "cell_type": "code",
660 | "execution_count": 53,
661 | "metadata": {
662 | "id": "Umdey8pIw8yp"
663 | },
664 | "outputs": [
665 | {
666 | "name": "stdout",
667 | "output_type": "stream",
668 | "text": [
669 | "Predicted class is: NUM\n"
670 | ]
671 | }
672 | ],
673 | "source": [
674 | "pred_class = predict_class(model, \"How long did it take to train an epoch?\")\n",
675 | "print(f'Predicted class is: {LABEL.vocab.itos[pred_class]}')"
676 | ]
677 | },
678 | {
679 | "cell_type": "code",
680 | "execution_count": 57,
681 | "metadata": {
682 | "id": "8rbQ8FYRw-TM"
683 | },
684 | "outputs": [
685 | {
686 | "name": "stdout",
687 | "output_type": "stream",
688 | "text": [
689 | "Predicted class is: DESC\n"
690 | ]
691 | }
692 | ],
693 | "source": [
694 | "pred_class = predict_class(model, \"What is the model of GPU used?\")\n",
695 | "print(f'Predicted class is: {LABEL.vocab.itos[pred_class]}')"
696 | ]
697 | }
698 | ],
699 | "metadata": {
700 | "accelerator": "GPU",
701 | "colab": {
702 | "collapsed_sections": [],
703 | "name": "CNN.ipynb",
704 | "provenance": []
705 | },
706 | "kernelspec": {
707 | "display_name": "Python 3",
708 | "name": "python3"
709 | },
710 | "language_info": {
711 | "codemirror_mode": {
712 | "name": "ipython",
713 | "version": 3
714 | },
715 | "file_extension": ".py",
716 | "mimetype": "text/x-python",
717 | "name": "python",
718 | "nbconvert_exporter": "python",
719 | "pygments_lexer": "ipython3",
720 | "version": "3.9.7"
721 | }
722 | },
723 | "nbformat": 4,
724 | "nbformat_minor": 0
725 | }
726 |
--------------------------------------------------------------------------------
/text_classification/notebooks/FastText.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Installing Packages"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": null,
13 | "metadata": {},
14 | "outputs": [],
15 | "source": [
16 | "!pip install -U torchtext==0.6.0"
17 | ]
18 | },
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "bbMNpP192mb2"
23 | },
24 | "source": [
25 | "# Importing Required Libraries"
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": 2,
31 | "metadata": {
32 | "id": "slw2Y5t3taWQ"
33 | },
34 | "outputs": [],
35 | "source": [
36 | "import torch\n",
37 | "from torchtext import data, datasets\n",
38 | "import torch.nn as nn\n",
39 | "import torch.optim as optim\n",
40 | "import torch.nn.functional as F\n",
41 | "from torchtext.data import Field, LabelField, BucketIterator\n",
42 | "\n",
43 | "import random\n",
44 | "\n",
45 | "import matplotlib.pyplot as plt"
46 | ]
47 | },
48 | {
49 | "cell_type": "code",
50 | "execution_count": 3,
51 | "metadata": {
52 | "colab": {
53 | "base_uri": "https://localhost:8080/"
54 | },
55 | "id": "7kAMYpKr2tJV",
56 | "outputId": "5d7e7127-e114-496d-c1f0-08a57498694c"
57 | },
58 | "outputs": [
59 | {
60 | "name": "stdout",
61 | "output_type": "stream",
62 | "text": [
63 | "Notebook is running on cuda\n"
64 | ]
65 | }
66 | ],
67 | "source": [
68 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
69 | "print(\"Notebook is running on\", device)"
70 | ]
71 | },
72 | {
73 | "cell_type": "markdown",
74 | "metadata": {
75 | "id": "8ZOcRV2w2vpH"
76 | },
77 | "source": [
78 | "Fixing SEED for reproducibility of results"
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 4,
84 | "metadata": {
85 | "id": "N99mW-8XtnWr"
86 | },
87 | "outputs": [],
88 | "source": [
89 | "SEED = 4444\n",
90 | "\n",
91 | "random.seed(SEED)\n",
92 | "torch.manual_seed(SEED)\n",
93 | "torch.cuda.manual_seed(SEED)\n",
94 | "torch.backends.cudnn.deterministic = True"
95 | ]
96 | },
97 | {
98 | "cell_type": "markdown",
99 | "metadata": {
100 | "id": "sMxBvhY8y0wq"
101 | },
102 | "source": [
103 | "Generate NGRAMS for FastText"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 5,
109 | "metadata": {
110 | "id": "jk054NHay0fN"
111 | },
112 | "outputs": [],
113 | "source": [
114 | "def generate_n_grams(x, n=2):\n",
115 | " n_grams = set(zip(*[x[i:] for i in range(n)]))\n",
116 | " for n_gram in n_grams:\n",
117 | " x.append(' '.join(n_gram))\n",
118 | " return list(set(x))"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": 6,
124 | "metadata": {
125 | "id": "O5NaQke7touV"
126 | },
127 | "outputs": [],
128 | "source": [
129 | "FIELD = Field(tokenize = 'spacy',tokenizer_language = 'en_core_web_sm', preprocessing = generate_n_grams)\n",
130 | "\n",
131 | "LABEL = LabelField(dtype = torch.float)"
132 | ]
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "metadata": {
137 | "id": "RWXCd0V73YK7"
138 | },
139 | "source": [
140 | "# Splitting the data"
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": 7,
146 | "metadata": {
147 | "colab": {
148 | "base_uri": "https://localhost:8080/"
149 | },
150 | "id": "79ih2w2sttNq",
151 | "outputId": "b33d07a7-3983-4b49-a81d-db6f2ca0b908"
152 | },
153 | "outputs": [],
154 | "source": [
155 | "train_data, test_data = datasets.IMDB.splits(FIELD, LABEL)"
156 | ]
157 | },
158 | {
159 | "cell_type": "code",
160 | "execution_count": 8,
161 | "metadata": {
162 | "id": "nxpdowpRtwNQ"
163 | },
164 | "outputs": [],
165 | "source": [
166 | "train_data, valid_data = train_data.split(random_state = random.seed(SEED))"
167 | ]
168 | },
169 | {
170 | "cell_type": "code",
171 | "execution_count": 9,
172 | "metadata": {
173 | "colab": {
174 | "base_uri": "https://localhost:8080/"
175 | },
176 | "id": "BSWt_wDwtzLt",
177 | "outputId": "59e4e52f-b3d7-4300-ef8f-876519cd0092"
178 | },
179 | "outputs": [
180 | {
181 | "name": "stdout",
182 | "output_type": "stream",
183 | "text": [
184 | "Number of training examples: 17500\n",
185 | "Number of validation examples: 7500\n",
186 | "Number of testing examples: 25000\n"
187 | ]
188 | }
189 | ],
190 | "source": [
191 | "print(f'Number of training examples: {len(train_data)}')\n",
192 | "print(f'Number of validation examples: {len(valid_data)}')\n",
193 | "print(f'Number of testing examples: {len(test_data)}')"
194 | ]
195 | },
196 | {
197 | "cell_type": "code",
198 | "execution_count": 10,
199 | "metadata": {
200 | "colab": {
201 | "base_uri": "https://localhost:8080/"
202 | },
203 | "id": "trFz-SmNt0fO",
204 | "outputId": "6535fa21-210f-49a5-c8ae-01e80e80b092"
205 | },
206 | "outputs": [],
207 | "source": [
208 | "MAX_VOCAB_SIZE = 25000 # excluding and token\n",
209 | "\n",
210 | "FIELD.build_vocab(train_data, max_size = MAX_VOCAB_SIZE, vectors=\"glove.6B.100d\", unk_init = torch.Tensor.normal_)\n",
211 | "LABEL.build_vocab(train_data)"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "execution_count": 11,
217 | "metadata": {
218 | "colab": {
219 | "base_uri": "https://localhost:8080/"
220 | },
221 | "id": "PQUUTTgat5hg",
222 | "outputId": "965f4522-3b08-4866-bb7d-f0a32c2c5649"
223 | },
224 | "outputs": [
225 | {
226 | "name": "stdout",
227 | "output_type": "stream",
228 | "text": [
229 | "Unique tokens in FIELD vocabulary: 25002\n",
230 | "Unique tokens in LABEL vocabulary: 2\n"
231 | ]
232 | }
233 | ],
234 | "source": [
235 | "print(f\"Unique tokens in FIELD vocabulary: {len(FIELD.vocab)}\")\n",
236 | "print(f\"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}\")"
237 | ]
238 | },
239 | {
240 | "cell_type": "markdown",
241 | "metadata": {
242 | "id": "BIZMVoIA4S2K"
243 | },
244 | "source": [
245 | "# Model Definition"
246 | ]
247 | },
248 | {
249 | "cell_type": "code",
250 | "execution_count": 12,
251 | "metadata": {
252 | "id": "egyx2GtzuEdP"
253 | },
254 | "outputs": [],
255 | "source": [
256 | "class FastText(nn.Module):\n",
257 | " def __init__(self, vocab_size, emb_dim, output_dim, pad_idx):\n",
258 | " super().__init__()\n",
259 | " self.embedding = nn.Embedding(vocab_size, emb_dim, padding_idx=pad_idx)\n",
260 | " self.fc = nn.Linear(emb_dim, output_dim)\n",
261 | " \n",
262 | " def forward(self, input): # [input] = [input_length, batch_size]\n",
263 | " embedded = self.embedding(input) # [embedded] = [seq_len, batch_size, emb_dim]\n",
264 | " embedded = embedded.permute(1, 0, 2) # [embedded] = [batch_size, seq_len, emb_dim]\n",
265 | " pooled = F.avg_pool2d(embedded, (embedded.shape[1], 1)) # [pooled] = [batch_size, 1, emb_dim] \n",
266 | " pooled = pooled.squeeze(1) # [pooled] = [batch size, embedding_dim]\n",
267 | " return self.fc(pooled)"
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "execution_count": 13,
273 | "metadata": {
274 | "id": "2PDdgoXiufHr"
275 | },
276 | "outputs": [],
277 | "source": [
278 | "def batch_accuracy(preds, y):\n",
279 | " #round predictions to the closest integer\n",
280 | " rounded_preds = torch.round(torch.sigmoid(preds))\n",
281 | " correct = (rounded_preds == y).float()\n",
282 | " acc = correct.sum() / len(correct)\n",
283 | " return acc"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {
289 | "id": "OpnqXXA1uvuD"
290 | },
291 | "source": [
292 | "# Training and Evaluation Functions"
293 | ]
294 | },
295 | {
296 | "cell_type": "code",
297 | "execution_count": 14,
298 | "metadata": {
299 | "id": "gKSFO3hRutOc"
300 | },
301 | "outputs": [],
302 | "source": [
303 | "def Train(model, iterator, optimizer, criterion):\n",
304 | " epoch_loss = 0\n",
305 | " epoch_acc = 0\n",
306 | " model.train()\n",
307 | " for batch in iterator:\n",
308 | " optimizer.zero_grad()\n",
309 | " inp = batch.text\n",
310 | " label = batch.label \n",
311 | " predictions = model(inp).squeeze(1)\n",
312 | " loss = criterion(predictions, label)\n",
313 | " acc = batch_accuracy(predictions, label)\n",
314 | " loss.backward()\n",
315 | " optimizer.step()\n",
316 | " epoch_loss += loss.item()\n",
317 | " epoch_acc += acc.item() \n",
318 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
319 | ]
320 | },
321 | {
322 | "cell_type": "code",
323 | "execution_count": 15,
324 | "metadata": {
325 | "id": "YqTp93Aruwoe"
326 | },
327 | "outputs": [],
328 | "source": [
329 | "def Evaluate(model, iterator, criterion):\n",
330 | " epoch_loss = 0\n",
331 | " epoch_acc = 0\n",
332 | " model.eval()\n",
333 | " with torch.no_grad():\n",
334 | " for batch in iterator: \n",
335 | " inp = batch.text\n",
336 | " label = batch.label \n",
337 | " predictions = model(inp).squeeze(1)\n",
338 | " loss = criterion(predictions, label)\n",
339 | " acc = batch_accuracy(predictions, label)\n",
340 | " epoch_loss += loss.item()\n",
341 | " epoch_acc += acc.item() \n",
342 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
343 | ]
344 | },
345 | {
346 | "cell_type": "markdown",
347 | "metadata": {
348 | "id": "v1_3yX3-42vO"
349 | },
350 | "source": [
351 | "# Data Iterators, Hyperparameters and Model Initialization"
352 | ]
353 | },
354 | {
355 | "cell_type": "code",
356 | "execution_count": 16,
357 | "metadata": {
358 | "id": "yIHX-jbs5ClS"
359 | },
360 | "outputs": [],
361 | "source": [
362 | "BATCH_SIZE = 64\n",
363 | "\n",
364 | "train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits((train_data, valid_data, test_data), batch_size = BATCH_SIZE, device = device)"
365 | ]
366 | },
367 | {
368 | "cell_type": "code",
369 | "execution_count": 17,
370 | "metadata": {
371 | "id": "o6c7ld9wuYh4"
372 | },
373 | "outputs": [],
374 | "source": [
375 | "VOCAB_SIZE = len(FIELD.vocab) # dimension of one-hot vector / vocabulary\n",
376 | "EMB_DIM = 100 # dimension of word embeddings\n",
377 | "OUTPUT_DIM = 1 # dimension of output layer\n",
378 | "\n",
379 | "NUM_EPOCHS = 10\n",
380 | "LR = 0.001"
381 | ]
382 | },
383 | {
384 | "cell_type": "code",
385 | "execution_count": 18,
386 | "metadata": {
387 | "id": "j5U3vbZcwEgr"
388 | },
389 | "outputs": [],
390 | "source": [
391 | "model = FastText(VOCAB_SIZE, EMB_DIM, OUTPUT_DIM, FIELD.vocab.stoi[FIELD.pad_token])"
392 | ]
393 | },
394 | {
395 | "cell_type": "code",
396 | "execution_count": 19,
397 | "metadata": {
398 | "id": "ziglTF1D5voa"
399 | },
400 | "outputs": [],
401 | "source": [
402 | "optimizer = optim.Adam(model.parameters(), lr=LR)\n",
403 | "\n",
404 | "criterion = nn.BCEWithLogitsLoss()\n",
405 | "\n",
406 | "model = model.to(device)\n",
407 | "criterion = criterion.to(device)"
408 | ]
409 | },
410 | {
411 | "cell_type": "code",
412 | "execution_count": 20,
413 | "metadata": {
414 | "colab": {
415 | "base_uri": "https://localhost:8080/"
416 | },
417 | "id": "X7Mm3BnuuZ2F",
418 | "outputId": "1c65ec04-2ac8-4f1d-fb03-08ef3b8f4114"
419 | },
420 | "outputs": [
421 | {
422 | "name": "stdout",
423 | "output_type": "stream",
424 | "text": [
425 | "The model has 2,500,301 trainable parameters\n"
426 | ]
427 | }
428 | ],
429 | "source": [
430 | "def count_parameters(model):\n",
431 | " return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
432 | "\n",
433 | "print(f'The model has {count_parameters(model):,} trainable parameters')"
434 | ]
435 | },
436 | {
437 | "cell_type": "markdown",
438 | "metadata": {
439 | "id": "99qvK1qw5aAV"
440 | },
441 | "source": [
442 | "# Training"
443 | ]
444 | },
445 | {
446 | "cell_type": "code",
447 | "execution_count": 21,
448 | "metadata": {
449 | "id": "WT1J71IjuySn"
450 | },
451 | "outputs": [],
452 | "source": [
453 | "import time\n",
454 | "\n",
455 | "def Epoch_time(start_time, end_time):\n",
456 | " elapsed_time = end_time - start_time\n",
457 | " elapsed_mins = int(elapsed_time / 60)\n",
458 | " elapsed_secs = int(elapsed_time - (elapsed_mins * 60))\n",
459 | " return elapsed_mins, elapsed_secs"
460 | ]
461 | },
462 | {
463 | "cell_type": "code",
464 | "execution_count": 22,
465 | "metadata": {
466 | "colab": {
467 | "base_uri": "https://localhost:8080/"
468 | },
469 | "id": "TKDOAVH5uz2s",
470 | "outputId": "aafc2306-93a3-4ee0-8678-4e8a276ea1e1"
471 | },
472 | "outputs": [
473 | {
474 | "name": "stdout",
475 | "output_type": "stream",
476 | "text": [
477 | "Learning Rate: 0.001\n",
478 | "Time taken for epoch 1: 0m 9s\n",
479 | "Training Loss: 0.6900 | Validation Loss: 0.6643\n",
480 | "Training Accuracy: 53.88 %| Validation Accuracy: 63.70 %\n",
481 | "Time taken for epoch 2: 0m 8s\n",
482 | "Training Loss: 0.6689 | Validation Loss: 0.5680\n",
483 | "Training Accuracy: 70.73 %| Validation Accuracy: 75.88 %\n",
484 | "Time taken for epoch 3: 0m 8s\n",
485 | "Training Loss: 0.6161 | Validation Loss: 0.4792\n",
486 | "Training Accuracy: 78.73 %| Validation Accuracy: 78.10 %\n",
487 | "Time taken for epoch 4: 0m 8s\n",
488 | "Training Loss: 0.5431 | Validation Loss: 0.3829\n",
489 | "Training Accuracy: 83.51 %| Validation Accuracy: 83.00 %\n",
490 | "Time taken for epoch 5: 0m 8s\n",
491 | "Training Loss: 0.4712 | Validation Loss: 0.3528\n",
492 | "Training Accuracy: 86.64 %| Validation Accuracy: 85.13 %\n",
493 | "Time taken for epoch 6: 0m 8s\n",
494 | "Training Loss: 0.4132 | Validation Loss: 0.3434\n",
495 | "Training Accuracy: 88.35 %| Validation Accuracy: 86.67 %\n",
496 | "Time taken for epoch 7: 0m 8s\n",
497 | "Training Loss: 0.3627 | Validation Loss: 0.3479\n",
498 | "Training Accuracy: 89.37 %| Validation Accuracy: 87.30 %\n",
499 | "Time taken for epoch 8: 0m 8s\n",
500 | "Training Loss: 0.3263 | Validation Loss: 0.3536\n",
501 | "Training Accuracy: 90.39 %| Validation Accuracy: 87.87 %\n",
502 | "Time taken for epoch 9: 0m 8s\n",
503 | "Training Loss: 0.2976 | Validation Loss: 0.3649\n",
504 | "Training Accuracy: 91.05 %| Validation Accuracy: 88.28 %\n",
505 | "Time taken for epoch 10: 0m 8s\n",
506 | "Training Loss: 0.2725 | Validation Loss: 0.3771\n",
507 | "Training Accuracy: 91.55 %| Validation Accuracy: 88.56 %\n",
508 | "Model with Train Loss 0.4132, Validation Loss: 0.3434 was saved.\n"
509 | ]
510 | }
511 | ],
512 | "source": [
513 | "print(f\"Learning Rate: {LR}\")\n",
514 | "train_losses = []\n",
515 | "valid_losses = []\n",
516 | "min_losses = [float('inf'), float('inf')]\n",
517 | "\n",
518 | "start_time = time.time()\n",
519 | "for epoch in range(1, NUM_EPOCHS+1):\n",
520 | " \n",
521 | " train_loss, train_acc = Train(model, train_iterator, optimizer, criterion)\n",
522 | " train_losses.append(train_loss)\n",
523 | " valid_loss, valid_acc = Evaluate(model, valid_iterator, criterion)\n",
524 | " valid_losses.append(valid_loss)\n",
525 | "\n",
526 | " if valid_loss < min_losses[0]:\n",
527 | " min_losses[0] = valid_loss\n",
528 | " min_losses[1] = train_loss\n",
529 | " torch.save(model.state_dict(), 'FastText.pt')\n",
530 | "\n",
531 | " elapsed_time = Epoch_time(start_time, time.time())\n",
532 | " print(f\"Time taken for epoch {epoch}: {elapsed_time[0]}m {elapsed_time[1]}s\")\n",
533 | " start_time = time.time()\n",
534 | " print(f\"Training Loss: {train_loss:.4f} | Validation Loss: {valid_loss:.4f}\")\n",
535 | " print(f\"Training Accuracy: {train_acc*100:.2f} %| Validation Accuracy: {valid_acc*100:.2f} %\")\n",
536 | "\n",
537 | "print(f\"Model with Train Loss {min_losses[1]:.4f}, Validation Loss: {min_losses[0]:.4f} was saved.\")"
538 | ]
539 | },
540 | {
541 | "cell_type": "code",
542 | "execution_count": 23,
543 | "metadata": {
544 | "colab": {
545 | "base_uri": "https://localhost:8080/",
546 | "height": 295
547 | },
548 | "id": "OkjBpvPt8BmJ",
549 | "outputId": "04320b26-1bc8-44d2-c904-17650335ee40"
550 | },
551 | "outputs": [
552 | {
553 | "data": {
554 | "image/png": "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",
555 | "text/plain": [
556 | ""
557 | ]
558 | },
559 | "metadata": {
560 | "needs_background": "light"
561 | },
562 | "output_type": "display_data"
563 | }
564 | ],
565 | "source": [
566 | "plt.title(\"Sentiment Analysis (FastText): Learning Curves\")\n",
567 | "plt.xlabel(\"Number of Epochs\")\n",
568 | "plt.ylabel(\"Binary Cross Entropy Loss\")\n",
569 | "plt.plot(train_losses, label = \"Training Loss\")\n",
570 | "plt.plot(valid_losses, label= \"Validation Loss\")\n",
571 | "plt.legend()\n",
572 | "plt.show()"
573 | ]
574 | },
575 | {
576 | "cell_type": "markdown",
577 | "metadata": {},
578 | "source": [
579 | "# Testing"
580 | ]
581 | },
582 | {
583 | "cell_type": "code",
584 | "execution_count": 24,
585 | "metadata": {
586 | "colab": {
587 | "base_uri": "https://localhost:8080/"
588 | },
589 | "id": "YLpKGbjyu2OK",
590 | "outputId": "fbad5f78-802f-441e-8f09-a461c781732e"
591 | },
592 | "outputs": [
593 | {
594 | "name": "stdout",
595 | "output_type": "stream",
596 | "text": [
597 | "Test Loss: 0.3499\n",
598 | "Test Accuracy: 86.28%\n"
599 | ]
600 | }
601 | ],
602 | "source": [
603 | "model.load_state_dict(torch.load('FastText.pt'))\n",
604 | "\n",
605 | "test_loss, test_acc = Evaluate(model, test_iterator, criterion)\n",
606 | "\n",
607 | "print(f'Test Loss: {test_loss:.4f}')\n",
608 | "print(f'Test Accuracy: {test_acc*100:.2f}%')"
609 | ]
610 | },
611 | {
612 | "cell_type": "markdown",
613 | "metadata": {
614 | "id": "o3vZ2NNn8sM6"
615 | },
616 | "source": [
617 | "# Sampling"
618 | ]
619 | },
620 | {
621 | "cell_type": "code",
622 | "execution_count": 25,
623 | "metadata": {
624 | "id": "e0hc5XtDsqIH"
625 | },
626 | "outputs": [],
627 | "source": [
628 | "import spacy\n",
629 | "nlp = spacy.load('en_core_web_sm')\n",
630 | "\n",
631 | "def predict_sentiment(model, text):\n",
632 | " model.eval()\n",
633 | " tokenized = generate_n_grams([tok.text for tok in nlp.tokenizer(text)], n=2)\n",
634 | " indexed = [FIELD.vocab.stoi[t] for t in tokenized]\n",
635 | " tensor = torch.LongTensor(indexed).to(device)\n",
636 | " tensor = tensor.unsqueeze(1)\n",
637 | " prediction = torch.sigmoid(model(tensor))\n",
638 | " return prediction.item()"
639 | ]
640 | },
641 | {
642 | "cell_type": "code",
643 | "execution_count": 26,
644 | "metadata": {
645 | "colab": {
646 | "base_uri": "https://localhost:8080/"
647 | },
648 | "id": "vc0zO3gTws-d",
649 | "outputId": "1ab04c54-b9e4-4323-943d-31cf2600127a"
650 | },
651 | "outputs": [
652 | {
653 | "data": {
654 | "text/plain": [
655 | "4.2760206042657956e-07"
656 | ]
657 | },
658 | "execution_count": 26,
659 | "metadata": {},
660 | "output_type": "execute_result"
661 | }
662 | ],
663 | "source": [
664 | "predict_sentiment(model, \"This film is not bad\")"
665 | ]
666 | },
667 | {
668 | "cell_type": "code",
669 | "execution_count": 27,
670 | "metadata": {
671 | "colab": {
672 | "base_uri": "https://localhost:8080/"
673 | },
674 | "id": "Umdey8pIw8yp",
675 | "outputId": "de24d02b-3c28-4dfa-f0b8-c4f0a4650340"
676 | },
677 | "outputs": [
678 | {
679 | "data": {
680 | "text/plain": [
681 | "1.0"
682 | ]
683 | },
684 | "execution_count": 27,
685 | "metadata": {},
686 | "output_type": "execute_result"
687 | }
688 | ],
689 | "source": [
690 | "predict_sentiment(model, \"This film is excellent\")"
691 | ]
692 | },
693 | {
694 | "cell_type": "code",
695 | "execution_count": 28,
696 | "metadata": {
697 | "colab": {
698 | "base_uri": "https://localhost:8080/"
699 | },
700 | "id": "8rbQ8FYRw-TM",
701 | "outputId": "37bb1381-ac04-42ac-de39-e48de16ae9db"
702 | },
703 | "outputs": [
704 | {
705 | "data": {
706 | "text/plain": [
707 | "2.538240104210665e-11"
708 | ]
709 | },
710 | "execution_count": 28,
711 | "metadata": {},
712 | "output_type": "execute_result"
713 | }
714 | ],
715 | "source": [
716 | "predict_sentiment(model, \"This film is bad\")"
717 | ]
718 | }
719 | ],
720 | "metadata": {
721 | "accelerator": "GPU",
722 | "colab": {
723 | "name": "FastText.ipynb",
724 | "provenance": []
725 | },
726 | "kernelspec": {
727 | "display_name": "Python 3",
728 | "name": "python3"
729 | },
730 | "language_info": {
731 | "codemirror_mode": {
732 | "name": "ipython",
733 | "version": 3
734 | },
735 | "file_extension": ".py",
736 | "mimetype": "text/x-python",
737 | "name": "python",
738 | "nbconvert_exporter": "python",
739 | "pygments_lexer": "ipython3",
740 | "version": "3.9.7"
741 | }
742 | },
743 | "nbformat": 4,
744 | "nbformat_minor": 0
745 | }
746 |
--------------------------------------------------------------------------------
/text_classification/notebooks/LSTM.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Installing Packages"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {
13 | "id": "bbMNpP192mb2"
14 | },
15 | "source": [
16 | "# Importing Required Libraries"
17 | ]
18 | },
19 | {
20 | "cell_type": "code",
21 | "execution_count": 1,
22 | "metadata": {
23 | "id": "slw2Y5t3taWQ"
24 | },
25 | "outputs": [],
26 | "source": [
27 | "import torch\n",
28 | "from torchtext import data, datasets\n",
29 | "import torch.nn as nn\n",
30 | "import torch.optim as optim\n",
31 | "from torch.nn.utils.rnn import pack_padded_sequence\n",
32 | "from torchtext.data import Field, LabelField, BucketIterator\n",
33 | "\n",
34 | "import random\n",
35 | "\n",
36 | "import matplotlib.pyplot as plt"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": 2,
42 | "metadata": {
43 | "colab": {
44 | "base_uri": "https://localhost:8080/"
45 | },
46 | "id": "7kAMYpKr2tJV",
47 | "outputId": "1b33d632-6261-4881-8703-5a572fa8c210"
48 | },
49 | "outputs": [
50 | {
51 | "name": "stdout",
52 | "output_type": "stream",
53 | "text": [
54 | "Notebook is running on cuda\n"
55 | ]
56 | }
57 | ],
58 | "source": [
59 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
60 | "print(\"Notebook is running on\", device)"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {
66 | "id": "8ZOcRV2w2vpH"
67 | },
68 | "source": [
69 | "Fixing SEED for reproducibility of results"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 3,
75 | "metadata": {
76 | "id": "N99mW-8XtnWr"
77 | },
78 | "outputs": [],
79 | "source": [
80 | "SEED = 4444\n",
81 | "\n",
82 | "random.seed(SEED)\n",
83 | "torch.manual_seed(SEED)\n",
84 | "torch.cuda.manual_seed(SEED)\n",
85 | "torch.backends.cudnn.deterministic = True"
86 | ]
87 | },
88 | {
89 | "cell_type": "code",
90 | "execution_count": 4,
91 | "metadata": {
92 | "id": "O5NaQke7touV"
93 | },
94 | "outputs": [],
95 | "source": [
96 | "FIELD = Field(tokenize = 'spacy', tokenizer_language = 'en_core_web_sm', include_lengths=True)\n",
97 | "\n",
98 | "LABEL = LabelField(dtype = torch.float)"
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {
104 | "id": "RWXCd0V73YK7"
105 | },
106 | "source": [
107 | "# Splitting the data"
108 | ]
109 | },
110 | {
111 | "cell_type": "code",
112 | "execution_count": 5,
113 | "metadata": {
114 | "id": "79ih2w2sttNq"
115 | },
116 | "outputs": [],
117 | "source": [
118 | "train_data, test_data = datasets.IMDB.splits(FIELD, LABEL)"
119 | ]
120 | },
121 | {
122 | "cell_type": "code",
123 | "execution_count": 6,
124 | "metadata": {
125 | "id": "nxpdowpRtwNQ"
126 | },
127 | "outputs": [],
128 | "source": [
129 | "train_data, valid_data = train_data.split(random_state = random.seed(SEED))"
130 | ]
131 | },
132 | {
133 | "cell_type": "code",
134 | "execution_count": 7,
135 | "metadata": {
136 | "colab": {
137 | "base_uri": "https://localhost:8080/"
138 | },
139 | "id": "BSWt_wDwtzLt",
140 | "outputId": "a5c136ea-d381-4ee1-8e91-a908e5f8ece1"
141 | },
142 | "outputs": [
143 | {
144 | "name": "stdout",
145 | "output_type": "stream",
146 | "text": [
147 | "Number of training examples: 17500\n",
148 | "Number of validation examples: 7500\n",
149 | "Number of testing examples: 25000\n"
150 | ]
151 | }
152 | ],
153 | "source": [
154 | "print(f'Number of training examples: {len(train_data)}')\n",
155 | "print(f'Number of validation examples: {len(valid_data)}')\n",
156 | "print(f'Number of testing examples: {len(test_data)}')"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 8,
162 | "metadata": {
163 | "id": "trFz-SmNt0fO"
164 | },
165 | "outputs": [],
166 | "source": [
167 | "MAX_VOCAB_SIZE = 25000 # excluding and token\n",
168 | "\n",
169 | "FIELD.build_vocab(train_data, max_size = MAX_VOCAB_SIZE, vectors=\"glove.6B.100d\", unk_init = torch.Tensor.normal_)\n",
170 | "LABEL.build_vocab(train_data)"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "execution_count": 9,
176 | "metadata": {
177 | "colab": {
178 | "base_uri": "https://localhost:8080/"
179 | },
180 | "id": "PQUUTTgat5hg",
181 | "outputId": "6fde1f1d-4150-4e21-aba1-f66137439cee"
182 | },
183 | "outputs": [
184 | {
185 | "name": "stdout",
186 | "output_type": "stream",
187 | "text": [
188 | "Unique tokens in FIELD vocabulary: 25002\n",
189 | "Unique tokens in LABEL vocabulary: 2\n"
190 | ]
191 | }
192 | ],
193 | "source": [
194 | "print(f\"Unique tokens in FIELD vocabulary: {len(FIELD.vocab)}\")\n",
195 | "print(f\"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}\")"
196 | ]
197 | },
198 | {
199 | "cell_type": "markdown",
200 | "metadata": {
201 | "id": "BIZMVoIA4S2K"
202 | },
203 | "source": [
204 | "# Model Definition"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": 10,
210 | "metadata": {
211 | "id": "egyx2GtzuEdP"
212 | },
213 | "outputs": [],
214 | "source": [
215 | "class LSTM(nn.Module):\n",
216 | " def __init__(self, vocab_size, emb_size, hidden_size, output_size, num_layers, pad_idx):\n",
217 | " super().__init__()\n",
218 | " self.embedding = nn.Embedding(vocab_size, emb_size, padding_idx = pad_idx)\n",
219 | " self.lstm = nn.LSTM(emb_size, hidden_size, num_layers = num_layers, bidirectional=True, dropout=0.5)\n",
220 | " self.fc = nn.Linear(hidden_size*2, output_size)\n",
221 | " self.dropout = nn.Dropout(0.5)\n",
222 | " \n",
223 | " def forward(self, input, input_lengths): # [input] = [seq_len, batch_size]\n",
224 | " embedded = self.dropout(self.embedding(input)) # [embedded] = [sent_len, batch_size, embedding_size]\n",
225 | " packed_embedded = pack_padded_sequence(embedded, input_lengths.to('cpu')) # inputs lengths need to be on CPU\n",
226 | " packed_output, (hidden, cell) = self.lstm(packed_embedded)\n",
227 | " output, output_lengths = nn.utils.rnn.pad_packed_sequence(packed_output)\n",
228 | " # [output] = [seq_len, batch_size, hidden_size*2]\n",
229 | " # [hidden] = [num_layers * 2, batch_size, hidden_size]\n",
230 | " # [cell] = [num_layers * 2, batch_size, hidden_size]\n",
231 | " hidden = self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim = 1)) # [hidden] = [batch_size, hidden_size * 2]\n",
232 | " return self.fc(hidden)"
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": 11,
238 | "metadata": {
239 | "id": "2PDdgoXiufHr"
240 | },
241 | "outputs": [],
242 | "source": [
243 | "def batch_accuracy(preds, y):\n",
244 | "\n",
245 | " #round predictions to the closest integer\n",
246 | " rounded_preds = torch.round(torch.sigmoid(preds))\n",
247 | " correct = (rounded_preds == y).float()\n",
248 | " acc = correct.sum() / len(correct)\n",
249 | " return acc"
250 | ]
251 | },
252 | {
253 | "cell_type": "markdown",
254 | "metadata": {
255 | "id": "OpnqXXA1uvuD"
256 | },
257 | "source": [
258 | "# Training and Evaluation Functions"
259 | ]
260 | },
261 | {
262 | "cell_type": "code",
263 | "execution_count": 12,
264 | "metadata": {
265 | "id": "gKSFO3hRutOc"
266 | },
267 | "outputs": [],
268 | "source": [
269 | "def Train(model, iterator, optimizer, criterion):\n",
270 | " epoch_loss = 0\n",
271 | " epoch_acc = 0\n",
272 | " model.train()\n",
273 | " for batch in iterator:\n",
274 | " optimizer.zero_grad()\n",
275 | " inp, inp_lengths = batch.text\n",
276 | " label = batch.label \n",
277 | " predictions = model(inp, inp_lengths).squeeze(1)\n",
278 | " loss = criterion(predictions, label)\n",
279 | " acc = batch_accuracy(predictions, label)\n",
280 | " loss.backward()\n",
281 | " optimizer.step()\n",
282 | " epoch_loss += loss.item()\n",
283 | " epoch_acc += acc.item()\n",
284 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
285 | ]
286 | },
287 | {
288 | "cell_type": "code",
289 | "execution_count": 13,
290 | "metadata": {
291 | "id": "YqTp93Aruwoe"
292 | },
293 | "outputs": [],
294 | "source": [
295 | "def Evaluate(model, iterator, criterion):\n",
296 | " epoch_loss = 0\n",
297 | " epoch_acc = 0\n",
298 | " model.eval()\n",
299 | " with torch.no_grad():\n",
300 | " for batch in iterator:\n",
301 | " inp, inp_lengths = batch.text\n",
302 | " label = batch.label \n",
303 | " predictions = model(inp, inp_lengths).squeeze(1)\n",
304 | " loss = criterion(predictions, label)\n",
305 | " acc = batch_accuracy(predictions, label)\n",
306 | " epoch_loss += loss.item()\n",
307 | " epoch_acc += acc.item()\n",
308 | " return epoch_loss / len(iterator), epoch_acc / len(iterator)"
309 | ]
310 | },
311 | {
312 | "cell_type": "markdown",
313 | "metadata": {
314 | "id": "v1_3yX3-42vO"
315 | },
316 | "source": [
317 | "# Data Iterators, Hyperparameters and Model Initialization"
318 | ]
319 | },
320 | {
321 | "cell_type": "code",
322 | "execution_count": 14,
323 | "metadata": {
324 | "id": "yIHX-jbs5ClS"
325 | },
326 | "outputs": [],
327 | "source": [
328 | "BATCH_SIZE = 64\n",
329 | "\n",
330 | "train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits((train_data, valid_data, test_data), batch_size = BATCH_SIZE, sort_within_batch = True, device = device)"
331 | ]
332 | },
333 | {
334 | "cell_type": "code",
335 | "execution_count": 15,
336 | "metadata": {
337 | "id": "o6c7ld9wuYh4"
338 | },
339 | "outputs": [],
340 | "source": [
341 | "VOCAB_SIZE = len(FIELD.vocab) # dimension of one-hot vector / vocabulary\n",
342 | "EMB_DIM = 100 # dimension of word embeddings\n",
343 | "HIDDEN_DIM = 256 # dimension of hidden layer\n",
344 | "OUTPUT_DIM = 1 # dimension of output layer\n",
345 | "NUM_LAYERS = 2\n",
346 | "\n",
347 | "NUM_EPOCHS = 10\n",
348 | "LR = 0.001"
349 | ]
350 | },
351 | {
352 | "cell_type": "code",
353 | "execution_count": 16,
354 | "metadata": {
355 | "id": "j5U3vbZcwEgr"
356 | },
357 | "outputs": [],
358 | "source": [
359 | "model = LSTM(VOCAB_SIZE, EMB_DIM, HIDDEN_DIM, OUTPUT_DIM, NUM_LAYERS, FIELD.vocab.stoi[FIELD.pad_token])"
360 | ]
361 | },
362 | {
363 | "cell_type": "code",
364 | "execution_count": 17,
365 | "metadata": {
366 | "id": "ziglTF1D5voa"
367 | },
368 | "outputs": [],
369 | "source": [
370 | "optimizer = optim.Adam(model.parameters(), lr=LR)\n",
371 | "\n",
372 | "criterion = nn.BCEWithLogitsLoss()\n",
373 | "\n",
374 | "model = model.to(device)\n",
375 | "criterion = criterion.to(device)"
376 | ]
377 | },
378 | {
379 | "cell_type": "code",
380 | "execution_count": 18,
381 | "metadata": {
382 | "colab": {
383 | "base_uri": "https://localhost:8080/"
384 | },
385 | "id": "X7Mm3BnuuZ2F",
386 | "outputId": "6645fdd0-8293-41df-a4ff-cd29eea63919"
387 | },
388 | "outputs": [
389 | {
390 | "name": "stdout",
391 | "output_type": "stream",
392 | "text": [
393 | "The model has 4,810,857 trainable parameters\n"
394 | ]
395 | }
396 | ],
397 | "source": [
398 | "def count_parameters(model):\n",
399 | " return sum(p.numel() for p in model.parameters() if p.requires_grad)\n",
400 | "\n",
401 | "print(f'The model has {count_parameters(model):,} trainable parameters')"
402 | ]
403 | },
404 | {
405 | "cell_type": "markdown",
406 | "metadata": {
407 | "id": "99qvK1qw5aAV"
408 | },
409 | "source": [
410 | "# Training"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 19,
416 | "metadata": {
417 | "id": "WT1J71IjuySn"
418 | },
419 | "outputs": [],
420 | "source": [
421 | "import time\n",
422 | "\n",
423 | "def Epoch_time(start_time, end_time):\n",
424 | " elapsed_time = end_time - start_time\n",
425 | " elapsed_mins = int(elapsed_time / 60)\n",
426 | " elapsed_secs = int(elapsed_time - (elapsed_mins * 60))\n",
427 | " return elapsed_mins, elapsed_secs"
428 | ]
429 | },
430 | {
431 | "cell_type": "code",
432 | "execution_count": 20,
433 | "metadata": {
434 | "colab": {
435 | "base_uri": "https://localhost:8080/"
436 | },
437 | "id": "TKDOAVH5uz2s",
438 | "outputId": "57357c85-df7f-4e9a-a609-dd367866adea"
439 | },
440 | "outputs": [
441 | {
442 | "name": "stdout",
443 | "output_type": "stream",
444 | "text": [
445 | "Learning Rate: 0.001, Hidden Dimensions: 256\n",
446 | "Time taken for epoch 1: 0m 35s\n",
447 | "Training Loss: 0.6791 | Validation Loss: 0.7054\n",
448 | "Training Accuracy: 56.48 %| Validation Accuracy: 52.33 %\n",
449 | "Time taken for epoch 2: 0m 34s\n",
450 | "Training Loss: 0.6756 | Validation Loss: 0.6665\n",
451 | "Training Accuracy: 56.92 %| Validation Accuracy: 57.87 %\n",
452 | "Time taken for epoch 3: 0m 35s\n",
453 | "Training Loss: 0.6262 | Validation Loss: 0.5267\n",
454 | "Training Accuracy: 64.63 %| Validation Accuracy: 74.09 %\n",
455 | "Time taken for epoch 4: 0m 35s\n",
456 | "Training Loss: 0.5106 | Validation Loss: 0.4333\n",
457 | "Training Accuracy: 75.00 %| Validation Accuracy: 79.46 %\n",
458 | "Time taken for epoch 5: 0m 35s\n",
459 | "Training Loss: 0.4344 | Validation Loss: 0.3877\n",
460 | "Training Accuracy: 80.39 %| Validation Accuracy: 82.77 %\n",
461 | "Time taken for epoch 6: 0m 35s\n",
462 | "Training Loss: 0.3672 | Validation Loss: 0.3312\n",
463 | "Training Accuracy: 84.22 %| Validation Accuracy: 86.01 %\n",
464 | "Time taken for epoch 7: 0m 35s\n",
465 | "Training Loss: 0.3312 | Validation Loss: 0.3588\n",
466 | "Training Accuracy: 86.08 %| Validation Accuracy: 84.35 %\n",
467 | "Time taken for epoch 8: 0m 35s\n",
468 | "Training Loss: 0.2889 | Validation Loss: 0.3066\n",
469 | "Training Accuracy: 87.88 %| Validation Accuracy: 87.55 %\n",
470 | "Time taken for epoch 9: 0m 35s\n",
471 | "Training Loss: 0.2686 | Validation Loss: 0.2816\n",
472 | "Training Accuracy: 89.10 %| Validation Accuracy: 88.37 %\n",
473 | "Time taken for epoch 10: 0m 35s\n",
474 | "Training Loss: 0.2380 | Validation Loss: 0.3224\n",
475 | "Training Accuracy: 90.45 %| Validation Accuracy: 87.09 %\n",
476 | "Model with Train Loss 0.2686, Validation Loss: 0.2816 was saved.\n"
477 | ]
478 | }
479 | ],
480 | "source": [
481 | "print(f\"Learning Rate: {LR}, Hidden Dimensions: {HIDDEN_DIM}\")\n",
482 | "train_losses = []\n",
483 | "valid_losses = []\n",
484 | "min_losses = [float('inf'), float('inf')]\n",
485 | "\n",
486 | "start_time = time.time()\n",
487 | "for epoch in range(1, NUM_EPOCHS+1):\n",
488 | " \n",
489 | " train_loss, train_acc = Train(model, train_iterator, optimizer, criterion)\n",
490 | " train_losses.append(train_loss)\n",
491 | " valid_loss, valid_acc = Evaluate(model, valid_iterator, criterion)\n",
492 | " valid_losses.append(valid_loss)\n",
493 | "\n",
494 | " if valid_loss < min_losses[0]:\n",
495 | " min_losses[0] = valid_loss\n",
496 | " min_losses[1] = train_loss\n",
497 | " torch.save(model.state_dict(), 'LSTM.pt')\n",
498 | "\n",
499 | " elapsed_time = Epoch_time(start_time, time.time())\n",
500 | " print(f\"Time taken for epoch {epoch}: {elapsed_time[0]}m {elapsed_time[1]}s\")\n",
501 | " start_time = time.time()\n",
502 | " print(f\"Training Loss: {train_loss:.4f} | Validation Loss: {valid_loss:.4f}\")\n",
503 | " print(f\"Training Accuracy: {train_acc*100:.2f} %| Validation Accuracy: {valid_acc*100:.2f} %\")\n",
504 | "\n",
505 | "print(f\"Model with Train Loss {min_losses[1]:.4f}, Validation Loss: {min_losses[0]:.4f} was saved.\")"
506 | ]
507 | },
508 | {
509 | "cell_type": "code",
510 | "execution_count": 21,
511 | "metadata": {
512 | "colab": {
513 | "base_uri": "https://localhost:8080/",
514 | "height": 295
515 | },
516 | "id": "OkjBpvPt8BmJ",
517 | "outputId": "e7d60c8f-a210-43a1-e465-afc3ca5153f8"
518 | },
519 | "outputs": [
520 | {
521 | "data": {
522 | "image/png": "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",
523 | "text/plain": [
524 | ""
525 | ]
526 | },
527 | "metadata": {
528 | "needs_background": "light"
529 | },
530 | "output_type": "display_data"
531 | }
532 | ],
533 | "source": [
534 | "plt.title(\"Sentiment Analysis (LSTM): Learning Curves\")\n",
535 | "plt.xlabel(\"Number of Epochs\")\n",
536 | "plt.ylabel(\"Binary Cross Entropy Loss\")\n",
537 | "plt.plot(train_losses, label = \"Training Loss\")\n",
538 | "plt.plot(valid_losses, label= \"Validation Loss\")\n",
539 | "plt.legend()\n",
540 | "plt.show()"
541 | ]
542 | },
543 | {
544 | "cell_type": "markdown",
545 | "metadata": {},
546 | "source": [
547 | "# Testing"
548 | ]
549 | },
550 | {
551 | "cell_type": "code",
552 | "execution_count": 22,
553 | "metadata": {
554 | "colab": {
555 | "base_uri": "https://localhost:8080/"
556 | },
557 | "id": "YLpKGbjyu2OK",
558 | "outputId": "2ba60055-1f76-4b99-a5b9-4b4315e8e5df"
559 | },
560 | "outputs": [
561 | {
562 | "name": "stdout",
563 | "output_type": "stream",
564 | "text": [
565 | "Test Loss: 0.2986\n",
566 | "Test Accuracy: 87.62%\n"
567 | ]
568 | }
569 | ],
570 | "source": [
571 | "model.load_state_dict(torch.load('LSTM.pt'))\n",
572 | "\n",
573 | "test_loss, test_acc = Evaluate(model, test_iterator, criterion)\n",
574 | "\n",
575 | "print(f'Test Loss: {test_loss:.4f}')\n",
576 | "print(f'Test Accuracy: {test_acc*100:.2f}%')"
577 | ]
578 | },
579 | {
580 | "cell_type": "markdown",
581 | "metadata": {
582 | "id": "o3vZ2NNn8sM6"
583 | },
584 | "source": [
585 | "# Sampling"
586 | ]
587 | },
588 | {
589 | "cell_type": "code",
590 | "execution_count": 23,
591 | "metadata": {
592 | "id": "e0hc5XtDsqIH"
593 | },
594 | "outputs": [],
595 | "source": [
596 | "import spacy\n",
597 | "nlp = spacy.load('en_core_web_sm')\n",
598 | "\n",
599 | "def predict_sentiment(model, text):\n",
600 | " model.eval()\n",
601 | " tokenized = [tok.text for tok in nlp.tokenizer(text)]\n",
602 | " indexed = [FIELD.vocab.stoi[t] for t in tokenized]\n",
603 | " length = [len(indexed)]\n",
604 | " tensor = torch.LongTensor(indexed).to(device)\n",
605 | " tensor = tensor.unsqueeze(1)\n",
606 | " length_tensor = torch.LongTensor(length)\n",
607 | " prediction = torch.sigmoid(model(tensor, length_tensor))\n",
608 | " return prediction.item()"
609 | ]
610 | },
611 | {
612 | "cell_type": "code",
613 | "execution_count": 24,
614 | "metadata": {
615 | "colab": {
616 | "base_uri": "https://localhost:8080/",
617 | "height": 311
618 | },
619 | "id": "vc0zO3gTws-d",
620 | "outputId": "fde91c09-6b91-4f2b-e49d-124d528c52aa"
621 | },
622 | "outputs": [
623 | {
624 | "data": {
625 | "text/plain": [
626 | "0.011234746314585209"
627 | ]
628 | },
629 | "execution_count": 24,
630 | "metadata": {},
631 | "output_type": "execute_result"
632 | }
633 | ],
634 | "source": [
635 | "predict_sentiment(model, \"This film is not bad\")"
636 | ]
637 | },
638 | {
639 | "cell_type": "code",
640 | "execution_count": 25,
641 | "metadata": {
642 | "id": "Umdey8pIw8yp"
643 | },
644 | "outputs": [
645 | {
646 | "data": {
647 | "text/plain": [
648 | "0.939202070236206"
649 | ]
650 | },
651 | "execution_count": 25,
652 | "metadata": {},
653 | "output_type": "execute_result"
654 | }
655 | ],
656 | "source": [
657 | "predict_sentiment(model, \"This film is excellent\")"
658 | ]
659 | },
660 | {
661 | "cell_type": "code",
662 | "execution_count": 26,
663 | "metadata": {
664 | "id": "8rbQ8FYRw-TM"
665 | },
666 | "outputs": [
667 | {
668 | "data": {
669 | "text/plain": [
670 | "0.0072547681629657745"
671 | ]
672 | },
673 | "execution_count": 26,
674 | "metadata": {},
675 | "output_type": "execute_result"
676 | }
677 | ],
678 | "source": [
679 | "predict_sentiment(model, \"This film is bad\")"
680 | ]
681 | }
682 | ],
683 | "metadata": {
684 | "accelerator": "GPU",
685 | "colab": {
686 | "name": "LSTM.ipynb",
687 | "provenance": []
688 | },
689 | "kernelspec": {
690 | "display_name": "Python 3",
691 | "name": "python3"
692 | },
693 | "language_info": {
694 | "codemirror_mode": {
695 | "name": "ipython",
696 | "version": 3
697 | },
698 | "file_extension": ".py",
699 | "mimetype": "text/x-python",
700 | "name": "python",
701 | "nbconvert_exporter": "python",
702 | "pygments_lexer": "ipython3",
703 | "version": "3.9.7"
704 | }
705 | },
706 | "nbformat": 4,
707 | "nbformat_minor": 0
708 | }
709 |
--------------------------------------------------------------------------------
/text_classification/plots/BERT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/text_classification/plots/BERT.png
--------------------------------------------------------------------------------
/text_classification/plots/CNN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/text_classification/plots/CNN.png
--------------------------------------------------------------------------------
/text_classification/plots/FastText.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/text_classification/plots/FastText.png
--------------------------------------------------------------------------------
/text_classification/plots/LSTM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/text_classification/plots/LSTM.png
--------------------------------------------------------------------------------
/word_rnn/README.md:
--------------------------------------------------------------------------------
1 | # Paragraph generation (Language modeling)
2 |
3 | Model was trained over Book 1 - Philosopher's stone.txt which is 1st edition of Harry Potter franchise.
4 |
5 | Text consists of
6 | 5978 distinct words (vocabilary size)
7 | 3275 usable paragraphs
8 |
9 |
10 | > It is observed that model trained with nn.RNN is unable to form long term dependencies. Paragraphs formed were very short.
11 | Meaning of sentence is lost just in 3-4 words . Although it is able to recognise end of paragraph. Model is wise enough to choose proper punctuation marks. For example- double quotes are closed in almost every trial.
12 |
13 | > Whereas , model trained with nn.LSTM is able to form long term dependencies. Even next sentence formed after one shows some context shared. LSTM shows better results that RNN and GRU. Sentences and paragraphs are ended at proper position and proper meaning than other two.
14 |
15 | > GRU Gives somewhat similar results like LSTM. Sentences show some what meaning and shared context. But next sentence formed looses previous context. Sentence ending and paragraph ending is done properly. Punctuations are also maintained. Also you can observe that , length of sequence formed decreases.
16 |
17 |
18 | GRU Loss function
19 |
20 |
21 | 
22 |
23 | #embedding = 128
24 | #hidden_size = 256
25 | #num_layers = 4
26 | #learning_rate = 0.0006
27 | #epochs = 25
28 | #3,782,234 trainable parameters
29 |
30 | LSTM Loss function
31 |
32 |
33 | 
34 |
35 | #embedding = 128
36 | #hidden_size = 256
37 | #num_layers = 4
38 | #learning_rate = 0.0006
39 | #epochs = 25
40 | #4,275,802 trainable parameters
41 |
42 | RNN Loss function
43 |
44 | 
45 |
46 | #embedding = 150
47 | #hidden_size = 400
48 | #num_layers = 3
49 | #learning_rate = 0.0006
50 | #epochs = 25
51 | #4,156,278 trainable parameters
52 | > Since RNN has no cell states or gates those help in remembering details from previous inputs, we have increased size of hidden layer and embedding layer. Increment in number of parameters show better results.
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | ## __ Results __ -
61 |
62 | 
63 |
64 | ## LSTM
65 |
66 | 1. testing2('“ i tell you , we’re going to win that')
67 | - “ i tell you , we’re going to win that in the summer - year waffle , something that he is to die — dumbledore says nothing about it , i’ll therefore nicolas ‘ rude with all with a fifty - points - points points that year , you were steamrollered ! ”
68 |
69 | 2. testing2('there was a very good chance they were going to get caught')
70 | - 'there was a very good chance they were going to get caught some point \\ ”'
71 |
72 |
73 | 3. testing2('they pulled on their bathrobes , picked up their wands ,')
74 | - 'they pulled on their bathrobes , picked up their wands , insisting themselves , and snape into the slytherin table . “ aren’t you ? ” screeched dumbledore , but she passed , but mr . dursley was , mysterious a long bite with broad soon .'
75 |
76 | 4. testing2('“ i am scared ”')
77 | - '“ i am scared ” . . . for the soul . “ i can knew it , ” said dumbledore , grinning , grinning down the mom , “ mom , mom . ” '
78 |
79 | 5. testing2('hermione took out a list of subjects and titles she had')
80 | - 'hermione took out a list of subjects and titles she had found talking to the ceiling . harry found a quiver again at the barrier , but the whisperers bear the platform as dressed there , too .'
81 |
82 | ## GRU
83 |
84 | 1. testing2('“ i tell you , we’re going to win that')
85 | - '“ i tell you , we’re going to win that , ” said harry .'
86 |
87 | 2. testing2('there was a very good chance they were going to get caught')
88 | - 'there was a very good chance they were going to get caught the fact . some and its common families and fifty trolls in the air ; it turned on the note .'
89 |
90 | 3. testing2('they pulled on their bathrobes , picked up their wands ,')
91 | - 'they pulled on their bathrobes , picked up their wands , stone - green - muggle words . the same thing was still around at quirrell’s mouth , a purple hand , and a still screamed of books into the ceiling , and a same same through the same one ; the last last time in harry’s hand , reached into the same wall . the rest of the first thing they were talking and down , and waving into the table and winked , it was a terrible nostrils in'
92 |
93 | 4. testing2('“ i am scared ”')
94 | - '“ i am scared ” . . . weasley face at harry . “ i said it , however , i thought . . . ”'
95 |
96 | 5. testing2('hermione took out a list of subjects and titles she had')
97 | - 'hermione took out a list of subjects and titles she had already passed at the table , and she looked forward to herself to be allowed to be looking at them . she looked very high , she looked at them .'
98 |
99 |
100 | ## RNN
101 |
102 | 1. testing2('“ i tell you , we’re going to win that')
103 | - “ i tell you , we’re going to win that hole . ”'
104 |
105 | 2. testing2('there was a very good chance they were going to get caught')
106 | - 'there was a very good chance they were going to get caught the whole day .'
107 |
108 | 3. testing2('they pulled on their bathrobes , picked up their wands ,')
109 | 'they pulled on their bathrobes , picked up their wands , and fell into blackness .'
110 |
111 | 4. testing2('“ i am scared ”')
112 | - '“ i am scared ” gasped . . . . ”'
113 |
114 | 5. testing2('hermione took out a list of subjects and titles she had')
115 | - 'hermione took out a list of subjects and titles she had to say .'
116 |
117 |
118 | ## Resources :
119 | https://youtu.be/iWea12EAu6U CS224N course over NLP.
120 |
--------------------------------------------------------------------------------
/word_rnn/ezgif.com-gif-maker.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/ezgif.com-gif-maker.gif
--------------------------------------------------------------------------------
/word_rnn/paragraph generation loss gru.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/paragraph generation loss gru.png
--------------------------------------------------------------------------------
/word_rnn/paragraph generation loss lstm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/paragraph generation loss lstm.png
--------------------------------------------------------------------------------
/word_rnn/paragraph generation loss rnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/paragraph generation loss rnn.png
--------------------------------------------------------------------------------
/word_rnn/wordRNN_paragraph_gru2.pth:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/wordRNN_paragraph_gru2.pth
--------------------------------------------------------------------------------
/word_rnn/wordRNN_paragraph_lstm2.pth:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/wordRNN_paragraph_lstm2.pth
--------------------------------------------------------------------------------
/word_rnn/wordRNN_paragraph_rnn2.pth:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IvLabs/Natural-Language-Processing/dcfd38d00a8d5137b122c778a67445d7e95cf53e/word_rnn/wordRNN_paragraph_rnn2.pth
--------------------------------------------------------------------------------