Delta-Ultra-Mini / delta /trainer.py
Delta-FlareAI's picture
Upload folder using huggingface_hub
a006332 verified
Raw
History Blame Contribute Delete
4.06 kB
"""Training utilities for Delta Ultra Mini using HuggingFace Trainer."""
from __future__ import annotations
import logging
import os
import json
from pathlib import Path
from typing import Any
import torch
from transformers import Trainer, TrainingArguments
from transformers.utils import SAFE_WEIGHTS_NAME
from delta.dataset import DeltaDataCollator, DeltaDataset
from delta.model import DeltaConfig, DeltaModel
from delta.tokenizer import load_tokenizer
logging.basicConfig(level=os.getenv("DELTA_LOG_LEVEL", "INFO").upper())
logger = logging.getLogger(__name__)
class DeltaTrainer(Trainer):
"""Trainer override that saves tied weights safely with safetensors."""
def _save(self, output_dir: str | None = None, state_dict: dict[str, torch.Tensor] | None = None) -> None:
output_dir = output_dir or self.args.output_dir
os.makedirs(output_dir, exist_ok=True)
state_dict = state_dict or self.model.state_dict()
weights_path = os.path.join(output_dir, SAFE_WEIGHTS_NAME)
try:
import safetensors.torch
safetensors.torch.save_file(state_dict, weights_path, metadata={"format": "pt"})
except RuntimeError as exc:
# When embeddings are tied, tensors share the same underlying storage.
# `save_file(state_dict, ...)` refuses that; `save_model(model, ...)` handles it.
if "share memory" not in str(exc):
raise
import safetensors.torch
safetensors.torch.save_model(self.model, weights_path, metadata={"format": "pt"})
def train(config_dict: dict[str, Any]) -> Trainer:
"""Train Delta Ultra Mini.
Args:
config_dict: Training and model configuration.
Returns:
The configured Trainer after training.
"""
data_path = Path(config_dict["data_path"])
output_dir = Path(config_dict["output_dir"])
tokenizer_path = Path(config_dict.get("tokenizer_path", output_dir / "tokenizer.json"))
epochs = float(config_dict.get("epochs", 1))
batch_size = int(config_dict.get("batch_size", 2))
resume_from_checkpoint = config_dict.get("resume_from_checkpoint")
model_config = DeltaConfig.from_dict(config_dict.get("model", config_dict))
tokenizer = load_tokenizer(tokenizer_path)
dataset = DeltaDataset(
data_path=data_path,
tokenizer=tokenizer,
max_seq_len=model_config.max_seq_len,
stride=int(config_dict.get("stride", 256)),
)
model = DeltaModel(model_config)
training_args = TrainingArguments(
output_dir=str(output_dir),
num_train_epochs=epochs,
per_device_train_batch_size=batch_size,
learning_rate=float(config_dict.get("learning_rate", 3e-4)),
weight_decay=float(config_dict.get("weight_decay", 0.01)),
warmup_steps=int(config_dict.get("warmup_steps", 500)),
lr_scheduler_type="cosine",
max_grad_norm=float(config_dict.get("max_grad_norm", 1.0)),
fp16=torch.cuda.is_available(),
save_steps=int(config_dict.get("save_steps", 1000)),
logging_steps=int(config_dict.get("logging_steps", 50)),
report_to=[],
remove_unused_columns=False,
dataloader_pin_memory=torch.cuda.is_available(),
)
trainer = DeltaTrainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=DeltaDataCollator(tokenizer.pad_token_id),
)
trainer.train(resume_from_checkpoint=resume_from_checkpoint)
trainer.save_model(str(output_dir))
output_dir.mkdir(parents=True, exist_ok=True)
model.save_checkpoint(
output_dir / "delta_checkpoint.pt",
optimizer=trainer.optimizer,
scheduler=trainer.lr_scheduler,
step=int(trainer.state.global_step),
)
with (output_dir / "config.json").open("w", encoding="utf-8") as handle:
json.dump(model_config.to_dict(), handle, ensure_ascii=False, indent=2)
logger.info("Saved Delta checkpoint to %s", output_dir / "delta_checkpoint.pt")
return trainer