Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .research/events.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
{"id": "b958b783d2b041f2ba43e072eb284abc", "ts": "2026-10-21T21:57:00+09:00", "task": "#35 MoE hot experts batched", "result": "batched hot experts 13.0 s/step vs host-only 13.5 (alternating steps, Qwen3-30B-A3B, RNGD); per-expert main 42.4 vs 17.2", "next": "more rows per call (longer S), hot fraction 0.5, drop the recomputed forward", "state": "active", "done": false, "blocker": "", "metrics": {"step_time_s": "13.0"}, "params": {}, "artifacts": [], "experiments": ["experiments/2026-10-21-moe-batched-hot-experts.md"], "labels": ["experiment", "benchmark"], "review": false, "todos": [], "note": "", "agent": "claude", "host": "control-node", "branch": "perf/35-batch-hot-experts", "commit": "9d5e498"}
{"id": "c37c232f20a045e0aa3315cc1c786106", "ts": "2026-10-21T22:27:58+09:00", "task": "#35 MoE hot experts batched", "result": "hot+keep_graph 5.19 s/step vs host-only+keep 8.00 (paired median -2.66 s, 6/6 rounds) and vs main host-only 9.21 s; Qwen3-30B-A3B S128 RNGD", "next": "", "state": "idle", "done": true, "blocker": "", "metrics": {"step_time_s": "5.19"}, "params": {}, "artifacts": [], "experiments": ["experiments/2026-10-21-moe-batched-hot-experts.md"], "labels": ["experiment", "benchmark"], "review": false, "todos": [], "note": "", "agent": "claude", "host": "control-node", "branch": "perf/35-hot-experts-faster", "commit": "1fee9f2-dirty"}
{"id": "924cf1d262d54d208adcb1b5c47ceff5", "ts": "2026-10-22T01:48:36+09:00", "task": "#40 resident AdamW DRAM_SHARED OOM", "result": "2 RNGD x 8 resident 200/200 steps, no OOM, 4.43 s/step (463 tok/s) steady; 1 card x 4 resident at low load 4.79 s vs 1-card offload 5.11 s, model +3.0%", "next": "report the runtime flag to Furiosa", "state": "idle", "done": true, "blocker": "", "metrics": {"tok_s": "462.5", "step_s": "4.43"}, "params": {"cards": "2", "resident_layers": "8", "steps": "200", "host_load": "15-50", "sdk": "furiosa-torch-2026.2.0"}, "artifacts": [], "experiments": ["experiments/2026-10-22-resident-200-steps.md"], "labels": ["benchmark"], "review": false, "todos": [], "note": "", "agent": "claude", "host": "control-node", "branch": "exp/40-resident-200-steps", "commit": "b3cb03b-dirty"}
{"id": "f20511ff9efe4bae939ee2520a5274f6", "ts": "2026-10-22T11:54:14+09:00", "task": "#46 rename package npu_lora to npu_train", "result": "package moved to npu_train; npu_lora kept as deprecated alias (same module objects, python -m npu_lora.X works); CPU tests 38/38 in a clean venv", "next": "maintainer review of PR; then uninstall npu-lora and pip install -e . on shared hosts", "state": "active", "done": false, "blocker": "", "metrics": {}, "params": {}, "artifacts": [], "experiments": [], "labels": ["infra"], "review": true, "todos": [], "note": "", "agent": "claude", "host": "dev-host", "branch": "refactor/46-npu-train-package", "commit": "af1e8f5-dirty"}
28 changes: 15 additions & 13 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@

---

이전 저장소 이름은 `npu-lora`입니다. Python 패키지, CLI, Helm chart 이름은 `npu-lora` 그대로입니다.
이전 저장소 이름은 `npu-lora`입니다. Python 패키지는 `npu_train`(배포 이름 `npu-train`)입니다. 예전 패키지 이름
`npu_lora`도 deprecated 별칭으로 그대로 import 하고 실행할 수 있습니다(`python -m npu_lora.<module>`). CLI 명령
`npu-lora`(`npu-train`으로도 설치됨), ai-rm workload 이름, Helm chart 이름은 `npu-lora` 그대로입니다.

