yongqiang commited on
Commit
fe14390
·
1 Parent(s): 18ff147

Update README and sample assets

Browse files
README.md CHANGED
@@ -2,79 +2,98 @@
2
  library_name: transformers
3
  license: apache-2.0
4
  base_model:
5
- - openbmb/MiniCPM-V-4.6
6
  pipeline_tag: image-text-to-text
7
  tags:
8
- - minicpm-v
9
- - vlm
10
- - axera
11
- - AX650
 
12
  language:
13
- - zh
14
- - en
15
  ---
16
 
17
  # MiniCPM-V-4.6 on AXERA NPU
18
 
19
- Ready-to-run AX650 deployment package for `openbmb/MiniCPM-V-4.6`.
20
 
21
- - Runtime: `axllm serve` and `axllm run`
22
- - Target: `AX650 / AX650N aarch64`
23
- - Text backend: Qwen3.5 dense LLM, `bf16`, non-GPTQ weights
24
- - Vision backend: fixed-shape `448x448` MiniCPM-V-4.6 vision encoder
25
- - Context layout: `prefill_len=128`, `kv_cache_len=2047`, `prefill_max_token_num=1280`
26
- - Validated capabilities in this release:
27
- - text-only chat
28
- - long prompt multi-chunk prefill
29
- - single-image understanding
30
- - video understanding
31
- - Included board binary:
32
- - `bin/axllm` for `AX650/AX650N aarch64`
33
-
34
- This package has been validated for text chat, single-image understanding, and video understanding through the OpenAI-compatible `axllm serve` API.
35
 
36
  ## Supported Platform
37
 
38
- - [x] AX650 / AX650N
 
 
 
 
 
 
39
 
40
- ## Performance and Footprint
41
 
42
- Measurements below are from the preserved AX650 runtime log in [Inference Log](#inference-log), plus a repeated text-only TTFT recheck on `2026-06-05`. `TTFT` means time to first token.
43
- The text-only smoke prompt is intentionally kept within one `128`-token prefill group. Its TTFT is the 5-run average for the prompt `1+1等于几?只输出数字。`; the response is one token, so decode throughput is not reported for that row.
 
44
 
45
  | Scenario | Input tokens | Prefill chunks | TTFT | Decode |
46
  |---|---:|---:|---:|---:|
47
  | Text-only smoke prompt | `22` | `1 x 128` | `240.45 ms avg` (`239.20-242.75 ms`) | `n/a` |
48
- | Video red-panda prompt | `1278` | `10 x 128` | `1795.28 ms` | `18.79 token/s` |
49
- | Image prompt | `358` | `3 x 128` | `518.23 ms` | `18.64 token/s` |
50
 
51
- ### Flash Footprint
52
 
53
- | Item | Value |
54
- |---|---:|
55
- | Text + post + vision axmodels | `1460.19 MiB` |
56
- | Package flash footprint, excluding `vision_cache/` | `1999.34 MiB` |
57
 
58
  ### Startup Runtime Footprint
59
 
60
- Measured on AX650 on `2026-06-05` by reading `/proc/ax_proc/mem_cmm_info` before startup and after the `/health` endpoint became ready. The measurement kept the existing GPTQ service on port `8000` running and records only the incremental CMM used by this extra service.
61
-
62
  | Item | Value |
63
  |---|---:|
64
- | Baseline CMM before startup | `1823 MB` |
65
- | CMM after `/health` ready | `3388 MB` |
66
- | Incremental runtime CMM | `1565 MB` |
67
- | Startup log `remain_cmm` after post axmodel init | `5388 MB` |
68
 
69
- The preserved standalone inference log below records `remain_cmm(6933 MB)` for an earlier single-service startup; use the incremental CMM row above for the board-side footprint measured during this README refresh.
70
 
71
- The runtime log also records the video sampling decision:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  ```text
74
- MiniCPM-V-4.6 video frames selected: 19/59 (configured_cap=0, tail_tokens=1278, max_tail=1280, precompute_len=0)
75
  ```
76
 
77
- ## Repository Layout
 
 
 
 
 
 
78
 
79
  ```text
80
  .
@@ -83,7 +102,9 @@ MiniCPM-V-4.6 video frames selected: 19/59 (configured_cap=0, tail_tokens=1278,
83
  │ ├── axllm
84
  │ └── axllm.version.json
85
  ├── assets/
86
- ── smoke_image.png
 
 
87
  ├── python/
88
  │ ├── infer_axmodel.py
89
  │ ├── infer_torch.py
@@ -99,7 +120,36 @@ MiniCPM-V-4.6 video frames selected: 19/59 (configured_cap=0, tail_tokens=1278,
99
  └── minicpm_v46_tokenizer.txt
100
  ```
101
 
102
- ## Install `axllm`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  Option 1: use the validated binary included in this repository:
105
 
@@ -107,18 +157,53 @@ Option 1: use the validated binary included in this repository:
107
  chmod +x ./bin/axllm
108
  ```
109
 
110
- Option 2: build or install the latest `ax-llm` yourself:
111
 
112
- - Repo: `https://github.com/AXERA-TECH/ax-llm`
113
- - The included binary metadata is recorded in `bin/axllm.version.json`.
 
 
 
114
 
115
- ## Run on AX650
116
 
117
- From the repository root on the board:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
  ```bash
120
- chmod +x ./bin/axllm
121
- ./bin/axllm serve . --port 18080
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  ```
123
 
124
  Expected model id:
@@ -127,10 +212,72 @@ Expected model id:
127
  AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047
128
  ```
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  ### Text Request
131
 
132
  ```bash
133
- curl http://127.0.0.1:18080/v1/chat/completions \
134
  -H 'Content-Type: application/json' \
135
  -d '{
136
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
@@ -138,7 +285,7 @@ curl http://127.0.0.1:18080/v1/chat/completions \
138
  {
139
  "role": "user",
140
  "content": [
141
- {"type": "text", "text": "1+1等于几?只输出数字。"}
142
  ]
143
  }
144
  ],
