fivetech/Harbour
041
1#!/usr/bin/env python32"""3Harbour Fine-tuning Script for Qwen3.6-35B-A3B (MoE)4Uses Unsloth + LoRA with GGUF quantized model5Optimized for CPU with 121GB RAM6"""7 8import json9import torch10from pathlib import Path11from datasets import Dataset12from unsloth import FastLanguageModel13from trl import SFTTrainer14from transformers import TrainingArguments15 16# Configuration17MODEL_NAME = "unsloth/Qwen3.6-35B-A3B-GGUF"18MODEL_FILE = "Qwen3.6-35B-A3B-UD-Q4_K_M.gguf"19TRAIN_FILE = Path("/home/fivetech/finetune/harbour_train.jsonl")20VAL_FILE = Path("/home/fivetech/finetune/harbour_val.jsonl")21OUTPUT_DIR = Path("/home/fivetech/finetune/output")22MAX_SEQ_LENGTH = 204823 24print("=" * 60)25print("Harbour Fine-tuning - Qwen3.6-35B-A3B (MoE) with Unsloth + LoRA")26print("=" * 60)27 28# 1. Load model from GGUF29print("\n1. Loading model from GGUF (Q4_K_M)...")30model, tokenizer = FastLanguageModel.from_pretrained(31 model_name=MODEL_NAME,32 gguf_file=MODEL_FILE,33 max_seq_length=MAX_SEQ_LENGTH,34 load_in_4bit=True,35 dtype=None,36)37 38# 2. LoRA configuration39print("2. Configuring LoRA...")40model = FastLanguageModel.get_peft_model(41 model,42 r=16,43 lora_alpha=32,44 lora_dropout=0.05,45 target_modules=["q_proj", "k_proj", "v_proj", "o_proj",46 "gate_proj", "up_proj", "down_proj"],47 bias="none",48 use_gradient_checkpointing="unsloth",49 random_state=42,50)51 52# 3. Load dataset53print("3. Loading dataset...")54 55def load_jsonl(path):56 data = []57 with open(path) as f:58 for line in f:59 data.append(json.loads(line))60 return data61 62train_data = load_jsonl(TRAIN_FILE)63val_data = load_jsonl(VAL_FILE)64 65print(f" Train: {len(train_data)} entries")66print(f" Val: {len(val_data)} entries")67 68# 4. Format conversations69print("4. Formatting conversations...")70 71def format_conversation(entry):72 messages = entry["messages"]73 text = tokenizer.apply_chat_template(74 messages,75 tokenize=False,76 add_generation_prompt=False,77 )78 return {"text": text}79 80train_dataset = Dataset.from_list([format_conversation(e) for e in train_data])81val_dataset = Dataset.from_list([format_conversation(e) for e in val_data])82 83# 5. Tokenize84print("5. Tokenizing...")85 86def tokenize_function(examples):87 return tokenizer(88 examples["text"],89 truncation=True,90 max_length=MAX_SEQ_LENGTH,91 padding=False,92 )93 94train_dataset = train_dataset.map(95 tokenize_function,96 batched=True,97 remove_columns=["text"],98 desc="Tokenizing train",99)100val_dataset = val_dataset.map(101 tokenize_function,102 batched=True,103 remove_columns=["text"],104 desc="Tokenizing val",105)106 107print(f" Train tokens: {sum(len(x) for x in train_dataset['input_ids']):,}")108print(f" Val tokens: {sum(len(x) for x in val_dataset['input_ids']):,}")109 110# 6. Training arguments111print("6. Setting up training...")112training_args = TrainingArguments(113 output_dir=str(OUTPUT_DIR),114 num_train_epochs=3,115 per_device_train_batch_size=1,116 gradient_accumulation_steps=16,117 learning_rate=1e-4,118 weight_decay=0.01,119 warmup_ratio=0.1,120 lr_scheduler_type="cosine",121 logging_steps=5,122 save_steps=50,123 save_total_limit=3,124 eval_strategy="steps",125 eval_steps=50,126 load_best_model_at_end=True,127 metric_for_best_model="eval_loss",128 bf16=False,129 fp16=False,130 dataloader_num_workers=1,131 report_to="none",132 remove_unused_columns=False,133 max_grad_norm=1.0,134 optim="adamw_8bit",135)136 137# 7. Create trainer138print("7. Creating trainer...")139trainer = SFTTrainer(140 model=model,141 tokenizer=tokenizer,142 args=training_args,143 train_dataset=train_dataset,144 eval_dataset=val_dataset,145 max_seq_length=MAX_SEQ_LENGTH,146 dataset_text_field="text",147)148 149# 8. Train150print("\n8. Starting training...")151print("=" * 60)152trainer.train()153 154# 9. Save LoRA adapter155print("\n9. Saving LoRA adapter...")156trainer.save_model(str(OUTPUT_DIR / "final"))157tokenizer.save_pretrained(str(OUTPUT_DIR / "final"))158 159# 10. Export to GGUF (optional)160print("\n10. Exporting to GGUF...")161model.save_pretrained_gguf(162 str(OUTPUT_DIR / "gguf"),163 tokenizer,164 quantization_method="q4_k_m",165)166 167print("\n" + "=" * 60)168print("Training complete!")169print(f"LoRA adapter saved to: {OUTPUT_DIR / 'final'}")170print(f"GGUF model saved to: {OUTPUT_DIR / 'gguf'}")171print("=" * 60)172 