**npu-lora**는 FuriosaAI RNGD에서 Llama 계열 모델을 학습한다. RNGD의 SDK는 추론용 컴파일러와 런타임만
제공한다. npu-lora는 역전파를 일반 컴파일 그래프로 바꾸고, optimizer는 host에서 돌리며, vLLM과 llm-d가 그대로
Expand Down Expand Up @@ -119,7 +121,7 @@ pip install -e .
apt-get install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dev
```

- **평가:** `vllm` (`npu_lora.bench`에만 필요).
- **평가:** `vllm` (`npu_train.bench`에만 필요).

```bash
# 1. RNGD 기울기가 CPU 기준과 일치하는지 확인 (앞 2 레이어).
Expand Down Expand Up @@ -174,9 +176,9 @@ Job은 공식 `furiosa-llm` 이미지에 ConfigMap으로 패키지를 마운트
<br>

```python
from npu_lora import LoRATrainer, LoRAConfig, TrainConfig
from npu_lora import backends, export
from npu_lora.data import PackedDataset
from npu_train import LoRATrainer, LoRAConfig, TrainConfig
from npu_train import backends, export
from npu_train.data import PackedDataset
from transformers import AutoTokenizer

trainer = LoRATrainer(
Expand Down Expand Up @@ -209,9 +211,9 @@ export.save_peft(trainer, "./adapter") # TrainConfig(full=True)이면 expor
| `npu-lora serve` | 실행 중인 vLLM에 어댑터 로드 |
| `npu-lora eval` | OpenAI 호환 엔드포인트로 키워드 정답률 평가 |
| `npu-lora job` | 쿠버네티스 학습 Job 출력 |
| `python -m npu_lora.bench` | 기본 모델 / 어댑터 / 전체 모델의 vLLM 오프라인 벤치마크 |
| `python -m npu_lora.compare` | 학습 loss 곡선 두 개 비교 |
| `python -m npu_lora.hwprobe` | host↔device 대역폭과 전송/계산 겹침 측정 |
| `python -m npu_train.bench` | 기본 모델 / 어댑터 / 전체 모델의 vLLM 오프라인 벤치마크 |
| `python -m npu_train.compare` | 학습 loss 곡선 두 개 비교 |
| `python -m npu_train.hwprobe` | host↔device 대역폭과 전송/계산 겹침 측정 |

자주 쓰는 학습 옵션:

Expand All @@ -237,7 +239,7 @@ npu-lora는 ai-rm 구성요소다(계층 `l3-serving`, kind `workload`, 성숙

| Entry-point 그룹 | 이름 | 객체 |
| --- | --- | --- |
| `airm.workloads` | `npu-lora` | `npu_lora.airm:train` |
| `airm.workloads` | `npu-lora` | `npu_train.airm:train` |

```python
from rm_core import Workload, registry
Expand Down Expand Up @@ -294,7 +296,7 @@ helm template deploy/helm/npu-lora --set train.model=… --set train.data=…

rm-core `METRICS` 이름을 쓴다. 학습 처리량 `tok_s`(Prometheus `airm_tok_s`, 태그 `component=npu-lora`,
`workload=train`, `model`, `vendor`, `run_id`; runner 반환값에도 들어 있다). 정확도 `accuracy_pct`는
`npu_lora.bench` 결과 JSON의 `measurements`(태그 `dataset=nsmc|mmlu`, `run_id`=변형 이름)에 있다. rm-core에 없는
`npu_train.bench` 결과 JSON의 `measurements`(태그 `dataset=nsmc|mmlu`, `run_id`=변형 이름)에 있다. rm-core에 없는
양은 `npu_lora_*`로 낸다(`npu_lora_loss`, `npu_lora_grad_norm`, `npu_lora_step_seconds` 등).

**Deprecated**: 예전 처리량 시리즈 `npu_lora_tokens_per_second`(라벨 `run`)는 `airm_tok_s`와 같은 값으로 프로토콜
Expand Down Expand Up @@ -346,16 +348,16 @@ python tests/test_cpu.py # CPU 회귀 테스트 (NPU 불필요)
새 모델이나 SDK 버전을 올릴 때:

1. `npu-lora check`가 통과해야 한다 (장치 대 CPU 기울기).
2. 컴파일이 실패하면 `npu_lora.diagnose.first_failing_node`로 처음 실패하는 연산을 찾고, 의미를 보존하는
2. 컴파일이 실패하면 `npu_train.diagnose.first_failing_node`로 처음 실패하는 연산을 찾고, 의미를 보존하는
재작성을 `graph.PASSES`에 추가한다.
3. 컴파일은 되는데 결과가 틀리면 `npu_lora.diagnose.compare_parts`로 컴파일된 조각마다 같은 입력에서 CPU와 비교한다.
3. 컴파일은 되는데 결과가 틀리면 `npu_train.diagnose.compare_parts`로 컴파일된 조각마다 같은 입력에서 CPU와 비교한다.