@@ -146,16 +293,34 @@ curl http://127.0.0.1:18080/v1/chat/completions \
146
  }'
147
  ```
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  ### Image Request
150
 
151
  ```bash
152
- python - <<'PY'
153
  import base64
154
  import json
155
  from pathlib import Path
156
  from urllib.request import Request, urlopen
157
 
158
- img = Path("assets/smoke_image.png").read_bytes()
159
  payload = {
160
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
161
  "messages": [
@@ -175,7 +340,7 @@ payload = {
175
  "max_tokens": 64,
176
  }
177
  req = Request(
178
- "http://127.0.0.1:18080/v1/chat/completions",
179
  data=json.dumps(payload).encode(),
180
  headers={"Content-Type": "application/json"},
181
  )
@@ -184,12 +349,30 @@ with urlopen(req, timeout=60) as resp:
184
  PY
185
  ```
186
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  ### Video Request
188
 
189
- `axllm serve` supports a frames directory or a raw video file:
190
 
191
  ```bash
192
- curl http://127.0.0.1:18080/v1/chat/completions \
193
  -H 'Content-Type: application/json' \
194
  -d '{
195
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
@@ -206,36 +389,56 @@ curl http://127.0.0.1:18080/v1/chat/completions \
206
  }'
207
  ```
208
 
209
- For a raw video file, use `video:/path/to/video.mp4` or `video:/path/to/video.mp4:2` to request a sampling FPS of `2`.
210
 
211
- ### Interactive CLI
212
 
213
  ```bash
214
- ./bin/axllm run .
215
  ```
216
 
217
- After each prompt:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
 
219
- - press `Enter` directly for text-only chat
220
- - input an image path for single-image chat
221
- - input `video:<frames_dir>` for video chat
222
 
223
- ## Python Reference Scripts
224
 
225
- ### Official PyTorch Reference
226
 
227
- `python/infer_torch.py` is a developer-side reference script. It requires the full upstream HuggingFace model with weights and is intended for x86/GPU validation.
228
 
229
- ```bash
230
- cd python
231
- python infer_torch.py \
232
- --model-path /data/tmp/yongqiang/nfs/auto_model_deployment/Minicpm-V-4.6-hf-original/MiniCPM-V-4.6 \
233
- --prompt "1+1等于几?请直接回答。"
234
- ```
235
 
236
- ### Python `.axmodel` Debug Runner
237
 
238
- `python/infer_axmodel.py` is a text-only per-layer debug runner for the compiled LLM package:
 
 
 
 
239
 
240
  ```bash
241
  cd python
@@ -243,159 +446,43 @@ python3 infer_axmodel.py \
243
  --hf-model ./minicpm_v46_tokenizer \
244
  --axmodel-dir .. \
245
  --mode generate \
246
- --prompt "1+1等于几?请直接回答。" \
247
  --prompt-mode prefill \
248
  --max-new-tokens 16 \
249
  --kv-cache-len 2047
250
  ```
251
 
252
- ## Notes
253
 
254
- 1. `.axmodel` files are board-only. Do not run them on x86.
255
- 2. This package was compiled with `--prefill_len 128 --kv_cache_len 2047`.
256
- 3. The AX650 build keeps `FLOAT_MATMUL_USE_CONV_EU=1` enabled to reduce TTFT.
257
- 4. `bin/axllm.version.json` records the exact runtime binary commit and verification metadata.
258
- 5. The packaged vision encoder is fixed at `448x448`; arbitrary image/video sizes are resized by the runtime preprocessor.
259
- 6. Video requests are isolated to the current user turn and drop KV cache after the response to avoid stale multimodal history reuse.
260
 
 
 
 
 
 
 
261
 
262
- ## Inference Log
263
 
264
- ```sh
265
- root@ax650 ~/yongqiang/auto_model_deployment/MiniCPM-V-4.6 # ./bin/axllm serve .
266
- 14:59:39.577 INF Init:2239 | LLM init start
267
- 14:59:39.577 INF Init:2248 | mixed attention enabled: full_attention_interval=4 ref_full_layer_idx=3
268
- 14:59:39.577 INF Init:2270 | attention config: layers=24 sliding=0 full=6 linear=18 sliding_window=0 ref_full_layer_idx=3
269
- tokenizer_type = 3
270
- huggingface tokenizer mode = gpt2_byte_bpe
271
- 44% | ############## | 12 / 27 [4.73s<10.63s, 2.54 count/s] init 10 axmodel ok,remain_cmm(7587 MB 96% | ############################## | 26 / 27 [6.15s<6.39s, 4.23 count/s] init post axmodel ok,remain_cmm(6933 MB)
272
- 14:59:45.729 INF Init:2420 | max_token_len : 2047
273
- 14:59:45.729 INF Init:2423 | kv_cache_size : 512, kv_cache_num: 2047
274
- 14:59:45.729 INF init_groups_from_model:1622 | prefill_token_num : 128
275
- 14:59:45.729 INF init_groups_from_model:1870 | decode grp: 0, gid: 0, max_token_len : 2047
276
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 0, gid: 1, history_cap: 0, total_cap: 128, symbolic_cap: 1
277
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 1, gid: 2, history_cap: 128, total_cap: 256, symbolic_cap: 128
278
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 2, gid: 3, history_cap: 256, total_cap: 384, symbolic_cap: 256
279
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 3, gid: 4, history_cap: 384, total_cap: 512, symbolic_cap: 384
280
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 4, gid: 5, history_cap: 512, total_cap: 640, symbolic_cap: 512
281
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 5, gid: 6, history_cap: 640, total_cap: 768, symbolic_cap: 640
282
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 6, gid: 7, history_cap: 768, total_cap: 896, symbolic_cap: 768
283
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 7, gid: 8, history_cap: 896, total_cap: 1024, symbolic_cap: 896
284
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 8, gid: 9, history_cap: 1024, total_cap: 1152, symbolic_cap: 1024
285
- 14:59:45.729 INF init_groups_from_model:1874 | prefill grp: 9, gid: 10, history_cap: 1152, total_cap: 1280, symbolic_cap: 1152
286
- 14:59:45.729 INF init_groups_from_model:1881 | prefill_max_token_num : 1280
287
- 14:59:45.729 INF init_layer_groups:1026 | layer 0 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
288
- 14:59:45.729 INF init_layer_groups:1026 | layer 1 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
289
- 14:59:45.729 INF init_layer_groups:1026 | layer 2 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
290
- 14:59:45.729 INF init_layer_groups:1026 | layer 4 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
291
- 14:59:45.729 INF init_layer_groups:1026 | layer 5 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
292
- 14:59:45.729 INF init_layer_groups:1026 | layer 6 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
293
- 14:59:45.729 INF init_layer_groups:1026 | layer 8 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
294
- 14:59:45.729 INF init_layer_groups:1026 | layer 9 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
295
- 14:59:45.729 INF init_layer_groups:1026 | layer 10 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
296
- 14:59:45.729 INF init_layer_groups:1026 | layer 12 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
297
- 14:59:45.729 INF init_layer_groups:1026 | layer 13 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
298
- 14:59:45.729 INF init_layer_groups:1026 | layer 14 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
299
- 14:59:45.730 INF init_layer_groups:1026 | layer 16 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
300
- 14:59:45.730 INF init_layer_groups:1026 | layer 17 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
301
- 14:59:45.730 INF init_layer_groups:1026 | layer 18 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
302
- 14:59:45.730 INF init_layer_groups:1026 | layer 20 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
303
- 14:59:45.730 INF init_layer_groups:1026 | layer 21 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
304
- 14:59:45.730 INF init_layer_groups:1026 | layer 22 prefill groups=2 ref=10, reuse gid 2 for later prefill chunks
305
- 14:59:45.730 INF Init:27 | LLaMaEmbedSelector use mmap
306
- 100% | ################################ | 27 / 27 [6.16s<6.16s, 4.39 count/s] embed_selector init ok
307
- 14:59:47.002 INF Init:1507 | MiniCPM-V-4.6 token ids: image_pad=248056 video_pad=248057
308
- 14:59:47.002 INF Init:1514 | VisionModule init ok: type=MiniCPMV46VL, tokens_per_block=64, embed_size=1024, out_dtype=fp32
309
- 14:59:47.002 WRN Init:1523 | Vision preprocess backend: SimpleCV (OpenCV not found at build time; minor differences vs OpenCV are possible)
310
- 14:59:47.004 INF load_config:444 | load config:
311
- 14:59:47.004 INF load_config:444 | {
312
- 14:59:47.004 INF load_config:444 | "enable_repetition_penalty": false,
313
- 14:59:47.004 INF load_config:444 | "enable_temperature": false,
314
- 14:59:47.004 INF load_config:444 | "enable_top_k_sampling": false,
315
- 14:59:47.004 INF load_config:444 | "enable_top_p_sampling": false,
316
- 14:59:47.004 INF load_config:444 | "penalty_window": 20,
317
- 14:59:47.004 INF load_config:444 | "repetition_penalty": 1.2,
318
- 14:59:47.004 INF load_config:444 | "temperature": 0.9,
319
- 14:59:47.004 INF load_config:444 | "top_k": 10,
320
- 14:59:47.004 INF load_config:444 | "top_p": 0.8
321
- 14:59:47.004 INF load_config:444 | }
322
- 14:59:47.004 INF Init:2532 | LLM init ok
323
- Starting server on port 8000 with model 'AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047'...
324
- API URLs:
325
- GET http://127.0.0.1:8000/health
326
- GET http://127.0.0.1:8000/v1/models
327
- POST http://127.0.0.1:8000/v1/chat/completions
328
- GET http://10.168.232.217:8000/health
329
- GET http://10.168.232.217:8000/v1/models
330
- POST http://10.168.232.217:8000/v1/chat/completions
331
- GET http://172.17.0.1:8000/health
332
- GET http://172.17.0.1:8000/v1/models
333
- POST http://172.17.0.1:8000/v1/chat/completions
334
- Aliases:
335
- GET http://127.0.0.1:8000/models
336
- POST http://127.0.0.1:8000/chat/completions
337
- GET http://10.168.232.217:8000/models
338
- POST http://10.168.232.217:8000/chat/completions
339
- GET http://172.17.0.1:8000/models
340
- POST http://172.17.0.1:8000/chat/completions
341
- OpenAI API Server starting on http://0.0.0.0:8000
342
- Max concurrency: 1
343
- Models: AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047
344
- 15:00:35.571 INF operator():2136 | OpenAI chat request: model=AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047 stream=1 max_tokens=2048 has_temperature=0 temperature=1.0000 has_top_p=0 top_p=1.0000 messages=1 stop=0
345
- 15:00:35.572 INF SetKVCache:3134 | decode_grpid:0 prefill_grpid:1 history_cap:0 total_cap:128 symbolic_cap:1 precompute_len:0 input_num_token:16 prefer_symbolic_group:0
346
- 15:00:35.572 INF SetKVCache:3156 | current prefill_max_token_num:1280
347
- 15:00:35.588 INF SetKVCache:3172 | first run
348
- 15:00:35.602 INF Run:3376 | input token num : 16, prefill_split_num : 1
349
- 15:00:35.602 INF Run:3387 | MiniCPM-V-4.6 short text prefill uses decode replay: input_tokens=16 prefill_tokens=128 precompute_len=0
350
- 15:00:35.602 INF Run:3471 | prefill chunk p=0 history_len=0 grpid=1 kv_cache_num=0 input_tokens=16
351
- 15:00:36.091 INF Run:3886 | ttft: 488.83 ms
352
- I'm a model from the MiniCPM series, developed by Modelbest and OpenBMB. For more details, you can visit https://github.com/OpenBMB/
353
-
354
- 15:00:37.997 NTC Run:4298 | hit eos,decode avg 17.84 token/s
355
- 15:00:37.997 INF GetKVCache:3087 | precompute_len:51, remaining:1229 (tracked)
356
- 15:01:11.728 INF operator():2136 | OpenAI chat request: model=AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047 stream=1 max_tokens=2048 has_temperature=0 temperature=1.0000 has_top_p=0 top_p=1.0000 messages=3 stop=0
357
- 15:01:11.941 WRN Run:4330 | video history is isolated to current user turn: old_history=3 new_history=1 old_media_inputs=1 new_media_inputs=1
358
- 15:01:12.096 INF extract_video_frames_ffmpeg:386 | Extracting raw video container to frames: /tmp/axllm_media/media_863804170273309_0.mp4 -> /tmp/axllm_video_frames/video_863804326631725_0 fps=1.9907760708716282
359
- 15:01:13.679 INF collect_video_frame_paths:466 | Video fps sampling: path=/tmp/axllm_media/media_863804170273309_0.mp4 fps=2 duration=30.139s target_frames=60 selected=59
360
- 15:01:13.687 INF Prepare:2594 | MiniCPM-V-4.6 video frames selected: 19/59 (configured_cap=0, tail_tokens=1278, max_tail=1280, precompute_len=0)
361
- 15:01:24.499 INF SetKVCache:3134 | decode_grpid:0 prefill_grpid:1 history_cap:0 total_cap:128 symbolic_cap:1 precompute_len:0 input_num_token:1278 prefer_symbolic_group:0
362
- 15:01:24.499 INF SetKVCache:3156 | current prefill_max_token_num:1280
363
- 15:01:24.516 INF SetKVCache:3172 | first run
364
- 15:01:24.531 INF Run:3376 | input token num : 1278, prefill_split_num : 10
365
- 15:01:24.531 INF Run:3471 | prefill chunk p=0 history_len=0 grpid=1 kv_cache_num=0 input_tokens=128
366
- 15:01:24.689 INF Run:3471 | prefill chunk p=1 history_len=128 grpid=3 kv_cache_num=256 input_tokens=128
367
- 15:01:24.865 INF Run:3471 | prefill chunk p=2 history_len=256 grpid=4 kv_cache_num=384 input_tokens=128
368
- 15:01:25.041 INF Run:3471 | prefill chunk p=3 history_len=384 grpid=5 kv_cache_num=512 input_tokens=128
369
- 15:01:25.219 INF Run:3471 | prefill chunk p=4 history_len=512 grpid=6 kv_cache_num=640 input_tokens=128
370
- 15:01:25.398 INF Run:3471 | prefill chunk p=5 history_len=640 grpid=7 kv_cache_num=768 input_tokens=128
371
- 15:01:25.578 INF Run:3471 | prefill chunk p=6 history_len=768 grpid=8 kv_cache_num=896 input_tokens=128
372
- 15:01:25.759 INF Run:3471 | prefill chunk p=7 history_len=896 grpid=9 kv_cache_num=1024 input_tokens=128
373
- 15:01:25.943 INF Run:3471 | prefill chunk p=8 history_len=1024 grpid=10 kv_cache_num=1152 input_tokens=128
374
- 15:01:26.128 INF Run:3471 | prefill chunk p=9 history_len=1152 grpid=10 kv_cache_num=1152 input_tokens=126
375
- 15:01:26.327 INF Run:3886 | ttft: 1795.28 ms
376
- 好的,我很乐意为您描述这个视频的内容。
377
-
378
- 这张图片展示了一个活泼可爱的红熊猫,它正积极地参与着某种游戏或探索活动。从画面来看,这只红熊猫有着标志性的红棕色和黑色相间的毛色,面部和胸部有白色的标记,非常醒目。它正用前爪紧紧抓住一根由竹子或类似材料搭建的木制梯子或支架,身体微微前倾,似乎正在用力或试图攀爬。它的姿态充满了动感和专注,显示出它对这个环境非常感兴趣。
379
-
380
- 在画面的下方,还有一只较小的红熊猫,它正抬头向上看,似乎是在观察上方那只正在攀爬的同伴,或者是在等待自己的机会。这两只红熊猫被安置在一个绿色的草地上,背景中可以看到一些绿色的围栏或墙壁,暗示这可能是在一个动物园或野生动物保护区的围栏内。
381
-
382
- 整个场景充满了自然和活力,红熊猫们通过互动和探索,展现了它们的天性和对环境的适应。这个视频捕捉到了它们 playful 和 curious 的瞬间,让人感受到它们活泼可爱的性格。
383
-
384
- 15:01:37.610 NTC Run:4298 | hit eos,decode avg 18.79 token/s
385
- 15:01:37.610 WRN Run:4631 | drop KV cache after isolated video-history request
386
- ^@15:02:51.406 INF operator():2136 | OpenAI chat request: model=AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047 stream=1 max_tokens=2048 has_temperature=0 temperature=1.0000 has_top_p=0 top_p=1.0000 messages=4 stop=0
387
- 15:02:51.622 INF EncodeForContent:2080 | MiniCPM-V-4.6 pixel_values bytes=602112 min=2 max=250 (w=448 h=448 ps=14)
388
- 15:02:52.151 INF EncodeForContent:2124 | vision cache store: /tmp/axllm_media/media_863903737595189_1.png
389
- 15:02:52.225 INF SetKVCache:3134 | decode_grpid:0 prefill_grpid:1 history_cap:0 total_cap:128 symbolic_cap:1 precompute_len:0 input_num_token:358 prefer_symbolic_group:0
390
- 15:02:52.225 INF SetKVCache:3156 | current prefill_max_token_num:1280
391
- 15:02:52.242 INF SetKVCache:3172 | first run
392
- 15:02:52.258 INF Run:3376 | input token num : 358, prefill_split_num : 3
393
- 15:02:52.258 INF Run:3471 | prefill chunk p=0 history_len=0 grpid=1 kv_cache_num=0 input_tokens=128
394
- 15:02:52.414 INF Run:3471 | prefill chunk p=1 history_len=128 grpid=3 kv_cache_num=256 input_tokens=128
395
- 15:02:52.587 INF Run:3471 | prefill chunk p=2 history_len=256 grpid=4 kv_cache_num=384 input_tokens=102
396
- 15:02:52.776 INF Run:3886 | ttft: 518.23 ms
397
- 这张图片展示了一个年轻的女性,她有着长长的银灰色头发,头发上装饰着一些花朵。她穿着一件浅灰色的比基尼,比基尼上有褶皱和蕾丝细节,显得非常优雅。她的面部表情平静,眼神直视前方,给人一种温柔和自信的感觉。背景是海滩,可以看到海浪轻轻拍打着沙滩,远处有绿色的树木,整个场景显得非常宁静和自然。女性的姿态轻松,似乎在享受海滩上的美好时光。
398
-
399
- 15:02:57.605 NTC Run:4298 | hit eos,decode avg 18.64 token/s
400
- 15:02:57.605 INF GetKVCache:3087 | precompute_len:449, remaining:831 (tracked)
401
- ```
 
2
  library_name: transformers
3
  license: apache-2.0
4
  base_model:
5
+ - openbmb/MiniCPM-V-4.6
6
  pipeline_tag: image-text-to-text
7
  tags:
8
+ - minicpm-v
9
+ - vlm
10
+ - video-understanding
11
+ - axera
12
+ - ax650
13
  language:
14
+ - zh
15
+ - en
16
  ---
17
 
18
  # MiniCPM-V-4.6 on AXERA NPU
19
 
20
+ Ready-to-run deployment package for `openbmb/MiniCPM-V-4.6` on AX650 / NPU3.
21
 
22
+ - This release packages the AX650 `axllm` runtime together with the compiled text and vision `.axmodel` files.
23
+ - The packaged text runtime uses the non-GPTQ BF16 build.
24
+ - The packaged vision runtime uses a fixed-shape `448x448` MiniCPM-V-4.6 vision encoder.
25
+ - The package supports text-only chat, single-image understanding, and video understanding through the OpenAI-compatible `axllm serve` API.
26
+ - The package also includes board-side and server-side Python reference scripts for debugging and comparison.
 
 
 
 
 
 
 
 
 
27
 
28
  ## Supported Platform
29
 
30
+ - [x] AX650 / NPU3
31
+
32
+ ## Validated Devices
33
+
34
+ This package has been validated on the following AX650-based device:
35
+
36
+ - AX650 / NPU3 development board
37
 
38
+ ## Performance
39
 
40
+ All measurements below were taken on AX650 / NPU3. `TTFT` stands for time to first token.
41
+
42
+ The text-only smoke prompt was kept within one `128`-token prefill chunk. The image and video rows were measured with the packaged fixed-shape `448x448` vision encoder.
43
 
44
  | Scenario | Input tokens | Prefill chunks | TTFT | Decode |
45
  |---|---:|---:|---:|---:|
46
  | Text-only smoke prompt | `22` | `1 x 128` | `240.45 ms avg` (`239.20-242.75 ms`) | `n/a` |
47
+ | Image prompt | `88` | `1 x 128` | `232.54 ms avg` (`231.53-233.22 ms`) | `18.97 token/s avg` |
48
+ | Video prompt | `1274` | `10 x 128` | `2468.50 ms` | `18.62 token/s` |
49
 
50
+ The packaged runtime uses the following context layout:
51
 
52
+ - `prefill_len=128`
53
+ - `kv_cache_len=2047`
54
+ - `prefill_max_token_num=1280`
 
55
 
56
  ### Startup Runtime Footprint
57
 
 
 
58
  | Item | Value |
59
  |---|---:|
60
+ | `Flash total (text + post + vision axmodels)` | `1.43 GiB` (`1460.19 MiB`) |
61
+ | `Package flash total (excluding vision_cache/)` | `1.93 GiB` (`1980.33 MiB`) |
62
+ | `Runtime CMM increment during board-side startup` | `1565 MB` |
 
63
 
64
+ The runtime CMM value above was measured during board-side startup on a shared AX650 system and should be treated as a practical reference value.
65
 
66
+ ## Vision Encoder Latency
67
+
68
+ Measured on AX650 / NPU3 with `/opt/bin/ax_run_model -m minicpmv4_6_vision_448.axmodel -g 0 -w 1 -r 5`.
69
+
70
+ | Model | Resolution | Soft Tokens | Time (ms) |
71
+ |---|---|---|---:|
72
+ | `minicpmv4_6_vision_448.axmodel` | `448x448` | `64` | `526.717 ms avg` |
73
+
74
+ For this packaged AX650 runtime, the visual token count is fixed by the shipped vision encoder configuration:
75
+
76
+ - `vision_width = 448`
77
+ - `vision_height = 448`
78
+ - `vision_patch_size = 14`
79
+ - patch grid = `(448 / 14) x (448 / 14) = 32 x 32`
80
+ - raw patch tokens = `32 x 32 = 1024`
81
+ - current packaged build uses the `16x` visual compression path
82
+ - `Soft Tokens = 1024 / 16 = 64`
83
+
84
+ So, for the fixed-shape runtime shipped in this repository, the relation is:
85
 
86
  ```text
87
+ Soft Tokens = (vision_width / patch_size) x (vision_height / patch_size) / 16
88
  ```
89
 
90
+ For the packaged sample image request used in this README, the board-side runtime log reports `input_num_token=88`. This is expected: the final request token count is larger than the visual soft-token count because the full prompt also includes user text and chat-template tokens. For this packaged sample, the complete image request still fits within a single `128`-token prefill chunk.
91
+
92
+ `Soft Tokens` is not a runtime-configurable value in this package. This repository ships only `minicpmv4_6_vision_448.axmodel`, so the board-side AX650 runtime always uses `448x448 -> 64` soft tokens for image encoding.
93
+
94
+ The upstream Hugging Face MiniCPM-V-4.6 processor supports other visual compression and slicing settings, but those are not exposed as a runtime option by this packaged fixed-shape AX650 release.
95
+
96
+ ## Package Layout
97
 
98
  ```text
99
  .
 
102
  │ ├── axllm
103
  │ └── axllm.version.json
104
  ├── assets/
105
+ ── openai_api_demo.png
106
+ │ ├── red-panda-openai.mp4
107
+ │ └── sample.png
108
  ├── python/
109
  │ ├── infer_axmodel.py
110
  │ ├── infer_torch.py
 
120
  └── minicpm_v46_tokenizer.txt
121
  ```
122
 
123
+ This package uses a hybrid layout: the packaged `axllm` runtime plus the compiled `.axmodel` files live at the repository root, while the Python reference scripts and the tokenizer directory used by those scripts stay under `python/`.
124
+
125
+ ## Sample Image
126
+
127
+ Both the `axllm` flow and the packaged Python examples can use the sample image:
128
+ `assets/sample.png`
129
+
130
+ ![sample](assets/sample.png)
131
+
132
+ ## Sample Video
133
+
134
+ The package also includes a packaged sample video for board-side video understanding validation:
135
+
136
+ - `assets/red-panda-openai.mp4`
137
+
138
+ ## Direct Inference with `axllm`
139
+
140
+ > The `axllm` workflow is still being refined. The instructions below reflect the current validated flow and may be adjusted as the packaging continues to evolve.
141
+
142
+ ### Download the Model Package
143
+
144
+ Download the release package from Hugging Face:
145
+
146
+ ```shell
147
+ mkdir -p AXERA-TECH/MiniCPM-V-4.6
148
+ cd AXERA-TECH/MiniCPM-V-4.6
149
+ hf download AXERA-TECH/MiniCPM-V-4.6 --local-dir .
150
+ ```
151
+
152
+ ### Install `axllm`
153
 
154
  Option 1: use the validated binary included in this repository:
155
 
 
157
  chmod +x ./bin/axllm
158
  ```
159
 
160
+ Option 2: install `axllm` from the public repository:
161
 
162
+ ```shell
163
+ git clone -b axllm https://github.com/AXERA-TECH/ax-llm.git
164
+ cd ax-llm
165
+ ./install.sh
166
+ ```
167
 
168
+ Option 3: install with a one-line command:
169
 
170
+ ```shell
171
+ curl -fsSL https://raw.githubusercontent.com/AXERA-TECH/ax-llm/axllm/install.sh | bash
172
+ ```
173
+
174
+ Option 4: download the prebuilt binary from GitHub Actions CI:
175
+
176
+ If you do not have a local build environment, download the latest CI-generated `axllm` binary from GitHub Actions:
177
+ `https://github.com/AXERA-TECH/ax-llm/actions?query=branch%3Aaxllm`
178
+ Then run:
179
+
180
+ ```shell
181
+ chmod +x axllm
182
+ sudo mv axllm /usr/bin/axllm
183
+ ```
184
+
185
+ ### Run on the Board
186
+
187
+ The package root is already arranged for `axllm`, so no extra runtime path arguments are required.
188
+
189
+ For multimodal testing, you can use the packaged sample image shown above: `./assets/sample.png`, or the packaged sample video: `./assets/red-panda-openai.mp4`.
190
 
191
  ```bash
192
+ ./bin/axllm run .
193
+ ```
194
+
195
+ In interactive mode:
196
+
197
+ - press `Enter` directly for text-only chat
198
+ - input an image path for single-image chat
199
+ - input `video:/path/to/frames_dir` or `video:/path/to/video.mp4` for video chat
200
+
201
+ ### Serve with `axllm`
202
+
203
+ From the package root on the board:
204
+
205
+ ```bash
206
+ ./bin/axllm serve . --port 8000
207
  ```
208
 
209
  Expected model id:
 
212
  AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047
213
  ```
214
 
215
+ Health check:
216
+
217
+ ```bash
218
+ curl http://127.0.0.1:8000/health
219
+ ```
220
+
221
+ A typical startup log looks like this:
222
+
223
+ ```text
224
+ INF Init | LLM init start
225
+ INF Init | mixed attention enabled: full_attention_interval=4 ref_full_layer_idx=3
226
+ INF Init | attention config: layers=24 sliding=0 full=6 linear=18 sliding_window=0 ref_full_layer_idx=3
227
+ tokenizer_type = 3
228
+ huggingface tokenizer mode = gpt2_byte_bpe
229
+ ...
230
+ INF Init | max_token_len : 2047
231
+ INF Init | kv_cache_size : 512, kv_cache_num: 2047
232
+ INF init_groups_from_model | prefill_token_num : 128
233
+ INF init_groups_from_model | prefill_max_token_num : 1280
234
+ INF Init | MiniCPM-V-4.6 token ids: image_pad=248056 video_pad=248057
235
+ INF Init | VisionModule init ok: type=MiniCPMV46VL, tokens_per_block=64, embed_size=1024, out_dtype=fp32
236
+ INF Init | LLM init ok
237
+ Starting server on port 8000 with model 'AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047'...
238
+ API URLs:
239
+ GET http://127.0.0.1:8000/health
240
+ GET http://127.0.0.1:8000/v1/models
241
+ POST http://127.0.0.1:8000/v1/chat/completions
242
+ OpenAI API Server starting on http://0.0.0.0:8000
243
+ Max concurrency: 1
244
+ Models: AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047
245
+ ```
246
+
247
+ You can then send requests to the server using the API endpoints shown in the log. For example, to check the health status and list the available models:
248
+
249
+ ```bash
250
+ curl http://127.0.0.1:8000/health
251
+ curl http://127.0.0.1:8000/v1/models
252
+ ```
253
+
254
+ Example output:
255
+
256
+ ```json
257
+ {
258
+ "concurrency": 0,
259
+ "max_concurrency": 1,
260
+ "status": "healthy"
261
+ }
262
+ {
263
+ "data": [
264
+ {
265
+ "created": 1780908633,
266
+ "id": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
267
+ "object": "model",
268
+ "owned_by": "openai-api"
269
+ }
270
+ ],
271
+ "object": "list"
272
+ }
273
+ ```
274
+
275
+ ![openai_api_demo](assets/openai_api_demo.png)
276
+
277
  ### Text Request
278
 
279
  ```bash
280
+ curl http://127.0.0.1:8000/v1/chat/completions \
281
  -H 'Content-Type: application/json' \
282
  -d '{
283
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
 
285
  {
286
  "role": "user",
287
  "content": [
288
+ {"type": "text", "text": "What is 1+1? Reply with the number only."}
289
  ]
290
  }
291
  ],
 
