|
Download README.md from LJTSG/npu-forge: direct link, hf CLI and curl.
- Browser
- Download file 6.47 kB
-
https://huggingface.co/LJTSG/npu-forge/resolve/main/README.md
- Command line
-
hf download hf://LJTSG/npu-forge/README.md
-
curl -L -o README.md https://huggingface.co/LJTSG/npu-forge/resolve/main/README.md
6.47 kB
| license: mit | |
| tags: | |
| - amd | |
| - ryzen-ai | |
| - npu | |
| - xdna2 | |
| - fastflowlm | |
| - strix-halo | |
| - lora | |
| - fine-tuning | |
| - tools | |
| pipeline_tag: text-generation | |
| # NPU-Forge 🔥 — fine-tune a model and put it on your AMD Ryzen AI NPU in ~3 minutes | |
| **Measured, on a Strix Halo (Ryzen AI MAX+ 395), June 2026:** a LoRA fine-tune of | |
| Llama-3.2-1B on 300+ real chat exchanges — trained, merged, behavior-verified, | |
| converted to GGUF, re-quantized to FastFlowLM's Q4NX, NPU-ready — in | |
| **183 seconds of cloud time** (≈ $0.10 on a rented T4): | |
| ``` | |
| forge tune my-chats.jsonl --name grandma # proven: coherent + IN-BAND on NPU | |
| ├─ LoRA fine-tune (cloud GPU) 122 s | |
| ├─ merge 3 s | |
| ├─ voice proof (model speaks first!) 5 s | |
| ├─ HF -> f16 -> Q4_K_M GGUF 20 s | |
| └─ GGUF -> Q4NX (NPU format) 24 s | |
| forge register (one UAC click) | |
| flm run grandma-forge:1b | |
| ``` | |
| The "voice proof" stage generates a sample from the merged model *inside the | |
| training job*, before any conversion — so you know the tune actually took. | |
| Ours came back with the persona's exact ritual phrases after 2 minutes of | |
| training. That's the bar. | |
| ## What's in this repo | |
| - **`forge.js` / `forge.bat`** — the CLI: `tune`, `convert`, `register`, | |
| `list`, `doctor`, `serve` | |
| - **`modal/tune_npu.py`** — the whole tune→NPU pipeline as one | |
| [Modal](https://modal.com) job (bring your own Modal account; T4 is plenty) | |
| - **`modal/convert_q4nx.py`** — just the GGUF→Q4NX stage (65 s for a 1B) | |
| - **`bin/assemble.js`** — downloads results and stages the FLM model folder | |
| - **`bin/register.js` + `register-admin.bat`** — the permanent custom-model | |
| registry that survives FLM updates (see below) | |
| - **`registry.example.json`** — entry template | |
| Chat data format: one JSON per line, `{"messages":[{"role":"user","content":...},{"role":"assistant","content":...}]}`. | |
| ## The registry problem (why `forge register` exists) | |
| FLM's `model_list.json` lives in `C:\Program Files\flm\` and **every FLM update | |
| resets it**, silently de-registering all your custom models. Your model files | |
| survive (they're in `Documents\flm\models\`) but they vanish from `flm list`. | |
| Forge keeps its own user-space `registry.json` forever and re-merges with one | |
| click. `forge doctor` tells you when an update has eaten your registrations. | |
| ## NEW in v0.3 — a voice-verifier "ear" that runs on the NPU | |
| Train a ~111KB classification head over EmbeddingGemma-300m embeddings | |
| (`modal/train_ear_head.py`, bring your own labeled texts), then run it locally | |
| with `bin/ear.js` against FLM's `/v1/embeddings` (`flm serve <model> --embed 1`). | |
| The embeddings come off the NPU; the head is plain JS. In our tests the | |
| 111KB head **matched a fine-tuned 268MB DistilBERT on real-voice accuracy | |
| (95.9%) and beat it on the hard boundary cases**, live on a Strix Halo NPU. | |
| Also measured: llama3.2:1b chat on the NPU = **47.8 tokens/s** including | |
| prefill (FLM, performance pmode). | |
| Snag #8: FLM's embeddings endpoint closes the TCP connection per request — | |
| retry once on ECONNRESET (ear.js does). | |
| `start.bat` gives you a menu: doctor / list / register / serve / tune guide. | |
| ## The snag ledger — ten walls we hit so you don't | |
| 1. **The Q4NX converter's `convert.py` CLI is broken at HEAD** (uncommented | |
| debug `sys.argv` override hijacks every invocation). Call the module API: | |
| `from q4nx import create_converter; create_converter(gguf, "").convert(q4nx_path=out, weights_type="language")` | |
| 2. Converter needs `einops` and `tqdm` beyond its README list, and **must run | |
| with cwd = its repo root** (relative `configs/<arch>.json` loads). | |
| 3. **Llama-3.2 tokenizers need `transformers>=4.46`** — the error | |
| `untagged enum ModelWrapper` is that wall exactly. | |
| 4. **`transformers 4.46` needs `accelerate>=1.0`** — the error | |
| `'AdamW' object has no attribute 'train'` at step 0 is that skew. | |
| 5. **T4 + Llama-3.2's 128k vocab OOMs at batch 4** (loss-logits blowup). | |
| Floor: batch 1 × grad-accum 8 + gradient checkpointing. | |
| 6. **NPU driver minimum for current FLM: `32.0.203.304`** (`.311` | |
| recommended). `flm validate` will tell you; so will `forge doctor`. | |
| 7. **EmbeddingGemma needs `transformers>=4.5x` + `sentence-transformers 5.x`** | |
| and the official weights are license-gated (use the `unsloth/` mirror, or | |
| accept the Gemma license on your HF account + pass an `HF_TOKEN` secret). | |
| 8. **FLM's `/v1/embeddings` closes the TCP connection per request** — retry | |
| once on `ECONNRESET` (the ear runtime does). | |
| 9. **For a FINE-TUNED model, exporting GGUF as `q8_0` produces repetition | |
| garbage on the NPU** even though the merged model is perfect — the q8_0 | |
| then Q4NX re-quant is a lossy double-quantization. **Use `Q4_K_M`.** | |
| 10. **The Q4NX converter's llama path rejects `f16`** (`not enough values to | |
| unpack` — it expects pre-quantized blocks). So the GGUF must be quantized | |
| *before* Q4NX, and `Q4_K_M` is the format proven to produce a coherent, | |
| in-voice NPU model. Pipeline: HF → f16 → `llama-quantize Q4_K_M` → Q4NX. | |
| **Frozen known-good stack** (the whole point — never debug this again): | |
| `torch 2.4.1 · transformers 4.46.3 · trl 0.9.6 · peft 0.12.0 · | |
| accelerate 1.1.1 · datasets 2.21.0 · gguf · amd-quark · einops · tqdm · | |
| protobuf` + a compiled `llama-quantize` (the Modal job builds it). | |
| ## Proven, measured (Strix Halo, June 2026) | |
| A LoRA fine-tune of Llama-3.2-1B on 300 real chat exchanges, run through the | |
| whole pipeline and served on the NPU: | |
| - **Coherent and in-voice** — the persona's rituals and endearments intact. | |
| - **41.9 tokens/s** on the NPU (FLM, performance pmode). | |
| - **In-band against the source voiceprint** — mean 0.845 vs the original's | |
| own held-out band of 0.83 ± 0.07 (3 prompts). A separate stylometric scorer | |
| certified the NPU model speaks like the source it was tuned on. | |
| That is the bar: not "it converts," but "it talks like itself, on the NPU." | |
| ## Requirements | |
| - AMD Ryzen AI machine with XDNA2 NPU (Strix, Strix Halo, Kraken…) + | |
| [FastFlowLM](https://github.com/FastFlowLM/FastFlowLM) | |
| - Node.js (the CLI), Python + a [Modal](https://modal.com) account (the cloud legs) | |
| - NPU driver ≥ 32.0.203.304 | |
| Part of an ongoing project to make local NPUs a first-class home for personal | |
| AI — voices you own, on silicon you own. | |