Instructions to use Subject-Emu-5259/NeuralAI with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use Subject-Emu-5259/NeuralAI with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Upload training/train_dpo.py with huggingface_hub
Browse files- training/train_dpo.py +74 -17
training/train_dpo.py
CHANGED
|
@@ -23,14 +23,29 @@ try:
|
|
| 23 |
except ImportError:
|
| 24 |
print("Install required packages: pip install transformers peft trl datasets torch")
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
# Configuration
|
| 27 |
@dataclass
|
| 28 |
class DPOTrainingConfig:
|
| 29 |
"""DPO training configuration"""
|
| 30 |
base_model: str = "HuggingFaceTB/SmolLM2-360M-Instruct"
|
| 31 |
-
dataset_path: str =
|
| 32 |
-
output_dir: str =
|
| 33 |
adapter_path: str = "" # Path to existing adapter if continuing training
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
# DPO parameters
|
| 36 |
beta: float = 0.1 # KL penalty coefficient
|
|
@@ -39,15 +54,20 @@ class DPOTrainingConfig:
|
|
| 39 |
gradient_accumulation_steps: int = 4
|
| 40 |
max_length: int = 512
|
| 41 |
max_prompt_length: int = 256
|
| 42 |
-
epochs: int =
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
# Optimization
|
| 45 |
warmup_ratio: float = 0.1
|
| 46 |
weight_decay: float = 0.01
|
| 47 |
lr_scheduler: str = "cosine"
|
| 48 |
|
| 49 |
# Device
|
| 50 |
-
device: str =
|
| 51 |
|
| 52 |
|
| 53 |
class DPODatasetBuilder:
|
|
@@ -263,16 +283,30 @@ def train_dpo(config: DPOTrainingConfig):
|
|
| 263 |
|
| 264 |
# Load tokenizer
|
| 265 |
tokenizer = AutoTokenizer.from_pretrained(config.base_model)
|
| 266 |
-
tokenizer.pad_token
|
|
|
|
| 267 |
|
| 268 |
# Load base model with memory optimization
|
|
|
|
| 269 |
model = AutoModelForCausalLM.from_pretrained(
|
| 270 |
config.base_model,
|
| 271 |
-
torch_dtype=
|
| 272 |
-
device_map=None,
|
| 273 |
).to(config.device)
|
| 274 |
|
| 275 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
if config.adapter_path and Path(config.adapter_path).exists():
|
| 277 |
print(f"Loading adapter from {config.adapter_path}")
|
| 278 |
model = PeftModel.from_pretrained(model, str(config.adapter_path), is_trainable=True)
|
|
@@ -324,12 +358,16 @@ def train_dpo(config: DPOTrainingConfig):
|
|
| 324 |
gradient_accumulation_steps=config.gradient_accumulation_steps,
|
| 325 |
use_cpu=(config.device == "cpu"),
|
| 326 |
max_length=config.max_length,
|
|
|
|
| 327 |
num_train_epochs=config.epochs,
|
| 328 |
warmup_ratio=config.warmup_ratio,
|
| 329 |
weight_decay=config.weight_decay,
|
| 330 |
lr_scheduler_type=config.lr_scheduler,
|
| 331 |
save_strategy="epoch",
|
| 332 |
logging_steps=1,
|
|
|
|
|
|
|
|
|
|
| 333 |
)
|
| 334 |
|
| 335 |
# Create trainer
|
|
@@ -345,11 +383,19 @@ def train_dpo(config: DPOTrainingConfig):
|
|
| 345 |
print(f"Starting DPO training on {len(dataset)} pairs...")
|
| 346 |
trainer.train()
|
| 347 |
|
| 348 |
-
# Save
|
| 349 |
-
|
|
|
|
| 350 |
tokenizer.save_pretrained(config.output_dir)
|
| 351 |
|
| 352 |
-
print(f"DPO
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
return trainer
|
| 355 |
|
|
@@ -358,14 +404,21 @@ def main():
|
|
| 358 |
"""Main entry point"""
|
| 359 |
config = DPOTrainingConfig()
|
| 360 |
|
| 361 |
-
# Check if running interactively
|
| 362 |
import argparse
|
| 363 |
-
parser = argparse.ArgumentParser(description="DPO Training")
|
| 364 |
parser.add_argument("--generate-only", action="store_true", help="Only generate preference dataset")
|
| 365 |
-
parser.add_argument("--beta", type=float, default=
|
| 366 |
-
parser.add_argument("--epochs", type=int, default=
|
| 367 |
-
parser.add_argument("--lr", type=float, default=
|
| 368 |
-
parser.add_argument("--data", type=str, default=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
args = parser.parse_args()
|
| 370 |
|
| 371 |
if args.generate_only:
|
|
@@ -378,6 +431,10 @@ def main():
|
|
| 378 |
config.epochs = args.epochs
|
| 379 |
config.learning_rate = args.lr
|
| 380 |
config.dataset_path = args.data
|
|
|
|
|
|
|
|
|
|
|
|
|
| 381 |
|
| 382 |
train_dpo(config)
|
| 383 |
|
|
|
|
| 23 |
except ImportError:
|
| 24 |
print("Install required packages: pip install transformers peft trl datasets torch")
|
| 25 |
|
| 26 |
+
# Resolve repo root so paths work on any machine (macOS, Linux, etc.)
|
| 27 |
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
| 28 |
+
|
| 29 |
+
def detect_device() -> str:
|
| 30 |
+
"""Pick the best available accelerator."""
|
| 31 |
+
if torch.cuda.is_available():
|
| 32 |
+
return "cuda"
|
| 33 |
+
if getattr(torch.backends, "mps", None) is not None and torch.backends.mps.is_available():
|
| 34 |
+
return "mps"
|
| 35 |
+
return "cpu"
|
| 36 |
+
|
| 37 |
# Configuration
|
| 38 |
@dataclass
|
| 39 |
class DPOTrainingConfig:
|
| 40 |
"""DPO training configuration"""
|
| 41 |
base_model: str = "HuggingFaceTB/SmolLM2-360M-Instruct"
|
| 42 |
+
dataset_path: str = str(REPO_ROOT / "data" / "train_dpo_v14.jsonl")
|
| 43 |
+
output_dir: str = str(REPO_ROOT / "checkpoints" / "dpo_model_v14")
|
| 44 |
adapter_path: str = "" # Path to existing adapter if continuing training
|
| 45 |
+
|
| 46 |
+
# Hugging Face upload (set push_to_hub=True to auto-sync after training)
|
| 47 |
+
push_to_hub: bool = False
|
| 48 |
+
hub_repo: str = "Subject-Emu-5259/NeuralAI"
|
| 49 |
|
| 50 |
# DPO parameters
|
| 51 |
beta: float = 0.1 # KL penalty coefficient
|
|
|
|
| 54 |
gradient_accumulation_steps: int = 4
|
| 55 |
max_length: int = 512
|
| 56 |
max_prompt_length: int = 256
|
| 57 |
+
epochs: int = 3
|
| 58 |
|
| 59 |
+
# LoRA (produces a small adapter compatible with the deployed demo)
|
| 60 |
+
lora_r: int = 16
|
| 61 |
+
lora_alpha: int = 32
|
| 62 |
+
lora_dropout: float = 0.05
|
| 63 |
+
|
| 64 |
# Optimization
|
| 65 |
warmup_ratio: float = 0.1
|
| 66 |
weight_decay: float = 0.01
|
| 67 |
lr_scheduler: str = "cosine"
|
| 68 |
|
| 69 |
# Device
|
| 70 |
+
device: str = detect_device()
|
| 71 |
|
| 72 |
|
| 73 |
class DPODatasetBuilder:
|
|
|
|
| 283 |
|
| 284 |
# Load tokenizer
|
| 285 |
tokenizer = AutoTokenizer.from_pretrained(config.base_model)
|
| 286 |
+
if tokenizer.pad_token is None:
|
| 287 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 288 |
|
| 289 |
# Load base model with memory optimization
|
| 290 |
+
dtype = torch.float32 if config.device == "cpu" else torch.bfloat16
|
| 291 |
model = AutoModelForCausalLM.from_pretrained(
|
| 292 |
config.base_model,
|
| 293 |
+
torch_dtype=dtype,
|
| 294 |
+
device_map=None,
|
| 295 |
).to(config.device)
|
| 296 |
|
| 297 |
+
# Wrap in LoRA so the output is a small adapter (matches the deployed demo)
|
| 298 |
+
lora_config = LoraConfig(
|
| 299 |
+
r=config.lora_r,
|
| 300 |
+
lora_alpha=config.lora_alpha,
|
| 301 |
+
lora_dropout=config.lora_dropout,
|
| 302 |
+
target_modules="all-linear",
|
| 303 |
+
bias="none",
|
| 304 |
+
task_type="CAUSAL_LM",
|
| 305 |
+
)
|
| 306 |
+
model = PeftModel(model, lora_config)
|
| 307 |
+
model.print_trainable_parameters()
|
| 308 |
+
|
| 309 |
+
# Load existing adapter if available (continue training)
|
| 310 |
if config.adapter_path and Path(config.adapter_path).exists():
|
| 311 |
print(f"Loading adapter from {config.adapter_path}")
|
| 312 |
model = PeftModel.from_pretrained(model, str(config.adapter_path), is_trainable=True)
|
|
|
|
| 358 |
gradient_accumulation_steps=config.gradient_accumulation_steps,
|
| 359 |
use_cpu=(config.device == "cpu"),
|
| 360 |
max_length=config.max_length,
|
| 361 |
+
max_prompt_length=config.max_prompt_length,
|
| 362 |
num_train_epochs=config.epochs,
|
| 363 |
warmup_ratio=config.warmup_ratio,
|
| 364 |
weight_decay=config.weight_decay,
|
| 365 |
lr_scheduler_type=config.lr_scheduler,
|
| 366 |
save_strategy="epoch",
|
| 367 |
logging_steps=1,
|
| 368 |
+
report_to="none",
|
| 369 |
+
push_to_hub=config.push_to_hub,
|
| 370 |
+
hub_model_id=config.hub_repo if config.push_to_hub else None,
|
| 371 |
)
|
| 372 |
|
| 373 |
# Create trainer
|
|
|
|
| 383 |
print(f"Starting DPO training on {len(dataset)} pairs...")
|
| 384 |
trainer.train()
|
| 385 |
|
| 386 |
+
# Save the LoRA adapter (not the full base model)
|
| 387 |
+
Path(config.output_dir).mkdir(parents=True, exist_ok=True)
|
| 388 |
+
model.save_pretrained(config.output_dir)
|
| 389 |
tokenizer.save_pretrained(config.output_dir)
|
| 390 |
|
| 391 |
+
print(f"DPO LoRA adapter saved to {config.output_dir}")
|
| 392 |
+
|
| 393 |
+
# Optionally push the adapter straight to the Hub
|
| 394 |
+
if config.push_to_hub:
|
| 395 |
+
print(f"Pushing adapter to Hugging Face: {config.hub_repo}")
|
| 396 |
+
model.push_to_hub(config.hub_repo, commit_message="DPO LoRA update")
|
| 397 |
+
tokenizer.push_to_hub(config.hub_repo, commit_message="DPO LoRA update")
|
| 398 |
+
print("✅ Adapter pushed to Hugging Face.")
|
| 399 |
|
| 400 |
return trainer
|
| 401 |
|
|
|
|
| 404 |
"""Main entry point"""
|
| 405 |
config = DPOTrainingConfig()
|
| 406 |
|
|
|
|
| 407 |
import argparse
|
| 408 |
+
parser = argparse.ArgumentParser(description="NeuralAI DPO Training")
|
| 409 |
parser.add_argument("--generate-only", action="store_true", help="Only generate preference dataset")
|
| 410 |
+
parser.add_argument("--beta", type=float, default=config.beta)
|
| 411 |
+
parser.add_argument("--epochs", type=int, default=config.epochs)
|
| 412 |
+
parser.add_argument("--lr", type=float, default=config.learning_rate)
|
| 413 |
+
parser.add_argument("--data", type=str, default=config.dataset_path,
|
| 414 |
+
help="Path to DPO jsonl (prompt/chosen/rejected)")
|
| 415 |
+
parser.add_argument("--output", type=str, default=config.output_dir,
|
| 416 |
+
help="Where to save the LoRA adapter")
|
| 417 |
+
parser.add_argument("--adapter", type=str, default="",
|
| 418 |
+
help="Existing adapter dir to continue training from")
|
| 419 |
+
parser.add_argument("--push", action="store_true",
|
| 420 |
+
help="Push the trained adapter to the Hugging Face Hub")
|
| 421 |
+
parser.add_argument("--hub-repo", type=str, default=config.hub_repo)
|
| 422 |
args = parser.parse_args()
|
| 423 |
|
| 424 |
if args.generate_only:
|
|
|
|
| 431 |
config.epochs = args.epochs
|
| 432 |
config.learning_rate = args.lr
|
| 433 |
config.dataset_path = args.data
|
| 434 |
+
config.output_dir = args.output
|
| 435 |
+
config.adapter_path = args.adapter
|
| 436 |
+
config.push_to_hub = args.push
|
| 437 |
+
config.hub_repo = args.hub_repo
|
| 438 |
|
| 439 |
train_dpo(config)
|
| 440 |
|