NanduVardhanreddy commited on
Commit
dd35b1e
1 Parent(s): 1707d49

Upload 5 files

Browse files
Nanduvardhanreddy_amireddy.ipynb ADDED
@@ -0,0 +1,576 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "173f674b-75a4-43ff-97ff-c03b5a32a74d",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Neural Network-Based Language Model for Next Token Prediction"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "markdown",
13
+ "id": "a27f24d0-0eb2-4424-8bfe-f2fbf5039883",
14
+ "metadata": {},
15
+ "source": [
16
+ "### Data Loading And Cleaning"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": 65,
22
+ "id": "6ddf05f0-8586-47b1-9c0f-f4cfe74db3f2",
23
+ "metadata": {
24
+ "editable": true,
25
+ "slideshow": {
26
+ "slide_type": ""
27
+ },
28
+ "tags": []
29
+ },
30
+ "outputs": [
31
+ {
32
+ "name": "stdout",
33
+ "output_type": "stream",
34
+ "text": [
35
+ "Training data size: 100\n",
36
+ "Validation data size: 100\n"
37
+ ]
38
+ }
39
+ ],
40
+ "source": [
41
+ "import json\n",
42
+ "import pandas as pd\n",
43
+ "\n",
44
+ "# Load English (alpaca_cleaned.json) and Assamese datasets (Assamese.json)\n",
45
+ "def load_data(english_path, assamese_path):\n",
46
+ " with open(english_path, 'r') as f:\n",
47
+ " english_data = json.load(f)\n",
48
+ " \n",
49
+ " with open(assamese_path, 'r') as f:\n",
50
+ " assamese_data = json.load(f)\n",
51
+ " \n",
52
+ " return english_data, assamese_data\n",
53
+ "\n",
54
+ "# Clean and extract the required data\n",
55
+ "def prepare_data(english_data, assamese_data, sample_size=50):\n",
56
+ " # Take the first 50 examples from each dataset for training\n",
57
+ " train_english = english_data[:sample_size]\n",
58
+ " train_assamese = assamese_data[:sample_size]\n",
59
+ " \n",
60
+ " # Take the last 50 examples from each dataset for validation\n",
61
+ " val_english = english_data[-sample_size:]\n",
62
+ " val_assamese = assamese_data[-sample_size:]\n",
63
+ " \n",
64
+ " # Merge training and validation datasets\n",
65
+ " train_data = train_english + train_assamese\n",
66
+ " val_data = val_english + val_assamese\n",
67
+ " \n",
68
+ " return train_data, val_data\n",
69
+ "\n",
70
+ "# Paths to data files\n",
71
+ "english_path = 'alpaca_cleaned.json'\n",
72
+ "assamese_path = 'Assamese.json'\n",
73
+ "\n",
74
+ "# Load and prepare the data\n",
75
+ "english_data, assamese_data = load_data(english_path, assamese_path)\n",
76
+ "train_data, val_data = prepare_data(english_data, assamese_data)\n",
77
+ "\n",
78
+ "# Display sample sizes\n",
79
+ "print(f'Training data size: {len(train_data)}')\n",
80
+ "print(f'Validation data size: {len(val_data)}')\n"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "markdown",
85
+ "id": "e3d4d293-30ac-4c00-9aa7-019203547b80",
86
+ "metadata": {},
87
+ "source": [
88
+ "# GP-2 Tokenizer"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "code",
93
+ "execution_count": 24,
94
+ "id": "4b5a09a4-458f-4b29-a600-27233ebf07bd",
95
+ "metadata": {},
96
+ "outputs": [
97
+ {
98
+ "name": "stdout",
99
+ "output_type": "stream",
100
+ "text": [
101
+ "Tokenized train data size: 100\n",
102
+ "Tokenized validation data size: 100\n"
103
+ ]
104
+ },
105
+ {
106
+ "name": "stderr",
107
+ "output_type": "stream",
108
+ "text": [
109
+ "/opt/anaconda3/lib/python3.12/site-packages/transformers/tokenization_utils_base.py:1601: FutureWarning: `clean_up_tokenization_spaces` was not set. It will be set to `True` by default. This behavior will be depracted in transformers v4.45, and will be then set to `False` by default. For more details check this issue: https://github.com/huggingface/transformers/issues/31884\n",
110
+ " warnings.warn(\n"
111
+ ]
112
+ }
113
+ ],
114
+ "source": [
115
+ " from transformers import GPT2Tokenizer\n",
116
+ "\n",
117
+ "# Load GPT-2 tokenizer\n",
118
+ "tokenizer = GPT2Tokenizer.from_pretrained(\"gpt2\")\n",
119
+ "\n",
120
+ "# Add padding tokens to the tokenizer\n",
121
+ "tokenizer.pad_token = tokenizer.eos_token\n",
122
+ "\n",
123
+ "# Function to tokenize a dataset\n",
124
+ "def tokenize_data(data, tokenizer, max_length=512):\n",
125
+ " inputs = []\n",
126
+ " outputs = []\n",
127
+ " \n",
128
+ " for entry in data:\n",
129
+ " instruction = entry.get('instruction', '')\n",
130
+ " input_text = entry.get('input', '')\n",
131
+ " output_text = entry.get('output', '')\n",
132
+ " \n",
133
+ " # Combine instruction and input for tokenization\n",
134
+ " combined_input = instruction + \" \" + input_text\n",
135
+ " tokenized_input = tokenizer(combined_input, truncation=True, padding='max_length', max_length=max_length)\n",
136
+ " tokenized_output = tokenizer(output_text, truncation=True, padding='max_length', max_length=max_length)\n",
137
+ " \n",
138
+ " inputs.append(tokenized_input['input_ids'])\n",
139
+ " outputs.append(tokenized_output['input_ids'])\n",
140
+ " \n",
141
+ " return inputs, outputs\n",
142
+ "\n",
143
+ "# Tokenize training and validation data\n",
144
+ "train_inputs, train_outputs = tokenize_data(train_data, tokenizer)\n",
145
+ "val_inputs, val_outputs = tokenize_data(val_data, tokenizer)\n",
146
+ "\n",
147
+ "print(f\"Tokenized train data size: {len(train_inputs)}\")\n",
148
+ "print(f\"Tokenized validation data size: {len(val_inputs)}\")\n"
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "markdown",
153
+ "id": "718ebcdd-53e9-463d-8448-eac6ab9e62a8",
154
+ "metadata": {},
155
+ "source": [
156
+ "# Embedding and LSTM Model Building"
157
+ ]
158
+ },
159
+ {
160
+ "cell_type": "code",
161
+ "execution_count": 26,
162
+ "id": "7f442566-4342-4840-9052-e5be41fe76d7",
163
+ "metadata": {},
164
+ "outputs": [
165
+ {
166
+ "data": {
167
+ "text/plain": [
168
+ "NextTokenModel(\n",
169
+ " (embedding): Embedding(50257, 256)\n",
170
+ " (rnn): GRU(256, 512, batch_first=True)\n",
171
+ " (fc): Linear(in_features=512, out_features=50257, bias=True)\n",
172
+ ")"
173
+ ]
174
+ },
175
+ "execution_count": 26,
176
+ "metadata": {},
177
+ "output_type": "execute_result"
178
+ }
179
+ ],
180
+ "source": [
181
+ "import torch\n",
182
+ "import torch.nn as nn\n",
183
+ "import torch.optim as optim\n",
184
+ "from torch.utils.data import DataLoader, TensorDataset\n",
185
+ "\n",
186
+ "# Neural Network model for next-token prediction\n",
187
+ "class NextTokenModel(nn.Module):\n",
188
+ " def __init__(self, vocab_size, embedding_dim, hidden_dim):\n",
189
+ " super(NextTokenModel, self).__init__()\n",
190
+ " self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
191
+ " self.rnn = nn.GRU(embedding_dim, hidden_dim, batch_first=True)\n",
192
+ " self.fc = nn.Linear(hidden_dim, vocab_size)\n",
193
+ " \n",
194
+ " def forward(self, x):\n",
195
+ " x = self.embedding(x)\n",
196
+ " rnn_out, _ = self.rnn(x)\n",
197
+ " logits = self.fc(rnn_out)\n",
198
+ " return logits\n",
199
+ "\n",
200
+ "# Create model\n",
201
+ "vocab_size = tokenizer.vocab_size\n",
202
+ "embedding_dim = 256\n",
203
+ "hidden_dim = 512\n",
204
+ "\n",
205
+ "model = NextTokenModel(vocab_size, embedding_dim, hidden_dim)\n",
206
+ "\n",
207
+ "# Loss and optimizer\n",
208
+ "criterion = nn.CrossEntropyLoss()\n",
209
+ "optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
210
+ "\n",
211
+ "# Move model to GPU if available\n",
212
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
213
+ "model.to(device)\n"
214
+ ]
215
+ },
216
+ {
217
+ "cell_type": "markdown",
218
+ "id": "22af2da3-5745-4f39-93a0-e58272073e54",
219
+ "metadata": {},
220
+ "source": [
221
+ "# Training and losses"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "execution_count": 28,
227
+ "id": "b79b57f2-83e2-446d-ac44-bea359c87b89",
228
+ "metadata": {},
229
+ "outputs": [
230
+ {
231
+ "name": "stdout",
232
+ "output_type": "stream",
233
+ "text": [
234
+ "Epoch 1, Train Loss: 7.73902153968811, Val Loss: 6.2885777950286865\n",
235
+ "Epoch 2, Train Loss: 3.731250762939453, Val Loss: 4.852449059486389\n",
236
+ "Checkpoint saved at checkpoint_epoch_2.pth\n",
237
+ "Epoch 3, Train Loss: 3.6915414333343506, Val Loss: 3.8921849131584167\n",
238
+ "Epoch 4, Train Loss: 2.490002751350403, Val Loss: 3.1142460107803345\n",
239
+ "Checkpoint saved at checkpoint_epoch_4.pth\n",
240
+ "Epoch 5, Train Loss: 2.497803032398224, Val Loss: 2.928856372833252\n",
241
+ "Epoch 6, Train Loss: 2.306287258863449, Val Loss: 2.9287983775138855\n",
242
+ "Checkpoint saved at checkpoint_epoch_6.pth\n",
243
+ "Epoch 7, Train Loss: 2.338519275188446, Val Loss: 3.0046048164367676\n",
244
+ "Epoch 8, Train Loss: 2.1667630076408386, Val Loss: 2.9524718821048737\n",
245
+ "Checkpoint saved at checkpoint_epoch_8.pth\n",
246
+ "Epoch 9, Train Loss: 2.4194843769073486, Val Loss: 2.948956310749054\n",
247
+ "Epoch 10, Train Loss: 2.283351480960846, Val Loss: 2.934361010789871\n",
248
+ "Checkpoint saved at checkpoint_epoch_10.pth\n"
249
+ ]
250
+ },
251
+ {
252
+ "data": {
253
+ "image/png": "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l+bz1KJyEkmlI3827M7G4XRhtahDrYiI1F5oaCiLFy82uwy/pBaVk+gSG0FIoIX8IgfbDtRt9kARERGpOwWVkwiwWujTuvTxz66G7SEuIiIiCiqnlKSJ30REREyjoHIKZRO/qUVFRESk4SmonELZVPppe3IoKjn5Og8iIiLiWQoqp9CueRi20ECKHE427cs1uxwREZEmRUHlFAzDOO7xT5a5xYiISL2df/75TJo0qfx9+/btefnll096jmEYfP755/W+t6eu05QoqNTAsQUKs8wtRESkCbv88stPOEHar7/+imEYrFmzptbXXblyJbfffnt9y6vgqaeeom/fvlX27927lxEjRnj0XpXNnj3bJxcXrCsFlRo4NvJHHWpFRMxy66238v3337Nz584qn7355pv07duX0047rdbXbdmyJWFhDbPwbHx8PMHBwQ1yr8ZCQaUGyjrUbt6fS0FRibnFiIg0UZdddhmxsbHMnj27wv6CggLmzp3LrbfeyqFDh7juuuto06YNYWFh9OnThw8++OCk16386GfLli2ce+65hISE0LNnz2rX43n44Yfp2rUrYWFhdOzYkcmTJ1NcXAy4WzSefvppUlNTMQwDwzDKa6786Gf9+vVceOGFhIaG0rx5c26//Xby8o5NMDp+/HhGjhzJP/7xDxISEmjevDkTJkwov1ddpKenc8UVVxAREUFUVBRjxoxh//795Z+npqZywQUXEBkZSVRUFP3792fVqlUA7Ny5k8svv5yYmBjCw8Pp1asX33zzTZ1rqQlNoV8D8bYQYiODycy189ueHAa2b2Z2SSIinuVyQXGBOfcODAPj1EuUBAQEcNNNNzF79myeeOIJjNJzPvroI4qKihg7diwFBQX079+fhx9+mKioKObNm8eNN95Ix44dOeOMM055D6fTyahRo2jRogXLly8nJyenQn+WMpGRkcyePZtWrVqxfv16/vznPxMZGclDDz3ENddcw4YNG5g/f375tPk2m63KNQoKChg+fDhnnnkmK1euJDMzk9tuu4277767Qhj74YcfSEhI4IcffuCPP/7gmmuuoW/fvvz5z38+5ddTmcvlYuTIkYSHh7N06VJKSkq46667uOaaa1iyZAkAY8eOpV+/fsyYMQOr1UpKSgqBgYEATJgwgaKiIn788UfCw8PZuHEjERERta6jNhRUaiipTTSL0/aTmpGloCIijU9xATzXypx7/3UPBIXX6NBbbrmFF198kSVLlnDBBRcA7sc+o0aNIiYmhpiYGB544IHy4ydOnMj8+fP56KOPahRUFi9eTFpaGjt27KBNmzYAPPfcc1X6lTz++OPl2+3bt+cvf/kLc+fO5aGHHiI0NJSIiAgCAgKIj48/4b3ee+89jh49yttvv014uPvrf/XVV7n88st54YUXiIuLAyAmJoZXX30Vq9VK9+7dufTSS/nuu+/qFFQWL17MunXr2L59O4mJiQC888479OrVi5UrVzJw4EDS09N58MEH6d69OwBdunQpPz89PZ3Ro0fTp08fADp27FjrGmpLj35qKFkTv4mImK579+4MGjSIN998E4CtW7fy008/ccsttwDgcDiYMmUKSUlJNG/enIiICBYuXEh6enqNrp+Wlkbbtm3LQwrAWWedVeW4jz/+mLPPPpv4+HgiIiKYPHlyje9x/L2Sk5PLQwrA4MGDcTqdbNq0qXxfr169sFqt5e8TEhLIzMys1b2Ov2diYmJ5SAHo2bMn0dHRpKWlAXD//fdz2223MXToUJ5//nm2bt1afuw999zDs88+y+DBg3nyySdZt25dneqoDbWo1FBSYjSgkT8i0kgFhrlbNsy6dy3ceuut3H333fzrX/9i1qxZtGvXjiFDhgAwbdo0pk+fzssvv0yfPn0IDw9n0qRJFBUV1ejaLperyj6j0mOp5cuXc+211/L0008zbNgwbDYbc+bMYdq0abX6OlwuV5VrV3fPsscux3/mdNZtAtIT3fP4/U899RTXX3898+bN49tvv+XJJ59kzpw5XHnlldx2220MGzaMefPmsXDhQqZOncq0adOYOHFineqpCbWo1FBS6eKEOw8VkFVQsx94ERG/YRjuxy9mvGrQP+V4Y8aMwWq18v777/PWW29x8803l/+S/emnn7jiiiu44YYbSE5OpmPHjmzZsqXG1+7Zsyfp6ens2XMstP36668Vjvnll19o164djz32GAMGDKBLly5VRiIFBQXhcDhOea+UlBTy8/MrXNtisdC1a9ca11wbZV9fRkZG+b6NGzeSnZ1Njx49yvd17dqV++67j4ULFzJq1ChmzZpV/lliYiJ33HEHn376KX/5y194/fXXvVJrGQWVGooJD6Jdc3fq1zBlERHzREREcM011/DXv/6VPXv2MH78+PLPOnfu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8VkKKiIiIuKzFFSq8e9//5sOHToQEhJC//79+emnn8wuqUmaOnUqAwcOJDIyktjYWEaOHMmmTZvMLktKTZ06FcMwmDRpktmlNGm7d+/mhhtuoHnz5oSFhdG3b19Wr15tdllNUklJCY8//jgdOnQgNDSUjh078swzz+B0Os0uza8pqFQyd+5cJk2axGOPPcbatWs555xzGDFiBOnp6WaX1uQsXbqUCRMmsHz5chYtWkRJSQkXX3wx+fn5ZpfW5K1cuZKZM2eSlJRkdilN2pEjRxg8eDCBgYF8++23bNy4kWnTphEdHW12aU3SCy+8wGuvvcarr75KWloaf//733nxxRf55z//aXZpfk3Dkys544wzOO2005gxY0b5vh49ejBy5EimTp1qYmVy4MABYmNjWbp0Keeee67Z5TRZeXl5nHbaafz73//m2WefpW/fvrz88stml9UkPfLII/zyyy9q9fURl112GXFxcbzxxhvl+0aPHk1YWBjvvPOOiZX5N7WoHKeoqIjVq1dz8cUXV9h/8cUXs2zZMpOqkjLZ2dkANGvWzORKmrYJEyZw6aWXMnToULNLafK+/PJLBgwYwNVXX01sbCz9+vXj9ddfN7usJuvss8/mu+++Y/PmzQCkpqby888/c8kll5hcmX/z60UJPe3gwYM4HA7i4uIq7I+Li2Pfvn0mVSXgXmnz/vvv5+yzz6Z3795ml9NkzZkzhzVr1rBy5UqzSxFg27ZtzJgxg/vvv5+//vWvrFixgnvuuYfg4GBuuukms8trch5++GGys7Pp3r07VqsVh8PBlClTuO6668wuza8pqFTDMIwK710uV5V90rDuvvtu1q1bx88//2x2KU1WRkYG9957LwsXLiQkJMTscgRwOp0MGDCA5557DoB+/frx22+/MWPGDAUVE8ydO5d3332X999/n169epGSksKkSZNo1aoV48aNM7s8v6WgcpwWLVpgtVqrtJ5kZmZWaWWRhjNx4kS+/PJLfvzxR9q0aWN2OU3W6tWryczMpH///uX7HA4HP/74I6+++ip2ux2r1WpihU1PQkICPXv2rLCvR48efPLJJyZV1LQ9+OCDPPLII1x77bUA9OnTh507dzJ16lQFlXpQH5XjBAUF0b9/fxYtWlRh/6JFixg0aJBJVTVdLpeLu+++m08//ZTvv/+eDh06mF1SkzZkyBDWr19PSkpK+WvAgAGMHTuWlJQUhRQTDB48uMqQ/c2bN9OuXTuTKmraCgoKsFgq/lq1Wq0anlxPalGp5P777+fGG29kwIABnHXWWcycOZP09HTuuOMOs0trciZMmMD777/PF198QWRkZHlLl81mIzQ01OTqmp7IyMgq/YPCw8Np3ry5+g2Z5L777mPQoEE899xzjBkzhhUrVjBz5kxmzpxpdmlN0uWXX86UKVNo27YtvXr1Yu3atbz00kvccsstZpfm31xSxb/+9S9Xu3btXEFBQa7TTjvNtXTpUrNLapKAal+zZs0yuzQpdd5557nuvfdes8to0r766itX7969XcHBwa7u3bu7Zs6caXZJTVZOTo7r3nvvdbVt29YVEhLi6tixo+uxxx5z2e12s0vza5pHRURERHyW+qiIiIiIz1JQEREREZ+loCIiIiI+S0FFREREfJaCioiIiPgsBRURERHxWQoqIiIi4rMUVETE7xmGweeff252GSLiBQoqIlIv48ePxzCMKq/hw4ebXZqINAJa60dE6m348OHMmjWrwr7g4GCTqhGRxkQtKiJSb8HBwcTHx1d4xcTEAO7HMjNmzGDEiBGEhobSoUMHPvroowrnr1+/ngsvvJDQ0FCaN2/O7bffTl5eXoVj3nzzTXr16kVwcDAJCQncfffdFT4/ePAgV155JWFhYXTp0oUvv/yy/LMjR44wduxYWrZsSWhoKF26dKkSrETENymoiIjXTZ48mdGjR5OamsoNN9zAddddR1paGgAFBQUMHz6cmJgYVq5cyUcffcTixYsrBJEZM2YwYcIEbr/9dtavX8+XX35J586dK9zj6aefZsyYMaxbt45LLrmEsWPHcvjw4fL7b9y4kW+//Za0tDRmzJhBixYtGu4vQETqzuxVEUXEv40bN85ltVpd4eHhFV7PPPOMy+Vyr4J9xx13VDjnjDPOcN15550ul8vlmjlzpismJsaVl5dX/vm8efNcFovFtW/fPpfL5XK1atXK9dhjj52wBsD1+OOPl7/Py8tzGYbh+vbbb10ul8t1+eWXu26++WbPfMEi0qDUR0VE6u2CCy5gxowZFfY1a9asfPuss86q8NlZZ51FSkoKAGlpaSQnJxMeHl7++eDBg3E6nWzatAnDMNizZw9Dhgw5aQ1JSUnl2+Hh4URGRpKZmQnAnXfeyejRo1mzZg0XX3wxI0eOZNCgQXX6WkWkYSmoiEi9hYeHV3kUcyqGYQDgcrnKt6s7JjQ0tEbXCwwMrHKu0+kEYMSIEezcuZN58+axePFihgwZwoQJE/jHP/5Rq5pFpOGpj4qIeN3y5curvO/evTsAPXv2JCUlhfz8/PLPf/nlFywWC127diUyMpL27dvz3Xff1auGli1bMn78eN59911efvllZs6cWa/riUjDUIuKiNSb3W5n3759FfYFBASUd1j96KOPGDBgAGeffTbvvfceK1as4I033gBg7NixPPnkk4wbN46nnnqKAwcOMHHiRG688Ubi4uIAeOqpp7jjjjuIjY1lxIgR5Obm8ssvvzBx4sQa1ffEE0/Qv39/evXqhd1u5+uvv6ZHjx4e/BsQEW9RUBGReps/fz4JCQkV9nXr1o3ff/8dcI/ImTNnDnfddRfx8fG899579OzZE4CwsDAWLFjAvffey8CBAwkLC2P06NG89NJL5dcaN24chYWFTJ8+nQceeIAWLVpw1VVX1bi+oKAgHn30UXbs2EFoaCjnnHMOc+bM8cBXLiLeZrhcLpfZRYhI42UYBp999hkjR440uxQR8UPqoyIiIiI+S0FFREREfJb6qIiIV+npsojUh1pURERExGcpqIiIiIjPUlARERERn6WgIiIiIj5LQUVERER8loKKiIiI+CwFFREREfFZCioiIiLisxRURERExGf9f8J8R2ewpuEiAAAAAElFTkSuQmCC",
254
+ "text/plain": [
255
+ "<Figure size 640x480 with 1 Axes>"
256
+ ]
257
+ },
258
+ "metadata": {},
259
+ "output_type": "display_data"
260
+ }
261
+ ],
262
+ "source": [
263
+ " import matplotlib.pyplot as plt\n",
264
+ "\n",
265
+ "# Create dataloaders\n",
266
+ "train_dataset = TensorDataset(torch.tensor(train_inputs), torch.tensor(train_outputs))\n",
267
+ "val_dataset = TensorDataset(torch.tensor(val_inputs), torch.tensor(val_outputs))\n",
268
+ "\n",
269
+ "train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\n",
270
+ "val_loader = DataLoader(val_dataset, batch_size=32)\n",
271
+ "\n",
272
+ "# Training function\n",
273
+ "def train(model, train_loader, val_loader, criterion, optimizer, epochs=10, checkpoint_interval=2):\n",
274
+ " train_losses = []\n",
275
+ " val_losses = []\n",
276
+ " \n",
277
+ " for epoch in range(epochs):\n",
278
+ " model.train()\n",
279
+ " train_loss = 0\n",
280
+ " \n",
281
+ " for inputs, targets in train_loader:\n",
282
+ " inputs, targets = inputs.to(device), targets.to(device)\n",
283
+ " \n",
284
+ " optimizer.zero_grad()\n",
285
+ " outputs = model(inputs)\n",
286
+ " \n",
287
+ " # Reshape outputs for loss calculation\n",
288
+ " loss = criterion(outputs.view(-1, vocab_size), targets.view(-1))\n",
289
+ " loss.backward()\n",
290
+ " optimizer.step()\n",
291
+ " \n",
292
+ " train_loss += loss.item()\n",
293
+ " \n",
294
+ " train_loss /= len(train_loader)\n",
295
+ " train_losses.append(train_loss)\n",
296
+ " \n",
297
+ " # Validation loss\n",
298
+ " model.eval()\n",
299
+ " val_loss = 0\n",
300
+ " with torch.no_grad():\n",
301
+ " for inputs, targets in val_loader:\n",
302
+ " inputs, targets = inputs.to(device), targets.to(device)\n",
303
+ " outputs = model(inputs)\n",
304
+ " loss = criterion(outputs.view(-1, vocab_size), targets.view(-1))\n",
305
+ " val_loss += loss.item()\n",
306
+ " \n",
307
+ " val_loss /= len(val_loader)\n",
308
+ " val_losses.append(val_loss)\n",
309
+ " \n",
310
+ " print(f\"Epoch {epoch+1}, Train Loss: {train_loss}, Val Loss: {val_loss}\")\n",
311
+ " \n",
312
+ " # Checkpoint saving\n",
313
+ " if (epoch + 1) % checkpoint_interval == 0:\n",
314
+ " checkpoint_path = f'checkpoint_epoch_{epoch+1}.pth'\n",
315
+ " torch.save(model.state_dict(), checkpoint_path)\n",
316
+ " print(f\"Checkpoint saved at {checkpoint_path}\")\n",
317
+ " \n",
318
+ " return train_losses, val_losses\n",
319
+ "\n",
320
+ "# Train the model\n",
321
+ "train_losses, val_losses = train(model, train_loader, val_loader, criterion, optimizer, epochs=10)\n",
322
+ "\n",
323
+ "# Plotting the loss curves\n",
324
+ "plt.plot(train_losses, label='Training Loss')\n",
325
+ "plt.plot(val_losses, label='Validation Loss')\n",
326
+ "plt.xlabel('Epochs')\n",
327
+ "plt.ylabel('Loss')\n",
328
+ "plt.legend()\n",
329
+ "plt.savefig('loss_curve.png')\n",
330
+ "plt.show()\n",
331
+ "\n",
332
+ "# Save the losses in a CSV file\n",
333
+ "loss_df = pd.DataFrame({'Epoch': range(1, 11), 'Train Loss': train_losses, 'Validation Loss': val_losses})\n",
334
+ "loss_df.to_csv('losses.csv', index=False)\n"
335
+ ]
336
+ },
337
+ {
338
+ "cell_type": "code",
339
+ "execution_count": 81,
340
+ "id": "4f38dafa-9979-4aa7-8c4b-a65de0b8cda3",
341
+ "metadata": {},
342
+ "outputs": [
343
+ {
344
+ "name": "stdout",
345
+ "output_type": "stream",
346
+ "text": [
347
+ "Epoch 1, Validation Perplexity: 538.3870875451362\n",
348
+ "Epoch 2, Validation Perplexity: 128.05361705905648\n",
349
+ "Epoch 3, Validation Perplexity: 49.01786939486888\n",
350
+ "Epoch 4, Validation Perplexity: 22.516446793441215\n",
351
+ "Epoch 5, Validation Perplexity: 18.706225311776535\n",
352
+ "Epoch 6, Validation Perplexity: 18.705140469723624\n",
353
+ "Epoch 7, Validation Perplexity: 20.178240411215985\n",
354
+ "Epoch 8, Validation Perplexity: 19.15323981208396\n",
355
+ "Epoch 9, Validation Perplexity: 19.086023452013098\n",
356
+ "Epoch 10, Validation Perplexity: 18.809480239422275\n"
357
+ ]
358
+ },
359
+ {
360
+ "data": {
361
+ "image/png": "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",
362
+ "text/plain": [
363
+ "<Figure size 640x480 with 1 Axes>"
364
+ ]
365
+ },
366
+ "metadata": {},
367
+ "output_type": "display_data"
368
+ }
369
+ ],
370
+ "source": [
371
+ "import torch\n",
372
+ "import numpy as np\n",
373
+ "import matplotlib.pyplot as plt\n",
374
+ "import pandas as pd\n",
375
+ "\n",
376
+ "# Calculate perplexity from validation losses\n",
377
+ "val_perplexities = [np.exp(loss) for loss in val_losses]\n",
378
+ "\n",
379
+ "# Print the validation perplexities for each epoch\n",
380
+ "for epoch, perplexity in enumerate(val_perplexities, 1):\n",
381
+ " print(f'Epoch {epoch}, Validation Perplexity: {perplexity}')\n",
382
+ "\n",
383
+ "# Plot the validation perplexity curve\n",
384
+ "plt.plot(val_perplexities, label='Validation Perplexity')\n",
385
+ "plt.xlabel('Epochs')\n",
386
+ "plt.ylabel('Perplexity')\n",
387
+ "plt.legend()\n",
388
+ "plt.title('Validation Perplexity Over Epochs')\n",
389
+ "plt.savefig('validation_perplexity_curve.png')\n",
390
+ "plt.show()\n",
391
+ "\n",
392
+ "# Optionally, save perplexity values to a CSV file\n",
393
+ "perplexity_df = pd.DataFrame({'Epoch': range(1, len(val_perplexities) + 1), 'Validation Perplexity': val_perplexities})\n",
394
+ "perplexity_df.to_csv('validation_perplexity.csv', index=False)\n"
395
+ ]
396
+ },
397
+ {
398
+ "cell_type": "markdown",
399
+ "id": "f2f48d30-a70f-4cef-bec5-69ba024e16b8",
400
+ "metadata": {},
401
+ "source": [
402
+ "# Next Token Prediction"
403
+ ]
404
+ },
405
+ {
406
+ "cell_type": "code",
407
+ "execution_count": 34,
408
+ "id": "fd89e131-200b-4089-a524-48d242f99b4c",
409
+ "metadata": {},
410
+ "outputs": [
411
+ {
412
+ "name": "stdout",
413
+ "output_type": "stream",
414
+ "text": [
415
+ "Random Model Output: Hello world England ax���������������\n"
416
+ ]
417
+ },
418
+ {
419
+ "name": "stderr",
420
+ "output_type": "stream",
421
+ "text": [
422
+ "/var/folders/fx/vbj5djls49z6lsrd_27sfk900000gn/T/ipykernel_2184/266914567.py:42: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
423
+ " model.load_state_dict(torch.load('checkpoint_epoch_10.pth')) # Load the final checkpoint\n"
424
+ ]
425
+ },
426
+ {
427
+ "name": "stdout",
428
+ "output_type": "stream",
429
+ "text": [
430
+ "Trained Model Output: Hello world England ax���������������\n",
431
+ "Assamese Model Output: Give three tips for staying healthy. nutritious nutritious withheld shaft Fight anarchistulate alludedtype revertedpendulate��\n"
432
+ ]
433
+ }
434
+ ],
435
+ "source": [
436
+ "# Function to generate text from the model\n",
437
+ "def generate_text(model, tokenizer, prompt, max_length=50):\n",
438
+ " model.eval()\n",
439
+ " inputs = tokenizer(prompt, return_tensors=\"pt\").input_ids.to(device)\n",
440
+ " outputs = model.generate(inputs, max_length=max_length)\n",
441
+ " return tokenizer.decode(outputs[0], skip_special_tokens=True)\n",
442
+ "\n",
443
+ "# Generate output from randomly initialized model\n",
444
+ "random_model_output = generate_text(model, tokenizer, prompt=\"Hello world\", max_length=50)\n",
445
+ "print(\"Random Model Output:\", random_model_output)\n",
446
+ "\n",
447
+ "# Generate output from trained model\n",
448
+ "model.load_state_dict(torch.load('checkpoint_epoch_10.pth')) # Load the final checkpoint\n",
449
+ "trained_model_output = generate_text(model, tokenizer, prompt=\"Hello world\", max_length=50)\n",
450
+ "print(\"Trained Model Output:\", trained_model_output)\n",
451
+ "\n",
452
+ "# Generate output in Assamese and translate to English using Google Translate manually\n",
453
+ "assamese_prompt = \"Give three tips for staying healthy.\"\n",
454
+ "assamese_output = generate_text(model, tokenizer, prompt=assamese_prompt, max_length=50)\n",
455
+ "print(\"Assamese Model Output:\", assamese_output)\n",
456
+ "\n",
457
+ " \n"
458
+ ]
459
+ },
460
+ {
461
+ "cell_type": "code",
462
+ "execution_count": 79,
463
+ "id": "fcbff2d4-6272-4815-ab78-44fa8f80bab6",
464
+ "metadata": {},
465
+ "outputs": [
466
+ {
467
+ "name": "stdout",
468
+ "output_type": "stream",
469
+ "text": [
470
+ "Random Model Output: Hello world England ax���������������\n"
471
+ ]
472
+ },
473
+ {
474
+ "name": "stderr",
475
+ "output_type": "stream",
476
+ "text": [
477
+ "/var/folders/fx/vbj5djls49z6lsrd_27sfk900000gn/T/ipykernel_2184/436038338.py:42: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
478
+ " model.load_state_dict(torch.load('checkpoint_epoch_10.pth')) # Load the final checkpoint\n"
479
+ ]
480
+ },
481
+ {
482
+ "name": "stdout",
483
+ "output_type": "stream",
484
+ "text": [
485
+ "Trained Model Output: Hello world England ax���������������\n",
486
+ "Assamese Model Output: Give three tips for staying healthy. nutritious nutritious withheld shaft Fight anarchistulate alludedtype revertedpendulate��\n"
487
+ ]
488
+ }
489
+ ],
490
+ "source": [
491
+ "import torch.nn.functional as F\n",
492
+ "\n",
493
+ "# Function to generate text from the model\n",
494
+ "def generate_text_custom(model, tokenizer, prompt, max_length=50):\n",
495
+ " model.eval()\n",
496
+ " input_ids = tokenizer(prompt, return_tensors=\"pt\").input_ids.to(device)\n",
497
+ " \n",
498
+ " generated_tokens = input_ids.tolist()[0] # Start with the input prompt\n",
499
+ " \n",
500
+ " # Manually generate tokens one by one\n",
501
+ " for _ in range(max_length):\n",
502
+ " # Convert current tokens to tensor\n",
503
+ " input_tensor = torch.tensor([generated_tokens]).to(device)\n",
504
+ " \n",
505
+ " # Get the model's output (logits)\n",
506
+ " with torch.no_grad():\n",
507
+ " logits = model(input_tensor)\n",
508
+ " \n",
509
+ " # Take the logits for the last token and apply softmax to get probabilities\n",
510
+ " next_token_logits = logits[0, -1, :]\n",
511
+ " next_token_probs = F.softmax(next_token_logits, dim=-1)\n",
512
+ " \n",
513
+ " # Sample the next token (or take the argmax for greedy decoding)\n",
514
+ " next_token = torch.argmax(next_token_probs).item()\n",
515
+ " \n",
516
+ " # Add the predicted token to the sequence\n",
517
+ " generated_tokens.append(next_token)\n",
518
+ " \n",
519
+ " # Stop if the model generates the end-of-sequence token\n",
520
+ " if next_token == tokenizer.eos_token_id:\n",
521
+ " break\n",
522
+ " \n",
523
+ " # Decode the generated tokens back into text\n",
524
+ " generated_text = tokenizer.decode(generated_tokens, skip_special_tokens=True)\n",
525
+ " return generated_text\n",
526
+ "\n",
527
+ "# Generate output from randomly initialized model\n",
528
+ "random_model_output = generate_text_custom(model, tokenizer, prompt=\"Hello world\", max_length=50)\n",
529
+ "print(\"Random Model Output:\", random_model_output)\n",
530
+ "\n",
531
+ "# Load trained model's checkpoint\n",
532
+ "model.load_state_dict(torch.load('checkpoint_epoch_10.pth')) # Load the final checkpoint\n",
533
+ "\n",
534
+ "# Generate output from the trained model\n",
535
+ "trained_model_output = generate_text_custom(model, tokenizer, prompt=\"Hello world\", max_length=50)\n",
536
+ "print(\"Trained Model Output:\", trained_model_output)\n",
537
+ "\n",
538
+ "# Generate output in Assamese\n",
539
+ "assamese_prompt = \"Give three tips for staying healthy.\"\n",
540
+ "assamese_output = generate_text_custom(model, tokenizer, prompt=assamese_prompt, max_length=50)\n",
541
+ "print(\"Assamese Model Output:\", assamese_output)\n",
542
+ "\n",
543
+ " "
544
+ ]
545
+ },
546
+ {
547
+ "cell_type": "code",
548
+ "execution_count": null,
549
+ "id": "f4c97bf9-81e1-4dae-8697-60e435c6d79f",
550
+ "metadata": {},
551
+ "outputs": [],
552
+ "source": []
553
+ }
554
+ ],
555
+ "metadata": {
556
+ "kernelspec": {
557
+ "display_name": "Python 3 (ipykernel)",
558
+ "language": "python",
559
+ "name": "python3"
560
+ },
561
+ "language_info": {
562
+ "codemirror_mode": {
563
+ "name": "ipython",
564
+ "version": 3
565
+ },
566
+ "file_extension": ".py",
567
+ "mimetype": "text/x-python",
568
+ "name": "python",
569
+ "nbconvert_exporter": "python",
570
+ "pygments_lexer": "ipython3",
571
+ "version": "3.12.4"
572
+ }
573
+ },
574
+ "nbformat": 4,
575
+ "nbformat_minor": 5
576
+ }
loss_curve.png ADDED
losses.csv ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Epochs,Train Loss,Validation Loss
2
+ 1,7.73902154,6.288577795
3
+ 2,3.731250763,4.852449059
4
+ 3,3.691541433,3.892184913
5
+ 4,2.490002751,3.114246011
6
+ 5,2.497803032,2.928856373
7
+ 6,2.306287259,2.928798378
8
+ 7,2.338519275,3.004604816
9
+ 8,2.166763008,2.952471882
10
+ 9,2.419484377,2.948956311
11
+ 10,2.283351481,2.934361011
validation_perplexity.csv ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Epoch,Validation Perplexity
2
+ 1,538.3870875451362
3
+ 2,128.05361705905648
4
+ 3,49.01786939486888
5
+ 4,22.516446793441215
6
+ 5,18.706225311776535
7
+ 6,18.705140469723624
8
+ 7,20.178240411215985
9
+ 8,19.15323981208396
10
+ 9,19.086023452013098
11
+ 10,18.809480239422275
validation_perplexity_curve.png ADDED