293
  }'
294
  ```
295
 
296
+ Example output:
297
+
298
+ ```json
299
+ {
300
+ "choices": [
301
+ {
302
+ "message": {
303
+ "role": "assistant",
304
+ "content": "1+1=2"
305
+ },
306
+ "finish_reason": "stop"
307
+ }
308
+ ],
309
+ "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
310
+ "object": "chat.completion"
311
+ }
312
+ ```
313
+
314
  ### Image Request
315
 
316
  ```bash
317
+ python3 - <<'PY'
318
  import base64
319
  import json
320
  from pathlib import Path
321
  from urllib.request import Request, urlopen
322
 
323
+ img = Path("assets/sample.png").read_bytes()
324
  payload = {
325
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
326
  "messages": [
 
340
  "max_tokens": 64,
341
  }
342
  req = Request(
343
+ "http://127.0.0.1:8000/v1/chat/completions",
344
  data=json.dumps(payload).encode(),
345
  headers={"Content-Type": "application/json"},
346
  )
 
349
  PY
350
  ```
351
 
352
+ Example output:
353
+
354
+ ```json
355
+ {
356
+ "choices": [
357
+ {
358
+ "message": {
359
+ "role": "assistant",
360
+ "content": "好的,这张图片是一个风格化的红色龙虾卡通形象。它有着夸张的表情和动态的姿势,显得非常活泼和有力。龙虾的肢体姿态显示出它正在准备出击或展示它的力量,整体设计充满了动感和趣味性。这个形象可能用于装饰或象征某种活力和力量。"
361
+ },
362
+ "finish_reason": "stop"
363
+ }
364
+ ],
365
+ "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
366
+ "object": "chat.completion"
367
+ }
368
+ ```
369
+
370
  ### Video Request
371
 
372
+ `axllm serve` accepts either a frames directory or a raw video file:
373
 
374
  ```bash
375
+ curl http://127.0.0.1:8000/v1/chat/completions \
376
  -H 'Content-Type: application/json' \
377
  -d '{
378
  "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
 
389
  }'
