bozcomlekci commited on
Commit
e511c9d
Β·
verified Β·
1 Parent(s): 39ea127

Upload train.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. train.py +129 -0
train.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fine-tune Ministral 3B on SKILL.md dataset (runs in HF Space with GPU)."""
2
+ import os
3
+ import json
4
+ import torch
5
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
6
+ from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
7
+ from trl import SFTTrainer, SFTConfig
8
+ from datasets import load_dataset
9
+ from huggingface_hub import HfApi
10
+
11
+ # ── Config ──────────────────────────────────────────────────────────
12
+ HF_TOKEN = os.environ.get("HF_TOKEN", "")
13
+ DATASET_REPO = "bozcomlekci/skillscroll-skill-md"
14
+ BASE_MODEL = "LakoMoor/Ministral-3-3B-Text-Only"
15
+ OUTPUT_MODEL = "bozcomlekci/ministral-3b-skillscroll-lora"
16
+ OUTPUT_DIR = "/tmp/results"
17
+ MAX_SEQ_LENGTH = 4096
18
+
19
+ print("=" * 60)
20
+ print(f"Fine-tuning {BASE_MODEL}")
21
+ print(f"Dataset: {DATASET_REPO}")
22
+ print(f"Output: {OUTPUT_MODEL}")
23
+ print(f"GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'None'}")
24
+ print(f"VRAM: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB" if torch.cuda.is_available() else "No GPU")
25
+ print("=" * 60)
26
+
27
+ # ── Load dataset ────────────────────────────────────────────────────
28
+ dataset = load_dataset(DATASET_REPO, token=HF_TOKEN)
29
+ train_dataset = dataset["train"]
30
+ eval_dataset = dataset["test"]
31
+ print(f"Dataset: {len(train_dataset)} train, {len(eval_dataset)} eval")
32
+
33
+ # ── Load tokenizer ──────────────────────────────────────────────────
34
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, token=HF_TOKEN, trust_remote_code=True)
35
+ if tokenizer.pad_token is None:
36
+ tokenizer.pad_token = tokenizer.eos_token
37
+ tokenizer.padding_side = "right"
38
+
39
+ # ── Format with chat template ───────────────────────────────────────
40
+ def format_chat(example):
41
+ text = tokenizer.apply_chat_template(
42
+ example["messages"],
43
+ tokenize=False,
44
+ add_generation_prompt=False,
45
+ )
46
+ return {"text": text}
47
+
48
+ train_dataset = train_dataset.map(format_chat)
49
+ eval_dataset = eval_dataset.map(format_chat)
50
+
51
+ # ── Load model with 4-bit quantization (QLoRA) ──────────────────────
52
+ bnb_config = BitsAndBytesConfig(
53
+ load_in_4bit=True,
54
+ bnb_4bit_quant_type="nf4",
55
+ bnb_4bit_compute_dtype=torch.bfloat16,
56
+ bnb_4bit_use_double_quant=True,
57
+ )
58
+
59
+ model = AutoModelForCausalLM.from_pretrained(
60
+ BASE_MODEL,
61
+ quantization_config=bnb_config,
62
+ device_map="auto",
63
+ token=HF_TOKEN,
64
+ trust_remote_code=True,
65
+ )
66
+ model = prepare_model_for_kbit_training(model)
67
+
68
+ # ── LoRA ────────────────────────────────────────────────────────────
69
+ lora_config = LoraConfig(
70
+ r=16,
71
+ lora_alpha=32,
72
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
73
+ "gate_proj", "up_proj", "down_proj"],
74
+ lora_dropout=0.05,
75
+ bias="none",
76
+ task_type="CAUSAL_LM",
77
+ )
78
+ model = get_peft_model(model, lora_config)
79
+ model.print_trainable_parameters()
80
+
81
+ # ── Training ────────────────────────────────────────────────────────
82
+ training_args = SFTConfig(
83
+ output_dir=OUTPUT_DIR,
84
+ per_device_train_batch_size=2,
85
+ gradient_accumulation_steps=4,
86
+ num_train_epochs=3,
87
+ learning_rate=2e-4,
88
+ warmup_ratio=0.03,
89
+ lr_scheduler_type="cosine",
90
+ logging_steps=5,
91
+ eval_strategy="steps",
92
+ eval_steps=50,
93
+ save_strategy="epoch",
94
+ report_to="none",
95
+ bf16=True,
96
+ max_length=MAX_SEQ_LENGTH,
97
+ dataset_text_field="text",
98
+ gradient_checkpointing=True,
99
+ optim="paged_adamw_8bit",
100
+ )
101
+
102
+ trainer = SFTTrainer(
103
+ model=model,
104
+ args=training_args,
105
+ train_dataset=train_dataset,
106
+ eval_dataset=eval_dataset,
107
+ processing_class=tokenizer,
108
+ )
109
+
110
+ print("\nStarting training...")
111
+ trainer.train()
112
+
113
+ # ── Save & push to Hub ──────────────────────────────────────────────
114
+ print("\nSaving model...")
115
+ trainer.save_model(OUTPUT_DIR)
116
+ tokenizer.save_pretrained(OUTPUT_DIR)
117
+
118
+ print(f"Pushing LoRA adapter to {OUTPUT_MODEL}...")
119
+ api = HfApi(token=HF_TOKEN)
120
+ api.upload_folder(
121
+ folder_path=OUTPUT_DIR,
122
+ repo_id=OUTPUT_MODEL,
123
+ token=HF_TOKEN,
124
+ )
125
+ print(f"\nDone! Model pushed to https://huggingface.co/{OUTPUT_MODEL}")
126
+
127
+ # Signal completion
128
+ with open("/tmp/DONE", "w") as f:
129
+ f.write("Training complete")