Llama_3B_Fine_Tuning.ipynb ADDED
@@ -0,0 +1,645 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# πŸš€ **Maring Language Translation Fine-Tuning**\n",
8
+ "\n",
9
+ "**Model:** Llama-3.2-3B-Instruct \n",
10
+ "**Task:** English ↔ Maring Translation \n",
11
+ "**Hardware:** Tesla T4 (Free Colab) \n",
12
+ "**Time:** ~18-22 minutes \n",
13
+ "\n",
14
+ "## πŸ“‹ **Steps:**\n",
15
+ "1. βœ… Mount Google Drive\n",
16
+ "2. βœ… Upload training data \n",
17
+ "3. βœ… Install dependencies \n",
18
+ "4. βœ… Load model \n",
19
+ "5. βœ… Train model \n",
20
+ "6. βœ… Save to Drive \n",
21
+ "7. βœ… Test inference\n",
22
+ "\n",
23
+ "## 🎯 **Optimizations Applied:**\n",
24
+ "- **Batch Size:** 4 (better learning)\n",
25
+ "- **LoRA Rank:** 32 (higher capacity)\n",
26
+ "- **Mixed Precision:** fp16 (memory efficient)\n",
27
+ "- **Beam Search:** 3 beams (better quality)\n",
28
+ "- **Temperature:** 0.3 (natural responses)\n",
29
+ "- **Max Tokens:** 100 (detailed answers)"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "markdown",
34
+ "metadata": {},
35
+ "source": [
36
+ "## πŸ—‚οΈ **STEP 1: Mount Google Drive**\n",
37
+ "\n",
38
+ "**⚠️ IMPORTANT:** This saves all models directly to your Google Drive for fast download!"
39
+ ]
40
+ },
41
+ {
42
+ "cell_type": "code",
43
+ "execution_count": null,
44
+ "metadata": {},
45
+ "outputs": [],
46
+ "source": [
47
+ "from google.colab import drive\n",
48
+ "drive.mount('/content/drive')\n",
49
+ "\n",
50
+ "# Create folder for our models\n",
51
+ "!mkdir -p \"/content/drive/MyDrive/Maring_Translation_Model\"\n",
52
+ "print(\"βœ… Google Drive mounted successfully!\")\n",
53
+ "print(\"πŸ“ Models will be saved to: /content/drive/MyDrive/Maring_Translation_Model\")"
54
+ ]
55
+ },
56
+ {
57
+ "cell_type": "markdown",
58
+ "metadata": {},
59
+ "source": [
60
+ "## πŸ“€ **STEP 2: Upload Training Data**\n",
61
+ "\n",
62
+ "**Upload your `training_data_improved.json` file to Colab:**\n",
63
+ "1. Click the πŸ“ folder icon (left sidebar)\n",
64
+ "2. Click the πŸ“€ upload button \n",
65
+ "3. Select your `training_data_improved.json` file\n",
66
+ "4. Wait for green checkmark βœ…"
67
+ ]
68
+ },
69
+ {
70
+ "cell_type": "code",
71
+ "execution_count": null,
72
+ "metadata": {},
73
+ "outputs": [],
74
+ "source": [
75
+ "import os\n",
76
+ "\n",
77
+ "# Check if training data exists\n",
78
+ "if os.path.exists('training_data_improved.json'):\n",
79
+ " file_size = os.path.getsize('training_data_improved.json')\n",
80
+ " print(f\"βœ… training_data_improved.json found! Size: {file_size:,} bytes\")\n",
81
+ "\n",
82
+ " # Copy to Drive as backup\n",
83
+ " !cp training_data_improved.json \"/content/drive/MyDrive/Maring_Translation_Model/\"\n",
84
+ " print(\"πŸ“‹ Training data backed up to Google Drive\")\n",
85
+ "else:\n",
86
+ " print(\"❌ training_data_improved.json NOT found!\")\n",
87
+ " print(\"πŸ“€ Please upload the file using the folder icon on the left\")"
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "markdown",
92
+ "metadata": {},
93
+ "source": [
94
+ "## πŸ”§ **STEP 3: Install Dependencies**\n",
95
+ "\n",
96
+ "**This installs Unsloth and all required libraries.**"
97
+ ]
98
+ },
99
+ {
100
+ "cell_type": "code",
101
+ "execution_count": null,
102
+ "metadata": {},
103
+ "outputs": [],
104
+ "source": [
105
+ "%%capture\n",
106
+ "import os, re\n",
107
+ "if \"COLAB_\" not in \"\".join(os.environ.keys()):\n",
108
+ " !pip install unsloth\n",
109
+ "else:\n",
110
+ " import torch\n",
111
+ " v = re.match(r'[\\d]{1,}\\.[\\d]{1,}', str(torch.__version__)).group(0)\n",
112
+ " xformers = 'xformers==' + {'2.10':'0.0.34','2.9':'0.0.33.post1','2.8':'0.0.32.post2'}.get(v, \"0.0.34\")\n",
113
+ " !pip install sentencepiece protobuf \"datasets==4.3.0\" \"huggingface_hub>=0.34.0\" hf_transfer\n",
114
+ " !pip install --no-deps unsloth_zoo bitsandbytes accelerate {xformers} peft trl triton unsloth\n",
115
+ "\n",
116
+ "!pip install transformers==4.56.2\n",
117
+ "!pip install --no-deps trl==0.22.2\n",
118
+ "\n",
119
+ "print(\"βœ… All dependencies installed successfully!\")"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "markdown",
124
+ "metadata": {},
125
+ "source": [
126
+ "## πŸ€– **STEP 4: Load Model & Setup LoRA**\n",
127
+ "\n",
128
+ "**This loads Llama-3.2-3B-Instruct and prepares it for training.**"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "from unsloth import FastLanguageModel\n",
138
+ "import torch\n",
139
+ "\n",
140
+ "# Model configuration\n",
141
+ "max_seq_length = 2048\n",
142
+ "dtype = None # Auto-detect for T4\n",
143
+ "load_in_4bit = True\n",
144
+ "\n",
145
+ "print(\"πŸ”„ Loading Llama-3.2-3B-Instruct...\")\n",
146
+ "model, tokenizer = FastLanguageModel.from_pretrained(\n",
147
+ " model_name = \"unsloth/Llama-3.2-3B-Instruct\",\n",
148
+ " max_seq_length = max_seq_length,\n",
149
+ " dtype = dtype,\n",
150
+ " load_in_4bit = load_in_4bit,\n",
151
+ ")\n",
152
+ "\n",
153
+ "print(\"⚑ Adding LoRA adapters...\")\n",
154
+ "model = FastLanguageModel.get_peft_model(\n",
155
+ " model,\n",
156
+ " r = 8, # CRITICAL FIX: Lower rank for better generalization with 11k examples\n",
157
+ " lora_alpha = 16, # Keep alpha higher than rank for stability\n",
158
+ " target_modules = [\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\",\n",
159
+ " \"gate_proj\", \"up_proj\", \"down_proj\"],\n",
160
+ " lora_dropout = 0,\n",
161
+ " bias = \"none\",\n",
162
+ " use_gradient_checkpointing = \"unsloth\",\n",
163
+ " random_state = 3407,\n",
164
+ " use_rslora = False,\n",
165
+ " loftq_config = None,\n",
166
+ ")\n",
167
+ "\n",
168
+ "print(\"βœ… Model loaded and LoRA adapters added!\")"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "markdown",
173
+ "metadata": {},
174
+ "source": [
175
+ "## πŸ“Š **STEP 5: Load & Prepare Training Data**\n",
176
+ "\n",
177
+ "**This loads your JSON data and formats it for training.**"
178
+ ]
179
+ },
180
+ {
181
+ "cell_type": "code",
182
+ "execution_count": null,
183
+ "metadata": {},
184
+ "outputs": [],
185
+ "source": [
186
+ "from unsloth.chat_templates import get_chat_template, standardize_sharegpt\n",
187
+ "import json\n",
188
+ "from datasets import Dataset\n",
189
+ "import collections\n",
190
+ "\n",
191
+ "# FIXED: Use correct chat template for Llama-3.2\n",
192
+ "tokenizer = get_chat_template(\n",
193
+ " tokenizer,\n",
194
+ " chat_template = \"llama-3.1\",\n",
195
+ ")\n",
196
+ "\n",
197
+ "# FIXED: Define system prompt for KomoAI\n",
198
+ "SYSTEM_PROMPT = \"You are KomoAI 3B, an expert translator between English and Maring language developed by Moshilning Koninga. Provide accurate translations and cultural information about the Maring tribe.\"\n",
199
+ "\n",
200
+ "def load_training_data(file_path):\n",
201
+ " \"\"\"Load training data from JSON file\"\"\"\n",
202
+ " data = []\n",
203
+ " try:\n",
204
+ " with open(file_path, 'r', encoding='utf-8') as f:\n",
205
+ " for line in f:\n",
206
+ " line = line.strip()\n",
207
+ " if line:\n",
208
+ " data.append(json.loads(line))\n",
209
+ " except FileNotFoundError:\n",
210
+ " print(f\"❌ Error: {file_path} not found\")\n",
211
+ " return []\n",
212
+ " except json.JSONDecodeError as e:\n",
213
+ " print(f\"❌ Error parsing JSON: {e}\")\n",
214
+ " return []\n",
215
+ " return data\n",
216
+ "\n",
217
+ "def convert_to_chat_format(data):\n",
218
+ " \"\"\"Convert instruction/input/output to chat format\"\"\"\n",
219
+ " conversations = []\n",
220
+ " for item in data:\n",
221
+ " instruction = item['instruction']\n",
222
+ " input_text = item['input']\n",
223
+ " output_text = item['output']\n",
224
+ "\n",
225
+ " # FIXED: Use colon to match inference format\n",
226
+ " user_message = f\"{instruction}: {input_text}\"\n",
227
+ " conversation = [\n",
228
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
229
+ " {\"role\": \"user\", \"content\": user_message},\n",
230
+ " {\"role\": \"assistant\", \"content\": output_text}\n",
231
+ " ]\n",
232
+ " conversations.append({\"conversations\": conversation})\n",
233
+ " return conversations\n",
234
+ "\n",
235
+ "def formatting_prompts_func(examples):\n",
236
+ " convos = examples[\"conversations\"]\n",
237
+ " texts = [tokenizer.apply_chat_template(convo, tokenize = False, add_generation_prompt = False) for convo in convos]\n",
238
+ " return { \"text\" : texts }\n",
239
+ "\n",
240
+ "# Load and process data\n",
241
+ "print(\"πŸ“‚ Loading training data...\")\n",
242
+ "training_data = load_training_data('training_data_improved.json')\n",
243
+ "print(f\"πŸ“Š Loaded {len(training_data)} training examples\")\n",
244
+ "\n",
245
+ "# CRITICAL FIX: Check for duplicates before training\n",
246
+ "user_messages = [f\"{item['instruction']}: {item['input']}\" for item in training_data]\n",
247
+ "counts = collections.Counter(user_messages)\n",
248
+ "dupes = [(msg, cnt) for msg, cnt in counts.items() if cnt > 5]\n",
249
+ "print(f\"βœ… Unique examples: {len(counts)}\")\n",
250
+ "if dupes:\n",
251
+ " print(f\"⚠️ Found {len(dupes)} duplicated patterns:\")\n",
252
+ " for msg, cnt in dupes[:3]:\n",
253
+ " print(f\" - '{msg}' appears {cnt} times\")\n",
254
+ "\n",
255
+ "if len(training_data) > 0:\n",
256
+ " # Convert to chat format\n",
257
+ " chat_data = convert_to_chat_format(training_data)\n",
258
+ " dataset = Dataset.from_list(chat_data)\n",
259
+ "\n",
260
+ " # Apply standardization and formatting\n",
261
+ " dataset = standardize_sharegpt(dataset)\n",
262
+ " dataset = dataset.map(formatting_prompts_func, batched = True)\n",
263
+ "\n",
264
+ " print(f\"βœ… Dataset ready: {len(dataset)} examples\")\n",
265
+ " print(f\"πŸ“ Sample: {dataset[0]['conversations'][1]['content'][:50]}...\")\n",
266
+ "else:\n",
267
+ " print(\"❌ No training data loaded!\")"
268
+ ]
269
+ },
270
+ {
271
+ "cell_type": "markdown",
272
+ "metadata": {},
273
+ "source": [
274
+ "## πŸ‹οΈ **STEP 6: Start Training**\n",
275
+ "\n",
276
+ "**⏱️ This will take 18-22 minutes. Watch the progress bar!**"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": null,
282
+ "metadata": {},
283
+ "outputs": [],
284
+ "source": [
285
+ "from trl import SFTConfig, SFTTrainer\n",
286
+ "from transformers import DataCollatorForSeq2Seq\n",
287
+ "from unsloth.chat_templates import train_on_responses_only\n",
288
+ "\n",
289
+ "# Create trainer\n",
290
+ "trainer = SFTTrainer(\n",
291
+ " model = model,\n",
292
+ " tokenizer = tokenizer,\n",
293
+ " train_dataset = dataset,\n",
294
+ " dataset_text_field = \"text\",\n",
295
+ " max_seq_length = max_seq_length,\n",
296
+ " data_collator = DataCollatorForSeq2Seq(tokenizer = tokenizer),\n",
297
+ " packing = False,\n",
298
+ " args = SFTConfig(\n",
299
+ " per_device_train_batch_size = 4,\n",
300
+ " gradient_accumulation_steps = 2,\n",
301
+ " warmup_steps = 50, # OPTIMIZED: Proper warmup (not too high, not too low)\n",
302
+ " num_train_epochs = 6,\n",
303
+ " learning_rate = 1e-4, # Slightly lower for stability\n",
304
+ " logging_steps = 10,\n",
305
+ " optim = \"adamw_8bit\",\n",
306
+ " weight_decay = 0.01, # Better regularization\n",
307
+ " lr_scheduler_type = \"cosine\", # Better final convergence\n",
308
+ " seed = 3407,\n",
309
+ " output_dir = \"outputs\",\n",
310
+ " report_to = \"none\",\n",
311
+ " # CRITICAL FIX: Remove fp16 and gradient_checkpointing - Unsloth handles these\n",
312
+ " ),\n",
313
+ ")\n",
314
+ "\n",
315
+ "# FIXED: Apply response masking for Llama-3.2 format\n",
316
+ "trainer = train_on_responses_only(\n",
317
+ " trainer,\n",
318
+ " instruction_part = \"<|start_header_id|>user<|end_header_id|>\\n\\n\",\n",
319
+ " response_part = \"<|start_header_id|>assistant<|end_header_id|>\\n\\n\",\n",
320
+ ")\n",
321
+ "\n",
322
+ "# Calculate actual total steps dynamically\n",
323
+ "total_steps = (len(dataset) // 8) * 6 # Dynamic calculation\n",
324
+ "\n",
325
+ "print(\"πŸš€ Starting training...\")\n",
326
+ "print(f\"πŸ“Š Training 6 epochs on {len(dataset)} examples\")\n",
327
+ "print(f\"πŸ”„ Total steps: ~{total_steps}\")\n",
328
+ "print(f\"πŸ”₯ Warmup: 50 steps ({50/total_steps*100:.1f}% of training)\")\n",
329
+ "\n",
330
+ "# Start training\n",
331
+ "trainer_stats = trainer.train()\n",
332
+ "\n",
333
+ "print(\"πŸŽ‰ Training completed!\")\n",
334
+ "print(f\"⏱️ Training time: {trainer_stats.metrics['train_runtime']:.1f} seconds\")"
335
+ ]
336
+ },
337
+ {
338
+ "cell_type": "markdown",
339
+ "metadata": {},
340
+ "source": [
341
+ "## πŸ’Ύ **STEP 7: Save Models to Google Drive**\n",
342
+ "\n",
343
+ "**All models will be saved to your Google Drive for fast download!**"
344
+ ]
345
+ },
346
+ {
347
+ "cell_type": "code",
348
+ "execution_count": null,
349
+ "metadata": {},
350
+ "outputs": [],
351
+ "source": [
352
+ "# Define save paths in Google Drive\n",
353
+ "drive_path = \"/content/drive/MyDrive/Maring_Translation_Model\"\n",
354
+ "lora_path = f\"{drive_path}/llama_maring_lora\"\n",
355
+ "gguf_path = f\"{drive_path}/llama_maring_gguf\"\n",
356
+ "\n",
357
+ "print(\"πŸ’Ύ Saving models to Google Drive...\")\n",
358
+ "\n",
359
+ "# FIXED: Clear cache before saving to prevent OOM\n",
360
+ "import torch\n",
361
+ "torch.cuda.empty_cache()\n",
362
+ "\n",
363
+ "# 1. Save LoRA adapters (main trained model)\n",
364
+ "print(\"πŸ“ Saving LoRA adapters...\")\n",
365
+ "model.save_pretrained(lora_path)\n",
366
+ "tokenizer.save_pretrained(lora_path)\n",
367
+ "print(f\"βœ… LoRA saved to: {lora_path}\")\n",
368
+ "\n",
369
+ "# 2. Save GGUF format (for fast local inference)\n",
370
+ "print(\"\\nπŸ”„ Converting to GGUF format...\")\n",
371
+ "model.save_pretrained_gguf(\n",
372
+ " gguf_path,\n",
373
+ " tokenizer,\n",
374
+ " quantization_method = \"q4_k_m\" # Recommended for good balance\n",
375
+ ")\n",
376
+ "print(f\"βœ… GGUF saved to: {gguf_path}\")\n",
377
+ "\n",
378
+ "# 3. Save 16-bit merged model (full model) - only if enough space\n",
379
+ "print(\"\\nπŸ”„ Saving 16-bit merged model...\")\n",
380
+ "try:\n",
381
+ " model.save_pretrained_merged(\n",
382
+ " f\"{drive_path}/llama_maring_16bit\",\n",
383
+ " tokenizer,\n",
384
+ " save_method = \"merged_16bit\"\n",
385
+ " )\n",
386
+ " print(f\"βœ… 16-bit model saved to: {drive_path}/llama_maring_16bit\")\n",
387
+ "except RuntimeError as e:\n",
388
+ " if \"no disk space\" in str(e):\n",
389
+ " print(\"⚠️ Not enough space for 16-bit model (this is normal)\")\n",
390
+ " print(\"βœ… LoRA and GGUF files are sufficient for most uses\")\n",
391
+ " else:\n",
392
+ " raise e\n",
393
+ "\n",
394
+ "print(\"\\nπŸŽ‰ All models saved to Google Drive!\")\n",
395
+ "print(\"πŸ“‚ Check your Drive: MyDrive/Maring_Translation_Model\")"
396
+ ]
397
+ },
398
+ {
399
+ "cell_type": "markdown",
400
+ "metadata": {},
401
+ "source": [
402
+ "## πŸ§ͺ **STEP 8: Test the Trained Model**\n",
403
+ "\n",
404
+ "**Test your fine-tuned translation model!**"
405
+ ]
406
+ },
407
+ {
408
+ "cell_type": "code",
409
+ "execution_count": null,
410
+ "metadata": {},
411
+ "outputs": [],
412
+ "source": [
413
+ "from unsloth.chat_templates import get_chat_template\n",
414
+ "from transformers import TextStreamer\n",
415
+ "\n",
416
+ "# Setup for inference\n",
417
+ "tokenizer = get_chat_template(tokenizer, chat_template = \"llama-3.1\")\n",
418
+ "FastLanguageModel.for_inference(model)\n",
419
+ "\n",
420
+ "print(\"πŸ§ͺ Testing translation capabilities...\\n\")\n",
421
+ "\n",
422
+ "# Test 1: English to Maring\n",
423
+ "print(\"πŸ“ Test 1: English to Maring\")\n",
424
+ "messages = [\n",
425
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
426
+ " {\"role\": \"user\", \"content\": \"Translate to Maring: gate\"}\n",
427
+ "]\n",
428
+ "inputs = tokenizer.apply_chat_template(\n",
429
+ " messages, tokenize = True, add_generation_prompt = True, return_tensors = \"pt\"\n",
430
+ ").to(\"cuda\")\n",
431
+ "\n",
432
+ "# CRITICAL FIX: Use beam search for translation (deterministic)\n",
433
+ "outputs = model.generate(\n",
434
+ " input_ids = inputs, \n",
435
+ " max_new_tokens = 64, # Reduced for single-word translations\n",
436
+ " use_cache = True,\n",
437
+ " num_beams = 3, # Beam search for quality\n",
438
+ " do_sample = False, # CRITICAL: Must be False with num_beams > 1\n",
439
+ " repetition_penalty = 1.1,\n",
440
+ ")\n",
441
+ "# IMPROVED: Better output parsing with special token removal\n",
442
+ "result = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0].split(\"assistant\")[-1].strip()\n",
443
+ "# Remove any trailing special tokens\n",
444
+ "result = result.replace(\"<|eot_id|>\", \"\").replace(\"<|end_of_text|>\", \"\").strip()\n",
445
+ "print(f\"πŸ”€ Result: {result}\\n\")\n",
446
+ "\n",
447
+ "# Test 2: Maring to English\n",
448
+ "print(\"πŸ“ Test 2: Maring to English\")\n",
449
+ "messages = [\n",
450
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
451
+ " {\"role\": \"user\", \"content\": \"Translate to English: Pater\"}\n",
452
+ "]\n",
453
+ "inputs = tokenizer.apply_chat_template(\n",
454
+ " messages, tokenize = True, add_generation_prompt = True, return_tensors = \"pt\"\n",
455
+ ").to(\"cuda\")\n",
456
+ "\n",
457
+ "# CRITICAL FIX: Use beam search for translation (deterministic)\n",
458
+ "outputs = model.generate(\n",
459
+ " input_ids = inputs, \n",
460
+ " max_new_tokens = 64, # Reduced for single-word translations\n",
461
+ " use_cache = True,\n",
462
+ " num_beams = 3, # Beam search for quality\n",
463
+ " do_sample = False, # CRITICAL: Must be False with num_beams > 1\n",
464
+ " repetition_penalty = 1.1,\n",
465
+ ")\n",
466
+ "result = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0].split(\"assistant\")[-1].strip()\n",
467
+ "# Remove any trailing special tokens\n",
468
+ "result = result.replace(\"<|eot_id|>\", \"\").replace(\"<|end_of_text|>\", \"\").strip()\n",
469
+ "print(f\"πŸ”€ Result: {result}\\n\")\n",
470
+ "\n",
471
+ "# Test 3: Cultural question (use sampling for variety)\n",
472
+ "print(\"πŸ“ Test 3: Cultural Question\")\n",
473
+ "messages = [\n",
474
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
475
+ " {\"role\": \"user\", \"content\": \"What is the prefix for the first-born son in Maring?\"}\n",
476
+ "]\n",
477
+ "inputs = tokenizer.apply_chat_template(\n",
478
+ " messages, tokenize = True, add_generation_prompt = True, return_tensors = \"pt\"\n",
479
+ ").to(\"cuda\")\n",
480
+ "\n",
481
+ "text_streamer = TextStreamer(tokenizer, skip_prompt = True)\n",
482
+ "print(\"πŸ”€ Streaming result: \")\n",
483
+ "# CRITICAL FIX: Use sampling for Q&A (not translation)\n",
484
+ "_ = model.generate(\n",
485
+ " input_ids = inputs, \n",
486
+ " streamer = text_streamer, \n",
487
+ " max_new_tokens = 150, # More tokens for detailed answers\n",
488
+ " use_cache = True, \n",
489
+ " num_beams = 1, # Single beam for Q&A\n",
490
+ " do_sample = True, # CRITICAL: Enable sampling for variety\n",
491
+ " temperature = 0.3, # Temperature for sampling\n",
492
+ " repetition_penalty = 1.1,\n",
493
+ ")\n",
494
+ "\n",
495
+ "print(\"\\nβœ… Model testing completed!\")"
496
+ ]
497
+ },
498
+ {
499
+ "cell_type": "markdown",
500
+ "metadata": {},
501
+ "source": [
502
+ "## πŸ’¬ **Interactive Model Testing**\n",
503
+ "\n",
504
+ "Use the cell below to test your fine-tuned model with custom prompts. Type your question or translation request and press Enter."
505
+ ]
506
+ },
507
+ {
508
+ "cell_type": "code",
509
+ "execution_count": null,
510
+ "metadata": {},
511
+ "outputs": [],
512
+ "source": [
513
+ "from unsloth.chat_templates import get_chat_template\n",
514
+ "from transformers import TextStreamer\n",
515
+ "\n",
516
+ "print(\"✨ Welcome to the Interactive Translation Tester! ✨\")\n",
517
+ "print(\"----------------------------------------------------\")\n",
518
+ "print(\"Type your translation request in English or Maring.\\n\")\n",
519
+ "print(\"Examples: 'Translate to Maring: hello' or 'Translate to English: Kumka'\\n\")\n",
520
+ "print(\"Type 'quit' to exit.\\n\")\n",
521
+ "\n",
522
+ "# Loop to allow continuous testing\n",
523
+ "while True:\n",
524
+ " user_input = input(\"➑️ Your input: \")\n",
525
+ " if user_input.lower().strip() == 'quit':\n",
526
+ " break\n",
527
+ " elif not user_input.strip():\n",
528
+ " print(\"Please enter some text.\")\n",
529
+ " continue\n",
530
+ "\n",
531
+ " # Detect if this is a translation or Q&A\n",
532
+ " is_translation = any(word in user_input.lower() for word in ['translate', 'convert', 'say', 'meaning of', 'what does'])\n",
533
+ " \n",
534
+ " # Format the input with system prompt\n",
535
+ " messages = [\n",
536
+ " {\"role\": \"system\", \"content\": SYSTEM_PROMPT},\n",
537
+ " {\"role\": \"user\", \"content\": user_input}\n",
538
+ " ]\n",
539
+ " inputs = tokenizer.apply_chat_template(\n",
540
+ " messages, tokenize = True, add_generation_prompt = True, return_tensors = \"pt\"\n",
541
+ " ).to(\"cuda\")\n",
542
+ "\n",
543
+ " # Generate the response\n",
544
+ " print(\"πŸ€– Model's Response:\")\n",
545
+ " text_streamer = TextStreamer(tokenizer, skip_prompt = True, clean_up_tokenization_spaces = True)\n",
546
+ " \n",
547
+ " # CRITICAL FIX: Use different parameters based on task type\n",
548
+ " if is_translation:\n",
549
+ " # For translations: use beam search (deterministic)\n",
550
+ " _ = model.generate(\n",
551
+ " input_ids = inputs,\n",
552
+ " streamer = text_streamer,\n",
553
+ " max_new_tokens = 64, # Shorter for translations\n",
554
+ " use_cache = True,\n",
555
+ " num_beams = 3, # Beam search\n",
556
+ " do_sample = False, # No sampling with beams\n",
557
+ " repetition_penalty = 1.1,\n",
558
+ " )\n",
559
+ " else:\n",
560
+ " # For Q&A: use sampling (more variety)\n",
561
+ " _ = model.generate(\n",
562
+ " input_ids = inputs,\n",
563
+ " streamer = text_streamer,\n",
564
+ " max_new_tokens = 150, # Longer for detailed answers\n",
565
+ " use_cache = True,\n",
566
+ " num_beams = 1, # Single beam\n",
567
+ " do_sample = True, # Enable sampling\n",
568
+ " temperature = 0.3, # Temperature for variety\n",
569
+ " repetition_penalty = 1.1,\n",
570
+ " )\n",
571
+ " \n",
572
+ " print(\"\\n----------------------------------------------------\")\n",
573
+ "\n",
574
+ "print(\"πŸ‘‹ Interactive testing ended. Thank you!\")"
575
+ ]
576
+ },
577
+ {
578
+ "cell_type": "markdown",
579
+ "metadata": {},
580
+ "source": [
581
+ "## πŸ“‚ **STEP 9: Download Models from Google Drive**\n",
582
+ "\n",
583
+ "**Your models are now in Google Drive! Download them anytime:**\n",
584
+ "\n",
585
+ "### πŸ“ **Files Created:**\n",
586
+ "- `llama_maring_lora/` - **LoRA adapters** (small, for loading with base model)\n",
587
+ "- `llama_maring_gguf.q4_k_m.gguf` - **GGUF format** (ready for local inference)\n",
588
+ "- `llama_maring_16bit/` - **Full 16-bit model** (larger, highest quality)\n",
589
+ "\n",
590
+ "### πŸš€ **How to Download:**\n",
591
+ "1. Open Google Drive (drive.google.com)\n",
592
+ "2. Go to `My Drive > Maring_Translation_Model`\n",
593
+ "3. Right-click any file/folder β†’ Download\n",
594
+ "\n",
595
+ "### πŸ’‘ **Recommended Usage:**\n",
596
+ "- **For development:** Use `llama_maring_lora/` (small, fast)\n",
597
+ "- **For deployment:** Use `llama_maring_gguf.q4_k_m.gguf` (single file)\n",
598
+ "- **For best quality:** Use `llama_maring_16bit/` (larger, most accurate)"
599
+ ]
600
+ },
601
+ {
602
+ "cell_type": "markdown",
603
+ "metadata": {},
604
+ "source": [
605
+ "## πŸŽ‰ **TRAINING COMPLETE!**\n",
606
+ "\n",
607
+ "### βœ… **What You Accomplished:**\n",
608
+ "- βœ… Fine-tuned Llama-3.2-3B on English-Maring translation\n",
609
+ "- βœ… Used improved training data with consistent translations\n",
610
+ "- βœ… Saved models in multiple formats\n",
611
+ "- βœ… Tested translation capabilities\n",
612
+ "- βœ… All files safely stored in Google Drive\n",
613
+ "\n",
614
+ "### πŸš€ **Next Steps:**\n",
615
+ "1. Download models from Google Drive\n",
616
+ "2. Use GGUF file with llama.cpp for local inference\n",
617
+ "3. Deploy LoRA adapters with Hugging Face\n",
618
+ "4. Share your translation model!\n",
619
+ "\n",
620
+ "**🎊 Congratulations on your improved Maring translation model!**"
621
+ ]
622
+ }
623
+ ],
624
+ "metadata": {
625
+ "kernelspec": {
626
+ "display_name": "Python 3",
627
+ "language": "python",
628
+ "name": "python3"
629
+ },
630
+ "language_info": {
631
+ "codemirror_mode": {
632
+ "name": "ipython",
633
+ "version": 3
634
+ },
635
+ "file_extension": ".py",
636
+ "mimetype": "text/x-python",
637
+ "name": "python",
638
+ "nbconvert_exporter": "python",
639
+ "pygments_lexer": "ipython3",
640
+ "version": "3.8.10"
641
+ }
642
+ },
643
+ "nbformat": 4,
644
+ "nbformat_minor": 4
645
+ }
training_data_improved.json ADDED
The diff for this file is too large to render. See raw diff