GautamKishore commited on
Commit
9cddb7c
·
verified ·
1 Parent(s): 1e14b9f

Complete rewrite: single setup cell, all imports in cell 1

Browse files
Files changed (1) hide show
  1. brahmi_lora_qlora.ipynb +82 -161
brahmi_lora_qlora.ipynb CHANGED
@@ -2,79 +2,60 @@
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
5
- "metadata": {
6
- "id": "heading"
7
- },
8
  "source": [
9
- "# Bharat-Tiny-LLM: LoRA/QLoRA Fine-tuning\n",
10
  "\n",
11
- "**Goal**: Fine-tune the full Qwen2.5-1.5B model with LoRA adapters to improve\n",
12
- "Hindi generation quality with the 300 new Devanagari tokens.\n",
13
  "\n",
14
- "**Approach**: QLoRA (4-bit quantized LoRA) for memory efficiency on T4 GPU.\n",
15
- "Trains attention layers while keeping base weights frozen.\n",
16
  "\n",
17
- "**Hardware**: T4 GPU (Colab free tier). ~2-3 hours.\n",
18
- "\n",
19
- "**Before starting**: Paste your HF_TOKEN below."
20
  ]
21
  },
22
  {
23
  "cell_type": "code",
24
  "execution_count": null,
25
- "metadata": {
26
- "id": "install"
27
- },
28
  "outputs": [],
29
  "source": [
30
- "import os\n",
31
- "from transformers import TrainingArguments\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  "\n",
33
- "DRIVE_DIR = '/content/drive/MyDrive/brahmi_lora'\n",
34
- "CKPT_DIR = os.path.join(DRIVE_DIR, 'checkpoints')\n",
35
- "os.makedirs(CKPT_DIR, exist_ok=True)\n",
36
  "\n",
37
- "training_args = TrainingArguments(\n",
38
- " output_dir=CKPT_DIR,\n",
39
- " num_train_epochs=2,\n",
40
- " per_device_train_batch_size=4,\n",
41
- " per_device_eval_batch_size=4,\n",
42
- " gradient_accumulation_steps=4,\n",
43
- " learning_rate=2e-4,\n",
44
- " weight_decay=0.01,\n",
45
- " warmup_ratio=0.1,\n",
46
- " lr_scheduler_type='cosine',\n",
47
- " logging_steps=25,\n",
48
- " eval_strategy='steps',\n",
49
- " eval_steps=100,\n",
50
- " save_strategy='steps',\n",
51
- " save_steps=100,\n",
52
- " save_total_limit=3,\n",
53
- " load_best_model_at_end=True,\n",
54
- " metric_for_best_model='eval_loss',\n",
55
- " greater_is_better=False,\n",
56
- " bf16=True,\n",
57
- " gradient_checkpointing=True,\n",
58
- " gradient_checkpointing_kwargs={'use_reentrant': False},\n",
59
- " optim='paged_adamw_8bit',\n",
60
- " max_grad_norm=1.0,\n",
61
- " report_to='none',\n",
62
- ")\n",
63
  "\n",
64
- "print(f'Effective batch size: {training_args.per_device_train_batch_size * training_args.gradient_accumulation_steps}')"
 
 
 
65
  ]
66
  },
67
  {
68
  "cell_type": "code",
69
  "execution_count": null,
70
- "metadata": {
71
- "id": "load_model"
72
- },
73
  "outputs": [],
74
  "source": [
75
- "MODEL_ID = 'eulogik/Bharat-Tiny-LLM-v2'\n",
76
- "\n",
77
- "# 4-bit quantization config (QLoRA)\n",
78
  "bnb_config = BitsAndBytesConfig(\n",
79
  " load_in_4bit=True,\n",
80
  " bnb_4bit_quant_type='nf4',\n",
@@ -82,7 +63,6 @@
82
  " bnb_4bit_use_double_quant=True,\n",
83
  ")\n",
84
  "\n",
85
- "print(f'Loading {MODEL_ID} in 4-bit...')\n",
86
  "tok = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\n",
87
  "if tok.pad_token is None:\n",
88
  " tok.pad_token = tok.eos_token\n",
@@ -96,25 +76,20 @@
96
  "\n",
97
  "model = prepare_model_for_kbit_training(model)\n",
98
  "\n",
99
- "# Identify new tokens\n",
100
  "new_ids = sorted(\n",
101
  " tid for tid, t in tok.added_tokens_decoder.items()\n",
102
  " if not str(t).startswith('<') and not getattr(t, 'special', False)\n",
103
  ")\n",
104
- "new_id_set = set(new_ids)\n",
105
  "print(f'Found {len(new_ids)} new tokens')\n",
106
- "print(f'Model loaded: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M params')"
107
  ]
108
  },
