algorythmtechnologies commited on
Commit
98c0fff
·
verified ·
1 Parent(s): 947d4a1

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. training/train_fsdp_full.py +210 -0
  2. 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()