390
  ```
391
 
392
+ For a raw video file, use `video:/path/to/video.mp4`. If you need to request a specific sampling FPS, use the form `video:/path/to/video.mp4:2`.
393
 
394
+ To test the packaged sample video from the package root, you can set:
395
 
396
  ```bash
397
+ VIDEO_PATH="$(pwd)/assets/red-panda-openai.mp4"
398
  ```
399
 
400
+ and then use `video:${VIDEO_PATH}:2` in the request payload.
401
+
402
+ Example output:
403
+
404
+ ```json
405
+ {
406
+ "choices": [
407
+ {
408
+ "message": {
409
+ "role": "assistant",
410
+ "content": "好的,这是当前对视频内容的详细描述:画面中,两只红熊猫正在一个由竹竿搭建的攀爬架周围活动。一只红熊猫正趴在竹竿上,身体伸展,尾巴自然垂落;另一只红熊猫则蹲在下方,抬头向上,似乎正在尝试攀爬或探索竹竿结���。背景是绿色的围栏和草地,整个场景展现了它们活泼、好奇的互动状态。"
411
+ },
412
+ "finish_reason": "stop"
413
+ }
414
+ ],
415
+ "model": "AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047",
416
+ "object": "chat.completion"
417
+ }
418
+ ```
419
 
420
+ ### Browser UI with `lite_webui`
 
 
421
 
422
+ If you want a browser UI for the OpenAI-compatible service started by `axllm serve`, use [AXERA-TECH/lite_webui](https://huggingface.co/AXERA-TECH/lite_webui/tree/main).
423
 
424
+ Set the OpenAI base URL to `http://<board-ip>:8000` and the model name to `AXERA-TECH/MiniCPM-V-4.6-AX650-C128-P1152-CTX2047`.
425
 
