onw 0.4.1: Japanese README (README.md) + English (README_en.md); setup/start call find_python.bat by path
Browse files- README.md +152 -145
- README_en.md +136 -0
- onw/__init__.py +1 -1
- pyproject.toml +1 -1
- setup.bat +44 -44
- start.bat +52 -52
README.md
CHANGED
|
@@ -1,145 +1,152 @@
|
|
| 1 |
-
---
|
| 2 |
-
license: apache-2.0
|
| 3 |
-
library_name: openvino
|
| 4 |
-
|
| 5 |
-
-
|
| 6 |
-
-
|
| 7 |
-
|
| 8 |
-
-
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
-
--
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
``
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
onw
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
| 62 |
-
|
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
|
| 129 |
-
|
|
| 130 |
-
| `onw/
|
| 131 |
-
| `
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: openvino
|
| 4 |
+
language:
|
| 5 |
+
- ja
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- openvino
|
| 9 |
+
- npu
|
| 10 |
+
- intel
|
| 11 |
+
- intel-npu
|
| 12 |
+
- moe
|
| 13 |
+
- inference-engine
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# onw — 俺のNPUがこんなに動くわけない
|
| 17 |
+
|
| 18 |
+
**日本語** | [English](README_en.md)
|
| 19 |
+
|
| 20 |
+
LLM を **Intel NPU だけで** 動かす小さなエンジンです。MoE(専門家混合)モデルや Gated DeltaNet 系のハイブリッドモデル、
|
| 21 |
+
画像入力にも対応し、**OpenAI 互換 API サーバー**とブラウザのチャット画面を備えています。
|
| 22 |
+
llama.cpp と GGUF の関係と同じく、エンジンとモデルは別々にダウンロードします。エンジンは一つ、コマンドも一つで、
|
| 23 |
+
変換済みのモデルならどれでも動きます。
|
| 24 |
+
|
| 25 |
+
```bash
|
| 26 |
+
hf download ryugyosoft/onw --local-dir onw && cd onw
|
| 27 |
+
setup.bat # Windows:タスクトレイ常駐アプリ(おすすめ)
|
| 28 |
+
bash setup.sh # Ubuntu:右上に常駐するアプリ
|
| 29 |
+
start.bat # サーバーを一度だけ起動する場合(既定モデル:LFM2-8B-A1B)
|
| 30 |
+
bash start.sh ryugyosoft/Qwen3.6-35B-A3B-onw # Ubuntu で別のモデルを起動
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
`setup` は Python 3.10 以上を探し(Windows で見つからない場合は winget で Python 3.12 を入れるか確認します)、
|
| 34 |
+
`.venv` にエンジンと `onw` コマンドを入れ、スタートメニュー/アプリ一覧に **onw** を登録して常駐アプリを起動します
|
| 35 |
+
(Windows はタスクトレイ、Ubuntu は右上のインジケーター)。この時点ではモデルはまだ入っていません。
|
| 36 |
+
開いた **onw ウィンドウ**の「モデル」タブで、サイズ・必要メモリ・この PC で足りるかを見てモデルを選び、
|
| 37 |
+
「ダウンロード」を押します。あとは「サーバー」タブから起動します。モデルの初回起動時だけ NPU 向けのコンパイルが
|
| 38 |
+
走り、2 回目以降は約 20 秒で起動します。「設定」タブでは、ポート、LAN からの接続、API キー、コンテキスト長、デバイス、
|
| 39 |
+
先読み検証(PLD)、64 トークン処理、ログイン時の自動起動、モデルの保存先を変えられます。
|
| 40 |
+
|
| 41 |
+
**サーバーは OpenAI 互換 API です。** 他のアプリからは base URL に `http://localhost:8000/v1`、モデル名にウィンドウに
|
| 42 |
+
表示される名前を指定します。`GET /` でサーバーの案内(JSON)、`/health` でモデルの読み込み完了を確認できます。
|
| 43 |
+
CORS は開放済みで、LAN に公開する場合は API キー(`--api-key` または設定画面)で `/v1` を保護できます。
|
| 44 |
+
動作確認用に、チャット画面(`/chat`)と、テキスト・先読み検証・2 ターン会話・画像の検証を一括実行して速度を表に
|
| 45 |
+
する検証ページ(`/check`)もあり、どちらもトレイのメニューとウィンドウから開けます。
|
| 46 |
+
NPU ドライバーがない環境では CPU で動きます。
|
| 47 |
+
|
| 48 |
+
## `onw` コマンド
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
onw serve MODEL [--port 8000] [--host 0.0.0.0] [--api-key KEY] [--context 4096] [--device NPU|CPU] [--no-pld] [--open]
|
| 52 |
+
onw chat MODEL [--think] [--context 4096] # ターミナルでチャット
|
| 53 |
+
onw tray # 常駐アプリ(setup が起動するもの)
|
| 54 |
+
onw window [--tab models] # モデル管理・サーバー操作・設定のウィンドウ
|
| 55 |
+
onw convert HF_DIR OUT_DIR [--compact] [--prune SAL.json --keep 0.5] [--graphs-only]
|
| 56 |
+
onw list # 対応アーキテクチャ
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
設定を変えたときに何が必要か:
|
| 60 |
+
|
| 61 |
+
| 設定 | 変え方 | 再コンパイル |
|
| 62 |
+
|---|---|---|
|
| 63 |
+
| temperature、top_p、top_k、繰り返し抑制(repetition / presence / frequency penalty)、max_tokens、stop、seed、思考モード | リクエストごと(API またはチャット画面) | 不要 |
|
| 64 |
+
| ポート、待ち受けアドレス、モデル、デバイス、先読み検証のオン/オフ | サーバーのオプション/設定画面、再起動(約 20 秒) | 不要 |
|
| 65 |
+
| **コンテキスト長**(`--context`) | サーバーのオプション/設定画面 | **長さごとに 1 回**(入力の形が変わるだけで、モデルファイルはそのまま) |
|
| 66 |
+
| 64 トークン処理(Gemma) | `ONW_S64=1/0`/設定画面 | 初回のみ |
|
| 67 |
+
| ブロックサイズ、画像サイズ、量子化 | `onw convert` | 必要(変換し直し) |
|
| 68 |
+
|
| 69 |
+
コンテキスト長を長くすると、短い会話でも 1 トークンごとの計算とメモリが増えます(固定長の KV キャッシュ全体を
|
| 70 |
+
��回参照するため)。モデルの最大値ではなく、必要な長さを選んでください。
|
| 71 |
+
|
| 72 |
+
`MODEL` には onw 形式のモデルフォルダか Hugging Face のリポジトリ ID を指定します(ID の場合は `./models` に
|
| 73 |
+
ダウンロードされ、途中から再開できます)。`onw` コマンドは初回の `setup`/`start` のあと `.venv` に入ります
|
| 74 |
+
(Windows は `.venv\Scripts\onw`、Linux は `source .venv/bin/activate`)。任意の環境に入れる場合は
|
| 75 |
+
`pip install --pre -e . --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly` です。
|
| 76 |
+
|
| 77 |
+
Git LFS への対策:Git LFS なしで `git clone` したモデルには、重みの代わりに約 130 バイトの「ポインタ」ファイルしか
|
| 78 |
+
入っていません。`onw` はこれを検出し、直し方を表示して止まります。`hf download` を使うか、リポジトリ ID をそのまま
|
| 79 |
+
渡してください。
|
| 80 |
+
|
| 81 |
+
## モデル
|
| 82 |
+
|
| 83 |
+
| onw モデル | アーキテクチャ | 入力 | NPU 3720 生成速度 | ダウンロード | 使用メモリ |
|
| 84 |
+
|---|---|---|---|---|---|
|
| 85 |
+
| [ryugyosoft/LFM2-8B-A1B-onw](https://huggingface.co/ryugyosoft/LFM2-8B-A1B-onw) | `lfm2_moe`(短い畳み込み+GQA+MoE 32 個から 4 個) | テキスト | 16〜17 tok/s(コード修正・要約では先読み検証で 29〜43) | 4.0 GB | 約 6 GB |
|
| 86 |
+
| [ryugyosoft/gemma-4-E4B-it-onw](https://huggingface.co/ryugyosoft/gemma-4-E4B-it-onw) | `gemma4`(検証済みの Gemma NPU グラフを取り込み) | テキスト+画像 | 7.2 tok/s | 4.3 GB | 約 15 GB |
|
| 87 |
+
| [ryugyosoft/Qwen3.5-9B-onw](https://huggingface.co/ryugyosoft/Qwen3.5-9B-onw) | `qwen3_5`(Gated DeltaNet+ゲート付きアテンション、dense) | テキスト+画像 | 4.1 tok/s | 5.3 GB | 約 20 GB |
|
| 88 |
+
| [ryugyosoft/Qwen3.6-REAP-18B-A3B-onw](https://huggingface.co/ryugyosoft/Qwen3.6-REAP-18B-A3B-onw) | `qwen3_5_moe`、256 個中 128 個のエキスパートを残す(REAP) | テキスト+画像 | 6.8 tok/s | 9.6 GB | 約 15 GB |
|
| 89 |
+
| [ryugyosoft/Qwen3.6-35B-A3B-onw](https://huggingface.co/ryugyosoft/Qwen3.6-35B-A3B-onw) | `qwen3_5_moe`(Gated DeltaNet+ゲート付きアテンション+MoE 256 個から 8 個+共有エキスパート) | テキスト+画像 | 6.8 tok/s | 17 GB | 約 23 GB |
|
| 90 |
+
|
| 91 |
+
使用メモリは、テスト機(Core Ultra 9 285HX)で読み込んだあとのプロセスの作業セットです(OS が必要に応じて手放せる、
|
| 92 |
+
メモリマップされた重みファイル分を含みます)。先読み検証は、16 トークンの検証ブロックが十分安く済むモデル
|
| 93 |
+
(LFM2、Qwen3.5-9B、Gemma)で自動的に使われます。どのモデルも会話の状態をターン間で保持するので、画像付きの会話でも
|
| 94 |
+
2 ターン目は新しいメッセージだけを処理します(約 2 秒)。
|
| 95 |
+
|
| 96 |
+
## モデルを小さくする(onw convert --compact / --prune)
|
| 97 |
+
|
| 98 |
+
- `--compact`:1 トークン用と 16/64 トークン用のグラフが同じ重みファイルを共有します(ダウンロード量・ディスク)。
|
| 99 |
+
ホスト側で引くだけの表(出力層と共有していない埋め込み、Gemma の層ごとの埋め込み)は 32 要素ごとのスケール付き
|
| 100 |
+
INT4 に、Qwen の画像エンコーダーは INT8 にします。これらは使用メモリも減らしますが、重みファイルの共有だけは
|
| 101 |
+
ディスクにしか効きません(NPU はブロックサイズごとにコンパイル済みの重みを持つため)。
|
| 102 |
+
- `--prune SAL.json --keep 0.5`(MoE):REAP によるエキスパートの刈り込み。`python -m onw.prune calibrate HF_DIR SAL.json`
|
| 103 |
+
で各エキスパートの寄与度(日本語・英語・コードのチャットデータでの「ルーターの重み×出力の大きさ」の平均)を測り、
|
| 104 |
+
`python -m onw.prune eval` で残す割合ごとのパープレキシティを確認できます。Qwen3.6-35B-A3B は 256 個中 128 個を
|
| 105 |
+
残してパープレキシティ +8.9%(Qwen3.6-REAP-18B-A3B-onw として公開)。エキスパートが 32 個しかない LFM2 は
|
| 106 |
+
半分で +35% と落ち方が大きいため、刈り込んでいません。
|
| 107 |
+
|
| 108 |
+
## MoE を NPU で動かす仕組み
|
| 109 |
+
|
| 110 |
+
NPU は形の決まったグラフしか扱えませんが、MoE はトークンごとに違うエキスパートを選びます。NPU 3720 で Qwen3.6 の
|
| 111 |
+
寸法の 1 層・1 トークンを測ると、全エキスパートを計算すると 45 ms、グラフ内の Gather で選ぶ方式は INT4 定数では
|
| 112 |
+
コンパイルできず、INT8 や詰め込み形式でも 18〜135 ms(NPU が表全体を転送するため)でした。
|
| 113 |
+
**選んだエキスパートを実行時の入力として渡す方式なら 1.7 ms** で、NPU のメモリ帯域いっぱいに出ます。そこで:
|
| 114 |
+
|
| 115 |
+
- ネットワークを **MoE のルーターの直後で区間に分け**、ルーターの上位 k 個をホストが受け取って、次の区間に選ばれた
|
| 116 |
+
エキスパートの��みバッファを結び付けます(`set_tensor`、コピーなし。全エキスパートは NPU から見えるホストメモリ上の
|
| 117 |
+
`experts.bin` にあります)。
|
| 118 |
+
- エキスパートは **チャネル単位 INT4 を 1 エキスパート 1 テンソルに詰めた形** にします。実行時に渡す重みを NPU が
|
| 119 |
+
全速で扱えるのはこの形だけです(グループ単位のスケールを付けると要素ごとの遅い処理になり、20 倍遅くなります)。
|
| 120 |
+
- それ以外は区間の中のグループ 128 の INT4 定数です。出力層は共有の INT8 入力として独立した区間に置き(ブロック
|
| 121 |
+
サイズが違っても 1 つだけ、ロジットが不要なプロンプト処理では飛ばす)、埋め込みと Gemma の 2.7 GB の層ごとの
|
| 122 |
+
埋め込みはホストで引きます(実行時入力からの Gather は NPU が表全体を転送するため)。
|
| 123 |
+
- プロンプトのブロックではブロック内の全トークンが選んだエキスパートの和集合を、生成時はそのトークンの上位 k 個を
|
| 124 |
+
結び付けます。
|
| 125 |
+
|
| 126 |
+
## エンジンの構成
|
| 127 |
+
|
| 128 |
+
| ファイル | 内容 |
|
| 129 |
+
|---|---|
|
| 130 |
+
| `onw/ir.py` | グラフ部品:量子化線形層、RMSNorm(FP16 で溢れない前処理つき)、RoPE/部分 RoPE、ホスト管理の KV キャッシュ上のアテンション、エキスパート枠、Gated DeltaNet(1 トークン用の行列形式、ブロック倍々の厳密な逆行列によるチャンク並列形式) |
|
| 131 |
+
| `onw/runtime.py` | 区間の実行、命名規則による状態管理(KV の行、畳み込み窓、再帰状態)、エキスパートの結び付け、MRoPE、スライディング窓マスク、ホスト側の表引き、先読み検証のための正確な巻き戻し |
|
| 132 |
+
| `onw/chat.py` | 生成ループ:画像(Qwen/Gemma)、サンプリング、停止文字列、先読み検証(正確な巻き戻し、再帰状態を持つモデルでは遅延やり直し、効く場合だけ自動で有効)、ターン間の差分処理 |
|
| 133 |
+
| `onw/models/` | アーキテクチャごとの組み立て定義:`lfm2_moe`、`qwen3_5_moe`(dense と MoE)、`qwen_vision`、`gemma4` |
|
| 134 |
+
| `onw/hub.py`、`onw/server.py`、`onw/web/` | モデルのダウンロードと LFS 対策、OpenAI 互換サーバー、チャット画面(`/chat`)、検証ページ(`/check`) |
|
| 135 |
+
| `onw/app.py`、`onw/tray.py`、`setup.*`、`find_python.bat` | onw ウィンドウ(モデル/サーバー/設定)、トレイアイコン、インストーラー(Python の検出と winget) |
|
| 136 |
+
| `check_ref.py`、`check_vision.py`、`test_chat.py`、`test_image.py`、`probe_segments.py`、`prof_*.py` | 元の HF モデルとの比較、生成・画像・複数ターンの検証、区間ごとの NPU と CPU の比較、速度計測 |
|
| 137 |
+
|
| 138 |
+
## 注意点と制限
|
| 139 |
+
|
| 140 |
+
- コンテキスト長の既定は 1024 トークンです。`--context`/設定画面で読み込み時に変えられます(長さごとに NPU 向け
|
| 141 |
+
コンパイルが 1 回走ります)。Qwen の画像は 512×512(256 トークン)に縮小し、Gemma の画像は縦横比を保ちます
|
| 142 |
+
(最大 280 トークン)。
|
| 143 |
+
- エキスパートはチャネル単位 INT4(四捨五入量子化)です。確認した範囲では、最初のトークンのロジットは bf16 との差が
|
| 144 |
+
約 33% で、1 位の予測は一致しました。回答は自然ですが、数トークン先から言い回しが bf16 モデルと分かれます。
|
| 145 |
+
- 16 トークンより大きいプロンプトブロック(Gemma の 64 トークン版)は RAM 24 GB 以上のときだけ読み込みます
|
| 146 |
+
(`ONW_S64=1/0` で強制)。
|
| 147 |
+
- OpenVINO のプレリリース版(2026.5 nightly)が必要です。NPU 3720(Windows 11)で動作確認済み、CPU での動作は
|
| 148 |
+
Ubuntu 22.04(WSL)で確認しています。NPU 4000(Lunar Lake)と Ubuntu の右上常駐は、このエンジンではまだ未確認です。
|
| 149 |
+
|
| 150 |
+
## ライセンス
|
| 151 |
+
|
| 152 |
+
コードは Apache 2.0。変換済みモデルは元のモデルのライセンスに従います(各モデルのリポジトリを参照)。
|
README_en.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# onw — 俺のNPUがこんなに動くわけない
|
| 2 |
+
|
| 3 |
+
[日本語](README.md) | **English**
|
| 4 |
+
|
| 5 |
+
*(Ore no NPU ga konna ni ugoku wake nai — "There's no way my NPU runs this well")*
|
| 6 |
+
|
| 7 |
+
A small engine that runs LLMs — including MoE and hybrid DeltaNet models, with image input — **entirely on the
|
| 8 |
+
Intel NPU**, with an OpenAI-compatible server and a browser chat UI. Engine and models are separate downloads,
|
| 9 |
+
like llama.cpp + a GGUF: one engine, one command, any converted model.
|
| 10 |
+
|
| 11 |
+
```bash
|
| 12 |
+
hf download ryugyosoft/onw --local-dir onw && cd onw
|
| 13 |
+
setup.bat # Windows: resident task-tray app (recommended)
|
| 14 |
+
bash setup.sh # Ubuntu: resident top-bar app
|
| 15 |
+
start.bat # or just run the server once (default model: LFM2-8B-A1B)
|
| 16 |
+
bash start.sh ryugyosoft/Qwen3.6-35B-A3B-onw # Ubuntu, another model
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
`setup` finds Python 3.10+ (on Windows it offers to install Python 3.12 with winget when there is none),
|
| 20 |
+
installs the engine and the `onw` command into `.venv`, adds **onw** to the Start menu / application list and
|
| 21 |
+
starts a small resident app (task tray on Windows, top-bar indicator on Ubuntu). No model is downloaded yet:
|
| 22 |
+
the **onw window** opens on its *Models* tab - pick a model (sizes, memory needs and what fits this PC are shown)
|
| 23 |
+
and press *Download*. Then the *Server* tab starts it; the first start of a model compiles it for the NPU, later
|
| 24 |
+
starts take ~20 s. The *Settings* tab has port, LAN access, API key, context length, device, prompt lookup
|
| 25 |
+
decoding, 64-token blocks, start at login and the models folder.
|
| 26 |
+
|
| 27 |
+
**The server is an OpenAI-compatible API**: point other apps at `http://localhost:8000/v1` with the model name
|
| 28 |
+
shown in the window (`GET /` describes the server, `/health` answers once the model is loaded, CORS is open,
|
| 29 |
+
`--api-key` / the settings' API key protects `/v1`). For trying things out it also serves a chat UI at `/chat` and
|
| 30 |
+
a check page at `/check` that runs a text, prompt-lookup, two-turn and image test and shows the speeds; both open
|
| 31 |
+
from the tray menu and the window. Without an NPU driver everything runs on the CPU.
|
| 32 |
+
|
| 33 |
+
## The `onw` command
|
| 34 |
+
|
| 35 |
+
```bash
|
| 36 |
+
onw serve MODEL [--port 8000] [--host 0.0.0.0] [--api-key KEY] [--context 4096] [--device NPU|CPU] [--no-pld] [--open]
|
| 37 |
+
onw chat MODEL [--think] [--context 4096] # chat in the terminal
|
| 38 |
+
onw tray # the resident app (what setup starts)
|
| 39 |
+
onw window [--tab models] # model manager, server control, settings
|
| 40 |
+
onw convert HF_DIR OUT_DIR [--compact] [--prune SAL.json --keep 0.5] [--graphs-only]
|
| 41 |
+
onw list # supported architectures
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
What needs what:
|
| 45 |
+
|
| 46 |
+
| setting | how | recompile? |
|
| 47 |
+
|---|---|---|
|
| 48 |
+
| temperature, top_p, top_k, repetition / presence / frequency penalty, max_tokens, stop, seed, thinking | per request (API or chat UI) | no |
|
| 49 |
+
| port, address, model, device, prompt lookup on/off | server option / tray settings, restart (~20 s) | no |
|
| 50 |
+
| **context length** (`--context`) | server option / tray settings | **once per length** (input shapes change; the model files stay the same) |
|
| 51 |
+
| 64-token prompt blocks (Gemma) | `ONW_S64=1/0` / tray setting | once, the first time |
|
| 52 |
+
| block sizes, image size, quantization | `onw convert` | yes (new conversion) |
|
| 53 |
+
|
| 54 |
+
A longer context costs memory and time on every token (the static KV cache is attended in full), so pick what you
|
| 55 |
+
need rather than the model's maximum.
|
| 56 |
+
|
| 57 |
+
`MODEL` is an onw model folder or a Hugging Face repo id (downloaded into `./models`, resumable). The command is in
|
| 58 |
+
`.venv` after the first `start` (`.venv\Scripts\onw` on Windows, `source .venv/bin/activate` on Linux), or
|
| 59 |
+
install it anywhere with `pip install --pre -e . --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly`.
|
| 60 |
+
|
| 61 |
+
Git LFS guard: a model repo cloned with `git` but without Git LFS contains ~130-byte pointer files instead of the
|
| 62 |
+
weights; `onw` detects that and stops with instructions. Prefer `hf download` (or just pass the repo id).
|
| 63 |
+
|
| 64 |
+
## Models
|
| 65 |
+
|
| 66 |
+
| onw model | arch | input | NPU 3720 decode | download | memory in use |
|
| 67 |
+
|---|---|---|---|---|---|
|
| 68 |
+
| [ryugyosoft/LFM2-8B-A1B-onw](https://huggingface.co/ryugyosoft/LFM2-8B-A1B-onw) | `lfm2_moe` (short conv + GQA + MoE 32x top-4) | text | 16-17 tok/s (29-43 with prompt lookup on code / summaries) | 4.0 GB | ~6 GB |
|
| 69 |
+
| [ryugyosoft/gemma-4-E4B-it-onw](https://huggingface.co/ryugyosoft/gemma-4-E4B-it-onw) | `gemma4` (imported from the validated Gemma NPU graphs) | text + image | 7.2 tok/s | 4.3 GB | ~15 GB |
|
| 70 |
+
| [ryugyosoft/Qwen3.5-9B-onw](https://huggingface.co/ryugyosoft/Qwen3.5-9B-onw) | `qwen3_5` (Gated DeltaNet + gated attention, dense) | text + image | 4.1 tok/s | 5.3 GB | ~20 GB |
|
| 71 |
+
| [ryugyosoft/Qwen3.6-REAP-18B-A3B-onw](https://huggingface.co/ryugyosoft/Qwen3.6-REAP-18B-A3B-onw) | `qwen3_5_moe`, 128 of 256 experts kept (REAP) | text + image | 6.8 tok/s | 9.6 GB | ~15 GB |
|
| 72 |
+
| [ryugyosoft/Qwen3.6-35B-A3B-onw](https://huggingface.co/ryugyosoft/Qwen3.6-35B-A3B-onw) | `qwen3_5_moe` (Gated DeltaNet + gated attention + MoE 256x top-8 + shared expert) | text + image | 6.8 tok/s | 17 GB | ~23 GB |
|
| 73 |
+
|
| 74 |
+
Memory is the process working set on the test machine after loading (includes memory-mapped weight files the
|
| 75 |
+
OS can page out).
|
| 76 |
+
|
| 77 |
+
Measured with an image chat / text prompts on Core Ultra 9 285HX; prompt lookup decoding is used automatically
|
| 78 |
+
where a 16-token verification block is cheap enough (LFM2, Qwen3.5-9B, Gemma), and every model keeps the
|
| 79 |
+
conversation state between turns (a follow-up with an image re-processes only the new message: ~2 s).
|
| 80 |
+
|
| 81 |
+
## Smaller models (onw convert --compact / --prune)
|
| 82 |
+
|
| 83 |
+
- `--compact`: the 1-token and 16/64-token graphs of a segment share one weights file (download / disk);
|
| 84 |
+
host-only lookup tables (token embeddings not tied to the LM head, Gemma's per-layer embeddings) are INT4 with a
|
| 85 |
+
scale per 32 values; the Qwen vision tower is INT8. These also shrink the memory in use, except the shared
|
| 86 |
+
weights file: the NPU keeps one compiled copy per block size.
|
| 87 |
+
- `--prune SAL.json --keep 0.5` (MoE): REAP expert pruning. `python -m onw.prune calibrate HF_DIR SAL.json`
|
| 88 |
+
measures each expert's saliency (mean router weight x output norm over chat data in Japanese, English and code),
|
| 89 |
+
`python -m onw.prune eval` reports the perplexity for several keep ratios. Qwen3.6-35B-A3B keeps 128 of 256
|
| 90 |
+
experts at +8.9% perplexity (published as Qwen3.6-REAP-18B-A3B-onw); LFM2 with only 32 experts loses +35% at
|
| 91 |
+
50%, so it is not pruned.
|
| 92 |
+
|
| 93 |
+
## How it runs a MoE on an NPU
|
| 94 |
+
|
| 95 |
+
NPUs need static graphs, and a sparse MoE picks different experts per token. Measured on NPU 3720 (Qwen3.6
|
| 96 |
+
sizes, per layer, one token): computing every expert 45 ms; selecting experts inside the graph with Gather does
|
| 97 |
+
not compile for INT4 constants and is 18-135 ms for INT8 / packed forms (the NPU moves whole tables);
|
| 98 |
+
**passing the chosen experts as runtime inputs: 1.7 ms**, at the NPU's memory bandwidth. So:
|
| 99 |
+
|
| 100 |
+
- the network is cut into **segments right after every MoE router**; the router's top-k goes to the host, which
|
| 101 |
+
binds the selected experts' weight buffers into the next segment (`set_tensor`, zero copy: all experts live in
|
| 102 |
+
NPU-visible host memory, `experts.bin`);
|
| 103 |
+
- experts are **channel-wise INT4 packed as one tensor per expert** — the only weights-as-inputs form the NPU runs
|
| 104 |
+
at full speed (group-wise scales on runtime weights fall back to slow element-wise work, 20x slower);
|
| 105 |
+
- everything else is group-128 INT4 constants inside the segments; the LM head is a shared INT8 input in its own
|
| 106 |
+
segment (one copy for all block sizes, skipped for prompt blocks that need no logits); token embeddings and
|
| 107 |
+
Gemma's 2.7 GB per-layer embeddings are looked up on the host (a gather from a runtime input makes the NPU move
|
| 108 |
+
the whole table);
|
| 109 |
+
- prompt blocks bind the union of the block's experts; decoding binds the token's top-k.
|
| 110 |
+
|
| 111 |
+
## Engine pieces
|
| 112 |
+
|
| 113 |
+
| file | what |
|
| 114 |
+
|---|---|
|
| 115 |
+
| `onw/ir.py` | graph blocks: quantized linears, RMSNorm (with an fp16-safe prescale), RoPE / partial RoPE, attention over a host KV cache, expert slots, Gated DeltaNet (1-token matrix form; chunkwise-parallel form with an exact block-doubling inverse) |
|
| 116 |
+
| `onw/runtime.py` | runs the segments; state by naming convention (KV rows, conv windows, recurrent states), expert binding, MRoPE, sliding-window masks, host table lookups, exact truncation for speculative verification |
|
| 117 |
+
| `onw/chat.py` | chat loop: images (Qwen / Gemma), sampling, stop strings, prompt lookup decoding (exact rewind, or lazy redo for recurrent models, switched on only when it pays), prefix reuse between turns |
|
| 118 |
+
| `onw/models/` | one builder per architecture: `lfm2_moe`, `qwen3_5_moe` (dense and MoE), `qwen_vision`, `gemma4` |
|
| 119 |
+
| `onw/hub.py`, `onw/server.py`, `onw/web/` | model download + LFS guard, OpenAI-compatible server, chat UI (`/chat`), check page (`/check`) |
|
| 120 |
+
| `onw/app.py`, `onw/tray.py`, `setup.*`, `find_python.bat` | onw window (models / server / settings), tray icon, installers (Python detection + winget) |
|
| 121 |
+
| `check_ref.py`, `check_vision.py`, `test_chat.py`, `test_image.py`, `probe_segments.py`, `prof_*.py` | vs the HF model, generation / image / multi-turn checks, NPU-vs-CPU per segment, timing |
|
| 122 |
+
|
| 123 |
+
## Notes and limitations
|
| 124 |
+
|
| 125 |
+
- The context is 1024 tokens by default; `--context` / the settings change it at load time (one NPU compile per
|
| 126 |
+
length). Qwen images are resized to 512x512 (256 tokens); Gemma images keep their aspect
|
| 127 |
+
ratio (up to 280 tokens).
|
| 128 |
+
- Experts are channel-wise INT4 (round-to-nearest): first-token logits within ~33% of bf16 with the same top-1 on
|
| 129 |
+
our checks; answers are fluent, word choices diverge from the bf16 model after a few tokens.
|
| 130 |
+
- Prompt blocks above 16 tokens (Gemma's 64-token block) are loaded only with >= 24 GB RAM (`ONW_S64=1/0`).
|
| 131 |
+
- Needs a pre-release OpenVINO (2026.5 nightly). Tested on NPU 3720 (Windows 11); CPU fallback on Ubuntu 22.04
|
| 132 |
+
(WSL). NPU 4000 (Lunar Lake) untested with this engine.
|
| 133 |
+
|
| 134 |
+
## License
|
| 135 |
+
|
| 136 |
+
Code: Apache 2.0. Converted models carry their base model's license (see each model repo).
|
onw/__init__.py
CHANGED
|
@@ -2,4 +2,4 @@
|
|
| 2 |
|
| 3 |
A small engine that runs LLMs entirely on the Intel NPU: static segment graphs + host-managed state.
|
| 4 |
"""
|
| 5 |
-
__version__ = "0.4.
|
|
|
|
| 2 |
|
| 3 |
A small engine that runs LLMs entirely on the Intel NPU: static segment graphs + host-managed state.
|
| 4 |
"""
|
| 5 |
+
__version__ = "0.4.1"
|
pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
| 4 |
|
| 5 |
[project]
|
| 6 |
name = "onw"
|
| 7 |
-
version = "0.4.
|
| 8 |
description = "Ore no NPU ga konna ni ugoku wake nai - LLMs entirely on the Intel NPU"
|
| 9 |
readme = "README.md"
|
| 10 |
license = {text = "Apache-2.0"}
|
|
|
|
| 4 |
|
| 5 |
[project]
|
| 6 |
name = "onw"
|
| 7 |
+
version = "0.4.1"
|
| 8 |
description = "Ore no NPU ga konna ni ugoku wake nai - LLMs entirely on the Intel NPU"
|
| 9 |
readme = "README.md"
|
| 10 |
license = {text = "Apache-2.0"}
|
setup.bat
CHANGED
|
@@ -1,44 +1,44 @@
|
|
| 1 |
-
@echo off
|
| 2 |
-
rem onw - Ore no NPU ga konna ni ugoku wake nai: install the engine and the resident tray app (Windows).
|
| 3 |
-
rem Finds Python 3.10+ (offers to install it with winget), creates .venv, installs onw + the tray, adds "onw" to
|
| 4 |
-
rem the Start menu and starts it in the task tray. Models are downloaded later from the onw window (Models tab).
|
| 5 |
-
setlocal
|
| 6 |
-
cd /d "%~dp0"
|
| 7 |
-
set PYTHONUTF8=1
|
| 8 |
-
|
| 9 |
-
if exist ".venv\installed-tray.txt" goto shortcut
|
| 10 |
-
if exist ".venv\Scripts\python.exe" goto install
|
| 11 |
-
call
|
| 12 |
-
if not defined PY (
|
| 13 |
-
pause
|
| 14 |
-
exit /b 1
|
| 15 |
-
)
|
| 16 |
-
echo [setup] creating Python environment in .venv ...
|
| 17 |
-
%PY% -m venv .venv
|
| 18 |
-
if errorlevel 1 (
|
| 19 |
-
echo [setup] could not create the Python environment.
|
| 20 |
-
pause
|
| 21 |
-
exit /b 1
|
| 22 |
-
)
|
| 23 |
-
:install
|
| 24 |
-
".venv\Scripts\python.exe" -m pip install -U pip
|
| 25 |
-
".venv\Scripts\python.exe" -m pip install --pre -e .[tray] --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
|
| 26 |
-
if errorlevel 1 (
|
| 27 |
-
echo [setup] package installation failed.
|
| 28 |
-
pause
|
| 29 |
-
exit /b 1
|
| 30 |
-
)
|
| 31 |
-
echo ok> ".venv\installed.txt"
|
| 32 |
-
echo ok> ".venv\installed-tray.txt"
|
| 33 |
-
|
| 34 |
-
:shortcut
|
| 35 |
-
rem Start menu entry: pythonw -m onw tray (no console window)
|
| 36 |
-
set "PYW=%CD%\.venv\Scripts\pythonw.exe"
|
| 37 |
-
powershell -NoProfile -Command ^
|
| 38 |
-
"$s = (New-Object -ComObject WScript.Shell).CreateShortcut([Environment]::GetFolderPath('Programs') + '\onw.lnk');" ^
|
| 39 |
-
"$s.TargetPath = '%PYW%'; $s.Arguments = '-m onw tray'; $s.WorkingDirectory = '%CD%';" ^
|
| 40 |
-
"$s.Description = 'onw - LLMs on the Intel NPU'; $s.Save()"
|
| 41 |
-
echo [setup] Start menu: onw
|
| 42 |
-
|
| 43 |
-
echo [start] onw is starting in the task tray. Pick a model to download in the window that opens.
|
| 44 |
-
start "" "%PYW%" -m onw tray
|
|
|
|
| 1 |
+
@echo off
|
| 2 |
+
rem onw - Ore no NPU ga konna ni ugoku wake nai: install the engine and the resident tray app (Windows).
|
| 3 |
+
rem Finds Python 3.10+ (offers to install it with winget), creates .venv, installs onw + the tray, adds "onw" to
|
| 4 |
+
rem the Start menu and starts it in the task tray. Models are downloaded later from the onw window (Models tab).
|
| 5 |
+
setlocal
|
| 6 |
+
cd /d "%~dp0"
|
| 7 |
+
set PYTHONUTF8=1
|
| 8 |
+
|
| 9 |
+
if exist ".venv\installed-tray.txt" goto shortcut
|
| 10 |
+
if exist ".venv\Scripts\python.exe" goto install
|
| 11 |
+
call "%~dp0find_python.bat"
|
| 12 |
+
if not defined PY (
|
| 13 |
+
pause
|
| 14 |
+
exit /b 1
|
| 15 |
+
)
|
| 16 |
+
echo [setup] creating Python environment in .venv ...
|
| 17 |
+
%PY% -m venv .venv
|
| 18 |
+
if errorlevel 1 (
|
| 19 |
+
echo [setup] could not create the Python environment.
|
| 20 |
+
pause
|
| 21 |
+
exit /b 1
|
| 22 |
+
)
|
| 23 |
+
:install
|
| 24 |
+
".venv\Scripts\python.exe" -m pip install -U pip
|
| 25 |
+
".venv\Scripts\python.exe" -m pip install --pre -e .[tray] --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
|
| 26 |
+
if errorlevel 1 (
|
| 27 |
+
echo [setup] package installation failed.
|
| 28 |
+
pause
|
| 29 |
+
exit /b 1
|
| 30 |
+
)
|
| 31 |
+
echo ok> ".venv\installed.txt"
|
| 32 |
+
echo ok> ".venv\installed-tray.txt"
|
| 33 |
+
|
| 34 |
+
:shortcut
|
| 35 |
+
rem Start menu entry: pythonw -m onw tray (no console window)
|
| 36 |
+
set "PYW=%CD%\.venv\Scripts\pythonw.exe"
|
| 37 |
+
powershell -NoProfile -Command ^
|
| 38 |
+
"$s = (New-Object -ComObject WScript.Shell).CreateShortcut([Environment]::GetFolderPath('Programs') + '\onw.lnk');" ^
|
| 39 |
+
"$s.TargetPath = '%PYW%'; $s.Arguments = '-m onw tray'; $s.WorkingDirectory = '%CD%';" ^
|
| 40 |
+
"$s.Description = 'onw - LLMs on the Intel NPU'; $s.Save()"
|
| 41 |
+
echo [setup] Start menu: onw
|
| 42 |
+
|
| 43 |
+
echo [start] onw is starting in the task tray. Pick a model to download in the window that opens.
|
| 44 |
+
start "" "%PYW%" -m onw tray
|
start.bat
CHANGED
|
@@ -1,52 +1,52 @@
|
|
| 1 |
-
@echo off
|
| 2 |
-
rem onw - Ore no NPU ga konna ni ugoku wake nai: run the server once from a console (Windows).
|
| 3 |
-
rem start.bat LFM2-8B-A1B (default, fits 16 GB machines)
|
| 4 |
-
rem start.bat ryugyosoft/Qwen3.6-35B-A3B-onw any onw model: a Hugging Face repo id or a local folder
|
| 5 |
-
rem start.bat MODEL --port 8080 further options go to "onw serve"
|
| 6 |
-
rem First run: finds / installs Python, creates .venv (~1 GB), downloads the model, compiles it for the NPU.
|
| 7 |
-
rem For the resident tray app with a model manager use setup.bat instead.
|
| 8 |
-
setlocal
|
| 9 |
-
cd /d "%~dp0"
|
| 10 |
-
set PYTHONUTF8=1
|
| 11 |
-
set "MODEL=ryugyosoft/LFM2-8B-A1B-onw"
|
| 12 |
-
set "FIRST=%~1"
|
| 13 |
-
if not "%FIRST%"=="" if not "%FIRST:~0,1%"=="-" (
|
| 14 |
-
set "MODEL=%FIRST%"
|
| 15 |
-
shift
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
if exist ".venv\installed.txt" goto args
|
| 19 |
-
if exist ".venv\Scripts\python.exe" goto install
|
| 20 |
-
call
|
| 21 |
-
if not defined PY (
|
| 22 |
-
pause
|
| 23 |
-
exit /b 1
|
| 24 |
-
)
|
| 25 |
-
echo [setup] creating Python environment in .venv ...
|
| 26 |
-
%PY% -m venv .venv
|
| 27 |
-
if errorlevel 1 (
|
| 28 |
-
echo [setup] could not create the Python environment.
|
| 29 |
-
pause
|
| 30 |
-
exit /b 1
|
| 31 |
-
)
|
| 32 |
-
:install
|
| 33 |
-
".venv\Scripts\python.exe" -m pip install -U pip
|
| 34 |
-
".venv\Scripts\python.exe" -m pip install --pre -e . --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
|
| 35 |
-
if errorlevel 1 (
|
| 36 |
-
echo [setup] package installation failed.
|
| 37 |
-
pause
|
| 38 |
-
exit /b 1
|
| 39 |
-
)
|
| 40 |
-
echo ok> ".venv\installed.txt"
|
| 41 |
-
|
| 42 |
-
:args
|
| 43 |
-
set "ARGS="
|
| 44 |
-
:collect
|
| 45 |
-
if "%~1"=="" goto run
|
| 46 |
-
set "ARGS=%ARGS% %1"
|
| 47 |
-
shift
|
| 48 |
-
goto collect
|
| 49 |
-
:run
|
| 50 |
-
echo [start] %MODEL% (first time: download + NPU compile, please wait) ...
|
| 51 |
-
".venv\Scripts\onw.exe" serve %MODEL% --open %ARGS%
|
| 52 |
-
pause
|
|
|
|
| 1 |
+
@echo off
|
| 2 |
+
rem onw - Ore no NPU ga konna ni ugoku wake nai: run the server once from a console (Windows).
|
| 3 |
+
rem start.bat LFM2-8B-A1B (default, fits 16 GB machines)
|
| 4 |
+
rem start.bat ryugyosoft/Qwen3.6-35B-A3B-onw any onw model: a Hugging Face repo id or a local folder
|
| 5 |
+
rem start.bat MODEL --port 8080 further options go to "onw serve"
|
| 6 |
+
rem First run: finds / installs Python, creates .venv (~1 GB), downloads the model, compiles it for the NPU.
|
| 7 |
+
rem For the resident tray app with a model manager use setup.bat instead.
|
| 8 |
+
setlocal
|
| 9 |
+
cd /d "%~dp0"
|
| 10 |
+
set PYTHONUTF8=1
|
| 11 |
+
set "MODEL=ryugyosoft/LFM2-8B-A1B-onw"
|
| 12 |
+
set "FIRST=%~1"
|
| 13 |
+
if not "%FIRST%"=="" if not "%FIRST:~0,1%"=="-" (
|
| 14 |
+
set "MODEL=%FIRST%"
|
| 15 |
+
shift
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
if exist ".venv\installed.txt" goto args
|
| 19 |
+
if exist ".venv\Scripts\python.exe" goto install
|
| 20 |
+
call "%~dp0find_python.bat"
|
| 21 |
+
if not defined PY (
|
| 22 |
+
pause
|
| 23 |
+
exit /b 1
|
| 24 |
+
)
|
| 25 |
+
echo [setup] creating Python environment in .venv ...
|
| 26 |
+
%PY% -m venv .venv
|
| 27 |
+
if errorlevel 1 (
|
| 28 |
+
echo [setup] could not create the Python environment.
|
| 29 |
+
pause
|
| 30 |
+
exit /b 1
|
| 31 |
+
)
|
| 32 |
+
:install
|
| 33 |
+
".venv\Scripts\python.exe" -m pip install -U pip
|
| 34 |
+
".venv\Scripts\python.exe" -m pip install --pre -e . --extra-index-url https://storage.openvinotoolkit.org/simple/wheels/nightly
|
| 35 |
+
if errorlevel 1 (
|
| 36 |
+
echo [setup] package installation failed.
|
| 37 |
+
pause
|
| 38 |
+
exit /b 1
|
| 39 |
+
)
|
| 40 |
+
echo ok> ".venv\installed.txt"
|
| 41 |
+
|
| 42 |
+
:args
|
| 43 |
+
set "ARGS="
|
| 44 |
+
:collect
|
| 45 |
+
if "%~1"=="" goto run
|
| 46 |
+
set "ARGS=%ARGS% %1"
|
| 47 |
+
shift
|
| 48 |
+
goto collect
|
| 49 |
+
:run
|
| 50 |
+
echo [start] %MODEL% (first time: download + NPU compile, please wait) ...
|
| 51 |
+
".venv\Scripts\onw.exe" serve %MODEL% --open %ARGS%
|
| 52 |
+
pause
|