You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: plugins/nemo-customizer/src/nemo_customizer/skills/nemo-customizer/SKILL.md
+75-6Lines changed: 75 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -141,6 +141,8 @@ Training never runs inside the `nemo` CLI process. After `submit`, the platform'
141
141
- For submit/image/plugin errors (both backends), read `references/troubleshooting.md`. Unsloth needs the `nmp-unsloth-training` container image on the **platform host's** Docker daemon (see `docker/unsloth/README.md`).
142
142
- **Missing training image on a remote platform** — if the user gave a non-localhost `NEMO_BASE_URL` / `NMP_BASE_URL` (e.g. `10.0.0.51:8080`) and the job errors with `Failed to pull image`, `manifest unknown`, or missing `nmp-unsloth-training` / automodel training image: **do not** run `docker build`, `docker pull`, or `docker buildx bake` on the agent machine. Report with **Report to user** (use **Output adapter fileset (planned):** on error), then append on-target build steps from `references/troubleshooting.md` § **Missing training images**.
143
143
- **Gated HuggingFace models** (Llama, Gemma, …) — confirm `hf-token` + fileset `token_secret` before submit; download fails with `Failed to access upstream storage` / 502 when missing. See **HuggingFace token (gated models)** and `references/troubleshooting.md` § **Gated HuggingFace models**.
144
+
- **Post-training eval format** — use the same CHAT `messages` JSONL as training. **Do not** flatten rows to `prompt`/`expected`for the evaluator. Send `messages[:-1]` at inference (exclude final assistant label); score against `messages[-1].content`. See `references/post-training-eval.md` and `references/eval_helpers.py`.
145
+
- **LoRA adapters load automatically for eval** — when a job completes, the adapter is registered on the model entity and hot-reloaded on any **READY** deployment with `lora_enabled: true`. **Do not** update deployments or providers before eval. **Do** route LoRA eval through the **provider** gateway (`/provider/<name>/-/v1` with `model: default--<adapter>`); the model-entity path (`/model/<entity>/-/v1`) always hits the base model. See `references/post-training-eval.md` § **Request routing (base vs LoRA)**.
144
146
145
147
## Workflow
146
148
@@ -162,12 +164,14 @@ Common steps then **branch by plugin pick**:
- [ ] Poll until top-level terminal (`poll_customization_job.sh`; default 15s interval, or 30–60s manual polls)
164
166
- [ ] Report using output template below
167
+
- [ ] Optional: compare base vs adapter on validation — `references/eval_helpers.py …` (CHAT format; adapters hot-reload automatically; see `references/post-training-eval.md`)
165
168
166
169
# unsloth branch (submit → Docker GPU job)
167
170
- [ ] Write /tmp/job.json using the UnslothJobInput shape (see Fast path — unsloth)
- [ ] Optional: compare base vs adapter on validation — `references/eval_helpers.py …` (CHAT format; adapters hot-reload automatically; see `references/post-training-eval.md`)
171
175
```
172
176
173
177
## Fast path — automodel
@@ -513,7 +517,7 @@ After polling reaches a **terminal** status (`completed`, `error`, or `cancelled
513
517
514
518
| Status | Notes |
515
519
|--------|-------|
516
-
| `completed` | Brief success summary (e.g. adapter registered on model entity). When `metrics.train_loss` has ≥2 entries, add a loss-drop sentence: *Loss dropped from \<first value, 1 dp\> at step 1 to \<last value, 3 dp\> at step \<N\>; validation loss was \<val or n/a\>.* |
520
+
| `completed` | Brief success summary (e.g. adapter registered on model entity). When `metrics.train_loss` has ≥2 entries, add a loss-drop sentence: *Loss dropped from \<first value, 1 dp\> at step 1 to \<last value, 3 dp\> at step \<N\>; validation loss was \<val or n/a\>.* Always append **Using the adapter** with discovered provider name and concrete gateway URLs (see below). |
517
521
| `error` | Quote `error_details.message` or the failing step; note setup that succeeded before the failure (auth, dataset upload, submit). |
518
522
| `cancelled` | Cancellation reason if available. |
519
523
@@ -580,21 +584,85 @@ After polling reaches a **terminal** status (`completed`, `error`, or `cancelled
580
584
| Output save method | lora |
581
585
```
582
586
583
-
**Using the adapter (`completed` only)** — after **Training configuration**, run `nemo models get <model-entity> --workspace default` (parse stdout only) to confirm the adapter is listed under `adapters`. Append this section:
587
+
**Using the adapter (`completed` only)** — after **Training configuration**, run these discovery commands (parse stdout only; do not pipe `2>&1` into JSON parsers):
588
+
589
+
1. `nemo models get <model-entity> --workspace default` — confirm `<output.name>` appears under `adapters` with `enabled: true`.
590
+
2. `nemo inference providers list --workspace default -f json` — pick a **READY** provider whose `served_models` includes `default/<model-entity>` (base or LoRA composite). Record its `name` as `<provider>` (often matches the deployment name).
591
+
592
+
On a deployment with `lora_enabled: true`, the adapter is **hot-reloaded automatically** — no deployment update or provider reconfiguration is required before inference or post-training eval. Append this section with **concrete URLs and provider name** from discovery:
584
593
585
594
```markdown
586
595
### Using the adapter
587
596
588
-
The adapter `<output.name>` is attached to `default/<model-entity>`. List adapters with:
597
+
The adapter `<output.name>` is registered on `default/<model-entity>`. Weights are hot-reloaded on LoRA-enabled deployments — no deployment or provider update is required after training.
598
+
599
+
#### Request routing (base vs LoRA)
600
+
601
+
| Target | Gateway path | OpenAI base URL | Request `"model"` field |
**Common mistake:** posting to the model-entity URL with `"model": "default--<output.name>"` still runs the **base** model. Base-vs-adapter eval will look identical until LoRA requests use the **provider** URL above. See `references/post-training-eval.md` § **Request routing (base vs LoRA)**.
607
+
608
+
#### Chat inference (CHAT-trained models)
609
+
610
+
Match training context at inference — send **`messages[:-1]`** (all turns except the final assistant label). Single-turn rows are just the user message; multi-turn rows keep prior user/assistant history.
611
+
612
+
| Setting | Value | Why |
613
+
|---------|-------|-----|
614
+
| `messages` | All turns except the final assistant label from the JSONL row | Same decode path as SFT |
615
+
| `max_tokens` | `64` for short assistant labels | Training targets are brief (e.g. MCQA choice text) |
| `chat_template_kwargs.enable_thinking` | `false` for Qwen3 short-answer SFT | Thinking mode needs extra tokens and changes output shape vs training |
618
+
619
+
#### Example — LoRA adapter via provider
620
+
621
+
\`\`\`bash
622
+
export NEMO_BASE_URL=<platform-url> # omit when using default localhost
623
+
nemo inference gateway provider post v1/chat/completions <provider> --workspace default \\
624
+
--body '{
625
+
"model": "default--<output.name>",
626
+
"messages": [<all turns except final assistant label from the eval row>],
Validation loss from training is **not** accuracy. To compare base vs adapter on the validation split with correct routing:
589
650
590
651
\`\`\`bash
591
-
export NEMO_BASE_URL=<platform-url> # omit line when using default localhost
592
652
cd /path/to/nemo-platform
593
-
nemo models get <model-entity> --workspace default
653
+
uv run python plugins/nemo-customizer/src/nemo_customizer/skills/nemo-customizer/references/eval_helpers.py \\
654
+
--base-url <platform-url> \\
655
+
--model-entity <model-entity> \\
656
+
--adapter <output.name> \\
657
+
--provider <provider> \\
658
+
--dataset-fileset <dataset-fileset> \\
659
+
--split validation.jsonl
594
660
\`\`\`
661
+
662
+
Uses CHAT `messages` rows unchanged from the training fileset (`messages[:-1]` at inference). Repeat `--adapter` for multi-adapter compare. `--provider` is optional when a READY provider is auto-discovered.
595
663
```
596
664
597
-
Use the user's platform URL in`NEMO_BASE_URL` when they overrode it; omit the export line for default `http://127.0.0.1:8080`. The JSON `adapters` array shows `name`, `fileset`, `finetuning_type`, and `lora_config`for each registered adapter.
665
+
Use the user's platform URL in`NEMO_BASE_URL` when they overrode it; omit the export line fordefault `http://127.0.0.1:8080`. Substitute `<provider>`, `<NEMO_BASE_URL>`, and entity/adapter names with values from discovery — do not leave generic placeholdersin the user-facing report. Do **not** tell the user to update the deployment or add the adapter to a provider before calling it — registration on the model entity is sufficient.
598
666
599
667
**Save report to `/tmp`** — unless the user opts out, write the full Markdown report (header, **Training configuration**, **Using the adapter** when `completed`, and **Resources created** when a slug or new filesets were used) to `/tmp/fine-tune-result-<slug-or-job-suffix>.md`. Use the random slug from the run when one was assigned; otherwise use the job id suffix (e.g. `a925b07ff678`).
600
668
@@ -626,5 +694,6 @@ For other terminal errors, keep the same header template; put remediation detail
Copy file name to clipboardExpand all lines: plugins/nemo-customizer/src/nemo_customizer/skills/nemo-customizer/references/dataset-formats.md
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -54,3 +54,15 @@ Optional fields on the unsloth `dataset` block:
54
54
- The automodel SFT format `{"prompt": "...", "completion": "..."}` is **not** directly consumable by unsloth — unsloth has no built-in `prompt`/`completion` concatenation. Convert to either messages or pre-rendered text before upload.
55
55
56
56
EMBEDDING and CUSTOM (automodel-only schemas) are not supported by unsloth today.
57
+
58
+
## Post-training evaluation
59
+
60
+
Eval rows must use the **same CHAT `messages` shape** as training. Do not flatten to `prompt`/`expected` for the evaluator.
|`messages` (single- or multi-turn) | Same fileset split (`validation.jsonl`) |`messages[:-1]` — exclude final assistant label — see `post-training-eval.md`|`{{ item.messages[-1].content }}`|
65
+
66
+
LoRA inference and eval use the **provider** gateway (`/provider/<name>/-/v1`, `model: default--<adapter>`). Base uses the **model-entity** path. See `post-training-eval.md` § **Request routing** and the **Using the adapter** section in `SKILL.md`.
67
+
68
+
Shared helpers and compare CLI: `references/eval_helpers.py`. Full workflow: `references/post-training-eval.md`.
0 commit comments