426
+ ## Python Runtime Requirements
427
 
428
+ Install the following packages before using the packaged Python reference scripts:
429
+
430
+ - Board-side `infer_axmodel.py`:
431
+ `pyaxengine`, `transformers`, `numpy`, `ml_dtypes`
432
+ - Server-side `infer_torch.py`:
433
+ `torch`, `transformers`
434
 
435
+ The packaged Python scripts are reference utilities rather than the main runtime path.
436
 
437
+ ## Legacy Python Demo Flow
438
+
439
+ ### Text-Only Inference
440
+
441
+ `python/infer_axmodel.py` is intended for board-side text debugging of the packaged runtime files:
442
 
443
  ```bash
444
  cd python
 
446
  --hf-model ./minicpm_v46_tokenizer \
447
  --axmodel-dir .. \
448
  --mode generate \
449
+ --prompt "What is 1+1? Reply with the number only." \
450
  --prompt-mode prefill \
451
  --max-new-tokens 16 \
452
  --kv-cache-len 2047
453
  ```
454
 
455
+ ### Hugging Face Reference Inference
456
 
457
+ `python/infer_torch.py` is intended for x86 or GPU-side comparison against the original Hugging Face model:
 
 
 
 
 
458
 
459
+ ```bash
460
+ cd python
461
+ python infer_torch.py \
462
+ --model-path /path/to/original/MiniCPM-V-4.6 \
463
+ --prompt "Please give a short self introduction."
464
+ ```
465
 
