Upload folder using huggingface_hub
Browse files- training/train_fsdp_full.py +210 -0
- training/train_full.py +204 -0
training/train_fsdp_full.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Red Rock — Full Fine-Tuning Script (No LoRA)
|
| 3 |
+
Target: < 2 hours on 1× H100 (80GB) or 1× A100 (80GB)
|
| 4 |
+
Updates ALL 7 billion parameters.
|
| 5 |
+
|
| 6 |
+
Estimate:
|
| 7 |
+
- 5,000 examples × 2048 max_len ÷ batch_eff_4 = 1,250 steps/epoch
|
| 8 |
+
- 3 epochs = 3,750 steps
|
| 9 |
+
- ~1.8 sec/step on H100 with BF16 + gradient checkpointing
|
| 10 |
+
- Total: ~1.9 hours on H100, ~1.7 hours on 2× A100
|
| 11 |
+
"""
|
| 12 |
+
import os
|
| 13 |
+
import torch
|
| 14 |
+
from datasets import load_dataset
|
| 15 |
+
from transformers import (
|
| 16 |
+
AutoModelForCausalLM,
|
| 17 |
+
AutoTokenizer,
|
| 18 |
+
TrainingArguments,
|
| 19 |
+
Trainer,
|
| 20 |
+
DataCollatorForLanguageModeling,
|
| 21 |
+
EarlyStoppingCallback
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# ============================================================
|
| 25 |
+
# PATHS — Adjust if your folder structure differs
|
| 26 |
+
# ============================================================
|
| 27 |
+
MODEL_PATH = "./model/qwen2.5-coder-7b-instruct-base"
|
| 28 |
+
OUTPUT_DIR = "./outputs/algorythm-prandtl-aero-7b-fft-v2"
|
| 29 |
+
DATASET_PATH = "./datasets/synthetic_nozzles.json"
|
| 30 |
+
|
| 31 |
+
# ============================================================
|
| 32 |
+
# DETECT HARDWARE
|
| 33 |
+
# ============================================================
|
| 34 |
+
NUM_GPUS = torch.cuda.device_count() if torch.cuda.is_available() else 0
|
| 35 |
+
GPU_NAME = torch.cuda.get_device_name(0) if NUM_GPUS > 0 else "CPU"
|
| 36 |
+
GPU_MEM = torch.cuda.get_device_properties(0).total_mem / 1e9 if NUM_GPUS > 0 else 0
|
| 37 |
+
|
| 38 |
+
print(f"╔══════════════════════════════════════════════════════╗")
|
| 39 |
+
print(f"║ AlgoRythm Prandtl Aero — Full Fine-Tuning (FFT) ║")
|
| 40 |
+
print(f"║ GPU: {GPU_NAME[:40]:<40s} ║")
|
| 41 |
+
print(f"║ VRAM: {GPU_MEM:.0f} GB × {NUM_GPUS} GPU(s) ║")
|
| 42 |
+
print(f"║ Mode: FULL PARAMETER UPDATE (7B params, NO LoRA) ║")
|
| 43 |
+
print(f"╚══════════════════════════════════════════════════════╝")
|
| 44 |
+
|
| 45 |
+
# ============================================================
|
| 46 |
+
# HYPERPARAMETERS — Optimized for < 2hr on 1× H100/A100
|
| 47 |
+
# ============================================================
|
| 48 |
+
# Batch size tuning:
|
| 49 |
+
# H100 80GB BF16 + grad ckpt: batch_size=2 fits comfortably (~60GB peak)
|
| 50 |
+
# A100 80GB BF16 + grad ckpt: batch_size=2 fits (~65GB peak)
|
| 51 |
+
# A100 40GB: batch_size=1 + more grad_accum
|
| 52 |
+
if GPU_MEM >= 70:
|
| 53 |
+
BATCH_SIZE = 2
|
| 54 |
+
GRAD_ACCUM = 2 # Effective batch = 4
|
| 55 |
+
MAX_LEN = 2048
|
| 56 |
+
elif GPU_MEM >= 35:
|
| 57 |
+
BATCH_SIZE = 1
|
| 58 |
+
GRAD_ACCUM = 4 # Effective batch = 4
|
| 59 |
+
MAX_LEN = 1536
|
| 60 |
+
else:
|
| 61 |
+
BATCH_SIZE = 1
|
| 62 |
+
GRAD_ACCUM = 4
|
| 63 |
+
MAX_LEN = 1024
|
| 64 |
+
|
| 65 |
+
# Use FSDP only when multi-GPU
|
| 66 |
+
USE_FSDP = NUM_GPUS > 1
|
| 67 |
+
|
| 68 |
+
def train():
|
| 69 |
+
print(f"\n[1/5] Loading tokenizer from {MODEL_PATH}...")
|
| 70 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
|
| 71 |
+
if tokenizer.pad_token is None:
|
| 72 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 73 |
+
|
| 74 |
+
print(f"[2/5] Loading 7B model in BF16 (full precision, NO quantization)...")
|
| 75 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 76 |
+
MODEL_PATH,
|
| 77 |
+
torch_dtype=torch.bfloat16,
|
| 78 |
+
trust_remote_code=True,
|
| 79 |
+
use_cache=False, # Must disable for gradient checkpointing
|
| 80 |
+
attn_implementation="eager", # Safest for training
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
# Enable gradient checkpointing (trades compute for VRAM)
|
| 84 |
+
model.gradient_checkpointing_enable()
|
| 85 |
+
|
| 86 |
+
# Verify: ALL parameters are trainable (no frozen layers)
|
| 87 |
+
total_params = sum(p.numel() for p in model.parameters())
|
| 88 |
+
train_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
|
| 89 |
+
print(f" Total parameters: {total_params:,}")
|
| 90 |
+
print(f" Trainable parameters: {train_params:,}")
|
| 91 |
+
assert train_params == total_params, "ERROR: Some parameters are frozen! This is FULL fine-tuning."
|
| 92 |
+
print(f" ✓ Confirmed: 100% of parameters will be updated (FULL FFT)")
|
| 93 |
+
|
| 94 |
+
print(f"\n[3/5] Loading dataset from {DATASET_PATH}...")
|
| 95 |
+
dataset = load_dataset("json", data_files=DATASET_PATH, split="train")
|
| 96 |
+
print(f" Loaded {len(dataset)} examples")
|
| 97 |
+
|
| 98 |
+
# Tokenize using Qwen2.5 ChatML format
|
| 99 |
+
def tokenize_fn(examples):
|
| 100 |
+
texts = []
|
| 101 |
+
for i in range(len(examples["input"])):
|
| 102 |
+
inp = examples["input"][i]
|
| 103 |
+
reasoning = examples["reasoning"][i]
|
| 104 |
+
output = examples["output"][i]
|
| 105 |
+
|
| 106 |
+
# ChatML format (Qwen2.5 native)
|
| 107 |
+
text = (
|
| 108 |
+
f"<|im_start|>system\n"
|
| 109 |
+
f"You are AlgoRythm Red Rock, a deterministic computational engineering model. "
|
| 110 |
+
f"You solve rocket engine design problems using first-principles physics. "
|
| 111 |
+
f"All dimensions are in mm (PicoGK convention). "
|
| 112 |
+
f"You must show complete derivations before generating code.\n"
|
| 113 |
+
f"<|im_end|>\n"
|
| 114 |
+
f"<|im_start|>user\n{inp}\n<|im_end|>\n"
|
| 115 |
+
f"<|im_start|>assistant\n{reasoning}\n\n{output}<|im_end|>"
|
| 116 |
+
)
|
| 117 |
+
texts.append(text)
|
| 118 |
+
|
| 119 |
+
tokenized = tokenizer(
|
| 120 |
+
texts,
|
| 121 |
+
truncation=True,
|
| 122 |
+
max_length=MAX_LEN,
|
| 123 |
+
padding="max_length",
|
| 124 |
+
return_tensors="pt"
|
| 125 |
+
)
|
| 126 |
+
tokenized["labels"] = tokenized["input_ids"].clone()
|
| 127 |
+
return tokenized
|
| 128 |
+
|
| 129 |
+
print(f" Tokenizing (max_length={MAX_LEN})...")
|
| 130 |
+
tokenized = dataset.map(tokenize_fn, batched=True, batch_size=100,
|
| 131 |
+
remove_columns=dataset.column_names)
|
| 132 |
+
|
| 133 |
+
# Split: 95% train, 5% eval
|
| 134 |
+
split = tokenized.train_test_split(test_size=0.05, seed=42)
|
| 135 |
+
train_ds = split["train"]
|
| 136 |
+
eval_ds = split["test"]
|
| 137 |
+
print(f" Train: {len(train_ds)} | Eval: {len(eval_ds)}")
|
| 138 |
+
|
| 139 |
+
# Training time estimate
|
| 140 |
+
steps_per_epoch = len(train_ds) // (BATCH_SIZE * GRAD_ACCUM * max(NUM_GPUS, 1))
|
| 141 |
+
total_steps = steps_per_epoch * 3
|
| 142 |
+
est_time_min = total_steps * 1.8 / 60 # ~1.8s/step on H100
|
| 143 |
+
print(f"\n[4/5] Training configuration:")
|
| 144 |
+
print(f" Batch size: {BATCH_SIZE} × grad_accum {GRAD_ACCUM} = effective {BATCH_SIZE * GRAD_ACCUM}")
|
| 145 |
+
print(f" Steps/epoch: ~{steps_per_epoch} | Total steps: ~{total_steps}")
|
| 146 |
+
print(f" Estimated time: ~{est_time_min:.0f} minutes ({est_time_min/60:.1f} hours)")
|
| 147 |
+
|
| 148 |
+
# Build TrainingArguments
|
| 149 |
+
training_args_dict = {
|
| 150 |
+
"output_dir": OUTPUT_DIR,
|
| 151 |
+
"num_train_epochs": 3,
|
| 152 |
+
"per_device_train_batch_size": BATCH_SIZE,
|
| 153 |
+
"gradient_accumulation_steps": GRAD_ACCUM,
|
| 154 |
+
"learning_rate": 2e-5, # Standard for full fine-tuning
|
| 155 |
+
"lr_scheduler_type": "cosine", # Smooth decay
|
| 156 |
+
"weight_decay": 0.01,
|
| 157 |
+
"warmup_ratio": 0.05,
|
| 158 |
+
"max_grad_norm": 1.0,
|
| 159 |
+
"bf16": True,
|
| 160 |
+
"tf32": True,
|
| 161 |
+
"gradient_checkpointing": True,
|
| 162 |
+
"logging_steps": 25,
|
| 163 |
+
"evaluation_strategy": "steps",
|
| 164 |
+
"eval_steps": 200,
|
| 165 |
+
"save_strategy": "steps",
|
| 166 |
+
"save_steps": 500,
|
| 167 |
+
"save_total_limit": 3,
|
| 168 |
+
"load_best_model_at_end": True,
|
| 169 |
+
"metric_for_best_model": "eval_loss",
|
| 170 |
+
"greater_is_better": False,
|
| 171 |
+
"dataloader_num_workers": 4,
|
| 172 |
+
"dataloader_pin_memory": True,
|
| 173 |
+
"report_to": "none", # Set to "wandb" if you have W&B
|
| 174 |
+
"remove_unused_columns": False,
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
# Add FSDP config only for multi-GPU
|
| 178 |
+
if USE_FSDP:
|
| 179 |
+
training_args_dict["fsdp"] = "full_shard auto_wrap"
|
| 180 |
+
training_args_dict["fsdp_transformer_layer_cls_to_wrap"] = "Qwen2DecoderLayer"
|
| 181 |
+
print(f" FSDP: ENABLED (sharding across {NUM_GPUS} GPUs)")
|
| 182 |
+
else:
|
| 183 |
+
print(f" FSDP: DISABLED (single GPU mode)")
|
| 184 |
+
|
| 185 |
+
training_args = TrainingArguments(**training_args_dict)
|
| 186 |
+
|
| 187 |
+
trainer = Trainer(
|
| 188 |
+
model=model,
|
| 189 |
+
args=training_args,
|
| 190 |
+
train_dataset=train_ds,
|
| 191 |
+
eval_dataset=eval_ds,
|
| 192 |
+
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
|
| 193 |
+
callbacks=[EarlyStoppingCallback(early_stopping_patience=5)]
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
print(f"\n[5/5] 🔥 LAUNCHING FULL FINE-TUNING (updating ALL {total_params:,} parameters)...")
|
| 197 |
+
print(f" Target: < 2 hours")
|
| 198 |
+
print(f" Loss should decrease: ~2.5 → ~0.5")
|
| 199 |
+
print(f"=" * 55)
|
| 200 |
+
|
| 201 |
+
trainer.train()
|
| 202 |
+
|
| 203 |
+
# Save final model
|
| 204 |
+
print(f"\n✅ Training complete! Saving to {OUTPUT_DIR}...")
|
| 205 |
+
trainer.save_model(OUTPUT_DIR)
|
| 206 |
+
tokenizer.save_pretrained(OUTPUT_DIR)
|
| 207 |
+
print(f"✅ Model saved. Ready for inference.")
|
| 208 |
+
|
| 209 |
+
if __name__ == "__main__":
|
| 210 |
+
train()
|
training/train_full.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
AlgoRythm Red Rock - FULL FINE-TUNING Script (Single A100/H100 Optimized)
|
| 3 |
+
Transforms Qwen2.5-Coder-7B into a Deterministic CEM (Physics-Native)
|
| 4 |
+
Training time: ~1.5h on Single H100 (using Paged AdamW 8-bit)
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import json
|
| 9 |
+
import torch
|
| 10 |
+
from datasets import Dataset
|
| 11 |
+
from transformers import (
|
| 12 |
+
AutoModelForCausalLM,
|
| 13 |
+
AutoTokenizer,
|
| 14 |
+
TrainingArguments,
|
| 15 |
+
Trainer,
|
| 16 |
+
DataCollatorForLanguageModeling,
|
| 17 |
+
EarlyStoppingCallback
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
# Configuration
|
| 21 |
+
MODEL_NAME = "Qwen/Qwen2.5-Coder-7B-Instruct"
|
| 22 |
+
OUTPUT_DIR = "./model/algorythm-prandtl-aero-7b-full-h100"
|
| 23 |
+
DATASET_DIR = "./datasets"
|
| 24 |
+
|
| 25 |
+
# Training Hyperparameters for SINGLE H100 FULL FINE-TUNING
|
| 26 |
+
# The "Secret Sauce": Paged AdamW 8-bit + BFloat16 + Gradient Checkpointing
|
| 27 |
+
TRAINING_CONFIG = {
|
| 28 |
+
"num_train_epochs": 2, # Optimized for 2.3hr limit with High-Density Data
|
| 29 |
+
"per_device_train_batch_size": 1, # Tiny batch size to fit in VRAM
|
| 30 |
+
"gradient_accumulation_steps": 32, # Large accumulation to simulate Batch Size ~32-64
|
| 31 |
+
"learning_rate": 1e-5, # Conservative LR for stability
|
| 32 |
+
"warmup_ratio": 0.05,
|
| 33 |
+
"weight_decay": 0.05,
|
| 34 |
+
"max_grad_norm": 0.3,
|
| 35 |
+
"bf16": True, # Mandatory for H100 speed
|
| 36 |
+
"gradient_checkpointing": True, # Mandatory to save Activation Memory
|
| 37 |
+
"optim": "paged_adamw_8bit", # THE KEY: Offloads optimizer state to CPU RAM
|
| 38 |
+
|
| 39 |
+
"logging_steps": 5,
|
| 40 |
+
"save_strategy": "steps",
|
| 41 |
+
"save_steps": 50,
|
| 42 |
+
"evaluation_strategy": "steps",
|
| 43 |
+
"eval_steps": 50,
|
| 44 |
+
"load_best_model_at_end": True,
|
| 45 |
+
"max_seq_length": 4096,
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
SYSTEM_PROMPT = """You are AlgoRythm Prandtl Aero, a deterministic Computational Engineering Model.
|
| 49 |
+
You generate ONLY physically valid designs using PicoGK.
|
| 50 |
+
|
| 51 |
+
RESPONSE FORMAT:
|
| 52 |
+
[REQUIREMENTS_PARSE] - Extract requirements
|
| 53 |
+
[PHYSICS_DERIVATION] - Step-by-step math with LaTeX (Von Mises, Bartz, Navier-Stokes)
|
| 54 |
+
[CONSTRAINT_VALIDATION] - Check physical limits (Yield, Overhangs, Thermal)
|
| 55 |
+
[PICOGK_CODE] - Generate executable C# code
|
| 56 |
+
|
| 57 |
+
NEVER guess constants. ALWAYS show derivations. ALWAYS validate."""
|
| 58 |
+
|
| 59 |
+
def load_datasets():
|
| 60 |
+
"""Load all JSON datasets from the datasets directory"""
|
| 61 |
+
all_examples = []
|
| 62 |
+
for filename in os.listdir(DATASET_DIR):
|
| 63 |
+
if filename.endswith('.json'):
|
| 64 |
+
filepath = os.path.join(DATASET_DIR, filename)
|
| 65 |
+
with open(filepath, 'r') as f:
|
| 66 |
+
data = json.load(f)
|
| 67 |
+
all_examples.extend(data)
|
| 68 |
+
print(f"Loaded {len(all_examples)} training examples")
|
| 69 |
+
return all_examples
|
| 70 |
+
|
| 71 |
+
def format_for_training(examples, tokenizer):
|
| 72 |
+
"""Format examples into training format"""
|
| 73 |
+
formatted = []
|
| 74 |
+
for ex in examples:
|
| 75 |
+
instruction = f"""<|im_start|>system
|
| 76 |
+
{SYSTEM_PROMPT}<|im_end|>
|
| 77 |
+
<|im_start|>user
|
| 78 |
+
{ex['input']}<|im_end|>
|
| 79 |
+
<|im_start|>assistant
|
| 80 |
+
{ex['reasoning']}
|
| 81 |
+
|
| 82 |
+
[PICOGK_CODE]
|
| 83 |
+
```csharp
|
| 84 |
+
{ex['output']}
|
| 85 |
+
```<|im_end|>"""
|
| 86 |
+
formatted.append({"text": instruction})
|
| 87 |
+
return Dataset.from_list(formatted)
|
| 88 |
+
|
| 89 |
+
def main():
|
| 90 |
+
print("="*60)
|
| 91 |
+
print("ALGORYTHM PRANDTL AERO - SINGLE H100 FULL FINE-TUNING")
|
| 92 |
+
print("Optimization: Paged AdamW 8-bit + Gradient Checkpointing")
|
| 93 |
+
print("="*60)
|
| 94 |
+
|
| 95 |
+
# Load tokenizer
|
| 96 |
+
print("\n[1/4] Loading tokenizer...")
|
| 97 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
|
| 98 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 99 |
+
|
| 100 |
+
# Load Base Model (Full Precision Weights,cast to BF16 on fly)
|
| 101 |
+
print("\n[2/4] Loading base model...")
|
| 102 |
+
|
| 103 |
+
# --- SAFETY CHECK: PRE-FLIGHT ENVIRONMENT AUDIT ---
|
| 104 |
+
print("\n >>> RUNNING PRE-FLIGHT SAFETY CHECKS (User Order: No Financial Waste) <<<")
|
| 105 |
+
# 1. CUDA Check
|
| 106 |
+
if not torch.cuda.is_available():
|
| 107 |
+
raise RuntimeError("FATAL: No GPU detected! Aborting to save money.")
|
| 108 |
+
print(" [PASS] GPU Detected: " + torch.cuda.get_device_name(0))
|
| 109 |
+
|
| 110 |
+
# 2. BF16 Check (Required for H100 Optimization)
|
| 111 |
+
if not torch.cuda.is_bf16_supported():
|
| 112 |
+
print(" [WARNING] BF16 not supported on this GPU. Falling back to FP16 (Slower).")
|
| 113 |
+
TRAINING_CONFIG["bf16"] = False
|
| 114 |
+
TRAINING_CONFIG["fp16"] = True
|
| 115 |
+
else:
|
| 116 |
+
print(" [PASS] BF16 Operations Supported.")
|
| 117 |
+
|
| 118 |
+
# 3. RAM Check (Prevent OOM crash after 10 mins)
|
| 119 |
+
import psutil
|
| 120 |
+
mem = psutil.virtual_memory()
|
| 121 |
+
if mem.total < 30 * 1024**3: # Check for at least 30GB System RAM for offloading
|
| 122 |
+
print(f" [WARNING] System RAM is low ({mem.total/1024**3:.1f} GB). Paged Optimizer might swap heavily.")
|
| 123 |
+
else:
|
| 124 |
+
print(f" [PASS] System RAM: {mem.total/1024**3:.1f} GB (Healthy for Offloading).")
|
| 125 |
+
|
| 126 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 127 |
+
MODEL_NAME,
|
| 128 |
+
torch_dtype=torch.bfloat16 if TRAINING_CONFIG.get("bf16", True) else torch.float16,
|
| 129 |
+
trust_remote_code=True,
|
| 130 |
+
use_cache=False,
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
# Enable Gradient Checkpointing (Crucial for VRAM)
|
| 134 |
+
model.gradient_checkpointing_enable()
|
| 135 |
+
|
| 136 |
+
# Load and format dataset
|
| 137 |
+
print("\n[3/4] Loading datasets...")
|
| 138 |
+
examples = load_datasets()
|
| 139 |
+
if not examples:
|
| 140 |
+
raise ValueError("FATAL: Dataset is empty! check ./datasets folder.")
|
| 141 |
+
|
| 142 |
+
# --- SAFETY CHECK: DATA INTEGRITY ---
|
| 143 |
+
print(f" [PASS] Loaded {len(examples)} examples.")
|
| 144 |
+
print(" [AUDIT] Inspecting First Training Sample for Corruption:")
|
| 145 |
+
print("-" * 40)
|
| 146 |
+
print(f"INPUT PREVIEW:\n{examples[0]['input'][:200]}...")
|
| 147 |
+
print(f"OUTPUT PREVIEW:\n{examples[0]['output'][:200]}...")
|
| 148 |
+
print("-" * 40)
|
| 149 |
+
|
| 150 |
+
dataset = format_for_training(examples, tokenizer)
|
| 151 |
+
|
| 152 |
+
# Tokenize
|
| 153 |
+
def tokenize(examples):
|
| 154 |
+
return tokenizer(
|
| 155 |
+
examples["text"],
|
| 156 |
+
truncation=True,
|
| 157 |
+
max_length=TRAINING_CONFIG["max_seq_length"],
|
| 158 |
+
padding="max_length"
|
| 159 |
+
)
|
| 160 |
+
tokenized_dataset = dataset.map(tokenize, batched=True)
|
| 161 |
+
|
| 162 |
+
# Training arguments
|
| 163 |
+
print("\n[4/4] Setting up Paged 8-bit Optimizer...")
|
| 164 |
+
training_args = TrainingArguments(
|
| 165 |
+
output_dir=OUTPUT_DIR,
|
| 166 |
+
num_train_epochs=TRAINING_CONFIG["num_train_epochs"],
|
| 167 |
+
per_device_train_batch_size=TRAINING_CONFIG["per_device_train_batch_size"],
|
| 168 |
+
gradient_accumulation_steps=TRAINING_CONFIG["gradient_accumulation_steps"],
|
| 169 |
+
learning_rate=TRAINING_CONFIG["learning_rate"],
|
| 170 |
+
warmup_ratio=TRAINING_CONFIG["warmup_ratio"],
|
| 171 |
+
weight_decay=TRAINING_CONFIG["weight_decay"],
|
| 172 |
+
bf16=TRAINING_CONFIG["bf16"],
|
| 173 |
+
logging_steps=TRAINING_CONFIG["logging_steps"],
|
| 174 |
+
save_strategy=TRAINING_CONFIG["save_strategy"],
|
| 175 |
+
optim=TRAINING_CONFIG["optim"], # paged_adamw_8bit
|
| 176 |
+
report_to="none"
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
|
| 180 |
+
|
| 181 |
+
trainer = Trainer(
|
| 182 |
+
model=model,
|
| 183 |
+
args=training_args,
|
| 184 |
+
train_dataset=tokenized_dataset,
|
| 185 |
+
eval_dataset=tokenized_dataset.select(range(min(50, len(tokenized_dataset)))),
|
| 186 |
+
data_collator=data_collator,
|
| 187 |
+
callbacks=[EarlyStoppingCallback(early_stopping_patience=3)]
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
print("\nStarting FULL FINE-TUNING on Single H100...")
|
| 191 |
+
print("Strategy: CPU Offloading of Optimizer States to save VRAM.")
|
| 192 |
+
trainer.train()
|
| 193 |
+
|
| 194 |
+
print("\nSaving full model...")
|
| 195 |
+
trainer.save_model(OUTPUT_DIR)
|
| 196 |
+
tokenizer.save_pretrained(OUTPUT_DIR)
|
| 197 |
+
|
| 198 |
+
print("\n" + "="*60)
|
| 199 |
+
print("FULL FINE-TUNING COMPLETE!")
|
| 200 |
+
print(f"Model saved to: {OUTPUT_DIR}")
|
| 201 |
+
print("="*60)
|
| 202 |
+
|
| 203 |
+
if __name__ == "__main__":
|
| 204 |
+
main()
|