109
  {
110
  "cell_type": "code",
111
  "execution_count": null,
112
- "metadata": {
113
- "id": "lora_config"
114
- },
115
  "outputs": [],
116
  "source": [
117
- "# LoRA configuration\n",
118
  "lora_config = LoraConfig(\n",
119
  " task_type=TaskType.CAUSAL_LM,\n",
120
  " r=16,\n",
@@ -125,20 +100,15 @@
125
  ")\n",
126
  "\n",
127
  "model = get_peft_model(model, lora_config)\n",
128
- "model.print_trainable_parameters()\n",
129
- "\n"
130
  ]
131
  },
132
  {
133
  "cell_type": "code",
134
  "execution_count": null,
135
- "metadata": {
136
- "id": "data_load"
137
- },
138
  "outputs": [],
139
  "source": [
140
- "import requests, gzip, shutil\n",
141
- "\n",
142
  "DATA_URL = 'https://huggingface.co/eulogik/Bharat-Tiny-LLM-v2/resolve/main/train_gold_v3.jsonl.gz'\n",
143
  "DATA_FILE = '/content/train_gold_v3.jsonl'\n",
144
  "\n",
@@ -152,9 +122,7 @@
152
  " with gzip.open('/content/data.gz', 'rb') as gz, open(DATA_FILE, 'wb') as f:\n",
153
  " shutil.copyfileobj(gz, f)\n",
154
  " os.remove('/content/data.gz')\n",
155
- " print(f'Ready! {os.path.getsize(DATA_FILE) / 1e6:.0f} MB')\n",
156
  "\n",
157
- "from datasets import load_dataset\n",
158
  "dataset = load_dataset('text', data_files=DATA_FILE, split='train')\n",
159
  "print(f'Loaded {len(dataset)} rows')"
160
  ]
@@ -162,19 +130,15 @@
162
  {
163
  "cell_type": "code",
164
  "execution_count": null,
165
- "metadata": {
166
- "id": "tokenize"
167
- },
168
  "outputs": [],
169
  "source": [
170
  "CHUNKS_FILE = os.path.join(DRIVE_DIR, 'lora_chunks.json')\n",
171
  "\n",
172
  "if os.path.exists(CHUNKS_FILE):\n",
173
- " print('Loading cached chunks from Drive...')\n",
174
  " with open(CHUNKS_FILE) as f:\n",
175
  " all_chunks = json.load(f)\n",
176
- " random.shuffle(all_chunks)\n",
177
- " print(f'Loaded {len(all_chunks)} chunks')\n",
178
  "else:\n",
179
  " all_chunks = []\n",
180
  " for i, example in enumerate(dataset):\n",
@@ -194,12 +158,11 @@
194
  " print(f' Processed {i}/{len(dataset)} rows...')\n",
195
  "\n",
196
  " random.shuffle(all_chunks)\n",
197
- " # Cap at 20K chunks for feasible T4 training\n",
198
  " if len(all_chunks) > 20000:\n",
199
  " all_chunks = all_chunks[:20000]\n",
200
  " with open(CHUNKS_FILE, 'w') as f:\n",
201
  " json.dump(all_chunks, f)\n",
202
- " print(f'\\nTotal chunks: {len(all_chunks)}')\n",
203
  "\n",
204
  "split = int(len(all_chunks) * 0.95)\n",
205
  "train_chunks = all_chunks[:split]\n",
@@ -210,12 +173,10 @@
210
  {
211
  "cell_type": "code",
212
  "execution_count": null,
213
- "metadata": {
214
- "id": "dataset_class"
215
- },
216
  "outputs": [],
217
  "source": [
218
- "class ChunkDataset(torch.utils.data.Dataset):\n",
219
  " def __init__(self, chunks, max_len=512):\n",
220
  " self.chunks = chunks\n",
221
  " self.max_len = max_len\n",
@@ -225,26 +186,23 @@
225
  "\n",
226
  " def __getitem__(self, idx):\n",
227
  " ids = self.chunks[idx][:self.max_len]\n",
228
- " # Pad to max_len\n",
229
  " padded = ids + [tok.pad_token_id] * (self.max_len - len(ids))\n",
230
- " attention_mask = [1] * len(ids) + [0] * (self.max_len - len(ids))\n",
231
  " return {\n",
232
  " 'input_ids': torch.tensor(padded, dtype=torch.long),\n",
233
- " 'attention_mask': torch.tensor(attention_mask, dtype=torch.long),\n",
234
  " 'labels': torch.tensor(padded, dtype=torch.long),\n",
235
  " }\n",
236
  "\n",
237
  "train_dataset = ChunkDataset(train_chunks)\n",
238
  "val_dataset = ChunkDataset(val_chunks)\n",
239
- "print(f'Train dataset: {len(train_dataset)} samples')"
240
  ]
241
  },
242
  {
243
  "cell_type": "code",
244
  "execution_count": null,
245
- "metadata": {
246
- "id": "training_args"
247
- },
248
  "outputs": [],
249
  "source": [
250
  "CKPT_DIR = os.path.join(DRIVE_DIR, 'checkpoints')\n",
@@ -252,19 +210,19 @@
252
  "\n",
253
  "training_args = TrainingArguments(\n",
254
  " output_dir=CKPT_DIR,\n",
255
- " num_train_epochs=3,\n",
256
- " per_device_train_batch_size=2,\n",
257
- " per_device_eval_batch_size=2,\n",
258
- " gradient_accumulation_steps=8,\n",
259
  " learning_rate=2e-4,\n",
260
  " weight_decay=0.01,\n",
261
  " warmup_ratio=0.1,\n",
262
  " lr_scheduler_type='cosine',\n",
263
- " logging_steps=50,\n",
264
  " eval_strategy='steps',\n",
265
- " eval_steps=200,\n",
266
  " save_strategy='steps',\n",
267
- " save_steps=200,\n",
268
  " save_total_limit=3,\n",
269
  " load_best_model_at_end=True,\n",
270
  " metric_for_best_model='eval_loss',\n",
@@ -277,19 +235,6 @@
277
  " report_to='none',\n",
278
  ")\n",
279
  "\n",
280
- "print(f'Effective batch size: {training_args.per_device_train_batch_size * training_args.gradient_accumulation_steps}')"
281
- ]
282
- },
283
- {
284
- "cell_type": "code",
285
- "execution_count": null,
286
- "metadata": {
287
- "id": "train"
288
- },
289
- "outputs": [],
290
- "source": [
291
- "from transformers import Trainer\n",
292
- "\n",
293
  "trainer = Trainer(\n",
294
  " model=model,\n",
295
  " args=training_args,\n",
@@ -297,86 +242,71 @@
297
  " eval_dataset=val_dataset,\n",
298
  ")\n",
299
  "\n",
300
- "# Resume from checkpoint if exists\n",
301
- "resume_ckpt = None\n",
302
- "CKPT_DIR = '/content/drive/MyDrive/brahmi_lora/checkpoints'\n",
303
- "if os.path.exists(CKPT_DIR):\n",
304
- " checkpoints = [d for d in os.listdir(CKPT_DIR) if d.startswith('checkpoint-')]\n",
305
- " if checkpoints:\n",
306
- " latest = max(checkpoints, key=lambda x: int(x.split('-')[1]))\n",
307
- " resume_ckpt = os.path.join(CKPT_DIR, latest)\n",
308
- " print(f'Resuming from {latest}')\n",
309
  "\n",
 
 
310
  "print('Starting training...')\n",
311
- "trainer.train(resume_from_checkpoint=resume_ckpt)"
312
  ]
313
  },
314
  {
315
  "cell_type": "code",
316
  "execution_count": null,
317
- "metadata": {
318
- "id": "save_upload"
319
- },
320
  "outputs": [],
321
  "source": [
322
- "import os\n",
323
- "\n",
324
- "DRIVE_DIR = '/content/drive/MyDrive/brahmi_lora'\n",
325
  "ADAPTER_DIR = os.path.join(DRIVE_DIR, 'lora_adapter')\n",
326
  "model.save_pretrained(ADAPTER_DIR)\n",
327
  "tok.save_pretrained(ADAPTER_DIR)\n",
328
- "print(f'LoRA adapter saved to {ADAPTER_DIR}')\n",
329
  "\n",
330
- "from huggingface_hub import HfApi\n",
331
  "api = HfApi(token=HF_TOKEN)\n",
332
- "\n",
333
  "api.upload_folder(\n",
334
  " folder_path=ADAPTER_DIR,\n",
335
  " repo_id='eulogik/Bharat-Tiny-LLM-v2-LoRA',\n",
336
  " repo_type='model',\n",
337
- " commit_message='LoRA adapter: 3 epochs, 2e-4 LR, rank=16',\n",
338
  ")\n",
339
- "print('Uploaded to HF!')\n",
340
- "print('https://huggingface.co/eulogik/Bharat-Tiny-LLM-v2-LoRA')"
341
  ]
342
  },
343
  {
344
  "cell_type": "code",
345
  "execution_count": null,
346
- "metadata": {
347
- "id": "merge_upload"
348
- },
349
  "outputs": [],
350
  "source": [
351
- "import os\n",
352
- "\n",
353
- "DRIVE_DIR = '/content/drive/MyDrive/brahmi_lora'\n",
354
  "print('Merging LoRA into base model...')\n",
355
- "merged_model = model.merge_and_unload()\n",
356
  "\n",
357
- "MERGED_DIR = os.path.join(DRIVE_DIR, 'merged_model')\n",
358
- "merged_model.save_pretrained(MERGED_DIR)\n",
359
  "tok.save_pretrained(MERGED_DIR)\n",
360
  "print(f'Merged model saved to {MERGED_DIR}')\n",
361
  "\n",
362
- "from huggingface_hub import HfApi\n",
363
  "api = HfApi(token=HF_TOKEN)\n",
364
  "api.upload_folder(\n",
365
  " folder_path=MERGED_DIR,\n",
366
  " repo_id='eulogik/Bharat-Tiny-LLM-v2',\n",
367
  " repo_type='model',\n",
368
- " commit_message='LoRA merged: improved Hindi generation',\n",
369
  ")\n",
370
- "print('Merged model uploaded!')\n",
371
- "print('https://huggingface.co/eulogik/Bharat-Tiny-LLM-v2')"
372
  ]
373
  },
374
  {
375
  "cell_type": "code",
376
  "execution_count": null,
377
- "metadata": {
378
- "id": "generate"
379
- },
380
  "outputs": [],
381
  "source": [
382
  "prompts = [\n",
@@ -395,27 +325,18 @@
395
  " repetition_penalty=1.25,\n",
396
  " do_sample=True,\n",
397
  " )\n",
398
- " gen = tok.decode(out[0][inputs.input_ids.shape[-1]:],\n",
399
- " skip_special_tokens=True)\n",
400
  " print(f'Prompt: {p}')\n",
401
- " print(f' -> {gen}')\n",
402
- " print()"
403
  ]
404
  }
405
  ],
406
  "metadata": {
407
  "accelerator": "GPU",
408
- "colab": {
409
- "provenance": []
410
- },
411
- "kernelspec": {
412
- "display_name": "Python 3",
413
- "name": "python3"
414
- },
415
- "language_info": {
416
- "name": "python"
417
- }
418
  },
419
  "nbformat": 4,
420
  "nbformat_minor": 0
421
- }
 
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
5
+ "metadata": {"id": "heading"},
 
 
6
  "source": [
7
+ "# Bharat-Tiny-LLM v2: QLoRA Fine-tuning\n",
8
  "\n",
9
+ "**Goal**: Fine-tune Qwen2.5-1.5B (with 300 new Devanagari tokens) using QLoRA.\n",
10
+ "This teaches the model to USE the new tokens for coherent Hindi generation.\n",
11
  "\n",
12
+ "**Hardware**: T4 GPU (Colab free). ~1 hour for 20K chunks, 2 epochs.\n",
 
13
  "\n",
14
+ "**DO NOT run cells manually** use Runtime Run all."
 
 
15
  ]
16
  },