466
+ ## Packaged Python Runtime Paths
467
 
468
+ The packaged Python helper paths are:
469
+
470
+ - `python/infer_axmodel.py`
471
+ - `python/infer_torch.py`
472
+ - `python/minicpm_v46_tokenizer/`
473
+
474
+ The packaged `axllm` runtime does not depend on `python/minicpm_v46_tokenizer/`, but `python/infer_axmodel.py` uses it by default.
475
+
476
+ These path arguments apply to the Python demo flow only. The `axllm` flow reads the same root-level runtime files packaged in this repository.
477
+
478
+ ## Conversion References
479
+
480
+ If you need the original model files or want to rebuild the deployment artifacts, start with:
481
+
482
+ - Original Hugging Face model: [openbmb/MiniCPM-V-4.6](https://huggingface.co/openbmb/MiniCPM-V-4.6)
483
+ - AXERA conversion and deployment workflow: [AXERA-TECH/MiniCPM-V-4.6.axera](https://github.com/AXERA-TECH/MiniCPM-V-4.6.axera)
484
+
485
+ ## Discussion
486
+
487
+ - GitHub Issues
488
+ - QQ group: `139953715`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/openai_api_demo.png ADDED

Git LFS Details

  • SHA256: 28af9b42463c5f4b31b6c3a52a4d17a0f62399013f4f5a9c54b1fd812de09449
  • Pointer size: 131 Bytes
  • Size of remote file: 615 kB
assets/red-panda-openai.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d921c07bb97224d65a37801541d246067f0d506f08723ffa1ad85c217907ccb8
3
+ size 1867237
assets/sample.png ADDED

Git LFS Details

  • SHA256: e10040a55718d1e1157d919fd44051728bc9329e0e28008f940c6a316712e0cf
  • Pointer size: 131 Bytes
  • Size of remote file: 838 kB