asdfasdfqrqwer's picture
feat(cortex-ai): agent engine, tool registry, OpenAI-compatible API, fine-tuning pipeline
c63bc31
Raw History Blame Contribute Delete
5.02 kB
"""Fine-tuning entry point for CORTEX AI.
This script is written to run on GPU hardware. It is NOT executed in this
repository: the sandbox has 4 CPU cores, ~15 GiB of RAM and no accelerator, and
the checkpoint is 893 GB. Treat it as the documented path, not a verified run.
Usage::
python -m cortex_ai.training.train --config train_config.json
python -m cortex_ai.training.train --dataset data/cortex_sft.jsonl --epochs 1
Requires: torch, transformers, peft, datasets
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
from .config import TrainConfig
from .dataset import dataset_stats, iter_encoded, load_jsonl
def build_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Affinage de CORTEX AI")
parser.add_argument("--config", type=str, default="", help="fichier JSON de configuration")
parser.add_argument("--dataset", type=str, default="", help="dataset JSONL")
parser.add_argument("--output-dir", type=str, default="", help="dossier de sortie")
parser.add_argument("--epochs", type=int, default=0)
parser.add_argument("--dry-run", action="store_true", help="valider les donnees sans entrainer")
return parser
def main(argv: list[str] | None = None) -> int:
args = build_arg_parser().parse_args(argv)
config = TrainConfig.load(args.config) if args.config else TrainConfig()
if args.dataset:
config.dataset_path = args.dataset
if args.output_dir:
config.output_dir = args.output_dir
if args.epochs:
config.epochs = args.epochs
examples = load_jsonl(config.dataset_path)
stats = dataset_stats(examples)
print("=== Donnees ===")
for key, value in stats.items():
print(f" {key:20s} {value}")
# Encoding every example catches format problems before a GPU is booked.
encoded = list(iter_encoded(examples, config.thinking_mode))
print(f" {'exemples encodes':20s} {len(encoded)}")
print(f" {'prompt le plus long':20s} {max(len(e) for e in encoded)} caracteres")
if args.dry_run:
print("\n--dry-run : validation terminee, aucun entrainement lance.")
return 0
try:
import torch
from datasets import Dataset
from peft import LoraConfig, get_peft_model
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
DataCollatorForLanguageModeling,
Trainer,
TrainingArguments,
)
except ImportError as exc:
print(
f"\nDependance manquante : {exc.name}.\n"
"Installez torch, transformers, peft et datasets, puis relancez.\n"
"Sur cette machine (sans GPU, 893 Go de checkpoint), l'entrainement "
"n'est pas executable : utilisez --dry-run pour valider les donnees.",
file=sys.stderr,
)
return 2
if not torch.cuda.is_available():
print(
"\nAucun GPU detecte. L'affinage de ce checkpoint exige plusieurs "
"accelerateurs. Utilisez --dry-run pour valider les donnees.",
file=sys.stderr,
)
return 2
print("\n=== Chargement du modele ===")
tokenizer = AutoTokenizer.from_pretrained(config.model_id)
model = AutoModelForCausalLM.from_pretrained(
config.model_id, torch_dtype=torch.bfloat16, device_map="auto"
)
if config.method == "lora":
model = get_peft_model(
model,
LoraConfig(
r=config.lora.r,
lora_alpha=config.lora.alpha,
lora_dropout=config.lora.dropout,
target_modules=config.lora.target_modules,
task_type="CAUSAL_LM",
),
)
model.print_trainable_parameters()
dataset = Dataset.from_dict({"text": encoded})
def tokenize(batch):
return tokenizer(batch["text"], truncation=True, max_length=config.max_seq_length)
dataset = dataset.map(tokenize, batched=True, remove_columns=["text"])
training_args = TrainingArguments(
output_dir=config.output_dir,
num_train_epochs=config.epochs,
per_device_train_batch_size=config.batch_size,
gradient_accumulation_steps=config.gradient_accumulation_steps,
learning_rate=config.learning_rate,
warmup_ratio=config.warmup_ratio,
weight_decay=config.weight_decay,
logging_steps=config.logging_steps,
save_steps=config.save_steps,
bf16=True,
seed=config.seed,
report_to=[],
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
)
trainer.train()
trainer.save_model(config.output_dir)
tokenizer.save_pretrained(config.output_dir)
print(f"\nModele enregistre dans {config.output_dir}")
return 0
if __name__ == "__main__":
raise SystemExit(main())