17
  {
18
  "cell_type": "code",
19
  "execution_count": null,
20
+ "metadata": {"id": "setup"},
 
 
21
  "outputs": [],
22
  "source": [
23
+ "!pip install -q transformers torch datasets accelerate huggingface_hub peft bitsandbytes\n",
24
+ "\n",
25
+ "import json, os, math, time, random, requests, gzip, shutil\n",
26
+ "import numpy as np\n",
27
+ "import torch\n",
28
+ "import torch.nn as nn\n",
29
+ "from torch.utils.data import DataLoader, Dataset\n",
30
+ "from transformers import (\n",
31
+ " AutoTokenizer, AutoModelForCausalLM,\n",
32
+ " BitsAndBytesConfig, TrainingArguments, Trainer\n",
33
+ ")\n",
34
+ "from peft import LoraConfig, get_peft_model, TaskType, prepare_model_for_kbit_training\n",
35
+ "from huggingface_hub import login, HfApi\n",
36
+ "from google.colab import drive\n",
37
+ "from datasets import load_dataset\n",
38
  "\n",
39
+ "# === CONFIG ===\n",
40
+ "HF_TOKEN = \"hf_YOUR_TOKEN_HERE\"\n",
41
+ "MODEL_ID = 'eulogik/Bharat-Tiny-LLM-v2'\n",
42
  "\n",
43
+ "drive.mount('/content/drive')\n",
44
+ "DRIVE_DIR = '/content/drive/MyDrive/brahmi_lora'\n",
45
+ "os.makedirs(DRIVE_DIR, exist_ok=True)\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  "\n",
47
+ "login(token=HF_TOKEN)\n",
48
+ "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
49
+ "print(f'Device: {device}')\n",
50
+ "print(f'Drive: {DRIVE_DIR}')"
51
  ]
52
  },
