| from __future__ import annotations |
|
|
| import importlib.util |
| from dataclasses import asdict, dataclass |
| from pathlib import Path |
| from typing import Any |
|
|
| from training.planner import TrainingPlan, build_training_plan |
|
|
|
|
| @dataclass(frozen=True) |
| class LoraTrainerDependencyReport: |
| peft_available: bool |
| trl_available: bool |
| transformers_available: bool |
| torch_available: bool |
|
|
| @property |
| def ready(self) -> bool: |
| return all(asdict(self).values()) |
|
|
| def as_dict(self) -> dict[str, Any]: |
| data = asdict(self) |
| data["ready"] = self.ready |
| return data |
|
|
|
|
| @dataclass(frozen=True) |
| class LoraTrainingRequest: |
| model_id: str |
| dataset_path: str |
| output_dir: str |
| plan: TrainingPlan |
| dependency_report: LoraTrainerDependencyReport |
| execute_training: bool |
| command_preview: list[str] |
|
|
| def as_dict(self) -> dict[str, Any]: |
| return { |
| "model_id": self.model_id, |
| "dataset_path": self.dataset_path, |
| "output_dir": self.output_dir, |
| "plan": self.plan.as_dict(), |
| "dependency_report": self.dependency_report.as_dict(), |
| "execute_training": self.execute_training, |
| "command_preview": self.command_preview, |
| } |
|
|
|
|
| def lora_dependency_report() -> LoraTrainerDependencyReport: |
| return LoraTrainerDependencyReport( |
| peft_available=importlib.util.find_spec("peft") is not None, |
| trl_available=importlib.util.find_spec("trl") is not None, |
| transformers_available=importlib.util.find_spec("transformers") is not None, |
| torch_available=importlib.util.find_spec("torch") is not None, |
| ) |
|
|
|
|
| def build_lora_training_request( |
| model_id: str, |
| dataset_path: str, |
| rank: int = 16, |
| epochs: int = 1, |
| output_root: str | Path = "outputs/checkpoints", |
| ) -> LoraTrainingRequest: |
| plan = build_training_plan( |
| dataset_path=dataset_path, |
| rank=rank, |
| epochs=epochs, |
| output_root=output_root, |
| ) |
| report = lora_dependency_report() |
| return LoraTrainingRequest( |
| model_id=model_id, |
| dataset_path=dataset_path, |
| output_dir=plan.output_dir, |
| plan=plan, |
| dependency_report=report, |
| execute_training=False, |
| command_preview=[ |
| "python", |
| "-m", |
| "training.lora_trainer", |
| "--model-id", |
| model_id, |
| "--dataset", |
| dataset_path, |
| "--output-dir", |
| plan.output_dir, |
| ], |
| ) |
|
|
|
|
| def vision_finetuning_plan() -> dict[str, Any]: |
| return { |
| "implemented": False, |
| "recommended_tools": ["SWIFT", "LLaMA-Factory"], |
| "local_first_steps": [ |
| "Export corrected vision/OCR field notes to JSONL.", |
| "Choose MiniCPM-V model and verify local inference first.", |
| "Select SWIFT or LLaMA-Factory after hardware is known.", |
| "Keep checkpoints, datasets with private media, and model weights out of git.", |
| ], |
| "blocked_until": [ |
| "Final vision dataset schema is selected.", |
| "GPU/VRAM target is known.", |
| "Training framework dependency is approved for installation.", |
| ], |
| } |
|
|