Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| import importlib.util | |
| from dataclasses import asdict, dataclass | |
| from pathlib import Path | |
| from typing import Any | |
| import yaml | |
| class PlantTrainingPlan: | |
| execute_training: bool | |
| backend: str | |
| base_model: str | |
| dataset_path: str | |
| output_dir: str | |
| adapter_repo: str | |
| corrected_examples: int | |
| minimum_recommended_examples: int | |
| dependency_report: dict[str, bool] | |
| swift_command: list[str] | |
| llamafactory_command: list[str] | |
| publish_commands: list[list[str]] | |
| use_trained_model_command: list[str] | |
| notes: list[str] | |
| def to_dict(self) -> dict[str, Any]: | |
| return asdict(self) | |
| def build_plant_training_plan( | |
| config_path: str | Path = "plant/models.yaml", | |
| dataset_path: str | Path = "data/plant_training.jsonl", | |
| output_dir: str | Path = "checkpoints/plant_lora", | |
| adapter_repo: str = "your-username/minicpm-v46-plant-lora", | |
| corrected_examples: int = 0, | |
| ) -> PlantTrainingPlan: | |
| cfg = yaml.safe_load(Path(config_path).read_text(encoding="utf-8")) or {} | |
| models = cfg.get("models", {}) | |
| training = cfg.get("training", {}) | |
| lora = training.get("lora", {}) | |
| sft = training.get("sft", {}) | |
| base_model = str( | |
| models.get("plant_vlm", {}).get("hf_id") | |
| or models.get("plant_vlm_finetuned", {}).get("base_model") | |
| or "openbmb/MiniCPM-V-4.6" | |
| ) | |
| rank = int(lora.get("rank", 16)) | |
| epochs = int(sft.get("epochs", 3)) | |
| batch_size = int(sft.get("batch_size", 4)) | |
| grad_accum = int(sft.get("grad_accum", 4)) | |
| lr = str(sft.get("lr", "2.0e-4")) | |
| output = str(output_dir) | |
| dataset = str(dataset_path) | |
| return PlantTrainingPlan( | |
| execute_training=False, | |
| backend="SWIFT vision LoRA preferred; LLaMA-Factory plan documented as alternative", | |
| base_model=base_model, | |
| dataset_path=dataset, | |
| output_dir=output, | |
| adapter_repo=adapter_repo, | |
| corrected_examples=corrected_examples, | |
| minimum_recommended_examples=30, | |
| dependency_report=plant_training_dependency_report(), | |
| swift_command=[ | |
| "swift", | |
| "sft", | |
| "--model", | |
| base_model, | |
| "--dataset", | |
| dataset, | |
| "--lora_rank", | |
| str(rank), | |
| "--num_train_epochs", | |
| str(epochs), | |
| "--per_device_train_batch_size", | |
| str(batch_size), | |
| "--gradient_accumulation_steps", | |
| str(grad_accum), | |
| "--learning_rate", | |
| lr, | |
| "--freeze_vit", | |
| "true", | |
| "--output_dir", | |
| output, | |
| ], | |
| llamafactory_command=[ | |
| "llamafactory-cli", | |
| "train", | |
| "plant_lora.yaml", | |
| ], | |
| publish_commands=[ | |
| [ | |
| "huggingface-cli", | |
| "repo", | |
| "create", | |
| adapter_repo, | |
| "--type", | |
| "model", | |
| ], | |
| [ | |
| "huggingface-cli", | |
| "upload", | |
| adapter_repo, | |
| output, | |
| ".", | |
| ], | |
| ], | |
| use_trained_model_command=[ | |
| "python", | |
| "-m", | |
| "plant.app", | |
| "--model-mode", | |
| "finetuned", | |
| "--port", | |
| "7861", | |
| ], | |
| notes=[ | |
| "This plan does not start training automatically.", | |
| "Use OpenBMB MiniCPM-V zero-shot first, then collect corrected plant examples.", | |
| "Train only after reviewing dataset quality and GPU memory.", | |
| "Set models.plant_vlm_finetuned.adapter_id to your real adapter repo after upload.", | |
| ], | |
| ) | |
| def plant_training_dependency_report() -> dict[str, bool]: | |
| return { | |
| "torch": importlib.util.find_spec("torch") is not None, | |
| "transformers": importlib.util.find_spec("transformers") is not None, | |
| "datasets": importlib.util.find_spec("datasets") is not None, | |
| "peft": importlib.util.find_spec("peft") is not None, | |
| "trl": importlib.util.find_spec("trl") is not None, | |
| "swift": importlib.util.find_spec("swift") is not None, | |
| } | |
| def write_llamafactory_dataset_info( | |
| dataset_path: str | Path = "data/plant_training.jsonl", | |
| output_path: str | Path = "data/llamafactory_dataset_info.json", | |
| ) -> Path: | |
| output = Path(output_path) | |
| output.parent.mkdir(parents=True, exist_ok=True) | |
| output.write_text( | |
| ( | |
| "{\n" | |
| ' "plant_discovery": {\n' | |
| f' "file_name": "{Path(dataset_path).as_posix()}",\n' | |
| ' "formatting": "alpaca",\n' | |
| ' "columns": {\n' | |
| ' "prompt": "instruction",\n' | |
| ' "response": "response"\n' | |
| " }\n" | |
| " }\n" | |
| "}\n" | |
| ), | |
| encoding="utf-8", | |
| ) | |
| return output | |