53
  {
54
  "cell_type": "code",
55
  "execution_count": null,
56
+ "metadata": {"id": "load_model"},
 
 
57
  "outputs": [],
58
  "source": [
 
 
 
59
  "bnb_config = BitsAndBytesConfig(\n",
60
  " load_in_4bit=True,\n",
61
  " bnb_4bit_quant_type='nf4',\n",
 
63
  " bnb_4bit_use_double_quant=True,\n",
64
  ")\n",
65
  "\n",
 
66
  "tok = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\n",
67
  "if tok.pad_token is None:\n",
68
  " tok.pad_token = tok.eos_token\n",
 
76
  "\n",
77
  "model = prepare_model_for_kbit_training(model)\n",
78
  "\n",
 
79
  "new_ids = sorted(\n",
80
  " tid for tid, t in tok.added_tokens_decoder.items()\n",
81
  " if not str(t).startswith('<') and not getattr(t, 'special', False)\n",
82
  ")\n",
 
83
  "print(f'Found {len(new_ids)} new tokens')\n",
84
+ "print(f'Params: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M')"
85
  ]
86
  },
87
  {
88
  "cell_type": "code",
89
  "execution_count": null,
90
+ "metadata": {"id": "lora"},
 
 
91
  "outputs": [],
92
  "source": [
 
93
  "lora_config = LoraConfig(\n",
94
  " task_type=TaskType.CAUSAL_LM,\n",
95
  " r=16,\n",
 
100
  ")\n",
101
  "\n",
102
  "model = get_peft_model(model, lora_config)\n",
103
+ "model.print_trainable_parameters()"
 
104
  ]
105
  },
