Spaces:
Running
Running
| """Train Puck's character LoRA on Holotron-12B, on Modal. | |
| TRL SFT + PEFT LoRA over the 162-example chat curriculum (build_dataset.py). | |
| Text-only LoRA on the language side of the VLM β character/voice, not vision. | |
| Adapter is saved to a Modal volume (no HF token in env); publish later. | |
| cd molt && uv run build_dataset.py | |
| modal run --detach train_modal.py # .spawn() inside β truly detached | |
| modal volume get puck-lora /puck-holotron-12b-lora ./out | |
| β οΈ BLOCKED (2026-06-07): Hcompany/Holotron-12B's published trust_remote_code | |
| modeling.py imports a `_fully_shard.py` that isn't in the repo β an H Company | |
| packaging bug in their *training* path (vLLM inference is unaffected, which is | |
| why the vision endpoint works). transformers can't load it for TRL. | |
| Options when revisiting: (a) wait for H Company to publish the missing file; | |
| (b) train the character LoRA on the BASE nvidia/NVIDIA-Nemotron-Nano-12B-v2-VL | |
| (still Nemotron, still β€32B, dataset is base-agnostic β voice doesn't need | |
| Holotron's CUA tuning); (c) stub _fully_shard.py if it's a no-op FSDP helper. | |
| Character already lands well via the enriched prompt, so the LoRA (Well-Tuned | |
| badge) is lower priority than vision. | |
| Hybrid-Mamba caveat once unblocked: target_modules='all-linear', gradient | |
| checkpointing off (Mamba layers dislike it).""" | |
| import json | |
| from pathlib import Path | |
| import modal | |
| MODEL = "Hcompany/Holotron-12B" | |
| HERE = Path(__file__).resolve().parent | |
| image = ( | |
| modal.Image.debian_slim(python_version="3.12") | |
| .pip_install( | |
| "torch", | |
| "transformers>=4.48", | |
| "trl>=0.12", | |
| "peft>=0.14", | |
| "datasets", | |
| "accelerate", | |
| "huggingface_hub[hf_transfer]", | |
| "sentencepiece", | |
| "einops", # hybrid-Mamba modeling code often needs it | |
| ) | |
| .env({"HF_HUB_ENABLE_HF_TRANSFER": "1"}) | |
| ) | |
| vol = modal.Volume.from_name("puck-lora", create_if_missing=True) | |
| hf_cache = modal.Volume.from_name("puck-hf-cache", create_if_missing=True) | |
| app = modal.App("puck-train") | |
| def train(records: list[dict]): | |
| import torch | |
| from datasets import Dataset | |
| from peft import LoraConfig | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| from trl import SFTConfig, SFTTrainer | |
| # conversational dataset β TRL applies the chat template itself | |
| ds = Dataset.from_list([{"messages": r["messages"]} for r in records]) | |
| tok = AutoTokenizer.from_pretrained(MODEL, trust_remote_code=True) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| MODEL, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map="auto" | |
| ) | |
| peft_cfg = LoraConfig( | |
| r=16, | |
| lora_alpha=32, | |
| lora_dropout=0.05, | |
| bias="none", | |
| task_type="CAUSAL_LM", | |
| target_modules="all-linear", # robust across the hybrid's linear layers | |
| ) | |
| cfg = SFTConfig( | |
| output_dir="/adapter/run", | |
| num_train_epochs=4, | |
| per_device_train_batch_size=1, | |
| gradient_accumulation_steps=8, | |
| learning_rate=2e-4, | |
| warmup_ratio=0.05, | |
| logging_steps=5, | |
| save_strategy="epoch", | |
| bf16=True, | |
| gradient_checkpointing=False, # Mamba layers + checkpointing don't mix | |
| max_length=1024, | |
| report_to="none", | |
| ) | |
| trainer = SFTTrainer(model=model, args=cfg, train_dataset=ds, peft_config=peft_cfg) | |
| trainer.train() | |
| out = "/adapter/puck-holotron-12b-lora" | |
| trainer.save_model(out) | |
| tok.save_pretrained(out) | |
| vol.commit() | |
| print(f"saved adapter β {out}") | |
| return out | |
| def main(): | |
| records = [ | |
| json.loads(line) for line in (HERE / "data" / "sft.jsonl").read_text().splitlines() | |
| ] | |
| print(f"training on {len(records)} examples") | |
| # .spawn() so a detached run survives the local caller disconnecting | |
| # (.remote() is synchronous and Modal cancels it when the CLI exits). | |
| call = train.spawn(records) | |
| print(f"spawned: {call.object_id} β modal volume get puck-lora /puck-holotron-12b-lora ./out") | |