`scripts/vendor-into-lmd-top.sh`는 패키지를 lmd-top에 복사한다. lmd-top은 이를 자신이 만드는 Job에 넣는다.
</details>

### 한계

- Llama 구조만 지원한다. 다른 구조는 레이어를 순수 함수로 작성해야 한다(`npu_lora/llama.py` 참조).
- Llama 구조만 지원한다. 다른 구조는 레이어를 순수 함수로 작성해야 한다(`npu_train/llama.py` 참조).
- micro-batch당 패킹된 시퀀스 1개다. 더 큰 배치는 `--accum`을 쓴다.
- 첫 컴파일이 느리고(8B 모델은 수 시간) 시퀀스 길이마다 따로 컴파일한다.
- furiosa-torch는 privileged 컨테이너에서만 장치를 연다.
Expand Down
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@

---

Formerly the `npu-lora` repository; the Python package, CLI and Helm chart keep the name `npu-lora`.
Formerly the `npu-lora` repository. The Python package is `npu_train` (distribution `npu-train`); the old package
name `npu_lora` still imports and runs (`python -m npu_lora.<module>`) as a deprecated alias. The CLI command
`npu-lora` (also installed as `npu-train`), the ai-rm workload name and the Helm chart keep the name `npu-lora`.

**npu-train** (Python package and CLI `npu-lora`) trains Llama-family models on the FuriosaAI RNGD — an accelerator whose SDK ships only an
**npu-train** (Python package `npu_train`, CLI `npu-lora`) trains Llama-family models on the FuriosaAI RNGD — an accelerator whose SDK ships only an
inference compiler and runtime. It turns the backward pass into ordinary compiled graphs, keeps the
optimizer on the host, and produces standard Hugging Face artifacts (PEFT adapters or full models)
that vLLM and llm-d serve as-is. The same code runs on CUDA and CPU for reference runs.
Expand Down Expand Up @@ -120,7 +122,7 @@ Requirements:
apt-get install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dev
```

- **Evaluation:** `vllm` (only for `npu_lora.bench`).
- **Evaluation:** `vllm` (only for `npu_train.bench`).

```bash
# 1. Verify that RNGD gradients match the CPU reference (first 2 layers).
Expand Down Expand Up @@ -175,9 +177,9 @@ a ServiceMonitor. [lmd-top](https://github.com/ai-computing/lmd-top) builds the
<br>

```python
from npu_lora import LoRATrainer, LoRAConfig, TrainConfig
from npu_lora import backends, export
from npu_lora.data import PackedDataset
from npu_train import LoRATrainer, LoRAConfig, TrainConfig
from npu_train import backends, export
from npu_train.data import PackedDataset
from transformers import AutoTokenizer

trainer = LoRATrainer(
Expand Down Expand Up @@ -210,9 +212,9 @@ export.save_peft(trainer, "./adapter") # export.save_full(...) with TrainCo
| `npu-lora serve` | Load an adapter into a running vLLM |
| `npu-lora eval` | Keyword-accuracy evaluation against an OpenAI-compatible endpoint |
| `npu-lora job` | Print a Kubernetes training Job |
| `python -m npu_lora.bench` | vLLM offline benchmark of base / adapters / full models |
| `python -m npu_lora.compare` | Compare two training loss curves |
| `python -m npu_lora.hwprobe` | Measure host↔device bandwidth and transfer/compute overlap |
| `python -m npu_train.bench` | vLLM offline benchmark of base / adapters / full models |
| `python -m npu_train.compare` | Compare two training loss curves |
| `python -m npu_train.hwprobe` | Measure host↔device bandwidth and transfer/compute overlap |

Frequently used training options:

Expand All @@ -238,7 +240,7 @@ FuriosaAI RNGD, an inference-only ahead-of-time-compiled NPU, and produces HF PE

| Entry-point group | Name | Object |
| --- | --- | --- |
| `airm.workloads` | `npu-lora` | `npu_lora.airm:train` |
| `airm.workloads` | `npu-lora` | `npu_train.airm:train` |

```python
from rm_core import Workload, registry
Expand Down Expand Up @@ -296,7 +298,7 @@ helm template deploy/helm/npu-lora --set train.model=… --set train.data=…

Using rm-core `METRICS` names: training throughput `tok_s` (Prometheus `airm_tok_s`, tags
`component=npu-lora`, `workload=train`, `model`, `vendor`, `run_id`; also in the runner's return value).
Accuracy `accuracy_pct` is in the `measurements` of the `npu_lora.bench` result JSON (tag
Accuracy `accuracy_pct` is in the `measurements` of the `npu_train.bench` result JSON (tag
`dataset=nsmc|mmlu`, `run_id` = variant name). Quantities not in rm-core are exported as `npu_lora_*`
(`npu_lora_loss`, `npu_lora_grad_norm`, `npu_lora_step_seconds`, …).

Expand Down Expand Up @@ -351,9 +353,9 @@ synchronous update.
When you bring up a new model or SDK version:

1. `npu-lora check` must pass (device vs CPU gradients).
2. If compilation fails, `npu_lora.diagnose.first_failing_node` locates the first failing op; add a
2. If compilation fails, `npu_train.diagnose.first_failing_node` locates the first failing op; add a
semantics-preserving rewrite to `graph.PASSES`.
3. If results are wrong but compilation succeeds, `npu_lora.diagnose.compare_parts` compares every
3. If results are wrong but compilation succeeds, `npu_train.diagnose.compare_parts` compares every
compiled part with the CPU on the same inputs.

`scripts/vendor-into-lmd-top.sh` copies the package into lmd-top, which embeds it in the Jobs it
Expand All @@ -363,7 +365,7 @@ generates.
### Limitations

- Llama architecture only. Other architectures need their layer written as a pure function
(see `npu_lora/llama.py`).
(see `npu_train/llama.py`).
- One packed sequence per micro-batch; use `--accum` for larger batches.
- First compilation is slow (hours for an 8B model) and is per sequence length.
- furiosa-torch opens devices only from privileged containers.
Expand Down
20 changes: 13 additions & 7 deletions STATUS.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# STATUS — RNGD NPU 파인튜닝 학습

<!-- research-hub:header:begin (maintained by .research/report.py; keep the "- **Key**: value" format) -->
- **State**: idle
- **Updated**: 2026-10-22 01:48+09:00
- **Agent**: claude@control-node
- **Task**: #40 resident AdamW DRAM_SHARED OOM (done)
- **Last result**: 2 RNGD x 8 resident 200/200 steps, no OOM, 4.43 s/step (463 tok/s) steady; 1 card x 4 resident at low load 4.79 s vs 1-card offload 5.11 s, model +3.0%
- **Next**: report the runtime flag to Furiosa
- **State**: active
- **Updated**: 2026-10-22 11:54+09:00
- **Agent**: claude@dev-host
- **Task**: #46 rename package npu_lora to npu_train
- **Last result**: package moved to npu_train; npu_lora kept as deprecated alias (same module objects, python -m npu_lora.X works); CPU tests 38/38 in a clean venv
- **Next**: maintainer review of PR; then uninstall npu-lora and pip install -e . on shared hosts
- **Blockers**: none
<!-- research-hub:header:end -->

## Goal

추론 전용 AOT 컴파일 NPU인 Furiosa RNGD에서 LoRA와 full fine-tuning을 실용 수준으로 돌리고, 같은 조건의 A100 학습과 품질·속도를 비교한다. 구현은 공개 저장소 [ai-computing/npu-lora](https://github.com/ai-computing/npu-lora)의 `npu_lora` 패키지(백엔드 furiosa/cuda/cpu)다. 결과를 llm-d 서빙(vLLM `--enable-lora`)과 lmd-top(`--plan train`)에 붙이고, ai-rm 구성요소(`ai-rm.yaml`, protocol 0.1)로 내는 것까지 범위에 넣는다 (`README.md`).
추론 전용 AOT 컴파일 NPU인 Furiosa RNGD에서 LoRA와 full fine-tuning을 실용 수준으로 돌리고, 같은 조건의 A100 학습과 품질·속도를 비교한다. 구현은 공개 저장소 [ai-computing/npu-train](https://github.com/ai-computing/npu-train)의 `npu_train` 패키지(백엔드 furiosa/cuda/cpu, 예전 이름 `npu_lora`는 deprecated 별칭으로 남김, #46)다. 결과를 llm-d 서빙(vLLM `--enable-lora`)과 lmd-top(`--plan train`)에 붙이고, ai-rm 구성요소(`ai-rm.yaml`, protocol 0.1)로 내는 것까지 범위에 넣는다 (`README.md`).

## Findings

Expand Down Expand Up @@ -42,6 +42,12 @@

<!-- research-hub:log (report.py inserts new entries below this line, newest first) -->

### 2026-10-22 11:54+09:00 — #46 rename package npu_lora to npu_train

- Result: package moved to npu_train; npu_lora kept as deprecated alias (same module objects, python -m npu_lora.X works); CPU tests 38/38 in a clean venv
- Next: maintainer review of PR; then uninstall npu-lora and pip install -e . on shared hosts
- By: claude@dev-host · refactor/46-npu-train-package@af1e8f5-dirty

### 2026-10-22 01:48+09:00 — #40 resident AdamW DRAM_SHARED OOM ✅

- Result: 2 RNGD x 8 resident 200/200 steps, no OOM, 4.43 s/step (463 tok/s) steady; 1 card x 4 resident at low load 4.79 s vs 1-card offload 5.11 s, model +3.0%
Expand Down
4 changes: 2 additions & 2 deletions ai-rm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ test:
- python -m rm_core.conformance
adapters:
- group: airm.workloads
name: npu-lora # npu_lora.airm:train
name: npu-lora # npu_train.airm:train
deploy:
target: k8s
chart: deploy/helm/npu-lora # 학습 Job (helm template deploy/helm/npu-lora)
manifests: null # `npu-lora job ... | kubectl apply -f -` 도 같은 Job 을 만든다
image: null # 공식 furiosaai/furiosa-llm 이미지 + 시작 시 pip 설치(chart) 또는 ConfigMap(CLI)
metrics: [tok_s, accuracy_pct] # tok_s: 학습 처리량(workload=train), accuracy_pct: npu_lora.bench(dataset=nsmc|mmlu)
metrics: [tok_s, accuracy_pct] # tok_s: 학습 처리량(workload=train), accuracy_pct: npu_train.bench(dataset=nsmc|mmlu)
config:
env_example: cluster.example.env
interfaces:
Expand Down
2 changes: 1 addition & 1 deletion deploy/helm/npu-lora/templates/job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ spec:
- --
- python3
- -m
- npu_lora.cli
- npu_train.cli
- train
- --model
- {{ $t.model | quote }}
Expand Down
2 changes: 1 addition & 1 deletion deploy/helm/npu-lora/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ enabled: true
image: {repository: furiosaai/furiosa-llm, tag: latest}
imagePullPolicy: IfNotPresent
install:
pip: "npu-lora @ git+https://github.com/ai-computing/npu-train@main"
pip: "npu-train @ git+https://github.com/ai-computing/npu-train@main"
airm:
kvTransport: "" # 학습에는 KV 경로가 없다 — 비워 둔다
placement: ""
Expand Down
6 changes: 3 additions & 3 deletions docs/compiler-workarounds.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 컴파일러 우회 (furiosa-torch 2026.2)

추론용 AOT 컴파일러에 역전파 그래프를 넣으면서 만난 문제와 대응이다. 모든 대응은 `npu_lora/graph.py` 의
추론용 AOT 컴파일러에 역전파 그래프를 넣으면서 만난 문제와 대응이다. 모든 대응은 `npu_train/graph.py` 의
그래프 변환(`graph.PASSES`) 또는 분할·컴파일 단계에 있고, `graph.build` 가 변환 전후 결과를 CPU 로 비교한다.

| 증상 | 원인 | 대응 |
Expand All @@ -25,11 +25,11 @@
| 컴파일은 되는데 실행이 `failed to run TP program … TimedOut` | 전치 view 위에서 위치 축 mean + sub + bmm 이 한 조각에 있을 때 | mean 을 전치 전 `[S, nkv, hd]` 에서 |
| `npu-lora check` 가 엉뚱한 차이 | furiosa 를 불러오면 `torch.manual_seed` 가 장치 쪽에서 경고만 내고 끝나 두 trainer 의 A 초기값이 달라짐 | 어댑터 초기화에 전용 `torch.Generator` |

값이 틀리는 문제는 컴파일 오류가 나지 않는다. `npu_lora.diagnose.compare_parts` 로 조각마다 CPU 와 장치 출력을
값이 틀리는 문제는 컴파일 오류가 나지 않는다. `npu_train.diagnose.compare_parts` 로 조각마다 CPU 와 장치 출력을
같은 입력으로 비교한다. 학습 루프의 컴파일 샘플은 0/상수라서 이런 문제를 잡지 못하니, 새 모델은 반드시
`npu-lora check` 로 기울기를 비교한다.

새 모델·새 SDK 에서 컴파일이 실패하면 `npu_lora.diagnose.first_failing_node` 로 처음 실패하는 노드를 찾고,
새 모델·새 SDK 에서 컴파일이 실패하면 `npu_train.diagnose.first_failing_node` 로 처음 실패하는 노드를 찾고,
의미를 바꾸지 않는 변환을 `graph.PASSES` 에 넣는다. 모든 변환은 `graph.build` 가 CPU 재실행으로 결과가
같은지 확인한다.

Expand Down
Loading
Loading