106
  {
107
  "cell_type": "code",
108
  "execution_count": null,
109
+ "metadata": {"id": "download_data"},
 
 
110
  "outputs": [],
111
  "source": [
 
 
112
  "DATA_URL = 'https://huggingface.co/eulogik/Bharat-Tiny-LLM-v2/resolve/main/train_gold_v3.jsonl.gz'\n",
113
  "DATA_FILE = '/content/train_gold_v3.jsonl'\n",
114
  "\n",
 
122
  " with gzip.open('/content/data.gz', 'rb') as gz, open(DATA_FILE, 'wb') as f:\n",
123
  " shutil.copyfileobj(gz, f)\n",
124
  " os.remove('/content/data.gz')\n",
 
125
  "\n",
 
126
  "dataset = load_dataset('text', data_files=DATA_FILE, split='train')\n",
127
  "print(f'Loaded {len(dataset)} rows')"
128
  ]
 
130
  {
131
  "cell_type": "code",
132
  "execution_count": null,
133
+ "metadata": {"id": "tokenize"},
 
 
134
  "outputs": [],
135
  "source": [
136
  "CHUNKS_FILE = os.path.join(DRIVE_DIR, 'lora_chunks.json')\n",
137
  "\n",
138
  "if os.path.exists(CHUNKS_FILE):\n",
 
139
  " with open(CHUNKS_FILE) as f:\n",
140
  " all_chunks = json.load(f)\n",
141
+ " print(f'Loaded {len(all_chunks)} chunks from Drive')\n",
 
142
  "else:\n",
143
  " all_chunks = []\n",
144
  " for i, example in enumerate(dataset):\n",
 
158
  " print(f' Processed {i}/{len(dataset)} rows...')\n",
159
  "\n",
160
  " random.shuffle(all_chunks)\n",
 
161
  " if len(all_chunks) > 20000:\n",
162
  " all_chunks = all_chunks[:20000]\n",
163
  " with open(CHUNKS_FILE, 'w') as f:\n",
164
  " json.dump(all_chunks, f)\n",
165
+ " print(f'Total chunks: {len(all_chunks)} (saved to Drive)')\n",
166
  "\n",
167
  "split = int(len(all_chunks) * 0.95)\n",
168
  "train_chunks = all_chunks[:split]\n",
 
173
  {
174
  "cell_type": "code",
175
  "execution_count": null,
176
+ "metadata": {"id": "dataset"},
 
 
177
  "outputs": [],
178
  "source": [
179
+ "class ChunkDataset(Dataset):\n",
180
  " def __init__(self, chunks, max_len=512):\n",
181
  " self.chunks = chunks\n",
182
  " self.max_len = max_len\n",
 
186
  "\n",
187
  " def __getitem__(self, idx):\n",
188
  " ids = self.chunks[idx][:self.max_len]\n",
 
189
  " padded = ids + [tok.pad_token_id] * (self.max_len - len(ids))\n",
190
+ " mask = [1] * len(ids) + [0] * (self.max_len - len(ids))\n",
191
  " return {\n",
192
  " 'input_ids': torch.tensor(padded, dtype=torch.long),\n",
193
+ " 'attention_mask': torch.tensor(mask, dtype=torch.long),\n",
194
  " 'labels': torch.tensor(padded, dtype=torch.long),\n",
195
  " }\n",
196
  "\n",
197
  "train_dataset = ChunkDataset(train_chunks)\n",
198
  "val_dataset = ChunkDataset(val_chunks)\n",
199
+ "print(f'Train: {len(train_dataset)}, Val: {len(val_dataset)}')"
200
  ]
201
  },
202
  {
203
  "cell_type": "code",
204
  "execution_count": null,
205
+ "metadata": {"id": "train"},
 
 
206
  "outputs": [],
207
  "source": [
208
  "CKPT_DIR = os.path.join(DRIVE_DIR, 'checkpoints')\n",
 
210
  "\n",
211
  "training_args = TrainingArguments(\n",
212
  " output_dir=CKPT_DIR,\n",
213
+ " num_train_epochs=2,\n",
214
+ " per_device_train_batch_size=4,\n",
215
+ " per_device_eval_batch_size=4,\n",
216
+ " gradient_accumulation_steps=4,\n",
217
  " learning_rate=2e-4,\n",
218
  " weight_decay=0.01,\n",
219
  " warmup_ratio=0.1,\n",
220
  " lr_scheduler_type='cosine',\n",
221
+ " logging_steps=25,\n",
222
  " eval_strategy='steps',\n",
223
+ " eval_steps=100,\n",
224
  " save_strategy='steps',\n",
225
+ " save_steps=100,\n",
226
  " save_total_limit=3,\n",
227
  " load_best_model_at_end=True,\n",
228
  " metric_for_best_model='eval_loss',\n",
 
235
  " report_to='none',\n",
236
  ")\n",
237
  "\n",
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  "trainer = Trainer(\n",
239
  " model=model,\n",
240
  " args=training_args,\n",
 
242
  " eval_dataset=val_dataset,\n",
243
  ")\n",
244
  "\n",
245
+ "# Resume from last checkpoint if exists\n",
246
+ "checkpoints = [d for d in os.listdir(CKPT_DIR) if d.startswith('checkpoint-')]\n",
247
+ "resume = None\n",
248
+ "if checkpoints:\n",
249
+ " latest = max(checkpoints, key=lambda x: int(x.split('-')[1]))\n",
250
+ " resume = os.path.join(CKPT_DIR, latest)\n",
251
+ " print(f'Resuming from {latest}')\n",
 
 
252
  "\n",
253
+ "stats = training_args.per_device_train_batch_size * training_args.gradient_accumulation_steps\n",
254
+ "print(f'Effective batch size: {stats}')\n",
255
  "print('Starting training...')\n",
256
+ "trainer.train(resume_from_checkpoint=resume)"
257
  ]
258
  },
259
  {
260
  "cell_type": "code",
261
  "execution_count": null,
262
+ "metadata": {"id": "save_upload"},
 
 
263
  "outputs": [],
264
  "source": [
265
+ "# Save LoRA adapter to Drive and HF\n",
 
 
266
  "ADAPTER_DIR = os.path.join(DRIVE_DIR, 'lora_adapter')\n",
267
  "model.save_pretrained(ADAPTER_DIR)\n",
268
  "tok.save_pretrained(ADAPTER_DIR)\n",
269
+ "print(f'LoRA saved to {ADAPTER_DIR}')\n",
270
  "\n",
 
271
  "api = HfApi(token=HF_TOKEN)\n",
 
272
  "api.upload_folder(\n",
273
  " folder_path=ADAPTER_DIR,\n",
274
  " repo_id='eulogik/Bharat-Tiny-LLM-v2-LoRA',\n",
275
  " repo_type='model',\n",
276
+ " commit_message='LoRA: 2 epochs, rank=16, 2e-4',\n",
277
  ")\n",
278
+ "print('Uploaded LoRA to HF!')"
 
279
  ]
280
  },
281
  {
282
  "cell_type": "code",
283
  "execution_count": null,
284
+ "metadata": {"id": "merge"},
 
 
285
  "outputs": [],
286
  "source": [
287
+ "# Merge LoRA into base and upload\n",
 
 
288
  "print('Merging LoRA into base model...')\n",
289
+ "merged = model.merge_and_unload()\n",
290
  "\n",
291
+ "MERGED_DIR = os.path.join(DRIVE_DIR, 'merged')\n",
292
+ "merged.save_pretrained(MERGED_DIR)\n",
293
  "tok.save_pretrained(MERGED_DIR)\n",
294
  "print(f'Merged model saved to {MERGED_DIR}')\n",
295
  "\n",
 
296
  "api = HfApi(token=HF_TOKEN)\n",
297
  "api.upload_folder(\n",
298
  " folder_path=MERGED_DIR,\n",
299
  " repo_id='eulogik/Bharat-Tiny-LLM-v2',\n",
300
  " repo_type='model',\n",
301
+ " commit_message='LoRA merged: rank=16, 2 epochs',\n",
302
  ")\n",
303
+ "print('Merged model uploaded to HF!')"
 
304
  ]
305
  },
306
  {
307
  "cell_type": "code",
308
  "execution_count": null,
309
+ "metadata": {"id": "generate"},
 
 
310
  "outputs": [],
311
  "source": [
312
  "prompts = [\n",
 
325
  " repetition_penalty=1.25,\n",
326
  " do_sample=True,\n",
327
  " )\n",
328
+ " gen = tok.decode(out[0][inputs.input_ids.shape[-1]:], skip_special_tokens=True)\n",
 
329
  " print(f'Prompt: {p}')\n",
330
+ " print(f' -> {gen}\\n')"
 
331
  ]
332
  }
333
  ],
334
  "metadata": {
335
  "accelerator": "GPU",
336
+ "colab": {"provenance": []},
337
+ "kernelspec": {"display_name": "Python 3", "name": "python3"},
338
+ "language_info": {"name": "python"}
 
 
 
 
 
 
 
339
  },
340
  "nbformat": 4,
341
  "nbformat_minor": 0
342
+ }