Research zipvoice

#1
by inoryQwQ - opened
This view is limited to 50 files because it contains too many changes. See the raw diff here.
Files changed (50) hide show
  1. .gitattributes +12 -13
  2. README.md +11 -44
  3. cpp/.gitattributes +0 -2
  4. cpp/CMakeLists.txt +0 -53
  5. cpp/README.md +0 -84
  6. cpp/build_ax650.sh +0 -30
  7. cpp/build_axcl.sh +0 -34
  8. cpp/cmake/msp_dependencies.cmake +0 -71
  9. cpp/download_bsp.sh +0 -19
  10. cpp/install/ax650/zipvoice +0 -3
  11. cpp/install/ax650/zipvoice_axera +0 -3
  12. cpp/install/axcl/zipvoice +0 -3
  13. cpp/scripts/compare_vocoder.py +0 -277
  14. cpp/scripts/export_vocos_onnx.py +0 -125
  15. cpp/scripts/gen_cat_tokens.py +0 -44
  16. cpp/scripts/gen_pinyin_table.py +0 -95
  17. cpp/scripts/generate_vocoder_calib.py +0 -141
  18. cpp/scripts/py_daemon.py +0 -57
  19. cpp/scripts/quantize_vocoder.sh +0 -123
  20. cpp/src/EngineWrapper.cpp +0 -13
  21. cpp/src/EngineWrapper.hpp +0 -81
  22. cpp/src/EngineWrapper_axcl.cpp +0 -217
  23. cpp/src/EngineWrapper_axera.cpp +0 -283
  24. cpp/src/cmdline.hpp +0 -732
  25. cpp/src/fbank.cpp +0 -219
  26. cpp/src/fbank.hpp +0 -65
  27. cpp/src/middleware/ax_npu_runner.cc +0 -131
  28. cpp/src/middleware/ax_npu_runner.hpp +0 -65
  29. cpp/src/middleware/ax_npu_runner_impl.hpp +0 -640
  30. cpp/src/middleware/axcl_base.cc +0 -241
  31. cpp/src/middleware/axcl_base.hpp +0 -42
  32. cpp/src/middleware/axcl_native_runner.cc +0 -105
  33. cpp/src/middleware/axcl_native_runner.hpp +0 -57
  34. cpp/src/middleware/axcl_native_runner_impl.hpp +0 -504
  35. cpp/src/middleware/axcl_runtime_runner.cc +0 -105
  36. cpp/src/middleware/axcl_runtime_runner.hpp +0 -56
  37. cpp/src/middleware/axcl_runtime_runner_impl.hpp +0 -482
  38. cpp/src/middleware/runner.cc +0 -88
  39. cpp/src/middleware/runner.hpp +0 -67
  40. cpp/src/pinyin_table.hpp +0 -0
  41. cpp/src/tokenizer.cpp +0 -306
  42. cpp/src/tokenizer.hpp +0 -79
  43. cpp/src/utilities/file.hpp +0 -251
  44. cpp/src/utilities/file_mapper.hpp +0 -86
  45. cpp/src/utilities/log.hpp +0 -64
  46. cpp/src/utilities/scalar_guard.hpp +0 -60
  47. cpp/src/utilities/timer.hpp +0 -84
  48. cpp/src/utilities/vector_guard.hpp +0 -64
  49. cpp/src/vocoder.cpp +0 -153
  50. cpp/src/vocoder.hpp +0 -67
.gitattributes CHANGED
@@ -35,15 +35,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  assets/moss_prompts/en_4_4p5s.wav filter=lfs diff=lfs merge=lfs -text
37
  assets/moss_prompts/zh_1_4p5s.wav filter=lfs diff=lfs merge=lfs -text
38
- cpp/install/ax650/zipvoice filter=lfs diff=lfs merge=lfs -text
39
- cpp/install/ax650/zipvoice_axera filter=lfs diff=lfs merge=lfs -text
40
- cpp/install/axcl/zipvoice filter=lfs diff=lfs merge=lfs -text
41
- cpp/vocoder/vocos_full.axmodel filter=lfs diff=lfs merge=lfs -text
42
- models/axmodels/decoder_part0.axmodel filter=lfs diff=lfs merge=lfs -text
43
- models/axmodels/decoder_part1.axmodel filter=lfs diff=lfs merge=lfs -text
44
- models/axmodels/decoder_part2.axmodel filter=lfs diff=lfs merge=lfs -text
45
- models/axmodels/decoder_part3.axmodel filter=lfs diff=lfs merge=lfs -text
46
- models/axmodels/encoder.axmodel filter=lfs diff=lfs merge=lfs -text
47
  models/zipvoice_ax650/decoder_part0.axmodel filter=lfs diff=lfs merge=lfs -text
48
  models/zipvoice_ax650/decoder_part1.axmodel filter=lfs diff=lfs merge=lfs -text
49
  models/zipvoice_ax650/decoder_part2.axmodel filter=lfs diff=lfs merge=lfs -text
@@ -59,11 +50,19 @@ models/zipvoice_distill_ax650/decoder_part1.axmodel filter=lfs diff=lfs merge=lf
59
  models/zipvoice_distill_ax650/decoder_part2.axmodel filter=lfs diff=lfs merge=lfs -text
60
  models/zipvoice_distill_ax650/decoder_part3.axmodel filter=lfs diff=lfs merge=lfs -text
61
  models/zipvoice_distill_ax650/encoder.axmodel filter=lfs diff=lfs merge=lfs -text
62
- outputs/en_long_paragraph_ax650.wav filter=lfs diff=lfs merge=lfs -text
63
  outputs/en_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
64
- outputs/en_sentence_ax650.wav filter=lfs diff=lfs merge=lfs -text
65
  outputs/en_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
66
- outputs/zh_long_paragraph_ax650.wav filter=lfs diff=lfs merge=lfs -text
67
  outputs/zh_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
68
- outputs/zh_sentence_ax650.wav filter=lfs diff=lfs merge=lfs -text
69
  outputs/zh_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  assets/moss_prompts/en_4_4p5s.wav filter=lfs diff=lfs merge=lfs -text
37
  assets/moss_prompts/zh_1_4p5s.wav filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
38
  models/zipvoice_ax650/decoder_part0.axmodel filter=lfs diff=lfs merge=lfs -text
39
  models/zipvoice_ax650/decoder_part1.axmodel filter=lfs diff=lfs merge=lfs -text
40
  models/zipvoice_ax650/decoder_part2.axmodel filter=lfs diff=lfs merge=lfs -text
 
50
  models/zipvoice_distill_ax650/decoder_part2.axmodel filter=lfs diff=lfs merge=lfs -text
51
  models/zipvoice_distill_ax650/decoder_part3.axmodel filter=lfs diff=lfs merge=lfs -text
52
  models/zipvoice_distill_ax650/encoder.axmodel filter=lfs diff=lfs merge=lfs -text
53
+ outputs/en_long_paragraph.wav filter=lfs diff=lfs merge=lfs -text
54
  outputs/en_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
55
+ outputs/en_sentence.wav filter=lfs diff=lfs merge=lfs -text
56
  outputs/en_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
57
+ outputs/zh_long_paragraph.wav filter=lfs diff=lfs merge=lfs -text
58
  outputs/zh_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
59
+ outputs/zh_sentence.wav filter=lfs diff=lfs merge=lfs -text
60
  outputs/zh_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
61
+ en_long_paragraph_ax650.wav filter=lfs diff=lfs merge=lfs -text
62
+ en_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
63
+ en_sentence_ax650.wav filter=lfs diff=lfs merge=lfs -text
64
+ en_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
65
+ zh_long_paragraph_ax650.wav filter=lfs diff=lfs merge=lfs -text
66
+ zh_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
67
+ zh_sentence_ax650.wav filter=lfs diff=lfs merge=lfs -text
68
+ zh_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,39 +1,18 @@
1
  # ZipVoice.AXERA
2
 
3
- [ZipVoice]((https://github.com/k2-fsa/ZipVoice)) AXERA 板端 & AXCL 算力卡推理 demo。
4
 
5
  ## 功能
6
 
7
  - 支持中文和英文语音生成。
8
  - 支持语音克隆。
9
  - 支持 ZipVoice、ZipVoice Distill
10
- - 支持 C++ 和 Python 推理
11
- - 支持 AXERA 和 AXCL platform
12
 
13
  ## 模型说明
14
 
15
- ZipVoice Distill 是 ZipVoice 的蒸馏版本,主要优势是在较小性能损失下提升推理速度。
16
-
17
- ## 性能对比
18
-
19
- ### Distill 模型 (num_step=4)
20
-
21
- | 场景 | 音频时长 | Python AX650 (耗时/RTF) | C++ AX650 (耗时/RTF) | C++ AXCL (耗时/RTF) |
22
- |------|---------|------------------------|---------------------|---------------------|
23
- | 中文句子 | 6.41s | 1.992s / 0.311 | 1.057s / 0.165 | 0.918s / **0.143** |
24
- | 中文段落 | 44.97s | 13.457s / 0.301 | 7.357s / 0.164 | 6.443s / **0.143** |
25
- | 英文句子 | 6.41s | 2.045s / 0.319 | 1.067s / 0.166 | 0.919s / **0.143** |
26
- | 英文段落 | 59.16s | 19.715s / 0.305 | 10.529s / 0.178 | 9.207s / **0.156** |
27
-
28
- ### 普通模型 (num_step=10)
29
-
30
- | 场景 | 音频时长 | Python AX650 (耗时/RTF) | C++ AX650 (耗时/RTF) | C++ AXCL (耗时/RTF) |
31
- |------|---------|------------------------|---------------------|---------------------|
32
- | 中文句子 | 6.41s | 5.781s / 0.902 | 5.709s / 0.891 | 5.452s / **0.850** |
33
- | 中文段落 | 44.97s | 40.292s / 0.901 | 39.714s / 0.883 | 38.138s / **0.848** |
34
- | 英文句子 | 6.41s | 5.711s / 0.891 | 5.693s / 0.888 | 5.447s / **0.850** |
35
- | 英文段落 | 59.16s | 62.161s / 0.960 | 56.759s / 0.957 | 54.451s / **0.920** |
36
 
 
37
 
38
  ## 模型转换
39
 
@@ -53,7 +32,7 @@ ZipVoice Distill 是 ZipVoice 的蒸馏版本,主要优势是在较小性能
53
  ## 目录结构
54
 
55
  ```text
56
- ZipVoice.AXERA_AXCL/
57
  ├── assets/
58
  │ ├── moss_prompts/
59
  │ └── paragraphs/
@@ -64,21 +43,16 @@ ZipVoice.AXERA_AXCL/
64
  ├── resources/
65
  │ ├── vocos-mel-24khz/
66
  │ └── zipvoice_hf/
67
- ├── cpp/ # C++ 源码 (AXERA & AXCL)
68
  ├── scripts/
69
- ├── infer_zipvoice_axera.py # Python 推理入口
70
- ├── run_ax650.sh # AXERA 板端一键运行
71
- ├── run_axcl.sh # AXCL 算力卡一键运行
72
  ├── requirements.txt
73
  └── README.md
74
  ```
75
 
76
- ## Python
77
-
78
- ### 环境
79
 
80
  安装 pyaxengine:
81
- [pyaxengine Releases](https://github.com/AXERA-TECH/pyaxengine/releases/latest) 下载对应版本安装:
82
  ```bash
83
  pip3 install axengine-x.x.x-py3-none-any.whl
84
  ```
@@ -91,7 +65,7 @@ conda activate ZipVoice
91
  pip3 install -r requirements.txt
92
  ```
93
 
94
- ### 推理命令
95
 
96
  进入目录:
97
 
@@ -99,7 +73,7 @@ pip3 install -r requirements.txt
99
  cd ZipVoice.AXERA
100
  ```
101
 
102
- #### AX650 ZipVoice
103
 
104
  中文句子:
105
 
@@ -189,7 +163,7 @@ RTF: 0.9600
189
  音频:[outputs/en_long_paragraph_ax650.wav](outputs/en_long_paragraph_ax650.wav)
190
  提示音:[assets/moss_prompts/en_4_4p5s.wav](assets/moss_prompts/en_4_4p5s.wav)
191
 
192
- #### AX650 ZipVoice Distill
193
 
194
  中文句子:
195
 
@@ -280,7 +254,7 @@ RTF: 0.3045
280
  提示音:[assets/moss_prompts/en_4_4p5s.wav](assets/moss_prompts/en_4_4p5s.wav)
281
 
282
 
283
- ### 参数说明
284
 
285
  - `--model-name`:选择模型目录。可选 `zipvoice_ax650`、`zipvoice_distill_ax650`、`zipvoice_distill_ax630C`。
286
  - `--prompt-wav`:参考音频,用于控制音色,建议 3-5s。
@@ -288,13 +262,6 @@ RTF: 0.3045
288
  - `--num-step`:采样步数。默认从模型目录的 `runtime_config.json` 读取。
289
  - `--max-feat-len`:decoder 固定 feature 长度,当前模型均为 1024。
290
 
291
- ## C++
292
-
293
- C++ 推理实现。详见 [cpp/README.md](cpp/README.md)。
294
-
295
-
296
  ## 参考
297
 
298
  - [ZipVoice](https://github.com/k2-fsa/ZipVoice)
299
- - [Pulsar2 Docs](https://pulsar2-docs.readthedocs.io/en/latest/pulsar2/introduction.html)
300
- - [模型量化工程](https://github.com/AXERA-TECH/ZipVoice.AXERA)
 
1
  # ZipVoice.AXERA
2
 
3
+ [ZipVoice]((https://github.com/k2-fsa/ZipVoice)) AXERA 板端推理 demo。
4
 
5
  ## 功能
6
 
7
  - 支持中文和英文语音生成。
8
  - 支持语音克隆。
9
  - 支持 ZipVoice、ZipVoice Distill
 
 
10
 
11
  ## 模型说明
12
 
13
+ ZipVoice Distill 是 ZipVoice 的蒸馏版本,主要优势是在较小性能损失下提升推理速度。初步测试,AX650 ZipVoice Distill 在长文本场景下相比基础版模型约有 3 倍速度提升,RTF 在 0.3 左右,效果没有明显下降。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ AX630C 版本当前推理结果差,RTF 约为 1.5 左右,需要继续调优。
16
 
17
  ## 模型转换
18
 
 
32
  ## 目录结构
33
 
34
  ```text
35
+ ZipVoice.AXERA/
36
  ├── assets/
37
  │ ├── moss_prompts/
38
  │ └── paragraphs/
 
43
  ├── resources/
44
  │ ├── vocos-mel-24khz/
45
  │ └── zipvoice_hf/
 
46
  ├── scripts/
47
+ ├── infer_zipvoice_axera.py
 
 
48
  ├── requirements.txt
49
  └── README.md
50
  ```
51
 
52
+ ## 环境
 
 
53
 
54
  安装 pyaxengine:
55
+
56
  ```bash
57
  pip3 install axengine-x.x.x-py3-none-any.whl
58
  ```
 
65
  pip3 install -r requirements.txt
66
  ```
67
 
68
+ ## 推理命令
69
 
70
  进入目录:
71
 
 
73
  cd ZipVoice.AXERA
74
  ```
75
 
76
+ ### AX650 ZipVoice
77
 
78
  中文句子:
79
 
 
163
  音频:[outputs/en_long_paragraph_ax650.wav](outputs/en_long_paragraph_ax650.wav)
164
  提示音:[assets/moss_prompts/en_4_4p5s.wav](assets/moss_prompts/en_4_4p5s.wav)
165
 
166
+ ### AX650 ZipVoice Distill
167
 
168
  中文句子:
169
 
 
254
  提示音:[assets/moss_prompts/en_4_4p5s.wav](assets/moss_prompts/en_4_4p5s.wav)
255
 
256
 
257
+ ## 参数说明
258
 
259
  - `--model-name`:选择模型目录。可选 `zipvoice_ax650`、`zipvoice_distill_ax650`、`zipvoice_distill_ax630C`。
260
  - `--prompt-wav`:参考音频,用于控制音色,建议 3-5s。
 
262
  - `--num-step`:采样步数。默认从模型目录的 `runtime_config.json` 读取。
263
  - `--max-feat-len`:decoder 固定 feature 长度,当前模型均为 1024。
264
 
 
 
 
 
 
265
  ## 参考
266
 
267
  - [ZipVoice](https://github.com/k2-fsa/ZipVoice)
 
 
cpp/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- *.axmodel filter=lfs diff=lfs merge=lfs -text
2
- *.onnx filter=lfs diff=lfs merge=lfs -text
 
 
 
cpp/CMakeLists.txt DELETED
@@ -1,53 +0,0 @@
1
- cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
2
- project(zipvoice)
3
-
4
- if (NOT DEFINED CMAKE_CXX_STANDARD)
5
- set(CMAKE_CXX_STANDARD 14)
6
- endif()
7
-
8
- if(CMAKE_BUILD_TYPE MATCHES Debug)
9
- set(CMAKE_CXX_FLAGS "-fvisibility=hidden -g -O0")
10
- elseif(CMAKE_BUILD_TYPE MATCHES Release)
11
- set(CMAKE_CXX_FLAGS "-fvisibility=hidden -O2 -fdata-sections -ffunction-sections")
12
- endif()
13
-
14
- # Platform dependencies (AXERA or AXCL)
15
- include(cmake/msp_dependencies.cmake)
16
-
17
- include_directories(${MSP_INC_DIR})
18
-
19
- # Project includes
20
- include_directories(${CMAKE_SOURCE_DIR})
21
- include_directories(${CMAKE_SOURCE_DIR}/src/)
22
-
23
- # Core source files (common to AXERA and AXCL)
24
- set(SRC
25
- src/EngineWrapper.cpp
26
- src/tokenizer.cpp
27
- src/fbank.cpp
28
- src/zipvoice_engine.cpp
29
- src/vocoder.cpp
30
- third_party/kissfft/kiss_fft.c
31
- )
32
-
33
- # AXCL-only source files (middleware + utilities)
34
- if(AXCL)
35
- aux_source_directory(${CMAKE_SOURCE_DIR}/src/middleware AXCL_SRCS)
36
- aux_source_directory(${CMAKE_SOURCE_DIR}/src/utilities AXCL_SRCS)
37
- list(APPEND SRC ${AXCL_SRCS})
38
- message(STATUS "AXCL middleware: ${AXCL_SRCS}")
39
- endif()
40
-
41
- add_executable(${PROJECT_NAME} zipvoice.cpp ${SRC})
42
- target_include_directories(${PROJECT_NAME} PRIVATE third_party/kissfft)
43
- target_link_libraries(${PROJECT_NAME} ${MSP_LIBS})
44
-
45
- install(TARGETS ${PROJECT_NAME}
46
- RUNTIME DESTINATION ./)
47
- set_target_properties(${PROJECT_NAME}
48
- PROPERTIES
49
- INSTALL_RPATH "$ORIGIN/")
50
-
51
- message(STATUS "========================================")
52
- message(STATUS "ZipVoice C++ Build Configuration")
53
- message(STATUS "========================================")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/README.md DELETED
@@ -1,84 +0,0 @@
1
- # ZipVoice C++ — AXERA & AXCL
2
-
3
- ## 性能
4
-
5
- ### Distill 模型 (num_step=4)
6
-
7
- | 场景 | 音频时长 | Python AX650 (耗时/RTF) | C++ AX650 (耗时/RTF) | C++ AXCL (耗时/RTF) |
8
- |------|---------|------------------------|---------------------|---------------------|
9
- | 中文句子 | 6.41s | 1.992s / 0.311 | 1.057s / 0.165 | 0.918s / **0.143** |
10
- | 中文段落 | 44.97s | 13.457s / 0.301 | 7.357s / 0.164 | 6.443s / **0.143** |
11
- | 英文句子 | 6.41s | 2.045s / 0.319 | 1.067s / 0.166 | 0.919s / **0.143** |
12
- | 英文段落 | 59.16s | 19.715s / 0.305 | 10.529s / 0.178 | 9.207s / **0.156** |
13
-
14
- ### 普通模型 (num_step=10)
15
-
16
- | 场景 | 音频时长 | Python AX650 (耗时/RTF) | C++ AX650 (耗时/RTF) | C++ AXCL (耗时/RTF) |
17
- |------|---------|------------------------|---------------------|---------------------|
18
- | 中文句子 | 6.41s | 5.781s / 0.902 | 5.709s / 0.891 | 5.452s / **0.850** |
19
- | 中文段落 | 44.97s | 40.292s / 0.901 | 39.714s / 0.883 | 38.138s / **0.848** |
20
- | 英文句子 | 6.41s | 5.711s / 0.891 | 5.693s / 0.888 | 5.447s / **0.850** |
21
- | 英文段落 | 59.16s | 62.161s / 0.960 | 56.759s / 0.957 | 54.451s / **0.920** |
22
-
23
- ## 环境准备
24
-
25
- 下载交叉编译器、AXERA SDK、AXCL SDK 到指定目录(记为 `<TOOLCHAIN_DIR>`):
26
-
27
- ```bash
28
- bash download_bsp.sh
29
-
30
- # 或手动:
31
- mkdir -p <TOOLCHAIN_DIR> && cd <TOOLCHAIN_DIR>
32
- wget https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz
33
- tar -xf gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz
34
- git clone https://github.com/AXERA-TECH/ax650n_bsp_sdk.git --depth=1
35
- git clone https://github.com/Abandon-ht/axcl_bsp_sdk.git --depth=1
36
- ```
37
-
38
- 修改 `cmake/msp_dependencies.cmake` 和 `toolchains/aarch64-none-linux-gnu.toolchain.cmake` 中的路径。
39
-
40
- 英文分词需 Python 依赖(运行设备上安装):
41
- ```bash
42
- pip install jieba numpy pypinyin piper_phonemize
43
- ```
44
-
45
- ## 编译
46
-
47
- ```bash
48
- bash build_ax650.sh # → install/ax650/zipvoice
49
- bash build_axcl.sh # → install/axcl/zipvoice
50
- ```
51
-
52
- ## 运行
53
-
54
- 在 repo 根目录(`ZipVoice.AXERA/`)执行:
55
-
56
- ```bash
57
- # 板端
58
- bash run_ax650.sh distill zh sentence
59
- bash run_ax650.sh distill zh paragraph
60
- bash run_ax650.sh standard zh sentence
61
- bash run_ax650.sh standard zh paragraph
62
- bash run_ax650.sh distill en sentence
63
- bash run_ax650.sh distill en paragraph
64
- bash run_ax650.sh standard en sentence
65
- bash run_ax650.sh standard en paragraph
66
-
67
- # 算力卡
68
- bash run_axcl.sh distill zh paragraph
69
- bash run_axcl.sh standard en sentence
70
- ...
71
- ```
72
-
73
- ## 参数
74
-
75
- | 参数 | 说明 | 默认值 |
76
- |------|------|--------|
77
- | `--model-dir` | 模型目录 | 必填 |
78
- | `--prompt-wav` | 提示音频 | 必填 |
79
- | `--prompt-text` | 提示文本 | 必填 |
80
- | `--text` / `--text-file` | 合成文本 | 二选一 |
81
- | `--vocoder-model` | vocos_full.axmodel 路径 | 必填 |
82
- | `--output-wav` | 输出 WAV | output.wav |
83
- | `--num-step` | 采样步数 | 10 (distill: 4) |
84
- | `--seed` | 随机种子 | 42 |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/build_ax650.sh DELETED
@@ -1,30 +0,0 @@
1
- #!/bin/bash
2
- # Cross-compile ZipVoice for AXERA (AX650 demo board)
3
- #
4
- # Prerequisites:
5
- # - AX650 BSP SDK: cpp/ax650n_bsp_sdk/ (run download_bsp.sh first)
6
- # - Cross compiler: /data/shared/huyuan/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/
7
-
8
- set -e
9
-
10
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
- cd "$SCRIPT_DIR"
12
-
13
- rm -rf build_ax650
14
- mkdir -p build_ax650 && cd build_ax650
15
-
16
- cmake .. \
17
- -DAX650=ON \
18
- -DCMAKE_TOOLCHAIN_FILE=../toolchains/aarch64-none-linux-gnu.toolchain.cmake \
19
- -DCMAKE_INSTALL_PREFIX=../install/ax650 \
20
- -DCMAKE_BUILD_TYPE=Release \
21
- $@
22
-
23
- make -j$(nproc)
24
- make install
25
-
26
- echo ""
27
- echo "========================================"
28
- echo "Build complete!"
29
- echo "Executable: $(pwd)/../install/ax650/zipvoice"
30
- echo "========================================"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/build_axcl.sh DELETED
@@ -1,34 +0,0 @@
1
- #!/bin/bash
2
- # Cross-compile ZipVoice for AXCL (AXCL compute card)
3
- #
4
- # Prerequisites:
5
- # - AXCL BSP SDK: /data/shared/huyuan/toolchains/axcl_bsp_sdk/
6
- # - Cross compiler: /data/shared/huyuan/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/
7
- #
8
- # Clone SDK (one-time):
9
- # cd /data/shared/huyuan/toolchains
10
- # git clone https://github.com/Abandon-ht/axcl_bsp_sdk.git --depth=1
11
-
12
- set -e
13
-
14
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
15
- cd "$SCRIPT_DIR"
16
-
17
- rm -rf build_axcl
18
- mkdir -p build_axcl && cd build_axcl
19
-
20
- cmake .. \
21
- -DAXCL=ON \
22
- -DCMAKE_TOOLCHAIN_FILE=../toolchains/aarch64-none-linux-gnu.toolchain.cmake \
23
- -DCMAKE_INSTALL_PREFIX=../install/axcl \
24
- -DCMAKE_BUILD_TYPE=Release \
25
- $@
26
-
27
- make -j$(nproc)
28
- make install
29
-
30
- echo ""
31
- echo "========================================"
32
- echo "Build complete!"
33
- echo "Executable: $(pwd)/../install/axcl/zipvoice"
34
- echo "========================================"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/cmake/msp_dependencies.cmake DELETED
@@ -1,71 +0,0 @@
1
- # BSP / SDK Dependencies Configuration
2
- # Supports both AXERA (demo board) and AXCL (compute card)
3
- #
4
- # AXERA: AX650 / AX630C / AX620Q
5
- # AXCL: AXCL
6
-
7
- if (AX650)
8
- add_definitions(-DAX650)
9
- if(NOT BSP_MSP_DIR)
10
- set(BSP_MSP_DIR /data/shared/huyuan/toolchains/ax650n_bsp_sdk/msp/out)
11
- endif()
12
- if(NOT EXISTS ${BSP_MSP_DIR})
13
- message(FATAL_ERROR "BSP_MSP_DIR ${BSP_MSP_DIR} not exist. Run download_bsp.sh first.")
14
- endif()
15
- set(MSP_INC_DIR ${BSP_MSP_DIR}/include)
16
- set(MSP_LIB_DIR ${BSP_MSP_DIR}/lib)
17
- list(APPEND MSP_LIBS ax_sys ax_engine ax_interpreter)
18
-
19
- elseif(AX630C)
20
- add_definitions(-DAX630C)
21
- if(NOT BSP_MSP_DIR)
22
- set(BSP_MSP_DIR ${CMAKE_SOURCE_DIR}/ax620e_bsp_sdk/msp/out/arm64_glibc)
23
- endif()
24
- if(NOT EXISTS ${BSP_MSP_DIR})
25
- message(FATAL_ERROR "BSP_MSP_DIR ${BSP_MSP_DIR} not exist.")
26
- endif()
27
- set(MSP_INC_DIR ${BSP_MSP_DIR}/include)
28
- set(MSP_LIB_DIR ${BSP_MSP_DIR}/lib)
29
- list(APPEND MSP_LIBS ax_sys ax_engine ax_interpreter)
30
-
31
- elseif(AX620Q)
32
- add_definitions(-DAX620Q)
33
- if(NOT BSP_MSP_DIR)
34
- set(BSP_MSP_DIR ${CMAKE_SOURCE_DIR}/ax620e_bsp_sdk/msp/out/arm_uclibc)
35
- endif()
36
- if(NOT EXISTS ${BSP_MSP_DIR})
37
- message(FATAL_ERROR "BSP_MSP_DIR ${BSP_MSP_DIR} not exist.")
38
- endif()
39
- set(MSP_INC_DIR ${BSP_MSP_DIR}/include)
40
- set(MSP_LIB_DIR ${BSP_MSP_DIR}/lib)
41
- list(APPEND MSP_LIBS ax_sys ax_engine ax_interpreter)
42
-
43
- elseif(AXCL)
44
- add_definitions(-DAXCL)
45
- add_definitions(-DENV_AXCL_RUNTIME_API_ENABLE)
46
- add_definitions(-DENV_AXCL_NATIVE_API_ENABLE)
47
- add_definitions(-DENV_HAS_STD_FILESYSTEM)
48
- add_definitions(-DENV_HAS_POSIX_FILE_STAT)
49
-
50
- # AXCL SDK at /data/shared/huyuan/toolchains/axcl_bsp_sdk/out/
51
- if(NOT AXCL_SDK_DIR)
52
- set(AXCL_SDK_DIR /data/shared/huyuan/toolchains/axcl_bsp_sdk/out)
53
- endif()
54
- if(NOT EXISTS ${AXCL_SDK_DIR})
55
- message(FATAL_ERROR "AXCL_SDK_DIR ${AXCL_SDK_DIR} not exist. Run download_bsp.sh first.")
56
- endif()
57
- set(MSP_INC_DIR ${AXCL_SDK_DIR}/include ${AXCL_SDK_DIR}/bsp)
58
- set(MSP_LIB_DIR ${AXCL_SDK_DIR}/lib)
59
- list(APPEND MSP_LIBS
60
- axcl_rt axcl_pkg axcl_comm axcl_npu spdlog
61
- axcl_token axcl_pcie_msg axcl_pcie_dma)
62
- set(CMAKE_CXX_STANDARD 17)
63
-
64
- else()
65
- message(FATAL_ERROR "Unknown platform. Set -DAX650, -DAX630C, -DAX620Q, or -DAXCL.")
66
- endif()
67
-
68
- link_directories(${MSP_LIB_DIR})
69
- message(STATUS "MSP_INC_DIR: ${MSP_INC_DIR}")
70
- message(STATUS "MSP_LIB_DIR: ${MSP_LIB_DIR}")
71
- message(STATUS "MSP_LIBS: ${MSP_LIBS}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/download_bsp.sh DELETED
@@ -1,19 +0,0 @@
1
- #!/bin/bash
2
- # Download BSP SDKs to /data/shared/huyuan/toolchains/
3
- # AXERA: ax650n_bsp_sdk | AXCL: axcl_bsp_sdk
4
-
5
- TARGET=/data/shared/huyuan/toolchains
6
- mkdir -p $TARGET && cd $TARGET
7
-
8
- if [ ! -d ax650n_bsp_sdk ]; then
9
- echo "Downloading ax650n_bsp_sdk..."
10
- git clone https://github.com/AXERA-TECH/ax650n_bsp_sdk.git --depth=1
11
- fi
12
-
13
- if [ ! -d axcl_bsp_sdk ]; then
14
- echo "Downloading axcl_bsp_sdk..."
15
- git clone https://github.com/Abandon-ht/axcl_bsp_sdk.git --depth=1
16
- fi
17
-
18
- echo "Done. SDKs at $TARGET/"
19
- ls -d ax650n_bsp_sdk axcl_bsp_sdk 2>/dev/null
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/install/ax650/zipvoice DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:bb407d306e74de864ee7966937552da945db72207ccdea7c7b17950805642978
3
- size 582632
 
 
 
 
cpp/install/ax650/zipvoice_axera DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0d15168590f21a4255f223055008fb6832babf8a1f096c39f93afe0d78fb4c98
3
- size 582624
 
 
 
 
cpp/install/axcl/zipvoice DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f70b9a838f6505d99d2c1cc3131c89565aa25550109336387fbc8a3d49205165
3
- size 658128
 
 
 
 
cpp/scripts/compare_vocoder.py DELETED
@@ -1,277 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Compare PyTorch vocoder vs quantized axmodel output.
4
- Saves intermediate tensors for board-side comparison.
5
-
6
- Usage:
7
- # Dev machine: generate test data
8
- python3 compare_vocoder.py --save-test-data
9
-
10
- # Board: run axmodel on same input, save output
11
- python3 compare_vocoder.py --run-axmodel
12
-
13
- # Dev machine: compare results
14
- python3 compare_vocoder.py --compare
15
- """
16
- import sys, os, math, argparse
17
- import numpy as np
18
-
19
- REPO_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
20
- ONNX_DIR = os.path.join(REPO_DIR, 'cpp', 'vocoder_onnx')
21
- TEST_DIR = os.path.join(ONNX_DIR, 'test_data')
22
- os.makedirs(TEST_DIR, exist_ok=True)
23
-
24
- FEAT_SCALE = 0.1
25
- N_FFT = 1024
26
- HOP = 256
27
-
28
-
29
- def irfft_overlap_add(real_spec, imag_spec):
30
- """C++ IRFFT + overlap-add, verified to match PyTorch istft (cos_sim=0.999999)."""
31
- n_freqs = N_FFT // 2 + 1
32
- T = real_spec.shape[1]
33
- window = 0.5 * (1.0 - np.cos(2.0 * math.pi * np.arange(N_FFT) / (N_FFT - 1)))
34
- window_sq = window ** 2
35
-
36
- # Build IRFFT basis
37
- irfft_cos = np.zeros((N_FFT, n_freqs), dtype=np.float32)
38
- irfft_sin = np.zeros((N_FFT, n_freqs), dtype=np.float32)
39
- for n in range(N_FFT):
40
- for k in range(n_freqs):
41
- ang = 2.0 * math.pi * k * n / N_FFT
42
- if k == 0:
43
- irfft_cos[n, k] = 1.0 / N_FFT
44
- irfft_sin[n, k] = 0.0
45
- elif k == n_freqs - 1:
46
- irfft_cos[n, k] = math.cos(ang) / N_FFT
47
- irfft_sin[n, k] = 0.0
48
- else:
49
- irfft_cos[n, k] = math.cos(ang) * (2.0 / N_FFT)
50
- irfft_sin[n, k] = math.sin(ang) * (2.0 / N_FFT)
51
-
52
- out_len = (T - 1) * HOP + N_FFT
53
- audio = np.zeros(out_len, dtype=np.float32)
54
- envelope = np.zeros(out_len, dtype=np.float32)
55
-
56
- for t in range(T):
57
- r = real_spec[0, t, :]
58
- im = imag_spec[0, t, :]
59
- frame = irfft_cos @ r - irfft_sin @ im
60
- pos = t * HOP
61
- for n in range(N_FFT):
62
- p = pos + n
63
- if p < out_len:
64
- audio[p] += frame[n] * window[n]
65
- envelope[p] += window_sq[n]
66
-
67
- audio /= np.maximum(envelope, 1e-10)
68
- pad = N_FFT // 2
69
- return audio[pad:pad + (T - 1) * HOP]
70
-
71
-
72
- def compare(name, ref, test):
73
- ref = np.asarray(ref, dtype=np.float32).flatten()
74
- test = np.asarray(test, dtype=np.float32).flatten()
75
- if len(ref) != len(test):
76
- print(f" [{name}] SIZE MISMATCH: ref={ref.shape} test={test.shape}")
77
- return
78
- diff = np.abs(ref - test)
79
- sig = np.mean(np.abs(ref)) + 1e-10
80
- cos = np.dot(ref, test) / (np.linalg.norm(ref) * np.linalg.norm(test) + 1e-10)
81
- print(f" [{name}] max_err={diff.max():.2e} rel_err={diff.mean()/sig:.2e} cos_sim={cos:.6f}")
82
-
83
-
84
- def cmd_save_test_data():
85
- """Generate test mel and save PT/ONNX reference outputs."""
86
- import torch
87
- sys.path.insert(0, REPO_DIR)
88
- from scripts.local_vocos import LocalVocos
89
- import onnxruntime as ort
90
-
91
- # Load models
92
- vocoder = LocalVocos()
93
- sd = torch.load(f'{REPO_DIR}/resources/vocos-mel-24khz/pytorch_model.bin',
94
- weights_only=True, map_location='cpu')
95
- sd = {k: v for k, v in sd.items() if k.startswith(('backbone.', 'head.'))}
96
- vocoder.load_state_dict(sd)
97
- vocoder.eval()
98
-
99
- sess_f = ort.InferenceSession(f'{ONNX_DIR}/vocos_full_B1_T620.onnx')
100
-
101
- # Load real mel or generate random
102
- mel_bin = os.path.join(REPO_DIR, 'cpp', 'output_mel.bin')
103
- if os.path.exists(mel_bin):
104
- real_mel = np.fromfile(mel_bin, dtype=np.float32).reshape(-1, 100) # [T, 100]
105
- T = real_mel.shape[0]
106
- # Undo feat_scale, transpose to [1, 100, T]
107
- mel_input = (real_mel / FEAT_SCALE).T[np.newaxis, :, :].astype(np.float32) # [1, 100, T]
108
- print(f"Using real mel: shape={mel_input.shape}, range=[{mel_input.min():.3f}, {mel_input.max():.3f}]")
109
- else:
110
- T = 200
111
- mel_input = np.random.RandomState(42).randn(1, 100, T).astype(np.float32) * 3.0
112
- print(f"Using random mel: shape={mel_input.shape}")
113
-
114
- # Pad to 620 for ONNX
115
- T_pad = 620
116
- mel_onnx = np.zeros((1, 100, T_pad), dtype=np.float32)
117
- mel_onnx[:, :, :T] = mel_input[:, :, :T]
118
-
119
- # PT inference
120
- mel_pt = torch.from_numpy(mel_input)
121
- with torch.no_grad():
122
- features_pt = vocoder.backbone(mel_pt)
123
- audio_pt = vocoder.head(features_pt).squeeze().numpy()
124
- h = vocoder.head.out(features_pt)
125
- mag, phase = h.chunk(2, dim=-1)
126
- mag = torch.exp(mag).clamp(max=1e2)
127
- real_pt = (mag * torch.cos(phase)).numpy()
128
- imag_pt = (mag * torch.sin(phase)).numpy()
129
-
130
- # ONNX inference
131
- onnx_out = sess_f.run(None, {'mel': mel_onnx})
132
- real_onnx = onnx_out[0][:, :T, :]
133
- imag_onnx = onnx_out[1][:, :T, :]
134
- audio_onnx = irfft_overlap_add(real_onnx, imag_onnx)
135
-
136
- # Save everything
137
- np.save(f'{TEST_DIR}/mel_input.npy', mel_input)
138
- np.save(f'{TEST_DIR}/mel_onnx_padded.npy', mel_onnx)
139
- np.save(f'{TEST_DIR}/pt_real.npy', real_pt)
140
- np.save(f'{TEST_DIR}/pt_imag.npy', imag_pt)
141
- np.save(f'{TEST_DIR}/pt_audio.npy', audio_pt)
142
- np.save(f'{TEST_DIR}/onnx_real.npy', real_onnx)
143
- np.save(f'{TEST_DIR}/onnx_imag.npy', imag_onnx)
144
- np.save(f'{TEST_DIR}/onnx_audio.npy', audio_onnx)
145
- np.save(f'{TEST_DIR}/T_frames.npy', np.array([T], dtype=np.int32))
146
-
147
- # Meta
148
- with open(f'{TEST_DIR}/info.txt', 'w') as f:
149
- f.write(f"T={T}\n")
150
- f.write(f"feat_scale={FEAT_SCALE}\n")
151
- f.write(f"mel_range=[{mel_input.min():.4f}, {mel_input.max():.4f}]\n")
152
- f.write(f"pt_real_range=[{real_pt.min():.4f}, {real_pt.max():.4f}]\n")
153
- f.write(f"pt_audio_len={len(audio_pt)}\n")
154
-
155
- # Verify PT vs ONNX
156
- print("\n=== PT vs ONNX (dev machine) ===")
157
- compare('real_spectrum', real_pt, real_onnx)
158
- compare('imag_spectrum', imag_pt, imag_onnx)
159
- compare('audio', audio_pt, audio_onnx)
160
-
161
- # Also write audio files for listening
162
- import soundfile as sf
163
- sf.write(f'{TEST_DIR}/pt_audio.wav', audio_pt, 24000)
164
- sf.write(f'{TEST_DIR}/onnx_audio.wav', audio_onnx, 24000)
165
-
166
- print(f"\nTest data saved to {TEST_DIR}/")
167
- print("Copy to board and run: python3 compare_vocoder.py --run-axmodel")
168
-
169
-
170
- def cmd_run_axmodel():
171
- """Run axmodel on board with the same test mel, save output."""
172
- import onnxruntime as ort
173
- from axengine import InferenceSession
174
-
175
- T = int(np.load(f'{TEST_DIR}/T_frames.npy')[0])
176
- mel_onnx = np.load(f'{TEST_DIR}/mel_onnx_padded.npy')
177
-
178
- # Run axmodel
179
- model_path = f'{ONNX_DIR}/axmodel/vocos_full.axmodel'
180
- if not os.path.exists(model_path):
181
- print(f"ERROR: {model_path} not found")
182
- return
183
-
184
- print(f"Loading axmodel: {model_path}")
185
- sess = InferenceSession(model_path)
186
-
187
- print(f"Running inference (mel shape={mel_onnx.shape})...")
188
- outputs = sess.run(None, {'mel': mel_onnx})
189
- print(f"Output keys: {list(outputs.keys()) if isinstance(outputs, dict) else type(outputs)}")
190
-
191
- # Extract real/imag
192
- if isinstance(outputs, dict):
193
- real_ax = outputs['real'][:, :T, :]
194
- imag_ax = outputs['imag'][:, :T, :]
195
- elif isinstance(outputs, (list, tuple)):
196
- real_ax = outputs[0][:, :T, :]
197
- imag_ax = outputs[1][:, :T, :]
198
- else:
199
- real_ax = outputs[:, :T, :] # guess
200
- imag_ax = None
201
-
202
- audio_ax = irfft_overlap_add(real_ax, imag_ax)
203
-
204
- # Save
205
- np.save(f'{TEST_DIR}/ax_real.npy', real_ax)
206
- np.save(f'{TEST_DIR}/ax_imag.npy', imag_ax)
207
- np.save(f'{TEST_DIR}/ax_audio.npy', audio_ax)
208
- import soundfile as sf
209
- sf.write(f'{TEST_DIR}/ax_audio.wav', audio_ax, 24000)
210
-
211
- # Compare with ONNX reference
212
- onnx_real = np.load(f'{TEST_DIR}/onnx_real.npy')
213
- onnx_imag = np.load(f'{TEST_DIR}/onnx_imag.npy')
214
- onnx_audio = np.load(f'{TEST_DIR}/onnx_audio.npy')
215
-
216
- print("\n=== axmodel vs ONNX (board) ===")
217
- compare('real_spectrum', onnx_real, real_ax)
218
- compare('imag_spectrum', onnx_imag, imag_ax)
219
- compare('audio', onnx_audio, audio_ax)
220
-
221
- print(f"\nResults saved to {TEST_DIR}/")
222
- print("Copy back to dev machine and run: python3 compare_vocoder.py --compare")
223
-
224
-
225
- def cmd_compare():
226
- """Compare all outputs (dev machine, after copying ax_*.npy from board)."""
227
- pt_audio = np.load(f'{TEST_DIR}/pt_audio.npy')
228
- onnx_audio = np.load(f'{TEST_DIR}/onnx_audio.npy')
229
- ax_audio = np.load(f'{TEST_DIR}/ax_audio.npy')
230
-
231
- pt_real = np.load(f'{TEST_DIR}/pt_real.npy')
232
- onnx_real = np.load(f'{TEST_DIR}/onnx_real.npy')
233
- ax_real = np.load(f'{TEST_DIR}/ax_real.npy')
234
-
235
- pt_imag = np.load(f'{TEST_DIR}/pt_imag.npy')
236
- onnx_imag = np.load(f'{TEST_DIR}/onnx_imag.npy')
237
- ax_imag = np.load(f'{TEST_DIR}/ax_imag.npy')
238
-
239
- print("=== Full Comparison ===")
240
- print("\n--- Spectrum ---")
241
- compare('real: PT vs ONNX', pt_real, onnx_real)
242
- compare('real: PT vs axmodel', pt_real, ax_real)
243
- compare('real: ONNX vs axmodel', onnx_real, ax_real)
244
- print()
245
- compare('imag: PT vs ONNX', pt_imag, onnx_imag)
246
- compare('imag: PT vs axmodel', pt_imag, ax_imag)
247
- compare('imag: ONNX vs axmodel', onnx_imag, ax_imag)
248
-
249
- print("\n--- Audio ---")
250
- compare('audio: PT vs ONNX', pt_audio, onnx_audio)
251
- compare('audio: PT vs axmodel', pt_audio, ax_audio)
252
- compare('audio: ONNX vs axmodel', onnx_audio, ax_audio)
253
-
254
-
255
- def main():
256
- parser = argparse.ArgumentParser()
257
- parser.add_argument('--save-test-data', action='store_true')
258
- parser.add_argument('--run-axmodel', action='store_true')
259
- parser.add_argument('--compare', action='store_true')
260
- args = parser.parse_args()
261
-
262
- if args.save_test_data:
263
- cmd_save_test_data()
264
- elif args.run_axmodel:
265
- cmd_run_axmodel()
266
- elif args.compare:
267
- cmd_compare()
268
- else:
269
- print("Usage: --save-test-data | --run-axmodel | --compare")
270
- print("\nWorkflow:")
271
- print(" 1. Dev machine: python3 compare_vocoder.py --save-test-data")
272
- print(" 2. Copy TEST_DIR to board, run: python3 compare_vocoder.py --run-axmodel")
273
- print(" 3. Copy ax_*.npy back to dev, run: python3 compare_vocoder.py --compare")
274
-
275
-
276
- if __name__ == '__main__':
277
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/export_vocos_onnx.py DELETED
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Export Vocos ONNX models with onnxsim optimization.
4
-
5
- Static shapes (B=1, T=620):
6
- vocos_backbone_B1_T620.onnx mel [1,100,620] → features [1,620,512]
7
- vocos_head_linear_B1_T620.onnx features [1,620,512] → (real, imag) [1,620,513]
8
- vocos_full_B1_T620.onnx mel [1,100,620] → (real, imag) [1,620,513]
9
-
10
- IRFFT + window + overlap-add is handled in C++ (simple, ~50 lines with existing FFT).
11
- """
12
- import sys, os, math
13
- import numpy as np
14
- import torch
15
- import torch.nn as nn
16
- import onnx
17
- from onnxsim import simplify
18
-
19
- REPO_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
20
- sys.path.insert(0, REPO_DIR)
21
- from scripts.local_vocos import LocalVocos, ISTFTHead
22
-
23
- OUT_DIR = os.path.join(REPO_DIR, 'cpp', 'vocoder_onnx')
24
- os.makedirs(OUT_DIR, exist_ok=True)
25
-
26
-
27
- class HeadLinearOnly(nn.Module):
28
- """Linear(512→1026) + mag/phase → real/imag spectrum. No ISTFT."""
29
- def __init__(self, head: ISTFTHead):
30
- super().__init__()
31
- self.out = head.out # Linear(512, 1026)
32
- def forward(self, x): # x: [B, T, 512]
33
- h = self.out(x); mag, phase = h.chunk(2, dim=-1)
34
- mag = torch.exp(mag).clamp(max=1e2)
35
- return mag * torch.cos(phase), mag * torch.sin(phase)
36
-
37
-
38
- class FullModel(nn.Module):
39
- def __init__(self, backbone, head_linear):
40
- super().__init__()
41
- self.backbone = backbone
42
- self.head_linear = head_linear
43
- def forward(self, mel):
44
- return self.head_linear(self.backbone(mel))
45
-
46
-
47
- def export_onnx(model, dummy, path, in_names, out_names, dyn=None):
48
- tmp = path + '.tmp'
49
- torch.onnx.export(model, dummy, tmp,
50
- input_names=in_names, output_names=out_names,
51
- dynamic_axes=dyn, opset_version=17, do_constant_folding=True)
52
- model_simp, check = simplify(tmp)
53
- assert check, f"onnxsim verification failed for {path}"
54
- onnx.save(model_simp, path)
55
- os.remove(tmp)
56
- size_mb = os.path.getsize(path) / 1024 / 1024
57
- print(f" {os.path.basename(path):50s} {size_mb:6.1f} MB")
58
-
59
-
60
- def verify(name, pt_list, onnx_list):
61
- for i, (pt, onnx_val) in enumerate(zip(pt_list, onnx_list)):
62
- diff = np.abs(pt - onnx_val)
63
- sig = max(np.mean(np.abs(pt)), 1e-10)
64
- print(f" [{name}/{i}] max_err={diff.max():.2e} rel_err={diff.mean()/sig:.2e} "
65
- f"shape={pt.shape}")
66
-
67
-
68
- def main():
69
- print("Loading Vocos...")
70
- vocoder = LocalVocos()
71
- sd = torch.load(f'{REPO_DIR}/resources/vocos-mel-24khz/pytorch_model.bin',
72
- weights_only=True, map_location='cpu')
73
- sd = {k: v for k, v in sd.items() if k.startswith(('backbone.', 'head.'))}
74
- vocoder.load_state_dict(sd)
75
- vocoder.eval()
76
-
77
- backbone = vocoder.backbone
78
- head_linear = HeadLinearOnly(vocoder.head).eval()
79
-
80
- B, T = 1, 620
81
- dummy_mel = torch.randn(B, 100, T)
82
-
83
- with torch.no_grad():
84
- bb_out = backbone(dummy_mel)
85
- pt_real, pt_imag = head_linear(bb_out)
86
-
87
- print(f"PT output: real={pt_real.shape}, imag={pt_imag.shape}")
88
-
89
- # --- Export static (B=1, T=620) ---
90
- print("\n=== Static models (B=1, T=620) ===")
91
- export_onnx(backbone, dummy_mel,
92
- f'{OUT_DIR}/vocos_backbone_B1_T620.onnx',
93
- ['mel'], ['features'])
94
- export_onnx(head_linear, bb_out,
95
- f'{OUT_DIR}/vocos_head_linear_B1_T620.onnx',
96
- ['features'], ['real', 'imag'])
97
- export_onnx(FullModel(backbone, head_linear).eval(), dummy_mel,
98
- f'{OUT_DIR}/vocos_full_B1_T620.onnx',
99
- ['mel'], ['real', 'imag'])
100
-
101
- # --- Verify with onnxruntime ---
102
- print("\n=== Verification ===")
103
- import onnxruntime as ort
104
-
105
- for tag, model_file, input_dict, pt_expected in [
106
- ('backbone', 'vocos_backbone_B1_T620.onnx',
107
- {'mel': dummy_mel.numpy()}, [bb_out.numpy()]),
108
- ('head_linear', 'vocos_head_linear_B1_T620.onnx',
109
- {'features': bb_out.numpy()}, [pt_real.numpy(), pt_imag.numpy()]),
110
- ('full', 'vocos_full_B1_T620.onnx',
111
- {'mel': dummy_mel.numpy()}, [pt_real.numpy(), pt_imag.numpy()]),
112
- ]:
113
- sess = ort.InferenceSession(f'{OUT_DIR}/{model_file}')
114
- onnx_out = sess.run(None, input_dict)
115
- verify(tag, pt_expected, onnx_out)
116
-
117
- print("\nDone! All exported and verified.")
118
- for f in sorted(os.listdir(OUT_DIR)):
119
- if 'B1_T620' in f:
120
- size = os.path.getsize(f'{OUT_DIR}/{f}') / 1024 / 1024
121
- print(f" {f} ({size:.1f} MB)")
122
-
123
-
124
- if __name__ == '__main__':
125
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/gen_cat_tokens.py DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Generate cat_tokens binary for C++ ZipVoice inference. Works for any language.
3
-
4
- Usage:
5
- python3 gen_cat_tokens.py --prompt "prompt text" --text "target text"
6
- python3 gen_cat_tokens.py --prompt-file prompt.txt --text-file target.txt
7
- """
8
- import sys, os, argparse
9
- import numpy as np
10
-
11
- REPO_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # cpp/scripts → repo root
12
- sys.path.insert(0, REPO_DIR)
13
-
14
- from scripts.local_tokenizer import LocalEmiliaTokenizer
15
- from scripts.text_processing import normalize_punctuation
16
-
17
- parser = argparse.ArgumentParser()
18
- parser.add_argument('--prompt', default='')
19
- parser.add_argument('--text', default='')
20
- parser.add_argument('--prompt-file', default='')
21
- parser.add_argument('--text-file', default='')
22
- parser.add_argument('--output', default='cat_tokens.bin')
23
- parser.add_argument('--max-tokens', type=int, default=384)
24
- args = parser.parse_args()
25
-
26
- prompt = args.prompt or (open(args.prompt_file).read().strip() if args.prompt_file else '')
27
- text = args.text or (open(args.text_file).read().strip() if args.text_file else '')
28
-
29
- if not prompt or not text:
30
- print("ERROR: provide --prompt/--prompt-file and --text/--text-file")
31
- sys.exit(1)
32
-
33
- token_file = os.path.join(REPO_DIR, 'resources', 'zipvoice_hf', 'zipvoice', 'tokens.txt')
34
- tokenizer = LocalEmiliaTokenizer(token_file=token_file)
35
-
36
- pids = tokenizer.texts_to_token_ids([normalize_punctuation(prompt)])[0]
37
- tids = tokenizer.texts_to_token_ids([normalize_punctuation(text)])[0]
38
-
39
- cat = pids + tids + [tokenizer.pad_id]
40
- ct = np.full((args.max_tokens,), tokenizer.pad_id, dtype=np.int32)
41
- ct[:len(cat)] = np.array(cat, dtype=np.int32)
42
- ct.tofile(args.output)
43
-
44
- print(f'prompt_tokens_len={len(pids)} text_tokens_len={len(tids)} saved: {args.output}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/gen_pinyin_table.py DELETED
@@ -1,95 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Generate C++ header with Chinese character → pinyin token mapping."""
3
- import sys, os
4
- REPO_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
- sys.path.insert(0, REPO_DIR)
6
-
7
- from pypinyin.pinyin_dict import pinyin_dict
8
- from pypinyin.contrib.tone_convert import to_initials, to_finals_tone3
9
-
10
- TOKEN_FILE = os.path.join(REPO_DIR, 'resources', 'zipvoice_hf', 'zipvoice', 'tokens.txt')
11
- OUTPUT = os.path.join(REPO_DIR, 'cpp', 'src', 'pinyin_table.hpp')
12
-
13
- # Load token2id
14
- token2id = {}
15
- with open(TOKEN_FILE) as f:
16
- for line in f:
17
- if '\t' in line:
18
- t, tid = line.rstrip().split('\t')
19
- token2id[t] = int(tid)
20
-
21
- # Build char → token IDs
22
- char_entries = []
23
- for codepoint, pinyins in pinyin_dict.items():
24
- ch = chr(codepoint)
25
- py = pinyins.split(',')[0]
26
- initial = to_initials(py, strict=False)
27
- final = to_finals_tone3(py, strict=False, neutral_tone_with_five=True)
28
- if not final: continue
29
-
30
- ini_token = initial + '0' if initial else ''
31
- tokens = []
32
- if ini_token and ini_token in token2id:
33
- tokens.append(token2id[ini_token])
34
- if final in token2id:
35
- tokens.append(token2id[final])
36
-
37
- if tokens:
38
- char_entries.append((codepoint, tokens))
39
-
40
- # Sort by codepoint for binary search
41
- char_entries.sort(key=lambda x: x[0])
42
-
43
- # Generate C++ header
44
- with open(OUTPUT, 'w') as f:
45
- f.write('''// Auto-generated Chinese character → token ID mapping
46
- // Source: pypinyin.pinyin_dict, tokens.txt
47
- // Generated by gen_pinyin_table.py
48
-
49
- #pragma once
50
- #include <cstdint>
51
- #include <string>
52
- #include <vector>
53
-
54
- struct PinyinEntry {
55
- uint32_t codepoint;
56
- int16_t token1;
57
- int16_t token2; // -1 if only one token
58
- };
59
-
60
- // Sorted by codepoint, use binary search
61
- static const PinyinEntry PINYIN_TABLE[] = {
62
- ''')
63
-
64
- for codepoint, tokens in char_entries:
65
- t1 = tokens[0]
66
- t2 = tokens[1] if len(tokens) > 1 else -1
67
- f.write(f' {{0x{codepoint:04X}, {t1}, {t2}}}, // {chr(codepoint)}\n')
68
-
69
- f.write(f'''}};
70
-
71
- static const int PINYIN_TABLE_SIZE = {len(char_entries)};
72
-
73
- // Lookup tokens for a Chinese character. Returns empty vector if not found.
74
- inline std::vector<int> pinyin_lookup(uint32_t codepoint) {{
75
- // Binary search
76
- int lo = 0, hi = PINYIN_TABLE_SIZE - 1;
77
- while (lo <= hi) {{
78
- int mid = (lo + hi) / 2;
79
- if (PINYIN_TABLE[mid].codepoint == codepoint) {{
80
- std::vector<int> result;
81
- result.push_back(PINYIN_TABLE[mid].token1);
82
- if (PINYIN_TABLE[mid].token2 >= 0)
83
- result.push_back(PINYIN_TABLE[mid].token2);
84
- return result;
85
- }}
86
- if (PINYIN_TABLE[mid].codepoint < codepoint)
87
- lo = mid + 1;
88
- else
89
- hi = mid - 1;
90
- }}
91
- return {{}};
92
- }}
93
- ''')
94
-
95
- print(f"Generated {OUTPUT}: {len(char_entries)} entries")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/generate_vocoder_calib.py DELETED
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Generate vocoder calibration data on dev machine (no axengine needed).
4
-
5
- Collects mel features from:
6
- 1. Real mel output files (output_mel.bin from previous C++ runs)
7
- 2. Random mel features in the expected value range
8
- 3. Zero/silence mel features
9
- Then runs them through ONNX to get intermediate features for head_linear calibration.
10
-
11
- Usage:
12
- python3 generate_vocoder_calib.py --output-dir ./calib_data_vocoder
13
- """
14
- import sys, os, argparse, json, glob
15
- from pathlib import Path
16
- import numpy as np
17
- import onnxruntime as ort
18
-
19
- SCRIPT_DIR = Path(__file__).resolve().parent
20
- REPO_DIR = SCRIPT_DIR.parent.parent # scripts/ → cpp/ → repo root
21
- ONNX_DIR = SCRIPT_DIR.parent / "vocoder_onnx" # cpp/vocoder_onnx
22
-
23
-
24
- def main():
25
- parser = argparse.ArgumentParser()
26
- parser.add_argument("--output-dir", default=str(ONNX_DIR / "calib_data"))
27
- parser.add_argument("--num-samples", type=int, default=16)
28
- parser.add_argument("--seed", type=int, default=42)
29
- args = parser.parse_args()
30
-
31
- out_dir = Path(args.output_dir)
32
- out_dir.mkdir(parents=True, exist_ok=True)
33
- rng = np.random.RandomState(args.seed)
34
-
35
- T = 620
36
- mel_samples = []
37
-
38
- # --- Source 1: Real mel features if available (undo feat_scale to match vocoder input) ---
39
- feat_scale = 0.1
40
- for pattern in ["output_mel.bin", "output_mel_debug.bin"]:
41
- for p in [REPO_DIR / pattern, SCRIPT_DIR / pattern]:
42
- if p.exists():
43
- mel = np.fromfile(str(p), dtype=np.float32).reshape(-1, 100).T[np.newaxis, :, :] / feat_scale # [1, 100, frames]
44
- gen_frames = min(mel.shape[2], T)
45
- padded = np.zeros((1, 100, T), dtype=np.float32)
46
- padded[0, :, :gen_frames] = mel[0, :, :gen_frames]
47
- mel_samples.append(padded)
48
- print(f"Real mel from {p}: shape={mel.shape}")
49
-
50
- # --- Source 2: Random mel in vocoder input range (after /feat_scale) ---
51
- # Python: features / 0.1 before vocoder → range ~[-8.6, 4.0]
52
- # So calibration mel should be in [feat_scaled] range, divided by feat_scale
53
- # to match the actual vocoder input distribution
54
- feat_scale = 0.1
55
- for i in range(max(0, args.num_samples - len(mel_samples))):
56
- length = rng.randint(100, T + 1)
57
- # Generate in feat_scaled range, then undo feat_scale
58
- mel = (rng.randn(1, 100, T).astype(np.float32) * 0.3 - 0.04) / feat_scale
59
- mel[0, :, length:] = 0.0
60
- mel_samples.append(mel)
61
-
62
- # --- Source 3: Edge cases (with feat_scale undo) ---
63
- mel_samples.append(np.zeros((1, 100, T), dtype=np.float32))
64
- mel_samples.append(np.ones((1, 100, T), dtype=np.float32) * 0.5 / feat_scale)
65
- mel_samples.append(rng.randn(1, 100, T).astype(np.float32) * 0.1 / feat_scale)
66
- mel_samples.append(rng.randn(1, 100, T).astype(np.float32) / feat_scale)
67
-
68
- print(f"\nTotal mel samples: {len(mel_samples)}")
69
-
70
- # --- Run ONNX to get backbone outputs (for head_linear calibration) ---
71
- bb_path = ONNX_DIR / "vocos_backbone_B1_T620.onnx"
72
- hl_path = ONNX_DIR / "vocos_head_linear_B1_T620.onnx"
73
-
74
- if not bb_path.exists():
75
- print(f"ERROR: {bb_path} not found. Run export_vocos_onnx.py first.")
76
- return
77
-
78
- sess_bb = ort.InferenceSession(str(bb_path))
79
- print(f"Loaded backbone: {bb_path}")
80
-
81
- # --- Save backbone calibration data ---
82
- bb_dir = out_dir / "vocos_backbone" / "mel"
83
- bb_dir.mkdir(parents=True, exist_ok=True)
84
- bb_entries = []
85
- backbone_outputs = []
86
-
87
- for i, mel in enumerate(mel_samples):
88
- np.save(bb_dir / f"{i:04d}.npy", mel)
89
- bb_entries.append({"file": f"mel/{i:04d}.npy", "shape": list(mel.shape)})
90
-
91
- # Run ONNX to get head_linear input
92
- feat = sess_bb.run(None, {'mel': mel})[0]
93
- backbone_outputs.append(feat)
94
-
95
- print(f"Backbone calibration: {len(bb_entries)} samples")
96
-
97
- # --- Save head_linear calibration data ---
98
- hl_dir = out_dir / "vocos_head_linear" / "features"
99
- hl_dir.mkdir(parents=True, exist_ok=True)
100
- hl_entries = []
101
-
102
- for i, feat in enumerate(backbone_outputs):
103
- np.save(hl_dir / f"{i:04d}.npy", feat)
104
- hl_entries.append({"file": f"features/{i:04d}.npy", "shape": list(feat.shape)})
105
-
106
- print(f"Head_linear calibration: {len(hl_entries)} samples")
107
-
108
- # --- Verify head_linear ONNX with calibration data ---
109
- if hl_path.exists():
110
- sess_hl = ort.InferenceSession(str(hl_path))
111
- for i in range(min(3, len(backbone_outputs))):
112
- r, im = sess_hl.run(None, {'features': backbone_outputs[i]})
113
- print(f" Verify head[{i}]: real range=[{r.min():.3f},{r.max():.3f}], "
114
- f"imag range=[{im.min():.3f},{im.max():.3f}]")
115
-
116
- # --- Manifest ---
117
- manifest = {
118
- "description": "Vocoder ONNX calibration data",
119
- "backbone": {
120
- "model": "vocos_backbone_B1_T620.onnx",
121
- "input": "mel", "shape": [1, 100, 620], "dtype": "float32",
122
- "num_samples": len(bb_entries),
123
- "files": bb_entries,
124
- },
125
- "head_linear": {
126
- "model": "vocos_head_linear_B1_T620.onnx",
127
- "input": "features", "shape": [1, 620, 512], "dtype": "float32",
128
- "num_samples": len(hl_entries),
129
- "files": hl_entries,
130
- },
131
- }
132
- with open(out_dir / "calib_manifest.json", "w") as f:
133
- json.dump(manifest, f, indent=2, ensure_ascii=False)
134
-
135
- print(f"\nDone! Output: {out_dir}")
136
- print(f" vocos_backbone/mel/ : {len(bb_entries)} .npy files")
137
- print(f" vocos_head_linear/features/: {len(hl_entries)} .npy files")
138
-
139
-
140
- if __name__ == "__main__":
141
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/py_daemon.py DELETED
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- ZipVoice Python daemon: loads tokenizer once, handles C++ requests via stdin/stdout.
4
- Protocol (tab-separated lines to preserve spaces in text paths):
5
- count\t<prompt_file>\t<text_file>
6
- -> prints "COUNT <prompt_len> <text_len>"
7
- tokenize\t<prompt_file>\t<text_file>\t<max_tokens>\t<output_bin>
8
- -> prints "TOKENS <prompt_len> <text_len>"
9
- quit
10
- -> exits
11
- """
12
- import sys, os
13
- import numpy as np
14
-
15
- REPO_DIR = sys.argv[1]
16
- sys.path.insert(0, REPO_DIR)
17
-
18
- from scripts.local_tokenizer import LocalEmiliaTokenizer
19
- from scripts.text_processing import normalize_punctuation
20
-
21
- TOKEN_FILE = os.path.join(REPO_DIR, "resources", "zipvoice_hf", "zipvoice", "tokens.txt")
22
- tokenizer = LocalEmiliaTokenizer(token_file=TOKEN_FILE)
23
-
24
- print("READY", flush=True)
25
-
26
- for line in sys.stdin:
27
- line = line.rstrip("\n")
28
- if not line:
29
- continue
30
- parts = line.split("\t")
31
- cmd = parts[0]
32
-
33
- if cmd == "count":
34
- prompt_file, text_file = parts[1], parts[2]
35
- pt = normalize_punctuation(open(prompt_file).read().strip())
36
- tt = normalize_punctuation(open(text_file).read().strip())
37
- pids = tokenizer.texts_to_token_ids([pt])[0]
38
- tids = tokenizer.texts_to_token_ids([tt])[0]
39
- print(f"COUNT {len(pids)} {len(tids)}", flush=True)
40
-
41
- elif cmd == "tokenize":
42
- prompt_file, text_file, max_tokens, output_bin = parts[1], parts[2], int(parts[3]), parts[4]
43
- pt = normalize_punctuation(open(prompt_file).read().strip())
44
- tt = normalize_punctuation(open(text_file).read().strip())
45
- pids = tokenizer.texts_to_token_ids([pt])[0]
46
- tids = tokenizer.texts_to_token_ids([tt])[0]
47
- cat = pids + tids + [tokenizer.pad_id]
48
- if len(cat) > max_tokens:
49
- print(f"ERROR too_many_tokens {len(cat)}>{max_tokens}", flush=True)
50
- continue
51
- ct = np.full((max_tokens,), tokenizer.pad_id, dtype=np.int32)
52
- ct[:len(cat)] = np.array(cat, dtype=np.int32)
53
- ct.tofile(output_bin)
54
- print(f"TOKENS {len(pids)} {len(tids)}", flush=True)
55
-
56
- elif cmd == "quit":
57
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/scripts/quantize_vocoder.sh DELETED
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Quantize vocoder ONNX models to axmodel using pulsar2.
3
- #
4
- # Prerequisites:
5
- # 1. export_vocos_onnx.py (generates vocoder_onnx/*.onnx)
6
- # 2. generate_vocoder_calib.py (generates vocoder_onnx/calib_data/)
7
- # 3. source <npu_dev_env> (activates pulsar2, e.g. $HOME/npu-codebase/script/npu_dev)
8
- #
9
- # Usage:
10
- # bash quantize_vocoder.sh
11
-
12
- set -euo pipefail
13
-
14
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
- PARENT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
16
- cd "${PARENT_DIR}"
17
-
18
- ONNX_DIR="${PARENT_DIR}/vocoder_onnx"
19
- CALIB_DIR="${ONNX_DIR}/calib_data"
20
- BUILD_DIR="${ONNX_DIR}/pulsar2_build"
21
- AXMODEL_DIR="${ONNX_DIR}/axmodel"
22
-
23
- # --- Config ---
24
- TARGET_HARDWARE="${TARGET_HARDWARE:-AX650}"
25
- NPU_MODE="${NPU_MODE:-NPU3}"
26
- CHECK_LEVEL="${CHECK_LEVEL:-0}"
27
- DEFAULT_DATA_TYPE="${DEFAULT_DATA_TYPE:-U16}"
28
- CALIBRATION_SIZE="${CALIBRATION_SIZE:--1}"
29
-
30
- FULL_MODEL="${ONNX_DIR}/vocos_full_B1_T620.onnx"
31
- CALIB_DIR_BB="${CALIB_DIR}/vocos_backbone"
32
-
33
- if [ ! -f "${FULL_MODEL}" ]; then
34
- echo "ERROR: ${FULL_MODEL} not found. Run export_vocos_onnx.py first."
35
- exit 1
36
- fi
37
-
38
- if [ ! -d "${CALIB_DIR_BB}" ]; then
39
- echo "ERROR: ${CALIB_DIR_BB} not found. Run generate_vocoder_calib.py first."
40
- exit 1
41
- fi
42
-
43
- # Activate pulsar2 if not already available
44
- if ! command -v pulsar2 >/dev/null 2>&1; then
45
- echo "Activating pulsar2 environment..."
46
- set +u
47
- source "${NPU_DEV_ENV:-$HOME/npu-codebase/script/npu_dev}"
48
- set -u
49
- fi
50
-
51
- mkdir -p "${BUILD_DIR}" "${AXMODEL_DIR}"
52
-
53
- # --- Step 1: Package calibration data as tar.gz ---
54
- echo "=== Packaging calibration data ==="
55
-
56
- # Calibration for full model: mel -> (real, imag)
57
- # Input tensor is "mel", calibration data in vocos_backbone/mel/
58
- FULL_CALIB_TAR="${CALIB_DIR}/vocos_full_mel.tar.gz"
59
- INPUT_DIR="${CALIB_DIR_BB}/mel"
60
-
61
- if [ ! -f "${FULL_CALIB_TAR}" ]; then
62
- echo "Creating ${FULL_CALIB_TAR}..."
63
- cd "${INPUT_DIR}"
64
- tar czf "${FULL_CALIB_TAR}" --transform 's|.*/||' *.npy
65
- cd "${SCRIPT_DIR}"
66
- fi
67
- echo " ${FULL_CALIB_TAR} ($(du -h "${FULL_CALIB_TAR}" | cut -f1))"
68
-
69
- # --- Step 2: Build pulsar2 config ---
70
- echo ""
71
- echo "=== Quantizing vocos_full ==="
72
-
73
- CONFIG="${BUILD_DIR}/config_vocos_full.json"
74
-
75
- cat > "${CONFIG}" << EOF
76
- {
77
- "model_type": "ONNX",
78
- "npu_mode": "${NPU_MODE}",
79
- "input": "${FULL_MODEL}",
80
- "output_name": "vocos_full.axmodel",
81
- "output_dir": "${BUILD_DIR}",
82
- "target_hardware": "${TARGET_HARDWARE}",
83
- "onnx_opt": {"disable_onnx_optimization": false, "enable_onnxsim": true},
84
- "quant": {
85
- "input_configs": [
86
- {"tensor_name": "mel", "calibration_dataset": "${FULL_CALIB_TAR}", "calibration_format": "Numpy", "calibration_size": ${CALIBRATION_SIZE}}
87
- ],
88
- "layer_configs": [
89
- {"op_type": "Pow", "data_type": "U8"},
90
- {"start_tensor_names": ["DEFAULT"], "end_tensor_names": ["DEFAULT"], "data_type": "${DEFAULT_DATA_TYPE}"}
91
- ],
92
- "calibration_method": "MinMax",
93
- "enable_smooth_quant": true,
94
- "conv_bias_data_type": "FP32",
95
- "precision_analysis": true,
96
- "precision_analysis_method": "EndToEnd",
97
- "disable_auto_refine_scale": true,
98
- "transformer_opt_level": 0
99
- },
100
- "input_processors": [{"tensor_name": "DEFAULT"}],
101
- "compiler": {"check": ${CHECK_LEVEL}, "enable_slice_mode": false}
102
- }
103
- EOF
104
-
105
- echo "Config: ${CONFIG}"
106
- echo "Input shapes: mel:1x100x620"
107
-
108
- # --- Step 3: Run pulsar2 ---
109
- echo ""
110
- echo "=== Running pulsar2 build ==="
111
- pulsar2 build --config "${CONFIG}" --input_shapes "mel:1x100x620" 2>&1 | tee "${BUILD_DIR}/build_vocos_full.log"
112
-
113
- # --- Step 4: Copy output ---
114
- BUILD_OUTPUT="${BUILD_DIR}/vocos_full.axmodel"
115
- if [ -f "${BUILD_OUTPUT}" ]; then
116
- cp "${BUILD_OUTPUT}" "${AXMODEL_DIR}/"
117
- echo ""
118
- echo "=== Done! ==="
119
- ls -lh "${AXMODEL_DIR}/vocos_full.axmodel"
120
- else
121
- echo "ERROR: Build failed, ${BUILD_OUTPUT} not found"
122
- exit 1
123
- fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/EngineWrapper.cpp DELETED
@@ -1,13 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice C++ — Unified EngineWrapper implementation (AXERA & AXCL)
3
- *
4
- * Conditionally includes the platform-specific implementation.
5
- **************************************************************************************************/
6
-
7
- #if defined(AX650) || defined(AX630C) || defined(AX620Q)
8
- #include "EngineWrapper_axera.cpp"
9
- #elif defined(AXCL)
10
- #include "EngineWrapper_axcl.cpp"
11
- #else
12
- #error "Unknown platform. Define AX650, AX630C, AX620Q, or AXCL."
13
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/EngineWrapper.hpp DELETED
@@ -1,81 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice C++ — Unified EngineWrapper (AXERA & AXCL)
3
- *
4
- * Supports both AXERA (demo board) and AXCL (compute card) via conditional compilation.
5
- * AX650 / AX630C / AX620Q → AXERA path (ax_engine_api)
6
- * AXCL → AXCL path (middleware::runner)
7
- *
8
- * Interface is identical — callers don't need to know which backend is active.
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <string>
14
- #include <vector>
15
- #include <unordered_map>
16
- #include <cstring>
17
- #include <cstdint>
18
- #include <memory>
19
-
20
- #if defined(AX650) || defined(AX630C) || defined(AX620Q)
21
- #include "ax_engine_api.h"
22
- #elif defined(AXCL)
23
- #include "middleware/axcl_runtime_runner.hpp"
24
- #endif
25
-
26
- class EngineWrapper {
27
- public:
28
- EngineWrapper();
29
- ~EngineWrapper();
30
-
31
- /**
32
- * Initialize and load a model.
33
- * @param strModelPath Path to .axmodel file
34
- * @param nNpuType AXERA: VNPU type (0=default); AXCL: device_index (0=first card)
35
- * @param axclConfig AXCL: path to axcl.json (nullptr → /usr/local/axcl/axcl.json). Ignored on AXERA.
36
- */
37
- int Init(const char* strModelPath, uint32_t nNpuType = 0, const char* axclConfig = nullptr);
38
-
39
- // Index-based I/O
40
- int SetInput(void* pInput, int index);
41
- int RunSync();
42
- int GetOutput(void* pOutput, int index);
43
-
44
- // Name-based I/O
45
- int SetInputByName(const char* name, void* pInput);
46
- int GetOutputByName(const char* name, void* pOutput);
47
-
48
- int GetInputSize(int index);
49
- int GetOutputSize(int index);
50
- int GetInputSizeByName(const char* name);
51
- int GetOutputSizeByName(const char* name);
52
-
53
- int GetInputIndex(const char* name);
54
- int GetOutputIndex(const char* name);
55
- int GetInputCount() const { return m_input_num; }
56
- int GetOutputCount() const { return m_output_num; }
57
- const char* GetInputName(int index) const;
58
- const char* GetOutputName(int index) const;
59
- #if defined(AX650) || defined(AX630C) || defined(AX620Q)
60
- const char* GetInputDtypeStr(int index) const;
61
- const char* GetOutputDtypeStr(int index) const;
62
- #endif
63
-
64
- bool HasInit() const { return m_hasInit; }
65
- int Release();
66
-
67
- private:
68
- bool m_hasInit;
69
- int m_input_num, m_output_num;
70
-
71
- std::unordered_map<std::string, int> m_input_name_to_idx;
72
- std::unordered_map<std::string, int> m_output_name_to_idx;
73
-
74
- #if defined(AX650) || defined(AX630C) || defined(AX620Q)
75
- AX_ENGINE_HANDLE m_handle;
76
- AX_ENGINE_IO_INFO_T *m_io_info;
77
- AX_ENGINE_IO_T m_io;
78
- #elif defined(AXCL)
79
- std::unique_ptr<middleware::runner> m_runner;
80
- #endif
81
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/EngineWrapper_axcl.cpp DELETED
@@ -1,217 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXCL C++ Port
3
- *
4
- * EngineWrapper implementation using middleware::runner (AXCL Runtime API).
5
- *
6
- * Key differences from AXERA:
7
- * - Uses axclrtMemcpy for host↔device data transfer
8
- * - No CMM (contiguous memory) allocation
9
- * - Runner manages device-side memory and NPU execution
10
- **************************************************************************************************/
11
-
12
- #include "EngineWrapper.hpp"
13
-
14
- #include <cstdio>
15
- #include <cstdlib>
16
- #include <cstring>
17
-
18
- #include <axcl.h>
19
-
20
- EngineWrapper::EngineWrapper()
21
- : m_hasInit(false), m_input_num(0), m_output_num(0) {}
22
-
23
- EngineWrapper::~EngineWrapper() {
24
- Release();
25
- }
26
-
27
- int EngineWrapper::Init(const char* strModelPath,
28
- uint32_t nNpuType,
29
- const char* axclConfig) {
30
- const char* config = axclConfig ? axclConfig : "/usr/local/axcl/axcl.json";
31
- uint32_t device_index = nNpuType; // nNpuType = device_index on AXCL
32
- uint32_t npu_kind = 0; // AXCL_VNPU_DISABLE (default)
33
-
34
- // 1. Create runtime runner
35
- m_runner = std::make_unique<middleware::runtime_runner>();
36
-
37
- // 2. Initialize runner (handles axclrtEngineInit internally)
38
- if (!m_runner->init(config, device_index, npu_kind)) {
39
- fprintf(stderr, "[ERROR] AXCL runner init failed for model: %s\n", strModelPath);
40
- return -1;
41
- }
42
-
43
- // 3. Load model from file
44
- if (!m_runner->load(strModelPath)) {
45
- fprintf(stderr, "[ERROR] AXCL runner load failed for model: %s\n", strModelPath);
46
- return -1;
47
- }
48
-
49
- // 4. Prepare IO buffers (allocates device memory, sets up IO)
50
- if (!m_runner->prepare(true, true, 0, 0)) {
51
- fprintf(stderr, "[ERROR] AXCL runner prepare failed for model: %s\n", strModelPath);
52
- return -1;
53
- }
54
-
55
- // 5. Build name-to-index maps
56
- m_input_num = static_cast<int>(m_runner->get_input_count());
57
- m_output_num = static_cast<int>(m_runner->get_output_count());
58
-
59
- m_input_name_to_idx.clear();
60
- for (int i = 0; i < m_input_num; ++i) {
61
- std::string name = m_runner->get_input_name(i);
62
- m_input_name_to_idx[name] = i;
63
- }
64
-
65
- m_output_name_to_idx.clear();
66
- for (int i = 0; i < m_output_num; ++i) {
67
- std::string name = m_runner->get_output_name(i);
68
- m_output_name_to_idx[name] = i;
69
- }
70
-
71
- m_hasInit = true;
72
-
73
- printf("AXCL EngineWrapper loaded: %s (inputs=%d, outputs=%d)\n",
74
- strModelPath, m_input_num, m_output_num);
75
- for (int i = 0; i < m_input_num; ++i) {
76
- printf(" input[%d]: %s (%zu bytes)\n", i,
77
- m_runner->get_input_name(i).c_str(),
78
- (size_t)m_runner->get_input_size(i));
79
- }
80
- for (int i = 0; i < m_output_num; ++i) {
81
- printf(" output[%d]: %s (%zu bytes)\n", i,
82
- m_runner->get_output_name(i).c_str(),
83
- (size_t)m_runner->get_output_size(i));
84
- }
85
-
86
- return 0;
87
- }
88
-
89
- int EngineWrapper::SetInput(void* pInput, int index) {
90
- if (!m_hasInit || index < 0 || index >= m_input_num) return -1;
91
-
92
- uintmax_t size = m_runner->get_input_size(index);
93
- void* dev_ptr = m_runner->get_input_pointer(index);
94
-
95
- if (!dev_ptr || size == 0) {
96
- fprintf(stderr, "[ERROR] Invalid input pointer/size for index %d\n", index);
97
- return -1;
98
- }
99
-
100
- // Copy host data to device memory
101
- axclError ret = axclrtMemcpy(dev_ptr, pInput, size, AXCL_MEMCPY_HOST_TO_DEVICE);
102
- if (ret != 0) {
103
- fprintf(stderr, "[ERROR] axclrtMemcpy H2D failed for input %d: 0x%x\n", index, ret);
104
- return -1;
105
- }
106
-
107
- return 0;
108
- }
109
-
110
- int EngineWrapper::RunSync() {
111
- if (!m_hasInit) return -1;
112
-
113
- if (!m_runner->run(false)) {
114
- fprintf(stderr, "[ERROR] AXCL runner run failed\n");
115
- return -1;
116
- }
117
-
118
- return 0;
119
- }
120
-
121
- int EngineWrapper::GetOutput(void* pOutput, int index) {
122
- if (!m_hasInit || index < 0 || index >= m_output_num) return -1;
123
-
124
- uintmax_t size = m_runner->get_output_size(index);
125
- void* dev_ptr = m_runner->get_output_pointer(index);
126
-
127
- if (!dev_ptr || size == 0) {
128
- fprintf(stderr, "[ERROR] Invalid output pointer/size for index %d\n", index);
129
- return -1;
130
- }
131
-
132
- // Copy device data to host memory
133
- axclError ret = axclrtMemcpy(pOutput, dev_ptr, size, AXCL_MEMCPY_DEVICE_TO_HOST);
134
- if (ret != 0) {
135
- fprintf(stderr, "[ERROR] axclrtMemcpy D2H failed for output %d: 0x%x\n", index, ret);
136
- return -1;
137
- }
138
-
139
- return 0;
140
- }
141
-
142
- int EngineWrapper::SetInputByName(const char* name, void* pInput) {
143
- auto it = m_input_name_to_idx.find(std::string(name));
144
- if (it == m_input_name_to_idx.end()) {
145
- fprintf(stderr, "[ERROR] Input '%s' not found in model\n", name);
146
- return -1;
147
- }
148
- return SetInput(pInput, it->second);
149
- }
150
-
151
- int EngineWrapper::GetOutputByName(const char* name, void* pOutput) {
152
- auto it = m_output_name_to_idx.find(std::string(name));
153
- if (it == m_output_name_to_idx.end()) {
154
- fprintf(stderr, "[ERROR] Output '%s' not found in model\n", name);
155
- return -1;
156
- }
157
- return GetOutput(pOutput, it->second);
158
- }
159
-
160
- int EngineWrapper::GetInputSize(int index) {
161
- if (!m_hasInit || index < 0 || index >= m_input_num) return -1;
162
- return static_cast<int>(m_runner->get_input_size(index));
163
- }
164
-
165
- int EngineWrapper::GetOutputSize(int index) {
166
- if (!m_hasInit || index < 0 || index >= m_output_num) return -1;
167
- return static_cast<int>(m_runner->get_output_size(index));
168
- }
169
-
170
- int EngineWrapper::GetInputSizeByName(const char* name) {
171
- int idx = GetInputIndex(name);
172
- if (idx < 0) return -1;
173
- return GetInputSize(idx);
174
- }
175
-
176
- int EngineWrapper::GetOutputSizeByName(const char* name) {
177
- int idx = GetOutputIndex(name);
178
- if (idx < 0) return -1;
179
- return GetOutputSize(idx);
180
- }
181
-
182
- int EngineWrapper::GetInputIndex(const char* name) {
183
- auto it = m_input_name_to_idx.find(std::string(name));
184
- return (it != m_input_name_to_idx.end()) ? it->second : -1;
185
- }
186
-
187
- int EngineWrapper::GetOutputIndex(const char* name) {
188
- auto it = m_output_name_to_idx.find(std::string(name));
189
- return (it != m_output_name_to_idx.end()) ? it->second : -1;
190
- }
191
-
192
- int EngineWrapper::Release() {
193
- if (m_runner) {
194
- m_runner->final();
195
- m_runner.reset();
196
- }
197
- m_hasInit = false;
198
- m_input_name_to_idx.clear();
199
- m_output_name_to_idx.clear();
200
- m_input_num = 0;
201
- m_output_num = 0;
202
- return 0;
203
- }
204
-
205
- const char* EngineWrapper::GetInputName(int index) const {
206
- static thread_local std::string cached_name;
207
- if (!m_hasInit || index < 0 || index >= m_input_num) return nullptr;
208
- cached_name = m_runner->get_input_name(index);
209
- return cached_name.c_str();
210
- }
211
-
212
- const char* EngineWrapper::GetOutputName(int index) const {
213
- static thread_local std::string cached_name;
214
- if (!m_hasInit || index < 0 || index >= m_output_num) return nullptr;
215
- cached_name = m_runner->get_output_name(index);
216
- return cached_name.c_str();
217
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/EngineWrapper_axera.cpp DELETED
@@ -1,283 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * EngineWrapper implementation
5
- **************************************************************************************************/
6
-
7
- #include "EngineWrapper.hpp"
8
- #include "utils/io.hpp"
9
-
10
- #include <cstdlib>
11
-
12
- static const char *strAlgoModelType[AX_ENGINE_MODEL_TYPE_BUTT] = {"3.6T", "7.2T", "10.8T"};
13
-
14
- // NPU type enum
15
- typedef enum axNPU_TYPE_E {
16
- AX_NPU_DEFAULT = 0,
17
- AX_STD_VNPU_1 = (1 << 0),
18
- AX_STD_VNPU_2 = (1 << 1),
19
- AX_STD_VNPU_3 = (1 << 2),
20
- AX_BL_VNPU_1 = (1 << 3),
21
- AX_BL_VNPU_2 = (1 << 4)
22
- } AX_NPU_TYPE_E;
23
-
24
- static AX_S32 CheckModelVNpu(const std::string &strModel,
25
- const AX_ENGINE_MODEL_TYPE_T &eModelType,
26
- const AX_S32 &nNpuType, AX_U32 &nNpuSet) {
27
- AX_ENGINE_NPU_ATTR_T stNpuAttr;
28
- memset(&stNpuAttr, 0x00, sizeof(stNpuAttr));
29
-
30
- auto ret = AX_ENGINE_GetVNPUAttr(&stNpuAttr);
31
- if (ret == 0) {
32
- if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_DISABLE) {
33
- nNpuSet = 0x01;
34
- } else if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_STD) {
35
- if (eModelType == AX_ENGINE_MODEL_TYPE1 || eModelType == AX_ENGINE_MODEL_TYPE2)
36
- return -1;
37
- if (nNpuType == 0) nNpuSet = 0x02;
38
- else {
39
- if (nNpuType & AX_STD_VNPU_1) nNpuSet |= 0x01;
40
- if (nNpuType & AX_STD_VNPU_2) nNpuSet |= 0x02;
41
- if (nNpuType & AX_STD_VNPU_3) nNpuSet |= 0x04;
42
- }
43
- } else if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_BIG_LITTLE) {
44
- if (eModelType == AX_ENGINE_MODEL_TYPE2) return -1;
45
- if (nNpuType == 0) {
46
- nNpuSet = (eModelType == AX_ENGINE_MODEL_TYPE1) ? 0x01 : 0x02;
47
- } else {
48
- if (eModelType == AX_ENGINE_MODEL_TYPE1) {
49
- if (nNpuType & AX_BL_VNPU_2) return -1;
50
- if (nNpuType & AX_BL_VNPU_1) nNpuSet |= 0x01;
51
- } else {
52
- if (nNpuType & AX_BL_VNPU_1) nNpuSet |= 0x01;
53
- if (nNpuType & AX_BL_VNPU_2) nNpuSet |= 0x02;
54
- }
55
- }
56
- }
57
- }
58
- return ret;
59
- }
60
-
61
- EngineWrapper::EngineWrapper()
62
- : m_hasInit(false), m_handle(nullptr), m_io_info(nullptr),
63
- m_input_num(0), m_output_num(0) {
64
- memset(&m_io, 0, sizeof(m_io));
65
- }
66
-
67
- EngineWrapper::~EngineWrapper() {
68
- Release();
69
- }
70
-
71
- int EngineWrapper::Init(const char* strModelPath, uint32_t nNpuType, const char* axclConfig) {
72
- (void)axclConfig; // unused on AXERA
73
- // 1. Load model
74
- AX_BOOL bLoadModelUseCmm = AX_TRUE;
75
- AX_CHAR *pModelBufferVirAddr = nullptr;
76
- AX_U64 u64ModelBufferPhyAddr = 0;
77
- AX_U32 nModelBufferSize = 0;
78
-
79
- if (bLoadModelUseCmm) {
80
- if (!utils::read_file(strModelPath, (AX_VOID **)&pModelBufferVirAddr,
81
- u64ModelBufferPhyAddr, nModelBufferSize)) {
82
- printf("Read model(%s) fail\n", strModelPath);
83
- return -1;
84
- }
85
- } else {
86
- std::vector<char> model_buffer;
87
- if (!utils::read_file(strModelPath, model_buffer)) {
88
- printf("Read model(%s) fail\n", strModelPath);
89
- return -1;
90
- }
91
- pModelBufferVirAddr = model_buffer.data();
92
- nModelBufferSize = model_buffer.size();
93
- }
94
-
95
- auto freeModelBuffer = [&]() {
96
- if (bLoadModelUseCmm) {
97
- if (u64ModelBufferPhyAddr != 0)
98
- AX_SYS_MemFree(u64ModelBufferPhyAddr, &pModelBufferVirAddr);
99
- }
100
- };
101
-
102
- // 1.1 Get Model Type
103
- AX_ENGINE_MODEL_TYPE_T eModelType = AX_ENGINE_MODEL_TYPE0;
104
- AX_S32 ret = AX_ENGINE_GetModelType(pModelBufferVirAddr, nModelBufferSize, &eModelType);
105
- if (0 != ret || eModelType >= AX_ENGINE_MODEL_TYPE_BUTT) {
106
- printf("%s AX_ENGINE_GetModelType fail ret=%x\n", strModelPath, ret);
107
- freeModelBuffer();
108
- return -1;
109
- }
110
-
111
- // 1.2 Check VNPU
112
- AX_U32 nNpuSet = 0;
113
- ret = CheckModelVNpu(strModelPath, eModelType, nNpuType, nNpuSet);
114
- if (0 != ret) {
115
- printf("CheckModelVNpu fail\n");
116
- freeModelBuffer();
117
- return -1;
118
- }
119
-
120
- // 2. Create handle
121
- AX_ENGINE_HANDLE handle = nullptr;
122
- ret = AX_ENGINE_CreateHandle(&handle, pModelBufferVirAddr, nModelBufferSize);
123
- freeModelBuffer();
124
-
125
- auto deinit_handle = [&handle]() {
126
- if (handle) { AX_ENGINE_DestroyHandle(handle); }
127
- return -1;
128
- };
129
-
130
- if (0 != ret || !handle) {
131
- printf("Create model(%s) handle fail\n", strModelPath);
132
- return deinit_handle();
133
- }
134
-
135
- // 3. Create context
136
- ret = AX_ENGINE_CreateContext(handle);
137
- if (0 != ret) return deinit_handle();
138
-
139
- // 4. Get IO info
140
- m_io_info = nullptr;
141
- ret = AX_ENGINE_GetIOInfo(handle, &m_io_info);
142
- if (0 != ret) return deinit_handle();
143
-
144
- m_input_num = m_io_info->nInputSize;
145
- m_output_num = m_io_info->nOutputSize;
146
-
147
- // Build name-to-index maps
148
- m_input_name_to_idx.clear();
149
- for (int i = 0; i < m_input_num; ++i) {
150
- m_input_name_to_idx[std::string(m_io_info->pInputs[i].pName)] = i;
151
- }
152
- m_output_name_to_idx.clear();
153
- for (int i = 0; i < m_output_num; ++i) {
154
- m_output_name_to_idx[std::string(m_io_info->pOutputs[i].pName)] = i;
155
- }
156
-
157
- // 5. Prepare IO buffers
158
- ret = utils::prepare_io("enc", m_io_info, m_io, utils::IO_BUFFER_STRATEGY_DEFAULT);
159
- if (0 != ret) {
160
- printf("prepare io failed!\n");
161
- utils::free_io(m_io);
162
- return deinit_handle();
163
- }
164
-
165
- m_handle = handle;
166
- m_hasInit = true;
167
- return 0;
168
- }
169
-
170
- int EngineWrapper::SetInput(void* pInput, int index) {
171
- if (!m_hasInit || index < 0 || index >= m_input_num) return -1;
172
- return utils::push_io_input(pInput, index, m_io);
173
- }
174
-
175
- int EngineWrapper::RunSync() {
176
- if (!m_hasInit) return -1;
177
- auto ret = AX_ENGINE_RunSync(m_handle, &m_io);
178
- if (0 != ret) {
179
- printf("AX_ENGINE_RunSync failed. ret=0x%x\n", ret);
180
- }
181
- return ret;
182
- }
183
-
184
- int EngineWrapper::GetOutput(void* pOutput, int index) {
185
- if (!m_hasInit || index < 0 || index >= m_output_num) return -1;
186
- return utils::push_io_output(pOutput, index, m_io);
187
- }
188
-
189
- int EngineWrapper::SetInputByName(const char* name, void* pInput) {
190
- auto it = m_input_name_to_idx.find(std::string(name));
191
- if (it == m_input_name_to_idx.end()) {
192
- printf("Input '%s' not found in model\n", name);
193
- return -1;
194
- }
195
- return SetInput(pInput, it->second);
196
- }
197
-
198
- int EngineWrapper::GetOutputByName(const char* name, void* pOutput) {
199
- auto it = m_output_name_to_idx.find(std::string(name));
200
- if (it == m_output_name_to_idx.end()) {
201
- printf("Output '%s' not found in model\n", name);
202
- return -1;
203
- }
204
- return GetOutput(pOutput, it->second);
205
- }
206
-
207
- int EngineWrapper::GetInputSize(int index) {
208
- if (index < 0 || index >= m_input_num) return -1;
209
- return m_io.pInputs[index].nSize;
210
- }
211
-
212
- int EngineWrapper::GetOutputSize(int index) {
213
- if (index < 0 || index >= m_output_num) return -1;
214
- return m_io.pOutputs[index].nSize;
215
- }
216
-
217
- int EngineWrapper::GetInputSizeByName(const char* name) {
218
- int idx = GetInputIndex(name);
219
- if (idx < 0) return -1;
220
- return GetInputSize(idx);
221
- }
222
-
223
- int EngineWrapper::GetOutputSizeByName(const char* name) {
224
- int idx = GetOutputIndex(name);
225
- if (idx < 0) return -1;
226
- return GetOutputSize(idx);
227
- }
228
-
229
- int EngineWrapper::GetInputIndex(const char* name) {
230
- auto it = m_input_name_to_idx.find(std::string(name));
231
- return (it != m_input_name_to_idx.end()) ? it->second : -1;
232
- }
233
-
234
- int EngineWrapper::GetOutputIndex(const char* name) {
235
- auto it = m_output_name_to_idx.find(std::string(name));
236
- return (it != m_output_name_to_idx.end()) ? it->second : -1;
237
- }
238
-
239
- const char* EngineWrapper::GetInputName(int index) const {
240
- if (index < 0 || index >= m_input_num) return nullptr;
241
- return m_io_info->pInputs[index].pName;
242
- }
243
-
244
- const char* EngineWrapper::GetOutputName(int index) const {
245
- if (index < 0 || index >= m_output_num) return nullptr;
246
- return m_io_info->pOutputs[index].pName;
247
- }
248
-
249
- static const char* dtype_str(AX_ENGINE_DATA_TYPE_T t) {
250
- switch (t) {
251
- case AX_ENGINE_DT_FLOAT32: return "float32";
252
- case AX_ENGINE_DT_FLOAT64: return "float64";
253
- case AX_ENGINE_DT_SINT8: return "sint8";
254
- case AX_ENGINE_DT_UINT8: return "uint8";
255
- case AX_ENGINE_DT_SINT16: return "sint16";
256
- case AX_ENGINE_DT_UINT16: return "uint16";
257
- case AX_ENGINE_DT_SINT32: return "sint32";
258
- case AX_ENGINE_DT_UINT32: return "uint32";
259
- default: return "unknown";
260
- }
261
- }
262
-
263
- const char* EngineWrapper::GetInputDtypeStr(int index) const {
264
- if (index < 0 || index >= m_input_num) return "?";
265
- return dtype_str(m_io_info->pInputs[index].eDataType);
266
- }
267
-
268
- const char* EngineWrapper::GetOutputDtypeStr(int index) const {
269
- if (index < 0 || index >= m_output_num) return "?";
270
- return dtype_str(m_io_info->pOutputs[index].eDataType);
271
- }
272
-
273
- int EngineWrapper::Release() {
274
- if (m_handle) {
275
- utils::free_io(m_io);
276
- AX_ENGINE_DestroyHandle(m_handle);
277
- m_handle = nullptr;
278
- }
279
- m_hasInit = false;
280
- m_input_name_to_idx.clear();
281
- m_output_name_to_idx.clear();
282
- return 0;
283
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/cmdline.hpp DELETED
@@ -1,732 +0,0 @@
1
- /*
2
- Copyright (c) 2009, Hideyuki Tanaka
3
- All rights reserved.
4
-
5
- Redistribution and use in source and binary forms, with or without
6
- modification, are permitted provided that the following conditions are met:
7
- * Redistributions of source code must retain the above copyright
8
- notice, this list of conditions and the following disclaimer.
9
- * Redistributions in binary form must reproduce the above copyright
10
- notice, this list of conditions and the following disclaimer in the
11
- documentation and/or other materials provided with the distribution.
12
- * Neither the name of the <organization> nor the
13
- names of its contributors may be used to endorse or promote products
14
- derived from this software without specific prior written permission.
15
-
16
- THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
17
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
- DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
20
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
- */
27
-
28
- #pragma once
29
-
30
- #include <cxxabi.h>
31
-
32
- #include <algorithm>
33
- #include <cstdlib>
34
- #include <cstring>
35
- #include <iostream>
36
- #include <map>
37
- #include <sstream>
38
- #include <stdexcept>
39
- #include <string>
40
- #include <typeinfo>
41
- #include <vector>
42
-
43
- namespace cmdline {
44
-
45
- namespace detail {
46
-
47
- template <typename Target, typename Source, bool Same>
48
- class lexical_cast_t {
49
- public:
50
- static Target cast(const Source &arg) {
51
- Target ret;
52
- std::stringstream ss;
53
- if (!(ss << arg && ss >> ret && ss.eof())) throw std::bad_cast();
54
-
55
- return ret;
56
- }
57
- };
58
-
59
- template <typename Target, typename Source>
60
- class lexical_cast_t<Target, Source, true> {
61
- public:
62
- static Target cast(const Source &arg) { return arg; }
63
- };
64
-
65
- template <typename Source>
66
- class lexical_cast_t<std::string, Source, false> {
67
- public:
68
- static std::string cast(const Source &arg) {
69
- std::ostringstream ss;
70
- ss << arg;
71
- return ss.str();
72
- }
73
- };
74
-
75
- template <typename Target>
76
- class lexical_cast_t<Target, std::string, false> {
77
- public:
78
- static Target cast(const std::string &arg) {
79
- Target ret;
80
- std::istringstream ss(arg);
81
- if (!(ss >> ret && ss.eof())) throw std::bad_cast();
82
- return ret;
83
- }
84
- };
85
-
86
- template <typename T1, typename T2>
87
- struct is_same {
88
- static const bool value = false;
89
- };
90
-
91
- template <typename T>
92
- struct is_same<T, T> {
93
- static const bool value = true;
94
- };
95
-
96
- template <typename Target, typename Source>
97
- Target lexical_cast(const Source &arg) {
98
- return lexical_cast_t<Target, Source,
99
- detail::is_same<Target, Source>::value>::cast(arg);
100
- }
101
-
102
- static inline std::string demangle(const std::string &name) {
103
- int status = 0;
104
- char *p = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
105
- std::string ret(p);
106
- free(p);
107
- return ret;
108
- }
109
-
110
- template <class T>
111
- std::string readable_typename() {
112
- return demangle(typeid(T).name());
113
- }
114
-
115
- template <class T>
116
- std::string default_value(T def) {
117
- return detail::lexical_cast<std::string>(def);
118
- }
119
-
120
- template <>
121
- inline std::string readable_typename<std::string>() {
122
- return "string";
123
- }
124
-
125
- } // namespace detail
126
-
127
- //-----
128
-
129
- class cmdline_error : public std::exception {
130
- public:
131
- cmdline_error(const std::string &msg) : msg(msg) {}
132
- ~cmdline_error() throw() {}
133
- const char *what() const throw() { return msg.c_str(); }
134
-
135
- private:
136
- std::string msg;
137
- };
138
-
139
- template <class T>
140
- struct default_reader {
141
- T operator()(const std::string &str) { return detail::lexical_cast<T>(str); }
142
- };
143
-
144
- template <class T>
145
- struct range_reader {
146
- range_reader(const T &low, const T &high) : low(low), high(high) {}
147
- T operator()(const std::string &s) const {
148
- T ret = default_reader<T>()(s);
149
- if (!(ret >= low && ret <= high))
150
- throw cmdline::cmdline_error("range_error");
151
- return ret;
152
- }
153
-
154
- private:
155
- T low, high;
156
- };
157
-
158
- template <class T>
159
- range_reader<T> range(const T &low, const T &high) {
160
- return range_reader<T>(low, high);
161
- }
162
-
163
- template <class T>
164
- struct oneof_reader {
165
- T operator()(const std::string &s) {
166
- T ret = default_reader<T>()(s);
167
- if (std::find(alt.begin(), alt.end(), ret) == alt.end())
168
- throw cmdline_error("");
169
- return ret;
170
- }
171
- void add(const T &v) { alt.push_back(v); }
172
-
173
- private:
174
- std::vector<T> alt;
175
- };
176
-
177
- template <class T>
178
- oneof_reader<T> oneof(T a1) {
179
- oneof_reader<T> ret;
180
- ret.add(a1);
181
- return ret;
182
- }
183
-
184
- template <class T>
185
- oneof_reader<T> oneof(T a1, T a2) {
186
- oneof_reader<T> ret;
187
- ret.add(a1);
188
- ret.add(a2);
189
- return ret;
190
- }
191
-
192
- template <class T>
193
- oneof_reader<T> oneof(T a1, T a2, T a3) {
194
- oneof_reader<T> ret;
195
- ret.add(a1);
196
- ret.add(a2);
197
- ret.add(a3);
198
- return ret;
199
- }
200
-
201
- template <class T>
202
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4) {
203
- oneof_reader<T> ret;
204
- ret.add(a1);
205
- ret.add(a2);
206
- ret.add(a3);
207
- ret.add(a4);
208
- return ret;
209
- }
210
-
211
- template <class T>
212
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5) {
213
- oneof_reader<T> ret;
214
- ret.add(a1);
215
- ret.add(a2);
216
- ret.add(a3);
217
- ret.add(a4);
218
- ret.add(a5);
219
- return ret;
220
- }
221
-
222
- template <class T>
223
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6) {
224
- oneof_reader<T> ret;
225
- ret.add(a1);
226
- ret.add(a2);
227
- ret.add(a3);
228
- ret.add(a4);
229
- ret.add(a5);
230
- ret.add(a6);
231
- return ret;
232
- }
233
-
234
- template <class T>
235
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7) {
236
- oneof_reader<T> ret;
237
- ret.add(a1);
238
- ret.add(a2);
239
- ret.add(a3);
240
- ret.add(a4);
241
- ret.add(a5);
242
- ret.add(a6);
243
- ret.add(a7);
244
- return ret;
245
- }
246
-
247
- template <class T>
248
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8) {
249
- oneof_reader<T> ret;
250
- ret.add(a1);
251
- ret.add(a2);
252
- ret.add(a3);
253
- ret.add(a4);
254
- ret.add(a5);
255
- ret.add(a6);
256
- ret.add(a7);
257
- ret.add(a8);
258
- return ret;
259
- }
260
-
261
- template <class T>
262
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9) {
263
- oneof_reader<T> ret;
264
- ret.add(a1);
265
- ret.add(a2);
266
- ret.add(a3);
267
- ret.add(a4);
268
- ret.add(a5);
269
- ret.add(a6);
270
- ret.add(a7);
271
- ret.add(a8);
272
- ret.add(a9);
273
- return ret;
274
- }
275
-
276
- template <class T>
277
- oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9,
278
- T a10) {
279
- oneof_reader<T> ret;
280
- ret.add(a1);
281
- ret.add(a2);
282
- ret.add(a3);
283
- ret.add(a4);
284
- ret.add(a5);
285
- ret.add(a6);
286
- ret.add(a7);
287
- ret.add(a8);
288
- ret.add(a9);
289
- ret.add(a10);
290
- return ret;
291
- }
292
-
293
- //-----
294
-
295
- class parser {
296
- public:
297
- parser() {}
298
- ~parser() {
299
- for (std::map<std::string, option_base *>::iterator p = options.begin();
300
- p != options.end(); p++)
301
- delete p->second;
302
- }
303
-
304
- void add(const std::string &name, char short_name = 0,
305
- const std::string &desc = "") {
306
- if (options.count(name))
307
- throw cmdline_error("multiple definition: " + name);
308
- options[name] = new option_without_value(name, short_name, desc);
309
- ordered.push_back(options[name]);
310
- }
311
-
312
- template <class T>
313
- void add(const std::string &name, char short_name = 0,
314
- const std::string &desc = "", bool need = true, const T def = T()) {
315
- add(name, short_name, desc, need, def, default_reader<T>());
316
- }
317
-
318
- template <class T, class F>
319
- void add(const std::string &name, char short_name = 0,
320
- const std::string &desc = "", bool need = true, const T def = T(),
321
- F reader = F()) {
322
- if (options.count(name))
323
- throw cmdline_error("multiple definition: " + name);
324
- options[name] = new option_with_value_with_reader<T, F>(
325
- name, short_name, need, def, desc, reader);
326
- ordered.push_back(options[name]);
327
- }
328
-
329
- void footer(const std::string &f) { ftr = f; }
330
-
331
- void set_program_name(const std::string &name) { prog_name = name; }
332
-
333
- bool exist(const std::string &name) const {
334
- if (options.count(name) == 0)
335
- throw cmdline_error("there is no flag: --" + name);
336
- return options.find(name)->second->has_set();
337
- }
338
-
339
- template <class T>
340
- const T &get(const std::string &name) const {
341
- if (options.count(name) == 0)
342
- throw cmdline_error("there is no flag: --" + name);
343
- const option_with_value<T> *p =
344
- dynamic_cast<const option_with_value<T> *>(options.find(name)->second);
345
- if (p == NULL) throw cmdline_error("type mismatch flag '" + name + "'");
346
- return p->get();
347
- }
348
-
349
- const std::vector<std::string> &rest() const { return others; }
350
-
351
- bool parse(const std::string &arg) {
352
- std::vector<std::string> args;
353
-
354
- std::string buf;
355
- bool in_quote = false;
356
- for (std::string::size_type i = 0; i < arg.length(); i++) {
357
- if (arg[i] == '\"') {
358
- in_quote = !in_quote;
359
- continue;
360
- }
361
-
362
- if (arg[i] == ' ' && !in_quote) {
363
- args.push_back(buf);
364
- buf = "";
365
- continue;
366
- }
367
-
368
- if (arg[i] == '\\') {
369
- i++;
370
- if (i >= arg.length()) {
371
- errors.push_back("unexpected occurrence of '\\' at end of string");
372
- return false;
373
- }
374
- }
375
-
376
- buf += arg[i];
377
- }
378
-
379
- if (in_quote) {
380
- errors.push_back("quote is not closed");
381
- return false;
382
- }
383
-
384
- if (buf.length() > 0) args.push_back(buf);
385
-
386
- for (size_t i = 0; i < args.size(); i++)
387
- std::cout << "\"" << args[i] << "\"" << std::endl;
388
-
389
- return parse(args);
390
- }
391
-
392
- bool parse(const std::vector<std::string> &args) {
393
- int argc = static_cast<int>(args.size());
394
- std::vector<const char *> argv(argc);
395
-
396
- for (int i = 0; i < argc; i++) argv[i] = args[i].c_str();
397
-
398
- return parse(argc, &argv[0]);
399
- }
400
-
401
- bool parse(int argc, const char *const argv[]) {
402
- errors.clear();
403
- others.clear();
404
-
405
- if (argc < 1) {
406
- errors.push_back("argument number must be longer than 0");
407
- return false;
408
- }
409
- if (prog_name == "") prog_name = argv[0];
410
-
411
- std::map<char, std::string> lookup;
412
- for (std::map<std::string, option_base *>::iterator p = options.begin();
413
- p != options.end(); p++) {
414
- if (p->first.length() == 0) continue;
415
- char initial = p->second->short_name();
416
- if (initial) {
417
- if (lookup.count(initial) > 0) {
418
- lookup[initial] = "";
419
- errors.push_back(std::string("short option '") + initial +
420
- "' is ambiguous");
421
- return false;
422
- } else
423
- lookup[initial] = p->first;
424
- }
425
- }
426
-
427
- for (int i = 1; i < argc; i++) {
428
- if (strncmp(argv[i], "--", 2) == 0) {
429
- const char *p = strchr(argv[i] + 2, '=');
430
- if (p) {
431
- std::string name(argv[i] + 2, p);
432
- std::string val(p + 1);
433
- set_option(name, val);
434
- } else {
435
- std::string name(argv[i] + 2);
436
- if (options.count(name) == 0) {
437
- errors.push_back("undefined option: --" + name);
438
- continue;
439
- }
440
- if (options[name]->has_value()) {
441
- if (i + 1 >= argc) {
442
- errors.push_back("option needs value: --" + name);
443
- continue;
444
- } else {
445
- i++;
446
- set_option(name, argv[i]);
447
- }
448
- } else {
449
- set_option(name);
450
- }
451
- }
452
- } else if (strncmp(argv[i], "-", 1) == 0) {
453
- if (!argv[i][1]) continue;
454
- char last = argv[i][1];
455
- for (int j = 2; argv[i][j]; j++) {
456
- last = argv[i][j];
457
- if (lookup.count(argv[i][j - 1]) == 0) {
458
- errors.push_back(std::string("undefined short option: -") +
459
- argv[i][j - 1]);
460
- continue;
461
- }
462
- if (lookup[argv[i][j - 1]] == "") {
463
- errors.push_back(std::string("ambiguous short option: -") +
464
- argv[i][j - 1]);
465
- continue;
466
- }
467
- set_option(lookup[argv[i][j - 1]]);
468
- }
469
-
470
- if (lookup.count(last) == 0) {
471
- errors.push_back(std::string("undefined short option: -") + last);
472
- continue;
473
- }
474
- if (lookup[last] == "") {
475
- errors.push_back(std::string("ambiguous short option: -") + last);
476
- continue;
477
- }
478
-
479
- if (i + 1 < argc && options[lookup[last]]->has_value()) {
480
- set_option(lookup[last], argv[i + 1]);
481
- i++;
482
- } else {
483
- set_option(lookup[last]);
484
- }
485
- } else {
486
- others.push_back(argv[i]);
487
- }
488
- }
489
-
490
- for (std::map<std::string, option_base *>::iterator p = options.begin();
491
- p != options.end(); p++)
492
- if (!p->second->valid())
493
- errors.push_back("need option: --" + std::string(p->first));
494
-
495
- return errors.size() == 0;
496
- }
497
-
498
- void parse_check(const std::string &arg) {
499
- if (!options.count("help")) add("help", '?', "print this message");
500
- check(0, parse(arg));
501
- }
502
-
503
- void parse_check(const std::vector<std::string> &args) {
504
- if (!options.count("help")) add("help", '?', "print this message");
505
- check(args.size(), parse(args));
506
- }
507
-
508
- void parse_check(int argc, char *argv[]) {
509
- if (!options.count("help")) add("help", '?', "print this message");
510
- check(argc, parse(argc, argv));
511
- }
512
-
513
- std::string error() const { return errors.size() > 0 ? errors[0] : ""; }
514
-
515
- std::string error_full() const {
516
- std::ostringstream oss;
517
- for (size_t i = 0; i < errors.size(); i++) oss << errors[i] << std::endl;
518
- return oss.str();
519
- }
520
-
521
- std::string usage() const {
522
- std::ostringstream oss;
523
- oss << "usage: " << prog_name << " ";
524
- for (size_t i = 0; i < ordered.size(); i++) {
525
- if (ordered[i]->must()) oss << ordered[i]->short_description() << " ";
526
- }
527
-
528
- oss << "[options] ... " << ftr << std::endl;
529
- oss << "options:" << std::endl;
530
-
531
- size_t max_width = 0;
532
- for (size_t i = 0; i < ordered.size(); i++) {
533
- max_width = std::max(max_width, ordered[i]->name().length());
534
- }
535
- for (size_t i = 0; i < ordered.size(); i++) {
536
- if (ordered[i]->short_name()) {
537
- oss << " -" << ordered[i]->short_name() << ", ";
538
- } else {
539
- oss << " ";
540
- }
541
-
542
- oss << "--" << ordered[i]->name();
543
- for (size_t j = ordered[i]->name().length(); j < max_width + 4; j++)
544
- oss << ' ';
545
- oss << ordered[i]->description() << std::endl;
546
- }
547
- return oss.str();
548
- }
549
-
550
- private:
551
- void check(int argc, bool ok) {
552
- if ((argc == 1 && !ok) || exist("help")) {
553
- std::cerr << usage();
554
- exit(0);
555
- }
556
-
557
- if (!ok) {
558
- std::cerr << error() << std::endl << usage();
559
- exit(1);
560
- }
561
- }
562
-
563
- void set_option(const std::string &name) {
564
- if (options.count(name) == 0) {
565
- errors.push_back("undefined option: --" + name);
566
- return;
567
- }
568
- if (!options[name]->set()) {
569
- errors.push_back("option needs value: --" + name);
570
- return;
571
- }
572
- }
573
-
574
- void set_option(const std::string &name, const std::string &value) {
575
- if (options.count(name) == 0) {
576
- errors.push_back("undefined option: --" + name);
577
- return;
578
- }
579
- if (!options[name]->set(value)) {
580
- errors.push_back("option value is invalid: --" + name + "=" + value);
581
- return;
582
- }
583
- }
584
-
585
- class option_base {
586
- public:
587
- virtual ~option_base() {}
588
-
589
- virtual bool has_value() const = 0;
590
- virtual bool set() = 0;
591
- virtual bool set(const std::string &value) = 0;
592
- virtual bool has_set() const = 0;
593
- virtual bool valid() const = 0;
594
- virtual bool must() const = 0;
595
-
596
- virtual const std::string &name() const = 0;
597
- virtual char short_name() const = 0;
598
- virtual const std::string &description() const = 0;
599
- virtual std::string short_description() const = 0;
600
- };
601
-
602
- class option_without_value : public option_base {
603
- public:
604
- option_without_value(const std::string &name, char short_name,
605
- const std::string &desc)
606
- : nam(name), snam(short_name), desc(desc), has(false) {}
607
- ~option_without_value() {}
608
-
609
- bool has_value() const { return false; }
610
-
611
- bool set() {
612
- has = true;
613
- return true;
614
- }
615
-
616
- bool set(const std::string &) { return false; }
617
-
618
- bool has_set() const { return has; }
619
-
620
- bool valid() const { return true; }
621
-
622
- bool must() const { return false; }
623
-
624
- const std::string &name() const { return nam; }
625
-
626
- char short_name() const { return snam; }
627
-
628
- const std::string &description() const { return desc; }
629
-
630
- std::string short_description() const { return "--" + nam; }
631
-
632
- private:
633
- std::string nam;
634
- char snam;
635
- std::string desc;
636
- bool has;
637
- };
638
-
639
- template <class T>
640
- class option_with_value : public option_base {
641
- public:
642
- option_with_value(const std::string &name, char short_name, bool need,
643
- const T &def, const std::string &desc)
644
- : nam(name),
645
- snam(short_name),
646
- need(need),
647
- has(false),
648
- def(def),
649
- actual(def) {
650
- this->desc = full_description(desc);
651
- }
652
- ~option_with_value() {}
653
-
654
- const T &get() const { return actual; }
655
-
656
- bool has_value() const { return true; }
657
-
658
- bool set() { return false; }
659
-
660
- bool set(const std::string &value) {
661
- try {
662
- actual = read(value);
663
- has = true;
664
- } catch (const std::exception &e) {
665
- return false;
666
- }
667
- return true;
668
- }
669
-
670
- bool has_set() const { return has; }
671
-
672
- bool valid() const {
673
- if (need && !has) return false;
674
- return true;
675
- }
676
-
677
- bool must() const { return need; }
678
-
679
- const std::string &name() const { return nam; }
680
-
681
- char short_name() const { return snam; }
682
-
683
- const std::string &description() const { return desc; }
684
-
685
- std::string short_description() const {
686
- return "--" + nam + "=" + detail::readable_typename<T>();
687
- }
688
-
689
- protected:
690
- std::string full_description(const std::string &desc) {
691
- return desc + " (" + detail::readable_typename<T>() +
692
- (need ? "" : " [=" + detail::default_value<T>(def) + "]") + ")";
693
- }
694
-
695
- virtual T read(const std::string &s) = 0;
696
-
697
- std::string nam;
698
- char snam;
699
- bool need;
700
- std::string desc;
701
-
702
- bool has;
703
- T def;
704
- T actual;
705
- };
706
-
707
- template <class T, class F>
708
- class option_with_value_with_reader : public option_with_value<T> {
709
- public:
710
- option_with_value_with_reader(const std::string &name, char short_name,
711
- bool need, const T def,
712
- const std::string &desc, F reader)
713
- : option_with_value<T>(name, short_name, need, def, desc),
714
- reader(reader) {}
715
-
716
- private:
717
- T read(const std::string &s) { return reader(s); }
718
-
719
- F reader;
720
- };
721
-
722
- std::map<std::string, option_base *> options;
723
- std::vector<option_base *> ordered;
724
- std::string ftr;
725
-
726
- std::string prog_name;
727
- std::vector<std::string> others;
728
-
729
- std::vector<std::string> errors;
730
- };
731
-
732
- } // namespace cmdline
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/fbank.cpp DELETED
@@ -1,219 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * FBANK implementation with simple DFT-based STFT.
5
- * For production, use FFTW or an NPU-accelerated implementation.
6
- **************************************************************************************************/
7
-
8
- #include "fbank.hpp"
9
-
10
- #include <algorithm>
11
- #include <cstring>
12
- #include <cstdio>
13
-
14
- #ifndef M_PI
15
- #define M_PI 3.14159265358979323846
16
- #endif
17
-
18
- static float hz_to_mel(float freq) {
19
- return 2595.0f * std::log10(1.0f + freq / 700.0f);
20
- }
21
-
22
- static float mel_to_hz(float mel) {
23
- return 700.0f * (std::pow(10.0f, mel / 2595.0f) - 1.0f);
24
- }
25
-
26
- MelFilterBank::MelFilterBank() : m_n_freqs(0) {}
27
-
28
- int MelFilterBank::Init(const Config& config) {
29
- m_config = config;
30
- m_n_freqs = config.n_fft / 2 + 1;
31
-
32
- CreateWindow();
33
- CreateMelFilterbank();
34
-
35
- printf("FBANK init: n_mels=%d, n_fft=%d, hop=%d, sr=%d\n",
36
- config.n_mels, config.n_fft, config.hop_length, config.sampling_rate);
37
- return 0;
38
- }
39
-
40
- void MelFilterBank::CreateWindow() {
41
- m_window.resize(m_config.n_fft);
42
- for (int i = 0; i < m_config.n_fft; ++i) {
43
- m_window[i] = 0.5f * (1.0f - std::cos(2.0f * M_PI * i / (m_config.n_fft - 1)));
44
- }
45
- }
46
-
47
- void MelFilterBank::CreateMelFilterbank() {
48
- int n_freqs = m_n_freqs;
49
- int n_mels = m_config.n_mels;
50
-
51
- // Frequency points for each FFT bin
52
- std::vector<float> all_freqs(n_freqs);
53
- for (int i = 0; i < n_freqs; ++i) {
54
- all_freqs[i] = i * m_config.sampling_rate / (2.0f * (n_freqs - 1));
55
- }
56
-
57
- // Mel points
58
- float m_min = hz_to_mel(0.0f);
59
- float m_max = hz_to_mel(m_config.sampling_rate / 2.0f);
60
- std::vector<float> m_pts(n_mels + 2);
61
- for (int i = 0; i < n_mels + 2; ++i) {
62
- m_pts[i] = m_min + (m_max - m_min) * i / (n_mels + 1);
63
- }
64
-
65
- // Convert to Hz
66
- std::vector<float> f_pts(n_mels + 2);
67
- for (int i = 0; i < n_mels + 2; ++i) {
68
- f_pts[i] = mel_to_hz(m_pts[i]);
69
- }
70
-
71
- // Build filterbank matrix [n_freqs, n_mels]
72
- m_mel_basis.resize(n_freqs * n_mels, 0.0f);
73
-
74
- for (int m = 0; m < n_mels; ++m) {
75
- for (int k = 0; k < n_freqs; ++k) {
76
- float freq = all_freqs[k];
77
- float left = f_pts[m];
78
- float center = f_pts[m + 1];
79
- float right = f_pts[m + 2];
80
-
81
- float val = 0.0f;
82
- if (freq >= left && freq <= center) {
83
- val = (freq - left) / (center - left);
84
- } else if (freq >= center && freq <= right) {
85
- val = (right - freq) / (right - center);
86
- }
87
- m_mel_basis[k * n_mels + m] = val;
88
- }
89
- }
90
- }
91
-
92
- int MelFilterBank::ComputeNumFrames(int num_samples, int hop_length) {
93
- return (num_samples + hop_length / 2) / hop_length;
94
- }
95
-
96
- // Radix-2 FFT (in-place, complex)
97
- static void fft(std::vector<float>& real, std::vector<float>& imag, bool inverse = false) {
98
- int n = (int)real.size();
99
- // Bit-reversal permutation
100
- for (int i = 1, j = 0; i < n; ++i) {
101
- int bit = n >> 1;
102
- for (; j & bit; bit >>= 1) j ^= bit;
103
- j ^= bit;
104
- if (i < j) {
105
- std::swap(real[i], real[j]);
106
- std::swap(imag[i], imag[j]);
107
- }
108
- }
109
- // Butterfly
110
- for (int len = 2; len <= n; len <<= 1) {
111
- float angle = 2.0f * M_PI / len * (inverse ? 1.0f : -1.0f);
112
- float w_real = std::cos(angle);
113
- float w_imag = std::sin(angle);
114
- for (int i = 0; i < n; i += len) {
115
- float cur_real = 1.0f, cur_imag = 0.0f;
116
- for (int j = 0; j < len / 2; ++j) {
117
- int a = i + j;
118
- int b = i + j + len / 2;
119
- float t_real = cur_real * real[b] - cur_imag * imag[b];
120
- float t_imag = cur_real * imag[b] + cur_imag * real[b];
121
- real[b] = real[a] - t_real;
122
- imag[b] = imag[a] - t_imag;
123
- real[a] += t_real;
124
- imag[a] += t_imag;
125
- float next_real = cur_real * w_real - cur_imag * w_imag;
126
- cur_imag = cur_real * w_imag + cur_imag * w_real;
127
- cur_real = next_real;
128
- }
129
- }
130
- }
131
- if (inverse) {
132
- for (int i = 0; i < n; ++i) {
133
- real[i] /= n;
134
- imag[i] /= n;
135
- }
136
- }
137
- }
138
-
139
- void MelFilterBank::ComputeSTFT(const std::vector<float>& samples,
140
- std::vector<float>& spec_real,
141
- std::vector<float>& spec_imag,
142
- int& num_frames) {
143
- int n_fft = m_config.n_fft;
144
- int hop = m_config.hop_length;
145
- int num_samples = static_cast<int>(samples.size());
146
-
147
- num_frames = ComputeNumFrames(num_samples, hop);
148
- int n_freqs = n_fft / 2 + 1;
149
-
150
- spec_real.assign(num_frames * n_freqs, 0.0f);
151
- spec_imag.assign(num_frames * n_freqs, 0.0f);
152
-
153
- // Pad signal (center padding, matching Python torch.stft center=True)
154
- int pad_amount = n_fft / 2;
155
- std::vector<float> padded(pad_amount + num_samples + pad_amount, 0.0f);
156
- std::copy(samples.begin(), samples.end(), padded.begin() + pad_amount);
157
-
158
- // FFT workspace
159
- std::vector<float> fft_real(n_fft), fft_imag(n_fft);
160
-
161
- for (int frame = 0; frame < num_frames; ++frame) {
162
- int start = frame * hop;
163
- // Apply window and copy to FFT buffer
164
- for (int n = 0; n < n_fft; ++n) {
165
- fft_real[n] = padded[start + n] * m_window[n];
166
- fft_imag[n] = 0.0f;
167
- }
168
- // Forward FFT
169
- fft(fft_real, fft_imag, false);
170
- // Extract first n_freqs bins
171
- for (int k = 0; k < n_freqs; ++k) {
172
- spec_real[frame * n_freqs + k] = fft_real[k];
173
- spec_imag[frame * n_freqs + k] = fft_imag[k];
174
- }
175
- }
176
- }
177
-
178
- std::vector<float> MelFilterBank::Extract(const std::vector<float>& samples, int sample_rate) {
179
- if (sample_rate != m_config.sampling_rate) {
180
- printf("WARNING: sample_rate mismatch: expected %d, got %d\n",
181
- m_config.sampling_rate, sample_rate);
182
- }
183
-
184
- int num_frames;
185
- std::vector<float> spec_real, spec_imag;
186
- ComputeSTFT(samples, spec_real, spec_imag, num_frames);
187
-
188
- int n_freqs = m_n_freqs;
189
- int n_mels = m_config.n_mels;
190
-
191
- // Compute magnitude spectrogram [num_frames, n_freqs]
192
- std::vector<float> spec_mag(num_frames * n_freqs);
193
- for (int i = 0; i < num_frames * n_freqs; ++i) {
194
- spec_mag[i] = std::sqrt(spec_real[i] * spec_real[i] + spec_imag[i] * spec_imag[i]);
195
- }
196
-
197
- // Apply mel filterbank: mel[frame, m] = sum_freq(spec[frame, freq] * basis[freq, m])
198
- std::vector<float> mel(num_frames * n_mels, 0.0f);
199
- for (int f = 0; f < num_frames; ++f) {
200
- for (int m = 0; m < n_mels; ++m) {
201
- float sum = 0.0f;
202
- for (int k = 0; k < n_freqs; ++k) {
203
- sum += spec_mag[f * n_freqs + k] * m_mel_basis[k * n_mels + m];
204
- }
205
- mel[f * n_mels + m] = std::log(std::max(sum, 1e-7f));
206
- }
207
- }
208
-
209
- // Expected num_frames
210
- int expected_frames = ComputeNumFrames(static_cast<int>(samples.size()), m_config.hop_length);
211
- if (num_frames > expected_frames) {
212
- // Truncate
213
- std::vector<float> truncated(expected_frames * n_mels);
214
- std::copy(mel.begin(), mel.begin() + expected_frames * n_mels, truncated.begin());
215
- return truncated;
216
- }
217
-
218
- return mel;
219
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/fbank.hpp DELETED
@@ -1,65 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * FBANK: Mel filterbank feature extraction for prompt audio.
5
- *
6
- * Extracts log-mel spectrogram features from audio waveform, matching the
7
- * Python LocalVocosFbank behavior.
8
- **************************************************************************************************/
9
-
10
- #pragma once
11
-
12
- #include <vector>
13
- #include <cmath>
14
- #include <cstdint>
15
-
16
- class MelFilterBank {
17
- public:
18
- struct Config {
19
- int sampling_rate;
20
- int n_mels;
21
- int n_fft;
22
- int hop_length;
23
-
24
- Config() : sampling_rate(24000), n_mels(100), n_fft(1024), hop_length(256) {}
25
- };
26
-
27
- MelFilterBank();
28
-
29
- /**
30
- * Initialize the filterbank with given config.
31
- */
32
- int Init(const Config& config = Config());
33
-
34
- /**
35
- * Extract log-mel features from float32 audio samples [num_samples].
36
- * Returns features of shape [num_frames, n_mels].
37
- */
38
- std::vector<float> Extract(const std::vector<float>& samples, int sample_rate);
39
-
40
- /**
41
- * Get the number of frames for given number of samples.
42
- */
43
- static int ComputeNumFrames(int num_samples, int hop_length);
44
-
45
- const Config& GetConfig() const { return m_config; }
46
-
47
- private:
48
- Config m_config;
49
-
50
- // Mel filterbank matrix [n_freqs, n_mels]
51
- std::vector<float> m_mel_basis;
52
- int m_n_freqs;
53
-
54
- // Hann window
55
- std::vector<float> m_window;
56
-
57
- void CreateMelFilterbank();
58
- void CreateWindow();
59
-
60
- // Simple STFT
61
- void ComputeSTFT(const std::vector<float>& samples,
62
- std::vector<float>& spec_real,
63
- std::vector<float>& spec_imag,
64
- int& num_frames);
65
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/ax_npu_runner.cc DELETED
@@ -1,131 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #include "middleware/ax_npu_runner_impl.hpp"
12
-
13
- #if defined(ENV_AX_LOCAL_API_ENABLE)
14
- middleware::npu_runner::npu_runner() {
15
- this->impl_ = new impl();
16
- }
17
-
18
- middleware::npu_runner::~npu_runner() {
19
- delete this->impl_;
20
- }
21
-
22
- bool middleware::npu_runner::init(const std::string& config_file, const uint32_t& index, const uint32_t& kind) {
23
- std::ignore = config_file;
24
- std::ignore = index;
25
- return this->impl_->init(kind);
26
- }
27
-
28
- bool middleware::npu_runner::final() {
29
- return this->impl_->final();
30
- }
31
-
32
- bool middleware::npu_runner::load(const std::string& model_path) {
33
- return this->impl_->load(model_path);
34
- }
35
-
36
- bool middleware::npu_runner::prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
37
- return this->impl_->prepare(input_cached, output_cached, group, batch);
38
- }
39
-
40
- bool middleware::npu_runner::run(const bool& parallel) {
41
- return this->impl_->run(parallel);
42
- }
43
-
44
- uint32_t middleware::npu_runner::get_input_count() const {
45
- return this->impl_->get_input_count();
46
- }
47
-
48
- uint32_t middleware::npu_runner::get_output_count() const {
49
- return this->impl_->get_output_count();
50
- }
51
-
52
- std::string middleware::npu_runner::get_input_name(const uint32_t& index) const {
53
- return this->impl_->get_input_name(index);
54
- }
55
-
56
- std::string middleware::npu_runner::get_output_name(const uint32_t& index) const {
57
- return this->impl_->get_output_name(index);
58
- }
59
-
60
- void *middleware::npu_runner::get_input_pointer(const uint32_t& index) const {
61
- return this->impl_->get_input_pointer(index);
62
- }
63
-
64
- void *middleware::npu_runner::get_output_pointer(const uint32_t& index) const {
65
- return this->impl_->get_output_pointer(index);
66
- }
67
-
68
- uintmax_t middleware::npu_runner::get_input_size(const uint32_t& index) const {
69
- return this->impl_->get_input_size(index);
70
- }
71
-
72
- uintmax_t middleware::npu_runner::get_output_size(const uint32_t& index) const {
73
- return this->impl_->get_output_size(index);
74
- }
75
-
76
- uintmax_t middleware::npu_runner::get_shape_group_count() const {
77
- return this->impl_->get_shape_group_count();
78
- }
79
-
80
- bool middleware::npu_runner::flush_input() const {
81
- return this->impl_->flush_input();
82
- }
83
-
84
- bool middleware::npu_runner::invalidate_output() const {
85
- return this->impl_->invalidate_output();
86
- }
87
-
88
- bool middleware::npu_runner::feed(const std::string& input_folder, const std::string& stimulus_name) const {
89
- return this->impl_->feed(input_folder, stimulus_name);
90
- }
91
-
92
- bool middleware::npu_runner::verify(const std::string& output_folder, const std::string& stimulus_name) const {
93
- return this->impl_->verify(output_folder, stimulus_name);
94
- }
95
-
96
- bool middleware::npu_runner::save(const std::string& output_folder, const std::string& stimulus_name) const {
97
- return this->impl_->save(output_folder, stimulus_name);
98
- }
99
-
100
- std::string middleware::npu_runner::get_library_version() const {
101
- return this->impl_->get_library_version();
102
- }
103
-
104
- std::string middleware::npu_runner::get_model_version() const {
105
- return this->impl_->get_model_version();
106
- }
107
-
108
- int32_t middleware::npu_runner::get_model_type() const {
109
- return this->impl_->get_model_type();
110
- }
111
-
112
- int32_t middleware::npu_runner::get_npu_type() const {
113
- return this->impl_->get_npu_type();
114
- }
115
-
116
- int32_t middleware::npu_runner::get_batch_size() const {
117
- return this->impl_->get_batch_size();
118
- }
119
-
120
- intmax_t middleware::npu_runner::get_sys_usage() const {
121
- return this->impl_->get_sys_usage();
122
- }
123
-
124
- intmax_t middleware::npu_runner::get_cmm_usage() const {
125
- return this->impl_->get_cmm_usage();
126
- }
127
-
128
- void middleware::npu_runner::sleep_for(const uint32_t sleep_duration) const {
129
- impl::sleep_for(sleep_duration);
130
- }
131
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/ax_npu_runner.hpp DELETED
@@ -1,65 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #if defined(ENV_AX_LOCAL_API_ENABLE)
14
- #include "middleware/runner.hpp"
15
-
16
- namespace middleware {
17
-
18
- class npu_runner final : public runner {
19
- public:
20
- npu_runner();
21
- ~npu_runner() override;
22
-
23
- [[nodiscard]] bool init(const std::string& config_file, const uint32_t& index, const uint32_t& kind) override;
24
- [[nodiscard]] bool final() override;
25
-
26
- [[nodiscard]] bool load(const std::string& model_path) override;
27
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) override;
28
-
29
- [[nodiscard]] bool run(const bool& parallel) override;
30
-
31
- [[nodiscard]] uint32_t get_input_count() const override;
32
- [[nodiscard]] uint32_t get_output_count() const override;
33
- [[nodiscard]] std::string get_input_name(const uint32_t& index) const override;
34
- [[nodiscard]] std::string get_output_name(const uint32_t& index) const override;
35
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) const override;
36
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) const override;
37
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) const override;
38
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) const override;
39
- [[nodiscard]] uintmax_t get_shape_group_count() const override;
40
-
41
- [[nodiscard]] bool flush_input() const override;
42
- [[nodiscard]] bool invalidate_output() const override;
43
-
44
- [[nodiscard]] bool feed(const std::string& input_folder, const std::string& stimulus_name) const override;
45
- [[nodiscard]] bool verify(const std::string& output_folder, const std::string& stimulus_name) const override;
46
- [[nodiscard]] bool save(const std::string& output_folder, const std::string& stimulus_name) const override;
47
-
48
- [[nodiscard]] std::string get_library_version() const override;
49
- [[nodiscard]] std::string get_model_version() const override;
50
-
51
- [[nodiscard]] int32_t get_model_type() const override;
52
- [[nodiscard]] int32_t get_npu_type() const override;
53
- [[nodiscard]] int32_t get_batch_size() const override;
54
- [[nodiscard]] intmax_t get_sys_usage() const override;
55
- [[nodiscard]] intmax_t get_cmm_usage() const override;
56
-
57
- void sleep_for(uint32_t sleep_duration) const override;
58
-
59
- private:
60
- struct impl;
61
- impl *impl_;
62
- };
63
- #endif
64
-
65
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/ax_npu_runner_impl.hpp DELETED
@@ -1,640 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #if defined(ENV_AX_LOCAL_API_ENABLE)
14
- #include "middleware/ax_npu_runner.hpp"
15
-
16
- #include "utilities/scalar_guard.hpp"
17
- #include "utilities/file.hpp"
18
- #include "utilities/file_mapper.hpp"
19
- #include "utilities/log.hpp"
20
-
21
- #include <ax_hrtimer.h>
22
- #include <ax_sys_api.h>
23
- #include <ax_engine_api.h>
24
-
25
- #include <mutex>
26
-
27
- constexpr ::AX_U32 align_size = 128;
28
- constexpr ::AX_S8 token_name[] = "toolkit";
29
-
30
- struct middleware::npu_runner::impl {
31
- impl() = default;
32
-
33
- ~impl() {
34
- std::ignore = this->final();
35
- }
36
-
37
- [[nodiscard]] bool init(const uint32_t& kind) {
38
- std::lock_guard guard(this->mutex_);
39
-
40
- // 0. check the NPU kind
41
- if (kind >= ::AX_ENGINE_VIRTUAL_NPU_BUTT) {
42
- utilities::glog.print(utilities::log::type::error, "Specified NPU kind{%d} is out of range{total %d}.\n", kind, ::AX_ENGINE_VIRTUAL_NPU_BUTT);
43
- return false;
44
- }
45
-
46
- // 1. init ax system, using scalar_guard to ensure the finalization
47
- auto sys_guard = utilities::scalar_guard<::AX_S32>(
48
- ::AX_SYS_Init(),
49
- [](const ::AX_S32& state) {
50
- if (0 == state) {
51
- std::ignore = ::AX_SYS_Deinit();
52
- }
53
- });
54
-
55
- // 2. check the initialization result
56
- if (0 != sys_guard.get()) {
57
- utilities::glog.print(utilities::log::type::error, "AX SYS init failed{0x%08X}.\n", sys_guard.get());
58
- return false;
59
- }
60
- utilities::glog.print(utilities::log::type::info, "AX SYS inited.\n");
61
-
62
- // 3. init ax engine
63
- ::AX_ENGINE_NPU_ATTR_T attr{};
64
- attr.eHardMode = static_cast<::AX_ENGINE_NPU_MODE_T>(kind);
65
- if (const int ret = ::AX_ENGINE_Init(&attr); 0 != ret) {
66
- utilities::glog.print(utilities::log::type::error, "Init AX ENGINE as kind{%d} failed{0x%08X}.\n", kind, ret);
67
- return false;
68
- }
69
- utilities::glog.print(utilities::log::type::info, "AX ENGINE inited.\n");
70
-
71
- // 4. disable guard of env
72
- sys_guard.get() = -1;
73
-
74
- // 5. set the flag
75
- this->is_initialized_ = true;
76
- return true;
77
- }
78
-
79
- [[nodiscard]] bool final() {
80
- auto flag = true;
81
-
82
- std::lock_guard guard(this->mutex_);
83
-
84
- if (this->is_initialized_) {
85
- if (nullptr != this->handle_) {
86
- for (auto& input : inputs_) {
87
- if (0 != input.phyAddr) {
88
- flag &= 0 == ::AX_SYS_MemFree(input.phyAddr, input.pVirAddr);
89
- input.phyAddr = 0;
90
- }
91
- }
92
- for (auto& output : outputs_) {
93
- if (0 != output.phyAddr) {
94
- flag &= 0 == ::AX_SYS_MemFree(output.phyAddr, output.pVirAddr);
95
- output.phyAddr = 0;
96
- }
97
- }
98
-
99
- flag &= 0 == ::AX_ENGINE_DestroyHandle(this->handle_);
100
- }
101
-
102
- flag &= 0 == ::AX_ENGINE_Deinit();
103
- flag &= 0 == ::AX_SYS_Deinit();
104
- this->is_initialized_ = false;
105
- }
106
-
107
- return flag;
108
- }
109
-
110
- [[nodiscard]] bool load(const std::string& model_path) {
111
- std::lock_guard guard(this->mutex_);
112
-
113
- if (!this->is_initialized_) {
114
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
115
- return false;
116
- }
117
-
118
- if (nullptr != this->handle_) {
119
- utilities::glog.print(utilities::log::type::error, "Model is already loaded.\n");
120
- return false;
121
- }
122
-
123
- if (!utilities::exists(model_path)
124
- || !utilities::is_regular_file(model_path)
125
- || 0 == utilities::file_size(model_path)
126
- || utilities::error_size == utilities::file_size(model_path)) {
127
- utilities::glog.print(utilities::log::type::error, "Model file{%s} error, please check it.\n", model_path.c_str());
128
- return false;
129
- }
130
-
131
- const auto model_map = utilities::file_mapper(model_path);
132
- if (nullptr == model_map.get()) {
133
- utilities::glog.print(utilities::log::type::error, "Model file{%s} mapping failed.\n", model_path.c_str());
134
- return false;
135
- }
136
-
137
- const auto model_name = utilities::get_file_name(model_path);
138
- ::AX_ENGINE_HANDLE_EXTRA_T extra_param{};
139
- extra_param.pName = reinterpret_cast<::AX_S8*>(const_cast<char*>(model_name.c_str()));
140
- if (const auto ret = ::AX_ENGINE_CreateHandleV2(&this->handle_, model_map.get(), model_map.size(), &extra_param); 0 != ret) {
141
- utilities::glog.print(utilities::log::type::error, "Create model{%s} handle failed.\n", model_path.c_str());
142
- return false;
143
- }
144
-
145
- if (const auto ret = ::AX_ENGINE_CreateContextV2(this->handle_, &this->context_); 0 != ret) {
146
- utilities::glog.print(utilities::log::type::error, "Create model{%s} context failed.\n", model_path.c_str());
147
- return false;
148
- }
149
-
150
- return true;
151
- }
152
-
153
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
154
- std::lock_guard guard(this->mutex_);
155
-
156
- // 0. check the handle
157
- if (nullptr == this->handle_) {
158
- utilities::glog.print(utilities::log::type::error, "Model handle is null.\n");
159
- return false;
160
- }
161
-
162
- // 1. get the count of shape group
163
- if (const auto ret = ::AX_ENGINE_GetGroupIOInfoCount(this->handle_, &this->group_); 0 != ret) {
164
- utilities::glog.print(utilities::log::type::error, "Get model shape group count failed{0x%08X}.\n", ret);
165
- return false;
166
- }
167
-
168
- // 2. check the group index
169
- if (group >= this->group_) {
170
- utilities::glog.print(utilities::log::type::error, "Model group{%d} is out of range{total %d}.\n", group, this->group_);
171
- return false;
172
- }
173
-
174
- // 3. get the IO info
175
- if (1 == this->group_) {
176
- if (const auto ret = ::AX_ENGINE_GetIOInfo(this->handle_, &info_); 0 != ret) {
177
- utilities::glog.print(utilities::log::type::error, "Get model IO info failed{0x%08X}.\n", ret);
178
- return false;
179
- }
180
- } else {
181
- if (const auto ret = ::AX_ENGINE_GetGroupIOInfo(this->handle_, group, &info_); 0 != ret) {
182
- utilities::glog.print(utilities::log::type::error, "Get model group{index: %d} IO info failed{0x%08X}.\n", group, ret);
183
- return false;
184
- }
185
- }
186
-
187
- // 4. check the batch size
188
- this->batch = (0 == batch ? 1 : batch);
189
- this->io_.nBatchSize = this->batch;
190
-
191
- // 5. prepare the input and output
192
- this->inputs_.resize(this->info_->nInputSize, ::AX_ENGINE_IO_BUFFER_T{});
193
- this->io_.pInputs = this->inputs_.data();
194
- this->io_.nInputSize = this->info_->nInputSize;
195
-
196
- this->outputs_.resize(this->info_->nOutputSize, ::AX_ENGINE_IO_BUFFER_T{});
197
- this->io_.pOutputs = this->outputs_.data();
198
- this->io_.nOutputSize = this->info_->nOutputSize;
199
-
200
- this->input_cached_.resize(inputs_.size(), input_cached);
201
- this->output_cached_.resize(outputs_.size(), output_cached);
202
-
203
- // 6. prepare the memory, inputs
204
- for (::AX_U32 i = 0; i < this->info_->nInputSize; i++) {
205
- const auto& meta = this->info_->pInputs[i];
206
- auto& io = this->io_.pInputs[i];
207
- io.nSize = meta.nSize * this->batch;
208
-
209
- if (this->input_cached_[i]) {
210
- if (const auto ret = ::AX_SYS_MemAllocCached(&io.phyAddr, &io.pVirAddr, io.nSize, align_size, token_name); 0 != ret) {
211
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
212
- return false;
213
- }
214
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta.pName);
215
- } else {
216
- if (const auto ret = ::AX_SYS_MemAlloc(&io.phyAddr, &io.pVirAddr, io.nSize, align_size, token_name); 0 != ret) {
217
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
218
- return false;
219
- }
220
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta.pName);
221
- }
222
-
223
- // clean memory, some cases model may need to clean memory
224
- memset(io.pVirAddr, 0, io.nSize);
225
-
226
- if (this->output_cached_[i]) {
227
- if (const auto ret = ::AX_SYS_MflushCache(io.phyAddr, io.pVirAddr, io.nSize); 0 != ret) {
228
- utilities::glog.print(utilities::log::type::error, "Memory flush cache for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
229
- return false;
230
- }
231
- }
232
-
233
- utilities::glog.print(utilities::log::type::info, "Set tensor { name: %s, phy: %p, vir: %p, size: %u Bytes }.\n",
234
- meta.pName, reinterpret_cast<void*>(io.phyAddr), io.pVirAddr, io.nSize);
235
- }
236
-
237
- // 7. prepare the memory, outputs
238
- for (::AX_U32 i = 0; i < this->info_->nOutputSize; i++) {
239
- const auto& meta = this->info_->pOutputs[i];
240
- auto& io = this->io_.pOutputs[i];
241
- io.nSize = meta.nSize * this->batch;
242
-
243
- if (this->output_cached_[i]) {
244
- if (const auto ret = ::AX_SYS_MemAllocCached(&io.phyAddr, &io.pVirAddr, io.nSize, align_size, token_name); 0 != ret) {
245
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
246
- return false;
247
- }
248
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta.pName);
249
- } else {
250
- if (const auto ret = ::AX_SYS_MemAlloc(&io.phyAddr, &io.pVirAddr, io.nSize, align_size, token_name); 0 != ret) {
251
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
252
- return false;
253
- }
254
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta.pName);
255
- }
256
-
257
- // clean memory, some cases model may need to clean memory
258
- memset(io.pVirAddr, 0, io.nSize);
259
-
260
- if (this->output_cached_[i]) {
261
- if (const auto ret = ::AX_SYS_MflushCache(io.phyAddr, io.pVirAddr, io.nSize); 0 != ret) {
262
- utilities::glog.print(utilities::log::type::error, "Memory flush cache for tensor {%s} failed{0x%08X}.\n", meta.pName, ret);
263
- return false;
264
- }
265
- }
266
-
267
- utilities::glog.print(utilities::log::type::info, "Set tensor { name: %s, phy: %p, vir: %p, size: %u Bytes }.\n",
268
- meta.pName, reinterpret_cast<void*>(io.phyAddr), io.pVirAddr, io.nSize);
269
- }
270
-
271
- return true;
272
- }
273
-
274
- [[nodiscard]] bool run(const bool& parallel) {
275
- std::lock_guard guard(this->mutex_);
276
-
277
- this->io_.nParallelRun = (parallel ? 1 : 0);
278
-
279
- if (nullptr == this->handle_ || nullptr == this->context_) {
280
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
281
- return false;
282
- }
283
-
284
- if (0 == this->io_.nInputSize || 0 == this->io_.nOutputSize) {
285
- utilities::glog.print(utilities::log::type::error, "Model io is not set, prepare first.\n");
286
- return false;
287
- }
288
-
289
- ::AX_S32 ret = 0;
290
- if (1 == this->group_) {
291
- ret = ::AX_ENGINE_RunSyncV2(this->handle_, this->context_, &this->io_);
292
- } else {
293
- ret = ::AX_ENGINE_RunGroupIOSync(this->handle_, this->context_, this->group_, &this->io_);
294
- }
295
- if (0 != ret) {
296
- utilities::glog.print(utilities::log::type::error, "Run model failed{0x%08X}.\n", ret);
297
- return false;
298
- }
299
- utilities::glog.print(utilities::log::type::info, "Running done.\n");
300
-
301
- return true;
302
- }
303
-
304
- [[nodiscard]] uint32_t get_input_count() {
305
- std::lock_guard guard(this->mutex_);
306
-
307
- if (nullptr == this->info_) {
308
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
309
- return 0;
310
- }
311
-
312
- return this->info_->nInputSize;
313
- }
314
-
315
- [[nodiscard]] uint32_t get_output_count() {
316
- std::lock_guard guard(this->mutex_);
317
-
318
- if (nullptr == this->info_) {
319
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
320
- return 0;
321
- }
322
-
323
- return this->info_->nOutputSize;
324
- }
325
-
326
- [[nodiscard]] std::string get_input_name(const uint32_t& index) {
327
- std::lock_guard guard(this->mutex_);
328
-
329
- if (nullptr == this->info_) {
330
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
331
- return {};
332
- }
333
-
334
- if (index >= this->info_->nInputSize) {
335
- return {};
336
- }
337
- return std::string{this->info_->pInputs[index].pName};
338
- }
339
-
340
- [[nodiscard]] std::string get_output_name(const uint32_t& index) {
341
- std::lock_guard guard(this->mutex_);
342
-
343
- if (nullptr == this->info_) {
344
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
345
- return {};
346
- }
347
-
348
- if (index >= this->info_->nOutputSize) {
349
- return {};
350
- }
351
- return std::string{this->info_->pOutputs[index].pName};
352
- }
353
-
354
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) {
355
- std::lock_guard guard(this->mutex_);
356
-
357
- if (nullptr == this->info_) {
358
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
359
- return nullptr;
360
- }
361
-
362
- if (index >= this->info_->nInputSize) {
363
- return nullptr;
364
- }
365
- return reinterpret_cast<void *>(this->io_.pInputs[index].phyAddr);
366
- }
367
-
368
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) {
369
- std::lock_guard guard(this->mutex_);
370
-
371
- if (nullptr == this->info_) {
372
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
373
- return nullptr;
374
- }
375
-
376
- if (index >= this->info_->nOutputSize) {
377
- return nullptr;
378
- }
379
- return reinterpret_cast<void *>(this->io_.pOutputs[index].phyAddr);
380
- }
381
-
382
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) {
383
- std::lock_guard guard(this->mutex_);
384
-
385
- if (nullptr == this->info_) {
386
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
387
- return 0;
388
- }
389
-
390
- if (index >= this->info_->nInputSize) {
391
- return 0;
392
- }
393
- return this->io_.pInputs[index].nSize;
394
- }
395
-
396
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) {
397
- std::lock_guard guard(this->mutex_);
398
-
399
- if (nullptr == this->info_) {
400
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
401
- return 0;
402
- }
403
-
404
- if (index >= this->info_->nOutputSize) {
405
- return 0;
406
- }
407
- return this->io_.pOutputs[index].nSize;
408
- }
409
-
410
- [[nodiscard]] uintmax_t get_shape_group_count() {
411
- std::lock_guard guard(this->mutex_);
412
-
413
- if (nullptr == this->info_) {
414
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
415
- return 0;
416
- }
417
-
418
- return this->group_;
419
- }
420
-
421
- [[nodiscard]] bool flush_input() {
422
- std::lock_guard guard(this->mutex_);
423
-
424
- for (::AX_U32 i = 0; i < this->io_.nInputSize; i++) {
425
- const auto buffer = &(this->io_.pInputs[i]);
426
- if (const auto ret = ::AX_SYS_MflushCache(buffer->phyAddr, buffer->pVirAddr, buffer->nSize); 0 != ret) {
427
- utilities::glog.print(utilities::log::type::warn, "Flush input{index: %d} failed{0x%08X}.\n", i, ret);
428
- return false;
429
- }
430
- }
431
- return true;
432
- }
433
-
434
- [[nodiscard]] bool invalidate_output() {
435
- std::lock_guard guard(this->mutex_);
436
-
437
- for (::AX_U32 i = 0; i < this->io_.nOutputSize; i++) {
438
- const auto buffer = &(this->io_.pOutputs[i]);
439
- if (const auto ret = ::AX_SYS_MinvalidateCache(buffer->phyAddr, buffer->pVirAddr, buffer->nSize); 0 != ret) {
440
- utilities::glog.print(utilities::log::type::warn, "Invalidate output{index: %d} failed{0x%08X}.\n", i, ret);
441
- return false;
442
- }
443
- }
444
- return true;
445
- }
446
-
447
- [[nodiscard]] bool feed(const std::string& input_folder, const std::string& stimulus_name) {
448
- for (uint32_t i = 0; i < this->get_input_count(); i++) {
449
- const auto file_name = utilities::get_legal_name(this->get_input_name(i));
450
- auto file_path = input_folder;
451
- file_path.append("/").append(stimulus_name).append("/").append(file_name).append(".bin");
452
-
453
- if (!read(file_path, this->inputs_[i].pVirAddr, this->inputs_[i].nSize)) {
454
- utilities::glog.print(utilities::log::type::error, "Read tensor {idx: %d, name: %s} file {%s} failed.\n", i, file_name.c_str(), file_path.c_str());
455
- return false;
456
- }
457
-
458
- if (this->input_cached_[i]) {
459
- if (const auto ret = ::AX_SYS_MflushCache(this->inputs_[i].phyAddr, this->inputs_[i].pVirAddr, this->inputs_[i].nSize); 0 != ret) {
460
- utilities::glog.print(utilities::log::type::error, "Flush tensor {idx: %d, name: %s} cache failed{%d}.\n", i, file_name.c_str(), ret);
461
- return false;
462
- }
463
- utilities::glog.print(utilities::log::type::info, "Tensor {idx: %d, name: %s} cache flushed.\n", i, file_name.c_str());
464
- }
465
- }
466
- return true;
467
- }
468
-
469
- [[nodiscard]] bool verify(const std::string& output_folder, const std::string& stimulus_name) {
470
- for (uint32_t i = 0; i < this->get_output_count(); i++) {
471
- const auto file_name = utilities::get_legal_name(this->get_output_name(i));
472
- auto file_path = output_folder;
473
- file_path.append("/").append(stimulus_name).append("/").append(file_name).append(".bin");
474
-
475
- std::vector<uint8_t> file_buffer(this->get_output_size(i));
476
- if (!read(file_path, file_buffer.data(), file_buffer.size())) {
477
- utilities::glog.print(utilities::log::type::error, "Read tensor {idx: %d, name: %s} file {%s} failed.\n", i, file_name.c_str(), file_path.c_str());
478
- return false;
479
- }
480
-
481
- if (this->output_cached_[i]) {
482
- if (const auto ret = ::AX_SYS_MinvalidateCache(this->outputs_[i].phyAddr, this->outputs_[i].pVirAddr, this->outputs_[i].nSize); 0 != ret) {
483
- utilities::glog.print(utilities::log::type::error, "Invalidate tensor {idx: %d, name: %s} cache failed{%d}.\n", i, file_name.c_str(), ret);
484
- return false;
485
- }
486
- utilities::glog.print(utilities::log::type::info, "Tensor {idx: %d, name: %s} cache invalidated.\n", i, file_name.c_str());
487
- }
488
-
489
- if (!runner::verify(file_buffer.data(), this->outputs_[i].pVirAddr, this->outputs_[i].nSize)) {
490
- utilities::glog.print(utilities::log::type::error, "Verify tensor {idx: %d, name: %s} failed.\n", i, file_name.c_str());
491
- return false;
492
- }
493
- }
494
- return true;
495
- }
496
-
497
- [[nodiscard]] bool save(const std::string& output_folder, const std::string& stimulus_name) {
498
- auto file_folder = output_folder;
499
- file_folder.append("/").append(stimulus_name);
500
-
501
- if (!utilities::exists(file_folder) && !utilities::create_directory(file_folder)) {
502
- utilities::glog.print(utilities::log::type::error, "Create folder {%s} failed.\n", file_folder.c_str());
503
- return false;
504
- }
505
-
506
- for (uint32_t i = 0; i < this->get_output_count(); i++) {
507
- const auto file_name = utilities::get_legal_name(this->get_output_name(i));
508
- auto file_path = file_folder;
509
- file_path.append("/").append(file_name).append(".bin");
510
-
511
- if (this->output_cached_[i]) {
512
- if (const auto ret = ::AX_SYS_MinvalidateCache(this->outputs_[i].phyAddr, this->outputs_[i].pVirAddr, this->outputs_[i].nSize); 0 != ret) {
513
- utilities::glog.print(utilities::log::type::error, "Invalidate tensor {idx: %d, name: %s} cache failed{%d}.\n", i, file_name.c_str(), ret);
514
- return false;
515
- }
516
- utilities::glog.print(utilities::log::type::info, "Tensor {idx: %d, name: %s} cache invalidated.\n", i, file_name.c_str());
517
- }
518
-
519
- if (!write(file_path, this->outputs_[i].pVirAddr, this->outputs_[i].nSize)) {
520
- utilities::glog.print(utilities::log::type::error, "Write tensor {idx: %d, name: %s} file {%s} failed.\n", i, file_name.c_str(), file_path.c_str());
521
- return false;
522
- }
523
- }
524
- return true;
525
- }
526
-
527
- [[nodiscard]] std::string get_library_version() {
528
- std::lock_guard guard(this->mutex_);
529
-
530
- const auto ver = ::AX_ENGINE_GetVersion();
531
- if (nullptr == ver) {
532
- utilities::glog.print(utilities::log::type::error, "Get library version failed.\n");
533
- return "";
534
- }
535
- return {ver};
536
- }
537
-
538
- [[nodiscard]] std::string get_model_version() {
539
- std::lock_guard guard(this->mutex_);
540
-
541
- if (nullptr == this->handle_) {
542
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
543
- return "";
544
- }
545
- return {::AX_ENGINE_GetModelToolsVersion(this->handle_)};
546
- }
547
-
548
- [[nodiscard]] int32_t get_model_type() {
549
- std::lock_guard guard(this->mutex_);
550
-
551
- if (nullptr == this->handle_) {
552
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
553
- return -1;
554
- }
555
-
556
- ::AX_ENGINE_MODEL_TYPE_T type;
557
- if (const auto ret = ::AX_ENGINE_GetHandleModelType(this->handle_, &type); 0 != ret) {
558
- utilities::glog.print(utilities::log::type::error, "Get model type failed{0x%08X}.\n", ret);
559
- return -1;
560
- }
561
- return type;
562
- }
563
-
564
- [[nodiscard]] int32_t get_npu_type() {
565
- std::lock_guard guard(this->mutex_);
566
-
567
- if (!this->is_initialized_) {
568
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
569
- return false;
570
- }
571
-
572
- ::AX_ENGINE_NPU_ATTR_T attr{};
573
- if (const auto ret = ::AX_ENGINE_GetVNPUAttr(&attr); 0 != ret) {
574
- utilities::glog.print(utilities::log::type::error, "Get visual NPU type failed{0x%08X}.\n", ret);
575
- return -1;
576
- }
577
- return attr.eHardMode;
578
- }
579
-
580
- [[nodiscard]] int32_t get_batch_size() {
581
- std::lock_guard guard(this->mutex_);
582
-
583
- if (nullptr == this->handle_) {
584
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
585
- return -1;
586
- }
587
-
588
- return static_cast<int32_t>(this->batch);
589
- }
590
-
591
- [[nodiscard]] intmax_t get_sys_usage() {
592
- std::lock_guard guard(this->mutex_);
593
-
594
- if (nullptr == this->handle_) {
595
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
596
- return -1;
597
- }
598
-
599
- return 0;
600
- }
601
-
602
- [[nodiscard]] intmax_t get_cmm_usage() {
603
- std::lock_guard guard(this->mutex_);
604
-
605
- if (nullptr == this->handle_) {
606
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
607
- return -1;
608
- }
609
-
610
- ::AX_ENGINE_CMM_INFO usage{};
611
- if (const auto ret = ::AX_ENGINE_GetCMMUsage(this->handle_, &usage); 0 != ret) {
612
- utilities::glog.print(utilities::log::type::error, "Get model usage failed{0x%08X}.\n", ret);
613
- return -1;
614
- }
615
-
616
- return usage.nCMMSize;
617
- }
618
-
619
- static void sleep_for(const uint32_t sleep_duration) {
620
- ::AX_SYS_Msleep(sleep_duration);
621
- }
622
-
623
- private:
624
- uint32_t group_ = 0;
625
- uint32_t batch = 0;
626
-
627
- ::AX_ENGINE_HANDLE handle_{};
628
- ::AX_ENGINE_CONTEXT_T context_{};
629
- ::AX_ENGINE_IO_INFO_T* info_{};
630
- ::AX_ENGINE_IO_T io_{};
631
- std::vector<::AX_ENGINE_IO_BUFFER_T> inputs_;
632
- std::vector<::AX_ENGINE_IO_BUFFER_T> outputs_;
633
-
634
- std::vector<bool> input_cached_;
635
- std::vector<bool> output_cached_;
636
-
637
- bool is_initialized_ = false;
638
- std::mutex mutex_;
639
- };
640
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_base.cc DELETED
@@ -1,241 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #include "middleware/axcl_base.hpp"
12
-
13
-
14
- #if defined(ENV_AXCL_RUNTIME_API_ENABLE) || defined(ENV_AXCL_NATIVE_API_ENABLE)
15
-
16
- #include "utilities/scalar_guard.hpp"
17
- #include "utilities/file.hpp"
18
- #include "utilities/log.hpp"
19
-
20
- #include <axcl.h>
21
-
22
- #include <mutex>
23
-
24
- static int static_module_count{0};
25
- static std::mutex static_module_mutex;
26
-
27
- static bool module_init(const std::string& config, const uint32_t& index, const middleware::axcl_base::npu_func& func) {
28
- // 1. init axcl, using scalar_guard to ensure the finalization
29
- const auto cfg_flag = utilities::exists(config) && utilities::is_regular_file(config);
30
- utilities::glog.print(utilities::log::type::info, "axcl initializing...\n");
31
- auto env_guard = utilities::scalar_guard<int32_t>(
32
- axclInit(cfg_flag ? config.c_str() : nullptr),
33
- [](const int32_t& code) {
34
- if (0 == code) {
35
- std::ignore = axclFinalize();
36
- }
37
- }
38
- );
39
-
40
- // 2. check the initialization result
41
- if (const int ret = env_guard.get(); 0 != ret) {
42
- utilities::glog.print(utilities::log::type::error, "Init axcl failed{0x%08X}.\n", ret);
43
- return false;
44
- }
45
- utilities::glog.print(utilities::log::type::info, "axcl inited.\n");
46
-
47
- // 3. get device list
48
- axclrtDeviceList lst;
49
- if (const auto ret = axclrtGetDeviceList(&lst); 0 != ret || 0 == lst.num) {
50
- utilities::glog.print(utilities::log::type::error,
51
- "Get axcl device failed{0x%08X}, find total %d device.\n", ret, lst.num);
52
- return false;
53
- }
54
-
55
- // 4. check the device index
56
- if (index >= lst.num) {
57
- utilities::glog.print(utilities::log::type::error,
58
- "Specified device index{%d} is out of range{total %d}.\n", index, lst.num);
59
- return false;
60
- }
61
-
62
- // 5. set device
63
- if (const auto ret = axclrtSetDevice(lst.devices[index]); 0 != ret) {
64
- utilities::glog.print(utilities::log::type::error,
65
- "Set axcl device as index{%d} failed{0x%08X}.\n", index, ret);
66
- return false;
67
- }
68
- utilities::glog.print(utilities::log::type::info,
69
- "Select axcl device{index: %d} as {%d}.\n", index, lst.devices[index]);
70
-
71
- // 6. init NPU
72
- if (!func()) {
73
- utilities::glog.print(utilities::log::type::error, "Init NPU failed.\n");
74
- return false;
75
- }
76
-
77
- // 7. disengage guard of env
78
- env_guard.get() = -1;
79
- return true;
80
- }
81
-
82
- static bool module_final(const middleware::axcl_base::npu_func& func) {
83
- const auto flag = func();
84
- const auto ret = axclFinalize();
85
- return flag && (0 == ret);
86
- }
87
-
88
- bool middleware::axcl_base::init(const std::string &config, const uint32_t &index, const npu_func &func) {
89
- bool flag = false;
90
- {
91
- std::lock_guard lock(static_module_mutex);
92
- if (static_module_count == 0) {
93
- flag = module_init(config, index, func);
94
- if (flag) {
95
- static_module_count++;
96
- }
97
- } else {
98
- static_module_count++;
99
- flag = true;
100
- }
101
- }
102
-
103
- return flag;
104
- }
105
-
106
- bool middleware::axcl_base::final(const npu_func& func) {
107
- bool flag = false;
108
- {
109
- std::lock_guard lock(static_module_mutex);
110
- if (static_module_count == 1) {
111
- flag = module_final(func);
112
- if (flag) {
113
- static_module_count--;
114
- }
115
- } else if (static_module_count > 1) {
116
- static_module_count--;
117
- flag = true;
118
- }
119
- }
120
-
121
- return flag;
122
- }
123
-
124
- bool middleware::axcl_base::flush_input() const {
125
- return true;
126
- }
127
-
128
- bool middleware::axcl_base::invalidate_output() const {
129
- return true;
130
- }
131
-
132
- [[nodiscard]] bool middleware::axcl_base::feed(const std::string& input_folder, const std::string& stimulus_name) const {
133
- for (uint32_t i = 0; i < this->get_input_count(); i++) {
134
- if (const auto ret = feed(input_folder, stimulus_name, this->get_input_name(i), this->get_input_pointer(i), this->get_input_size(i) * this->get_batch_size()); !ret) {
135
- utilities::glog.print(utilities::log::type::error, "Feed tensor {idx: %d, name: %s} failed.\n", i, this->get_input_name(i).c_str());
136
- return false;
137
- }
138
- }
139
- return true;
140
- }
141
-
142
- [[nodiscard]] bool middleware::axcl_base::verify(const std::string& output_folder, const std::string& stimulus_name) const {
143
- for (uint32_t i = 0; i < this->get_output_count(); i++) {
144
- if (const auto ret = verify(output_folder, stimulus_name, this->get_output_name(i),this->get_output_pointer(i), this->get_output_size(i) * this->get_batch_size()); !ret) {
145
- utilities::glog.print(utilities::log::type::error, "Verify tensor {idx: %d, name: %s} failed.\n", i, this->get_output_name(i).c_str());
146
- return false;
147
- }
148
- }
149
- return true;
150
- }
151
-
152
- [[nodiscard]] bool middleware::axcl_base::save(const std::string& output_folder, const std::string& stimulus_name) const {
153
- auto file_folder = output_folder;
154
- file_folder.append("/").append(stimulus_name);
155
-
156
- if (!utilities::exists(file_folder) && !utilities::create_directory(file_folder)) {
157
- utilities::glog.print(utilities::log::type::error, "Create folder {%s} failed.\n", file_folder.c_str());
158
- return false;
159
- }
160
-
161
- for (uint32_t i = 0; i < this->get_output_count(); i++) {
162
- if (const auto ret = save(output_folder, stimulus_name, this->get_output_name(i), this->get_output_pointer(i), this->get_output_size(i) * this->get_batch_size()); !ret) {
163
- utilities::glog.print(utilities::log::type::error, "Save tensor {idx: %d, name: %s} failed.\n", i, this->get_output_name(i).c_str());
164
- return false;
165
- }
166
- }
167
- return true;
168
- }
169
-
170
- bool middleware::axcl_base::feed(const std::string& folder, const std::string& stimulus_name, const std::string& tensor_name, void* address, const uintmax_t size) {
171
- const auto file_name = utilities::get_legal_name(tensor_name);
172
- auto file_path(folder);
173
- file_path.append("/").append(stimulus_name).append("/").append(file_name).append(".bin");
174
-
175
- std::vector<uint8_t> tensor_buffer(size);
176
- if (!read(file_path, tensor_buffer.data(), tensor_buffer.size())) {
177
- utilities::glog.print(utilities::log::type::error,
178
- "Read tensor {name: %s} stimulus file {%s} failed.\n", tensor_name.c_str(), file_path.c_str());
179
- return false;
180
- }
181
-
182
- if (const auto ret = axclrtMemcpy(address, tensor_buffer.data(), size, AXCL_MEMCPY_HOST_TO_DEVICE); 0 != ret) {
183
- utilities::glog.print(utilities::log::type::error,
184
- "Receive tensor {name: %s, addr: 0x%08X, size: %ld} from host {addr: 0x%08X} failed{0x%08X}.\n",
185
- tensor_name.c_str(), address, size, tensor_buffer.data(), ret);
186
- return false;
187
- }
188
-
189
- return true;
190
- }
191
-
192
- bool middleware::axcl_base::verify(const std::string& folder, const std::string& stimulus_name, const std::string& tensor_name, void* address, const uintmax_t size) {
193
- const auto file_name = utilities::get_legal_name(tensor_name);
194
- auto file_path(folder);
195
- file_path.append("/").append(stimulus_name).append("/").append(file_name).append(".bin");
196
-
197
- std::vector<uint8_t> file_buffer(size);
198
- if (!read(file_path, file_buffer.data(), file_buffer.size())) {
199
- utilities::glog.print(utilities::log::type::error,
200
- "Read tensor {name: %s} file {%s} failed.\n", file_name.c_str(), file_path.c_str());
201
- return false;
202
- }
203
-
204
- std::vector<uint8_t> tensor_buffer(size);
205
-
206
- if (const auto ret = axclrtMemcpy(tensor_buffer.data(), address, size, AXCL_MEMCPY_DEVICE_TO_HOST); 0 != ret) {
207
- utilities::glog.print(utilities::log::type::error,
208
- "Send tensor {name: %s, addr: 0x%08X, size: %ld} to host {addr: 0x%08X} failed{0x%08X}.\n",
209
- file_name.c_str(), address, size, tensor_buffer.data(), ret);
210
- return false;
211
- }
212
-
213
- if (!runner::verify(file_buffer.data(), tensor_buffer.data(), file_buffer.size())) {
214
- utilities::glog.print(utilities::log::type::error, "Verify tensor {name: %s} failed.\n", file_name.c_str());
215
- return false;
216
- }
217
-
218
- return true;
219
- }
220
-
221
- bool middleware::axcl_base::save(const std::string& output_folder, const std::string& stimulus_name, const std::string& tensor_name, void* address, const uintmax_t size) {
222
- const auto file_name = utilities::get_legal_name(tensor_name);
223
- auto file_path(output_folder);
224
- file_path.append("/").append(stimulus_name).append("/").append(file_name).append(".bin");
225
-
226
- std::vector<uint8_t> tensor_buffer(size);
227
- if (const auto ret = axclrtMemcpy(tensor_buffer.data(), address, size, AXCL_MEMCPY_DEVICE_TO_HOST); 0 != ret) {
228
- utilities::glog.print(utilities::log::type::error,
229
- "Send tensor {name: %s, addr: 0x%08X, size: %ld} to host {addr: 0x%08X} failed{0x%08X}.\n",
230
- file_name.c_str(), address, size, tensor_buffer.data(), ret);
231
- return false;
232
- }
233
-
234
- if (!write(file_path, tensor_buffer.data(), tensor_buffer.size())) {
235
- utilities::glog.print(utilities::log::type::error, "Write tensor {name: %s} file {%s} failed.\n", file_name.c_str(), file_path.c_str());
236
- return false;
237
- }
238
-
239
- return true;
240
- }
241
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_base.hpp DELETED
@@ -1,42 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include "middleware/runner.hpp"
14
-
15
- #if defined(ENV_AXCL_RUNTIME_API_ENABLE) || defined(ENV_AXCL_NATIVE_API_ENABLE)
16
-
17
- #include <functional>
18
-
19
- namespace middleware {
20
-
21
- class axcl_base : public runner {
22
- public:
23
- using npu_func = std::function<bool()>;
24
-
25
- [[nodiscard]] static bool init(const std::string& config, const uint32_t& index, const npu_func& func);
26
- [[nodiscard]] static bool final(const npu_func& func);
27
-
28
- [[nodiscard]] bool flush_input() const override;
29
- [[nodiscard]] bool invalidate_output() const override;
30
-
31
- [[nodiscard]] bool feed(const std::string& input_folder, const std::string& stimulus_name) const override;
32
- [[nodiscard]] bool verify(const std::string& output_folder, const std::string& stimulus_name) const override;
33
- [[nodiscard]] bool save(const std::string& output_folder, const std::string& stimulus_name) const override;
34
-
35
- private:
36
- [[nodiscard]] static bool feed(const std::string& folder, const std::string& stimulus_name, const std::string& tensor_name, void* address, uintmax_t size) ;
37
- [[nodiscard]] static bool verify(const std::string &folder, const std::string &stimulus_name, const std::string &tensor_name, void *address, uintmax_t size) ;
38
- [[nodiscard]] static bool save(const std::string& output_folder, const std::string& stimulus_name, const std::string& tensor_name, void* address, uintmax_t size);
39
- };
40
-
41
- }
42
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_native_runner.cc DELETED
@@ -1,105 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #include "middleware/axcl_native_runner_impl.hpp"
12
-
13
- #if defined(ENV_AXCL_NATIVE_API_ENABLE)
14
- middleware::native_runner::native_runner() {
15
- this->impl_ = new impl();
16
- }
17
-
18
- middleware::native_runner::~native_runner() {
19
- delete this->impl_;
20
- }
21
-
22
- bool middleware::native_runner::init(const std::string& config_file, const uint32_t& device_index, const uint32_t& kind) {
23
- return this->impl_->init(config_file, device_index, kind);
24
- }
25
-
26
- bool middleware::native_runner::final() {
27
- return this->impl_->final();
28
- }
29
-
30
- bool middleware::native_runner::load(const std::string& model_path) {
31
- return this->impl_->load(model_path);
32
- }
33
-
34
- bool middleware::native_runner::prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
35
- return this->impl_->prepare(input_cached, output_cached, group, batch);
36
- }
37
-
38
- bool middleware::native_runner::run(const bool& parallel) {
39
- return this->impl_->run(parallel);
40
- }
41
-
42
- uint32_t middleware::native_runner::get_input_count() const {
43
- return this->impl_->get_input_count();
44
- }
45
-
46
- uint32_t middleware::native_runner::get_output_count() const {
47
- return this->impl_->get_output_count();
48
- }
49
-
50
- std::string middleware::native_runner::get_input_name(const uint32_t& index) const {
51
- return this->impl_->get_input_name(index);
52
- }
53
-
54
- std::string middleware::native_runner::get_output_name(const uint32_t& index) const {
55
- return this->impl_->get_output_name(index);
56
- }
57
-
58
- void *middleware::native_runner::get_input_pointer(const uint32_t& index) const {
59
- return this->impl_->get_input_pointer(index);
60
- }
61
-
62
- void *middleware::native_runner::get_output_pointer(const uint32_t& index) const {
63
- return this->impl_->get_output_pointer(index);
64
- }
65
-
66
- uintmax_t middleware::native_runner::get_input_size(const uint32_t& index) const {
67
- return this->impl_->get_input_size(index);
68
- }
69
-
70
- uintmax_t middleware::native_runner::get_output_size(const uint32_t& index) const {
71
- return this->impl_->get_output_size(index);
72
- }
73
-
74
- uintmax_t middleware::native_runner::get_shape_group_count() const {
75
- return this->impl_->get_shape_group_count();
76
- }
77
-
78
- std::string middleware::native_runner::get_library_version() const {
79
- return impl::get_library_version();
80
- }
81
-
82
- std::string middleware::native_runner::get_model_version() const {
83
- return this->impl_->get_model_version();
84
- }
85
-
86
- int32_t middleware::native_runner::get_model_type() const {
87
- return this->impl_->get_model_type();
88
- }
89
-
90
- int32_t middleware::native_runner::get_npu_type() const {
91
- return this->impl_->get_npu_type();
92
- }
93
-
94
- int32_t middleware::native_runner::get_batch_size() const {
95
- return this->impl_->get_batch_size();
96
- }
97
-
98
- intmax_t middleware::native_runner::get_sys_usage() const {
99
- return this->impl_->get_sys_usage();
100
- }
101
-
102
- intmax_t middleware::native_runner::get_cmm_usage() const {
103
- return this->impl_->get_cmm_usage();
104
- }
105
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_native_runner.hpp DELETED
@@ -1,57 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #if defined(ENV_AXCL_NATIVE_API_ENABLE)
14
-
15
- #include "middleware/axcl_base.hpp"
16
-
17
- namespace middleware {
18
-
19
- class native_runner final : public axcl_base {
20
- public:
21
- native_runner();
22
- ~native_runner() override;
23
-
24
- [[nodiscard]] bool init(const std::string& config_file, const uint32_t& device_index, const uint32_t& kind) override;
25
- [[nodiscard]] bool final() override;
26
-
27
- [[nodiscard]] bool load(const std::string& model_path) override;
28
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) override;
29
-
30
- [[nodiscard]] bool run(const bool& parallel) override;
31
-
32
- [[nodiscard]] uint32_t get_input_count() const override;
33
- [[nodiscard]] uint32_t get_output_count() const override;
34
- [[nodiscard]] std::string get_input_name(const uint32_t& index) const override;
35
- [[nodiscard]] std::string get_output_name(const uint32_t& index) const override;
36
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) const override;
37
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) const override;
38
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) const override;
39
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) const override;
40
- [[nodiscard]] uintmax_t get_shape_group_count() const override;
41
-
42
- [[nodiscard]] std::string get_library_version() const override;
43
- [[nodiscard]] std::string get_model_version() const override;
44
-
45
- [[nodiscard]] int32_t get_model_type() const override;
46
- [[nodiscard]] int32_t get_npu_type() const override;
47
- [[nodiscard]] int32_t get_batch_size() const override;
48
- [[nodiscard]] intmax_t get_sys_usage() const override;
49
- [[nodiscard]] intmax_t get_cmm_usage() const override;
50
-
51
- private:
52
- struct impl;
53
- impl *impl_;
54
- };
55
-
56
- }
57
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_native_runner_impl.hpp DELETED
@@ -1,504 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include "middleware/axcl_native_runner.hpp"
14
-
15
- #include "utilities/scalar_guard.hpp"
16
- #include "utilities/file.hpp"
17
- #include "utilities/file_mapper.hpp"
18
- #include "utilities/log.hpp"
19
-
20
- #include <axcl.h>
21
-
22
- #if defined(ENV_AXCL_NATIVE_API_ENABLE)
23
- #define MODEL_LEADING_NAME "axcl npu "
24
-
25
- struct middleware::native_runner::impl {
26
- impl() = default;
27
-
28
- ~impl() {
29
- std::ignore = this->final();
30
- }
31
-
32
- [[nodiscard]] bool init(const std::string& config_file, const uint32_t& index, const uint32_t& kind) {
33
- // 0. check the NPU kind
34
- if (kind >= ::AX_ENGINE_VIRTUAL_NPU_BUTT) {
35
- utilities::glog.print(utilities::log::type::error,
36
- "Specified NPU kind{%d} is out of range{total %d}.\n", kind, ::AX_ENGINE_VIRTUAL_NPU_BUTT);
37
- return false;
38
- }
39
-
40
- // 1. build the npu init function
41
- auto npu_init_func = [&kind]() {
42
- ::AX_ENGINE_NPU_ATTR_T attr{};
43
- attr.eHardMode = static_cast<::AX_ENGINE_NPU_MODE_T>(kind);
44
- if (const int ret = ::AXCL_ENGINE_Init(&attr); 0 != ret) {
45
- utilities::glog.print(utilities::log::type::error,
46
- "Init axcl NPU as kind{%d} failed{0x%08X}.\n", kind, ret);
47
- return false;
48
- }
49
- utilities::glog.print(utilities::log::type::info, "axcl NPU inited.\n");
50
- return true;
51
- };
52
-
53
- // 2. execute initialization
54
- if (const auto ret = axcl_base::init(config_file, index, npu_init_func); !ret) {
55
- return false;
56
- }
57
-
58
- // 3. set the flag
59
- this->is_initialized_ = true;
60
- return true;
61
- }
62
-
63
- [[nodiscard]] bool final() {
64
- auto flag = true;
65
-
66
- if (this->is_initialized_) {
67
- if (nullptr != this->handle_) {
68
- for (auto& input : inputs_) {
69
- if (0 != input.phyAddr) {
70
- flag &= 0 == ::axclrtFree(reinterpret_cast<void *>(input.phyAddr));
71
- input.phyAddr = 0;
72
- }
73
- }
74
- for (auto& output : outputs_) {
75
- if (0 != output.phyAddr) {
76
- flag &= 0 == ::axclrtFree(reinterpret_cast<void *>(output.phyAddr));
77
- output.phyAddr = 0;
78
- }
79
- }
80
-
81
- flag &= 0 == ::AXCL_ENGINE_DestroyHandle(this->handle_);
82
- }
83
-
84
- flag &= 0 == axcl_base::final([&]() {
85
- if (const auto ret = ::AXCL_ENGINE_Deinit(); 0 != ret) {
86
- utilities::glog.print(utilities::log::type::error, "Final axcl NPU failed{0x%08X}.\n", ret);
87
- return false;
88
- }
89
- utilities::glog.print(utilities::log::type::info, "axcl NPU finalized.\n");
90
- return true;
91
- });
92
-
93
- this->is_initialized_ = false;
94
- }
95
-
96
- return flag;
97
- }
98
-
99
- [[nodiscard]] bool load(const std::string& model_path) {
100
- if (!this->is_initialized_) {
101
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
102
- return false;
103
- }
104
-
105
- if (nullptr != this->handle_) {
106
- utilities::glog.print(utilities::log::type::error, "Model is already loaded.\n");
107
- return false;
108
- }
109
-
110
- if (!utilities::exists(model_path)
111
- || !utilities::is_regular_file(model_path)
112
- || 0 == utilities::file_size(model_path)
113
- || utilities::error_size == utilities::file_size(model_path)) {
114
- utilities::glog.print(utilities::log::type::error,
115
- "Model file{%s} error, please check it.\n", model_path.c_str());
116
- return false;
117
- }
118
-
119
- const auto file = utilities::file_mapper(model_path);
120
- if (nullptr == file.get()) {
121
- utilities::glog.print(utilities::log::type::error,
122
- "Model file{%s} mapping failed.\n", model_path.c_str());
123
- return false;
124
- }
125
-
126
- const auto file_size = utilities::file_size(model_path);
127
- auto device = utilities::scalar_guard<void*>(
128
- [&file_size]() -> void* {
129
- void *mem = nullptr;
130
- if (const auto ret = ::axclrtMalloc(&mem, file_size, ::axclrtMemMallocPolicy{}); 0 != ret) {
131
- utilities::glog.print(utilities::log::type::error,
132
- "Malloc on device for model file failed{0x%08X}.\n", ret);
133
- }
134
- return mem;
135
- },
136
- [](void*& dev) { if (dev != nullptr) std::ignore = ::axclrtFree(dev); }
137
- );
138
-
139
- if (nullptr == device.get()) {
140
- utilities::glog.print(utilities::log::type::error,
141
- "Malloc on device for file{%s} failed.\n", model_path.c_str());
142
- return false;
143
- }
144
-
145
- if (const auto ret = ::axclrtMemcpy(device.get(), file.get(), file_size, ::AXCL_MEMCPY_HOST_TO_DEVICE); 0 != ret) {
146
- utilities::glog.print(utilities::log::type::error,
147
- "Send model file{%s} to device failed{0x%08X}.\n", model_path.c_str(), ret);
148
- return false;
149
- }
150
-
151
- const auto model_name = std::string(MODEL_LEADING_NAME) + utilities::get_file_name(model_path);
152
- ::AX_ENGINE_HANDLE_EXTRA_T extra_param{};
153
- extra_param.pName = reinterpret_cast<::AX_S8 *>(const_cast<char *>(model_name.c_str()));
154
- if (const auto ret = ::AXCL_ENGINE_CreateHandleV2(&this->handle_, device.get(), file_size, &extra_param); 0 != ret) {
155
- utilities::glog.print(utilities::log::type::error,
156
- "Create model{%s} handle failed.\n", model_path.c_str());
157
- return false;
158
- }
159
-
160
- if (const auto ret = ::AXCL_ENGINE_CreateContextV2(this->handle_, &this->context_); 0 != ret) {
161
- utilities::glog.print(utilities::log::type::error,
162
- "Create model{%s} context failed.\n", model_path.c_str());
163
- return false;
164
- }
165
-
166
- return true;
167
- }
168
-
169
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
170
- std::ignore = input_cached;
171
- std::ignore = output_cached;
172
-
173
- // 0. check the handle
174
- if (nullptr == this->handle_) {
175
- utilities::glog.print(utilities::log::type::error, "Model handle is null.\n");
176
- return false;
177
- }
178
-
179
- // 1. get the count of shape group
180
- if (const auto ret = ::AXCL_ENGINE_GetGroupIOInfoCount(this->handle_, &this->group_count_); 0 != ret) {
181
- utilities::glog.print(utilities::log::type::error,
182
- "Get model shape group count failed{0x%08X}.\n", ret);
183
- return false;
184
- }
185
-
186
- // 2. check the group index
187
- if (group >= this->group_count_) {
188
- utilities::glog.print(utilities::log::type::error,
189
- "Model group{%d} is out of range{total %d}.\n", group, this->group_);
190
- return false;
191
- }
192
- this->group_ = group;
193
-
194
- // 3. get the IO info
195
- if (1 == this->group_count_) {
196
- if (const auto ret = ::AXCL_ENGINE_GetIOInfo(this->handle_, &info_); 0 != ret) {
197
- utilities::glog.print(utilities::log::type::error,
198
- "Get model IO info failed{0x%08X}.\n", ret);
199
- return false;
200
- }
201
- } else {
202
- if (const auto ret = ::AXCL_ENGINE_GetGroupIOInfo(this->handle_, group, &info_); 0 != ret) {
203
- utilities::glog.print(utilities::log::type::error,
204
- "Get model group{index: %d} IO info failed{0x%08X}.\n", group, ret);
205
- return false;
206
- }
207
- }
208
-
209
- // 4. check the batch size
210
- this->batch_ = (0 == batch ? 1 : batch);
211
- this->io_.nBatchSize = this->batch_;
212
-
213
- // 5. prepare the input and output
214
- this->inputs_.resize(this->info_->nInputSize, ::AX_ENGINE_IO_BUFFER_T{});
215
- this->io_.pInputs = this->inputs_.data();
216
- this->io_.nInputSize = this->info_->nInputSize;
217
-
218
- this->outputs_.resize(this->info_->nOutputSize, ::AX_ENGINE_IO_BUFFER_T{});
219
- this->io_.pOutputs = this->outputs_.data();
220
- this->io_.nOutputSize = this->info_->nOutputSize;
221
-
222
- // 6. prepare the memory, inputs
223
- for (::AX_U32 i = 0; i < this->info_->nInputSize; i++) {
224
- const auto meta = &(this->info_->pInputs[i]);
225
- this->io_.pInputs[i].nSize = meta->nSize * this->batch_;
226
-
227
- if (const auto ret = ::axclrtMalloc(
228
- reinterpret_cast<void **>(&this->io_.pInputs[i].phyAddr),
229
- this->io_.pInputs[i].nSize,
230
- ::axclrtMemMallocPolicy{}); 0 != ret) {
231
- utilities::glog.print(utilities::log::type::error,
232
- "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta->pName, ret);
233
- return false;
234
- }
235
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta->pName);
236
-
237
- // clean memory, some cases model may need to clean memory
238
- //::axclrtMemset(reinterpret_cast<void *>(this->io_.pInputs[i].phyAddr), 0, this->io_.pInputs[i].nSize);
239
-
240
- utilities::glog.print(utilities::log::type::info,
241
- "Set tensor { name: %s, phy: %p, vir: %p, size: %u Bytes }.\n",
242
- meta->pName,
243
- reinterpret_cast<void*>(this->io_.pInputs[i].phyAddr),
244
- this->io_.pInputs[i].pVirAddr,
245
- this->io_.pInputs[i].nSize);
246
- }
247
-
248
- // 7. prepare the memory, outputs
249
- for (::AX_U32 i = 0; i < this->info_->nOutputSize; i++) {
250
- const auto meta = &(this->info_->pOutputs[i]);
251
- this->io_.pOutputs[i].nSize = meta->nSize * this->batch_;
252
-
253
- if (const auto ret = ::axclrtMalloc(
254
- reinterpret_cast<void **>(&this->io_.pOutputs[i].phyAddr),
255
- this->io_.pOutputs[i].nSize,
256
- ::axclrtMemMallocPolicy{}); 0 != ret) {
257
- utilities::glog.print(utilities::log::type::error,
258
- "Memory allocation for tensor {%s} failed{0x%08X}.\n", meta->pName, ret);
259
- return false;
260
- }
261
- utilities::glog.print(utilities::log::type::info, "Memory for tensor {%s} is allocated.\n", meta->pName);
262
-
263
- // clean memory, some cases model may need to clean memory
264
- //::axclrtMemset(reinterpret_cast<void *>(this->io_.pOutputs[i].phyAddr), 0, this->io_.pOutputs[i].nSize);
265
-
266
- utilities::glog.print(utilities::log::type::info,
267
- "Set tensor { name: %s, phy: %p, vir: %p, size: %u Bytes }.\n",
268
- meta->pName,
269
- reinterpret_cast<void*>(this->io_.pOutputs[i].phyAddr),
270
- this->io_.pOutputs[i].pVirAddr,
271
- this->io_.pOutputs[i].nSize);
272
- }
273
-
274
- return true;
275
- }
276
-
277
- [[nodiscard]] bool run(const bool& parallel) {
278
- this->io_.nParallelRun = (parallel ? 1 : 0);
279
-
280
- if (nullptr == this->handle_ || nullptr == this->context_) {
281
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
282
- return false;
283
- }
284
-
285
- if (0 == this->io_.nInputSize || 0 == this->io_.nOutputSize) {
286
- utilities::glog.print(utilities::log::type::error, "Model io is not set, prepare first.\n");
287
- return false;
288
- }
289
-
290
- ::AX_S32 ret = 0;
291
- // Note: this is a workaround for the case that the model has only ONE group,
292
- // currently AXCL_ENGINE_GetGroupIOInfo will return error.
293
- // the bug of libax_engine.so will be fixed in the future.
294
- if (1 == this->group_count_) {
295
- ret = ::AXCL_ENGINE_RunSyncV2(this->handle_, this->context_, &this->io_);
296
- } else {
297
- ret = ::AXCL_ENGINE_RunGroupIOSync(this->handle_, this->context_, this->group_, &this->io_);
298
- }
299
- if (0 != ret) {
300
- utilities::glog.print(utilities::log::type::error, "Run model failed{0x%08X}.\n", ret);
301
- return false;
302
- }
303
- utilities::glog.print(utilities::log::type::info, "Running done.\n");
304
-
305
- return true;
306
- }
307
-
308
- [[nodiscard]] uint32_t get_input_count() const {
309
- if (nullptr == this->info_) {
310
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
311
- return 0;
312
- }
313
-
314
- return this->info_->nInputSize;
315
- }
316
-
317
- [[nodiscard]] uint32_t get_output_count() const {
318
- if (nullptr == this->info_) {
319
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
320
- return 0;
321
- }
322
-
323
- return this->info_->nOutputSize;
324
- }
325
-
326
- [[nodiscard]] std::string get_input_name(const uint32_t& index) const {
327
- if (nullptr == this->info_) {
328
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
329
- return {};
330
- }
331
-
332
- if (index >= this->info_->nInputSize) {
333
- return {};
334
- }
335
- return std::string{this->info_->pInputs[index].pName};
336
- }
337
-
338
- [[nodiscard]] std::string get_output_name(const uint32_t& index) const {
339
- if (nullptr == this->info_) {
340
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
341
- return {};
342
- }
343
-
344
- if (index >= this->info_->nOutputSize) {
345
- return {};
346
- }
347
- return std::string{this->info_->pOutputs[index].pName};
348
- }
349
-
350
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) const {
351
- if (nullptr == this->info_) {
352
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
353
- return nullptr;
354
- }
355
-
356
- if (index >= this->info_->nInputSize) {
357
- return nullptr;
358
- }
359
- return reinterpret_cast<void *>(this->io_.pInputs[index].phyAddr);
360
- }
361
-
362
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) const {
363
- if (nullptr == this->info_) {
364
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
365
- return nullptr;
366
- }
367
-
368
- if (index >= this->info_->nOutputSize) {
369
- return nullptr;
370
- }
371
- return reinterpret_cast<void *>(this->io_.pOutputs[index].phyAddr);
372
- }
373
-
374
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) const {
375
- if (nullptr == this->info_) {
376
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
377
- return 0;
378
- }
379
-
380
- if (index >= this->info_->nInputSize) {
381
- return 0;
382
- }
383
- return this->io_.pInputs[index].nSize;
384
- }
385
-
386
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) const {
387
- if (nullptr == this->info_) {
388
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
389
- return 0;
390
- }
391
-
392
- if (index >= this->info_->nOutputSize) {
393
- return 0;
394
- }
395
- return this->io_.pOutputs[index].nSize;
396
- }
397
-
398
- [[nodiscard]] uintmax_t get_shape_group_count() const {
399
- if (nullptr == this->info_) {
400
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
401
- return 0;
402
- }
403
-
404
- ::AX_U32 group = 0;
405
- if (const auto ret = ::AXCL_ENGINE_GetGroupIOInfoCount(this->handle_, &group); 0 != ret) {
406
- utilities::glog.print(utilities::log::type::error, "Get model shape group count failed{0x%08X}.\n", ret);
407
- return 0;
408
- }
409
- return group;
410
- }
411
-
412
- [[nodiscard]] static std::string get_library_version() {
413
- int32_t major = 0, minor = 0, patch = 0;
414
- if (const auto ret = ::axclrtGetVersion(&major, &minor, &patch); 0 != ret) {
415
- utilities::glog.print(utilities::log::type::error, "Get library version failed{0x%08X}.\n", ret);
416
- return "";
417
- }
418
- return {std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch) + " " + ::AXCL_ENGINE_GetVersion()};
419
- }
420
-
421
- [[nodiscard]] std::string get_model_version() const {
422
- if (nullptr == this->handle_) {
423
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
424
- return "";
425
- }
426
- return {::AXCL_ENGINE_GetModelToolsVersion(this->handle_)};
427
- }
428
-
429
- [[nodiscard]] int32_t get_model_type() const {
430
- if (nullptr == this->handle_) {
431
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
432
- return -1;
433
- }
434
-
435
- ::AX_ENGINE_MODEL_TYPE_T type;
436
- if (const auto ret = ::AXCL_ENGINE_GetHandleModelType(this->handle_, &type); 0 != ret) {
437
- utilities::glog.print(utilities::log::type::error, "Get model type failed{0x%08X}.\n", ret);
438
- return -1;
439
- }
440
- return type;
441
- }
442
-
443
- [[nodiscard]] int32_t get_npu_type() const {
444
- if (!this->is_initialized_) {
445
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
446
- return false;
447
- }
448
-
449
- ::AX_ENGINE_NPU_ATTR_T attr{};
450
- if (const auto ret = ::AXCL_ENGINE_GetVNPUAttr(&attr); 0 != ret) {
451
- utilities::glog.print(utilities::log::type::error, "Get visual NPU type failed{0x%08X}.\n", ret);
452
- return -1;
453
- }
454
- return attr.eHardMode;
455
- }
456
-
457
- [[nodiscard]] int32_t get_batch_size() const {
458
- if (nullptr == this->handle_) {
459
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
460
- return -1;
461
- }
462
-
463
- return static_cast<int32_t>(this->batch_);
464
- }
465
-
466
- [[nodiscard]] intmax_t get_sys_usage() const {
467
- if (nullptr == this->handle_) {
468
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
469
- return -1;
470
- }
471
-
472
- return 0;
473
- }
474
-
475
- [[nodiscard]] intmax_t get_cmm_usage() const {
476
- if (nullptr == this->handle_) {
477
- utilities::glog.print(utilities::log::type::error, "Model handle is not set, load model first.\n");
478
- return -1;
479
- }
480
-
481
- ::AX_ENGINE_CMM_INFO usage{};
482
- if (const auto ret = ::AXCL_ENGINE_GetCMMUsage(this->handle_, &usage); 0 != ret) {
483
- utilities::glog.print(utilities::log::type::error, "Get model usage failed{0x%08X}.\n", ret);
484
- return -1;
485
- }
486
-
487
- return usage.nCMMSize;
488
- }
489
-
490
- private:
491
- uint32_t group_count_ = 0;
492
- uint32_t group_ = 0;
493
- uint32_t batch_ = 0;
494
-
495
- ::AX_ENGINE_HANDLE handle_{};
496
- ::AX_ENGINE_CONTEXT_T context_{};
497
- ::AX_ENGINE_IO_INFO_T* info_{};
498
- ::AX_ENGINE_IO_T io_{};
499
- std::vector<::AX_ENGINE_IO_BUFFER_T> inputs_;
500
- std::vector<::AX_ENGINE_IO_BUFFER_T> outputs_;
501
-
502
- bool is_initialized_ = false;
503
- };
504
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_runtime_runner.cc DELETED
@@ -1,105 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #include "middleware/axcl_runtime_runner_impl.hpp"
12
-
13
- #if defined(ENV_AXCL_RUNTIME_API_ENABLE)
14
- middleware::runtime_runner::runtime_runner() {
15
- this->impl_ = new impl();
16
- }
17
-
18
- middleware::runtime_runner::~runtime_runner() {
19
- delete this->impl_;
20
- }
21
-
22
- bool middleware::runtime_runner::init(const std::string& config_file, const uint32_t& device_index, const uint32_t& kind) {
23
- return this->impl_->init(config_file, device_index, kind);
24
- }
25
-
26
- bool middleware::runtime_runner::final() {
27
- return this->impl_->final();
28
- }
29
-
30
- bool middleware::runtime_runner::load(const std::string& model_path) {
31
- return this->impl_->load(model_path);
32
- }
33
-
34
- bool middleware::runtime_runner::prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
35
- return this->impl_->prepare(input_cached, output_cached, group, batch);
36
- }
37
-
38
- bool middleware::runtime_runner::run(const bool& parallel) {
39
- return this->impl_->run(parallel);
40
- }
41
-
42
- uint32_t middleware::runtime_runner::get_input_count() const {
43
- return this->impl_->get_input_count();
44
- }
45
-
46
- uint32_t middleware::runtime_runner::get_output_count() const {
47
- return this->impl_->get_output_count();
48
- }
49
-
50
- std::string middleware::runtime_runner::get_input_name(const uint32_t& index) const {
51
- return this->impl_->get_input_name(index);
52
- }
53
-
54
- std::string middleware::runtime_runner::get_output_name(const uint32_t& index) const {
55
- return this->impl_->get_output_name(index);
56
- }
57
-
58
- void *middleware::runtime_runner::get_input_pointer(const uint32_t& index) const {
59
- return this->impl_->get_input_pointer(index);
60
- }
61
-
62
- void *middleware::runtime_runner::get_output_pointer(const uint32_t& index) const {
63
- return this->impl_->get_output_pointer(index);
64
- }
65
-
66
- uintmax_t middleware::runtime_runner::get_input_size(const uint32_t& index) const {
67
- return this->impl_->get_input_size(index);
68
- }
69
-
70
- uintmax_t middleware::runtime_runner::get_output_size(const uint32_t& index) const {
71
- return this->impl_->get_output_size(index);
72
- }
73
-
74
- uintmax_t middleware::runtime_runner::get_shape_group_count() const {
75
- return this->impl_->get_shape_group_count();
76
- }
77
-
78
- std::string middleware::runtime_runner::get_library_version() const {
79
- return impl::get_library_version();
80
- }
81
-
82
- std::string middleware::runtime_runner::get_model_version() const {
83
- return this->impl_->get_model_version();
84
- }
85
-
86
- int32_t middleware::runtime_runner::get_model_type() const {
87
- return this->impl_->get_model_type();
88
- }
89
-
90
- int32_t middleware::runtime_runner::get_npu_type() const {
91
- return this->impl_->get_npu_type();
92
- }
93
-
94
- int32_t middleware::runtime_runner::get_batch_size() const {
95
- return this->impl_->get_batch_size();
96
- }
97
-
98
- intmax_t middleware::runtime_runner::get_sys_usage() const {
99
- return this->impl_->get_sys_usage();
100
- }
101
-
102
- intmax_t middleware::runtime_runner::get_cmm_usage() const {
103
- return this->impl_->get_cmm_usage();
104
- }
105
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_runtime_runner.hpp DELETED
@@ -1,56 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include "middleware/axcl_base.hpp"
14
-
15
- namespace middleware {
16
-
17
- #if defined(ENV_AXCL_RUNTIME_API_ENABLE)
18
- class runtime_runner final : public axcl_base {
19
- public:
20
- runtime_runner();
21
- ~runtime_runner() override;
22
-
23
- [[nodiscard]] bool init(const std::string& config_file, const uint32_t& device_index, const uint32_t& kind) override;
24
- [[nodiscard]] bool final() override;
25
-
26
- [[nodiscard]] bool load(const std::string& model_path) override;
27
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) override;
28
-
29
- [[nodiscard]] bool run(const bool& parallel) override;
30
-
31
- [[nodiscard]] uint32_t get_input_count() const override;
32
- [[nodiscard]] uint32_t get_output_count() const override;
33
- [[nodiscard]] std::string get_input_name(const uint32_t& index) const override;
34
- [[nodiscard]] std::string get_output_name(const uint32_t& index) const override;
35
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) const override;
36
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) const override;
37
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) const override;
38
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) const override;
39
- [[nodiscard]] uintmax_t get_shape_group_count() const override;
40
-
41
- [[nodiscard]] std::string get_library_version() const override;
42
- [[nodiscard]] std::string get_model_version() const override;
43
-
44
- [[nodiscard]] int32_t get_model_type() const override;
45
- [[nodiscard]] int32_t get_npu_type() const override;
46
- [[nodiscard]] int32_t get_batch_size() const override;
47
- [[nodiscard]] intmax_t get_sys_usage() const override;
48
- [[nodiscard]] intmax_t get_cmm_usage() const override;
49
-
50
- private:
51
- struct impl;
52
- impl *impl_;
53
- };
54
- #endif
55
-
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/axcl_runtime_runner_impl.hpp DELETED
@@ -1,482 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include "middleware/axcl_runtime_runner.hpp"
14
-
15
- #include "middleware/axcl_base.hpp"
16
- #include "utilities/scalar_guard.hpp"
17
- #include "utilities/file.hpp"
18
- #include "utilities/log.hpp"
19
-
20
- #include <axcl.h>
21
-
22
- #if defined(ENV_AXCL_RUNTIME_API_ENABLE)
23
- struct middleware::runtime_runner::impl {
24
- impl() = default;
25
-
26
- ~impl() {
27
- std::ignore = this->final();
28
- }
29
-
30
- [[nodiscard]] bool init(const std::string& config_file, const uint32_t& index, const uint32_t& kind) {
31
- // 0. check the NPU kind
32
- if (kind > AXCL_VNPU_LITTLE_BIG) {
33
- utilities::glog.print(utilities::log::type::error,
34
- "Specified NPU kind{%d} is out of range{total %d}.\n", kind, static_cast<int>(AXCL_VNPU_LITTLE_BIG) + 1);
35
- return false;
36
- }
37
-
38
- // 1. build the npu init function
39
- auto npu_init_func = [&kind]() {
40
- if (const int ret = axclrtEngineInit(static_cast<axclrtEngineVNpuKind>(kind)); 0 != ret) {
41
- utilities::glog.print(utilities::log::type::error, "Init AXCLRT Engine as kind{%d} failed{0x%08X}.\n", kind, ret);
42
- return false;
43
- }
44
- utilities::glog.print(utilities::log::type::info, "AXCLRT Engine inited.\n");
45
- return true;
46
- };
47
-
48
- // 2. execute initialization
49
- if (const auto ret = axcl_base::init(config_file, index, npu_init_func); !ret) {
50
- return false;
51
- }
52
-
53
- // 3. set the flag
54
- this->is_initialized_ = true;
55
- return true;
56
- }
57
-
58
- [[nodiscard]] bool final() {
59
- auto flag = true;
60
-
61
- if (this->is_initialized_) {
62
- if (0 != this->model_id_) {
63
- for (auto& input : inputs_) {
64
- if (nullptr != input) {
65
- std::ignore = axclrtFree(input);
66
- input = nullptr;
67
- }
68
- }
69
- for (auto& output : outputs_) {
70
- if (nullptr != output) {
71
- std::ignore = axclrtFree(output);
72
- output = nullptr;
73
- }
74
- }
75
-
76
- flag &= 0 == axclrtEngineDestroyIOInfo(this->info_);
77
- flag &= 0 == axclrtEngineDestroyIO(this->io_);
78
- flag &= 0 == axclrtEngineUnload(this->model_id_);
79
- }
80
-
81
- flag &= 0 == axcl_base::final([&]() {
82
- if (const auto ret = axclrtEngineFinalize(); 0 != ret) {
83
- utilities::glog.print(utilities::log::type::error, "Final AXCLRT Engine failed{0x%08X}.\n", ret);
84
- return false;
85
- }
86
- utilities::glog.print(utilities::log::type::info, "AXCLRT Engine finalized.\n");
87
- return true;
88
- });
89
-
90
- this->is_initialized_ = false;
91
- }
92
-
93
- return flag;
94
- }
95
-
96
- [[nodiscard]] bool load(const std::string& model_path) {
97
- if (!this->is_initialized_) {
98
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
99
- return false;
100
- }
101
-
102
- if (0 != this->model_id_) {
103
- utilities::glog.print(utilities::log::type::error, "Model is already loaded.\n");
104
- return false;
105
- }
106
-
107
- if (!utilities::exists(model_path)
108
- || !utilities::is_regular_file(model_path)
109
- || 0 == utilities::file_size(model_path)
110
- || utilities::error_size == utilities::file_size(model_path)) {
111
- utilities::glog.print(utilities::log::type::error, "Model file{%s} error, please check it.\n", model_path.c_str());
112
- return false;
113
- }
114
-
115
- if (const auto ret = axclrtEngineLoadFromFile(model_path.c_str(), &this->model_id_); 0 != ret) {
116
- utilities::glog.print(utilities::log::type::error, "Create model{%s} handle failed.\n", model_path.c_str());
117
- return false;
118
- }
119
-
120
- if (const auto ret = axclrtEngineCreateContext(this->model_id_, &this->context_id_); 0 != ret) {
121
- utilities::glog.print(utilities::log::type::error, "Create model{%s} context failed.\n", model_path.c_str());
122
- return false;
123
- }
124
-
125
- return true;
126
- }
127
-
128
- [[nodiscard]] bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) {
129
- std::ignore = input_cached;
130
- std::ignore = output_cached;
131
-
132
- // 0. check the handle
133
- if (0 == this->model_id_) {
134
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
135
- return false;
136
- }
137
-
138
- // 1. get the IO info
139
- if (const auto ret = axclrtEngineGetIOInfo(this->model_id_, &this->info_); 0 != ret) {
140
- utilities::glog.print(utilities::log::type::error, "Get model io info failed{0x%08X}.\n", ret);
141
- return false;
142
- }
143
-
144
- // 2. get the count of shape group
145
- int32_t total_group = 0;
146
- if (const auto ret = axclrtEngineGetShapeGroupsCount(this->info_, &total_group); 0 != ret) {
147
- utilities::glog.print(utilities::log::type::error, "Get model shape group count failed{0x%08X}.\n", ret);
148
- return false;
149
- }
150
-
151
- // 3. check the group index
152
- if (group >= static_cast<decltype(group)>(total_group)) {
153
- utilities::glog.print(utilities::log::type::error, "Model group{%d} is out of range{total %d}.\n", group, total_group);
154
- return false;
155
- }
156
- this->group_ = static_cast<int32_t>(group);
157
-
158
- // 4. check the batch size
159
- this->batch_ = (0 == batch ? 1 : batch);
160
-
161
- // 5. get the count of inputs
162
- uint32_t input_count = 0;
163
- if (input_count = axclrtEngineGetNumInputs(this->info_); 0 == input_count) {
164
- utilities::glog.print(utilities::log::type::error, "Get model input count failed.\n");
165
- return false;
166
- }
167
-
168
- // 6. get the count of outputs
169
- uint32_t output_count = 0;
170
- if (output_count = axclrtEngineGetNumOutputs(this->info_); 0 == output_count) {
171
- utilities::glog.print(utilities::log::type::error, "Get model output count failed.\n");
172
- return false;
173
- }
174
-
175
- // 7. prepare the input and output
176
- this->inputs_.resize(input_count, nullptr);
177
- this->inputs_size_.resize(input_count, 0);
178
- this->outputs_.resize(output_count, nullptr);
179
- this->outputs_size_.resize(output_count, 0);
180
-
181
- // 8. prepare the memory, inputs
182
- for (uint32_t i = 0; i < input_count; i++) {
183
- uint32_t original_size = 0;
184
- if (original_size = axclrtEngineGetInputSizeByIndex(this->info_, group, i); 0 == original_size) {
185
- utilities::glog.print(utilities::log::type::error, "Get model input{index: %d} size failed.\n", i);
186
- return false;
187
- }
188
-
189
- this->inputs_size_[i] = original_size * this->batch_;
190
-
191
- if (const auto ret = axclrtMalloc(&this->inputs_[i], this->inputs_size_[i], axclrtMemMallocPolicy{}); 0 != ret) {
192
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor{index: %d} failed{0x%08X}.\n", i, ret);
193
- return false;
194
- }
195
- utilities::glog.print(utilities::log::type::info, "Memory for tensor{index: %d} is allocated.\n", i);
196
-
197
- // clean memory, some cases model may need to clean memory
198
- // axclrtMemset(this->inputs_[i], 0, size);
199
-
200
- utilities::glog.print(utilities::log::type::info,
201
- "Set tensor { index: %d, address: %p, size: %u Bytes }.\n", i, this->inputs_[i], this->inputs_size_[i]);
202
- }
203
-
204
- // 9. prepare the memory, outputs
205
- for (uint32_t i = 0; i < output_count; i++) {
206
- uint32_t original_size = 0;
207
- if (original_size = axclrtEngineGetOutputSizeByIndex(this->info_, group, i); 0 == original_size) {
208
- utilities::glog.print(utilities::log::type::error, "Get model output{index: %d} size failed.\n", i);
209
- return false;
210
- }
211
-
212
- this->outputs_size_[i] = original_size * this->batch_;
213
-
214
- if (const auto ret = axclrtMalloc(&this->outputs_[i], this->outputs_size_[i], axclrtMemMallocPolicy{}); 0 != ret) {
215
- utilities::glog.print(utilities::log::type::error, "Memory allocation for tensor{index: %d} failed{0x%08X}.\n", i, ret);
216
- return false;
217
- }
218
- utilities::glog.print(utilities::log::type::info, "Memory for tensor{index: %d} is allocated.\n", i);
219
-
220
- // clean memory, some cases model may need to clean memory
221
- // axclrtMemset(this->outputs_[i], 0, size);
222
-
223
- utilities::glog.print(utilities::log::type::info,
224
- "Set tensor { index: %d, address: %p, size: %u Bytes }.\n", i, this->outputs_[i], this->outputs_size_[i]);
225
- }
226
-
227
- // 10. create the IO
228
- if (const auto ret = axclrtEngineCreateIO(this->info_, &this->io_); 0 != ret) {
229
- utilities::glog.print(utilities::log::type::error, "Create model io failed{0x%08X}.\n", ret);
230
- return false;
231
- }
232
- utilities::glog.print(utilities::log::type::info, "AXCLRT Engine inited.\n");
233
-
234
- // 11. set the input and output buffer
235
- for (uint32_t i = 0; i < input_count; i++) {
236
- if (const auto ret = axclrtEngineSetInputBufferByIndex(this->io_, i, this->inputs_[i], this->inputs_size_[i]); 0 != ret) {
237
- utilities::glog.print(utilities::log::type::error, "Set input buffer{index: %d} failed{0x%08X}.\n", i, ret);
238
- return false;
239
- }
240
- }
241
- for (uint32_t i = 0; i < output_count; i++) {
242
- if (const auto ret = axclrtEngineSetOutputBufferByIndex(this->io_, i, this->outputs_[i], this->outputs_size_[i]); 0 != ret) {
243
- utilities::glog.print(utilities::log::type::error, "Set output buffer{index: %d} failed{0x%08X}.\n", i, ret);
244
- return false;
245
- }
246
- }
247
-
248
- // 12. set the batch size
249
- if (const auto ret = axclrtEngineSetDynamicBatchSize(this->io_, this->batch_); 0 != ret) {
250
- utilities::glog.print(utilities::log::type::error, "Set batch size{%d} failed{0x%08X}.\n", this->batch_, ret);
251
- return false;
252
- }
253
-
254
- return true;
255
- }
256
-
257
- [[nodiscard]] bool run(const bool& parallel) const {
258
- std::ignore = parallel;
259
-
260
- if (0 == this->model_id_ || 0 == this->context_id_) {
261
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
262
- return false;
263
- }
264
-
265
- if (nullptr == this->io_) {
266
- utilities::glog.print(utilities::log::type::error, "Model io is not set, prepare first.\n");
267
- return false;
268
- }
269
-
270
- if (const auto ret = axclrtEngineExecute(this->model_id_, this->context_id_, this->group_, this->io_); 0 != ret) {
271
- utilities::glog.print(utilities::log::type::error, "Run model failed{0x%08X}.\n", ret);
272
- return false;
273
- }
274
- utilities::glog.print(utilities::log::type::info, "Running done.\n");
275
-
276
- return true;
277
- }
278
-
279
- [[nodiscard]] uint32_t get_input_count() const {
280
- if (nullptr == this->info_) {
281
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
282
- return 0;
283
- }
284
-
285
- return axclrtEngineGetNumInputs(this->info_);
286
- }
287
-
288
- [[nodiscard]] uint32_t get_output_count() const {
289
- if (nullptr == this->info_) {
290
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
291
- return 0;
292
- }
293
-
294
- return axclrtEngineGetNumOutputs(this->info_);
295
- }
296
-
297
- [[nodiscard]] std::string get_input_name(const uint32_t& index) const {
298
- if (nullptr == this->info_) {
299
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
300
- return {};
301
- }
302
-
303
- if (index >= get_input_count()) {
304
- return {};
305
- }
306
- return std::string{axclrtEngineGetInputNameByIndex(this->info_, index)};
307
- }
308
-
309
- [[nodiscard]] std::string get_output_name(const uint32_t& index) const {
310
- if (nullptr == this->info_) {
311
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
312
- return {};
313
- }
314
-
315
- if (index >= get_output_count()) {
316
- return {};
317
- }
318
- return std::string{axclrtEngineGetOutputNameByIndex(this->info_, index)};
319
- }
320
-
321
- [[nodiscard]] void *get_input_pointer(const uint32_t& index) const {
322
- if (nullptr == this->info_) {
323
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
324
- return nullptr;
325
- }
326
-
327
- if (index >= get_input_count()) {
328
- return nullptr;
329
- }
330
- return this->inputs_[index];
331
- }
332
-
333
- [[nodiscard]] void *get_output_pointer(const uint32_t& index) const {
334
- if (nullptr == this->info_) {
335
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
336
- return nullptr;
337
- }
338
-
339
- if (index >= get_output_count()) {
340
- return nullptr;
341
- }
342
- return this->outputs_[index];
343
- }
344
-
345
- [[nodiscard]] uintmax_t get_input_size(const uint32_t& index) const {
346
- if (nullptr == this->info_) {
347
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
348
- return 0;
349
- }
350
-
351
- if (index >= get_input_count()) {
352
- return 0;
353
- }
354
- return axclrtEngineGetInputSizeByIndex(this->info_, this->group_, index);
355
- }
356
-
357
- [[nodiscard]] uintmax_t get_output_size(const uint32_t& index) const {
358
- if (nullptr == this->info_) {
359
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
360
- return 0;
361
- }
362
-
363
- if (index >= get_output_count()) {
364
- return 0;
365
- }
366
- return axclrtEngineGetOutputSizeByIndex(this->info_, this->group_, index);
367
- }
368
-
369
- [[nodiscard]] uintmax_t get_shape_group_count() const {
370
- if (nullptr == this->info_) {
371
- utilities::glog.print(utilities::log::type::error, "Model io info is not set, prepare first.\n");
372
- return 0;
373
- }
374
-
375
- int group = 0;
376
- if (const auto ret = axclrtEngineGetShapeGroupsCount(this->info_, &group); 0 != ret) {
377
- utilities::glog.print(utilities::log::type::error, "Get model shape group count failed{0x%08X}.\n", ret);
378
- return 0;
379
- }
380
- return group;
381
- }
382
-
383
- [[nodiscard]] static std::string get_library_version() {
384
- int32_t major = 0, minor = 0, patch = 0;
385
- if (const auto ret = axclrtGetVersion(&major, &minor, &patch); 0 != ret) {
386
- utilities::glog.print(utilities::log::type::error, "Get library version failed{0x%08X}.\n", ret);
387
- return "";
388
- }
389
- return {std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch)};
390
- }
391
-
392
- [[nodiscard]] std::string get_model_version() const {
393
- if (0 == this->model_id_) {
394
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
395
- return "";
396
- }
397
- return {axclrtEngineGetModelCompilerVersion(this->model_id_)};
398
- }
399
-
400
- [[nodiscard]] int32_t get_model_type() const {
401
- if (0 == this->model_id_) {
402
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
403
- return -1;
404
- }
405
-
406
- axclrtEngineModelKind type;
407
- if (const auto ret = axclrtEngineGetModelTypeFromModelId(this->model_id_, &type); 0 != ret) {
408
- utilities::glog.print(utilities::log::type::error, "Get model type failed{0x%08X}.\n", ret);
409
- return -1;
410
- }
411
- return type;
412
- }
413
-
414
- [[nodiscard]] int32_t get_npu_type() const {
415
- if (!this->is_initialized_) {
416
- utilities::glog.print(utilities::log::type::error, "axcl is not initialized.\n");
417
- return false;
418
- }
419
-
420
- axclrtEngineVNpuKind kind;
421
- if (const auto ret = axclrtEngineGetVNpuKind(&kind); 0 != ret) {
422
- utilities::glog.print(utilities::log::type::error, "Get visual NPU type failed{0x%08X}.\n", ret);
423
- return -1;
424
- }
425
- return kind;
426
- }
427
-
428
- [[nodiscard]] int32_t get_batch_size() const {
429
- if (0 == this->model_id_) {
430
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
431
- return -1;
432
- }
433
-
434
- return static_cast<int32_t>(this->batch_);
435
- }
436
-
437
- [[nodiscard]] intmax_t get_sys_usage() const {
438
- if (0 == this->model_id_) {
439
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
440
- return -1;
441
- }
442
-
443
- int64_t sys_size = 0, cmm_size = 0;
444
- if (const auto ret = axclrtEngineGetUsageFromModelId(this->model_id_, &sys_size, &cmm_size); 0 != ret) {
445
- utilities::glog.print(utilities::log::type::error, "Get model usage failed{0x%08X}.\n", ret);
446
- return -1;
447
- }
448
-
449
- return sys_size;
450
- }
451
-
452
- [[nodiscard]] intmax_t get_cmm_usage() const {
453
- if (0 == this->model_id_) {
454
- utilities::glog.print(utilities::log::type::error, "Model id is not set, load model first.\n");
455
- return -1;
456
- }
457
-
458
- int64_t sys_size = 0, cmm_size = 0;
459
- if (const auto ret = axclrtEngineGetUsageFromModelId(this->model_id_, &sys_size, &cmm_size); 0 != ret) {
460
- utilities::glog.print(utilities::log::type::error, "Get model usage failed{0x%08X}.\n", ret);
461
- return -1;
462
- }
463
-
464
- return cmm_size;
465
- }
466
-
467
- private:
468
- int32_t group_ = 0;
469
- uint32_t batch_ = 0;
470
-
471
- uint64_t model_id_{};
472
- uint64_t context_id_{};
473
- axclrtEngineIOInfo info_{};
474
- axclrtEngineIO io_{};
475
- std::vector<void*> inputs_;
476
- std::vector<void*> outputs_;
477
- std::vector<uintmax_t> inputs_size_;
478
- std::vector<uintmax_t> outputs_size_;
479
-
480
- bool is_initialized_ = false;
481
- };
482
- #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/runner.cc DELETED
@@ -1,88 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #include "middleware/runner.hpp"
12
-
13
- #include "utilities/file.hpp"
14
- #include "utilities/log.hpp"
15
-
16
- #include <chrono>
17
- #include <thread>
18
-
19
- void middleware::runner::sleep_for(const uint32_t sleep_duration) const {
20
- std::this_thread::sleep_for(std::chrono::milliseconds(sleep_duration));
21
- }
22
-
23
- std::vector<std::string> middleware::runner::read(const std::string& list_file) {
24
- if (!utilities::exists(list_file) || !utilities::is_regular_file(list_file)) {
25
- utilities::glog.print(utilities::log::type::error,
26
- "Stimulus list file{%s} is not exist.\n", list_file.c_str());
27
- return {};
28
- }
29
-
30
- std::vector<std::string> list;
31
-
32
- std::ifstream list_stream;
33
- list_stream.open(list_file, std::ios::in);
34
- if (!list_stream.is_open()) {
35
- utilities::glog.print(utilities::log::type::error,
36
- "Read stimulus list file{%s} failed.\n", list_file.c_str());
37
- return {};
38
- }
39
-
40
- std::string file_path;
41
- while (std::getline(list_stream, file_path)) {
42
- list.push_back(file_path);
43
- }
44
- list_stream.close();
45
-
46
- return list;
47
- }
48
-
49
- bool middleware::runner::read(const std::string& binary_file, void* address, const uintmax_t& size) {
50
- if (!utilities::exists(binary_file) || !utilities::is_regular_file(binary_file)) {
51
- utilities::glog.print(utilities::log::type::error,
52
- "Stimulus file{%s} is not exist.\n", binary_file.c_str());
53
- return false;
54
- }
55
-
56
- const auto file_size = utilities::file_size(binary_file);
57
- if (utilities::error_size == file_size) {
58
- utilities::glog.print(utilities::log::type::error, "Get stimulus file size failed.\n");
59
- return false;
60
- }
61
-
62
- if (file_size != size) {
63
- utilities::glog.print(utilities::log::type::error,
64
- "Size of stimulus file{%s} is not equal the specified{file: %d vs tensor: %d}.\n", binary_file.c_str(), file_size, size);
65
- return false;
66
- }
67
-
68
- return utilities::read(binary_file, address, size);
69
- }
70
-
71
- bool middleware::runner::write(const std::string& binary_file, const void* address, const uintmax_t& size) {
72
- return utilities::write(binary_file, address, size);
73
- }
74
-
75
- bool middleware::runner::verify(const void* dst, const void* src, const uintmax_t& size) {
76
- const auto* src_ptr = static_cast<const uint8_t*>(src);
77
- const auto* dst_ptr = static_cast<const uint8_t*>(dst);
78
-
79
- for (uintmax_t i = 0; i < size; i++) {
80
- if (src_ptr[i] != dst_ptr[i]) {
81
- utilities::glog.print(utilities::log::type::error,
82
- "Verify stimulus failed{offset: 0x%x; 0x%02X vs. 0x%02X}.\n", i, src_ptr[i], dst_ptr[i]);
83
- return false;
84
- }
85
- }
86
-
87
- return true;
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/middleware/runner.hpp DELETED
@@ -1,67 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <string>
14
- #include <vector>
15
- #include <cstdint>
16
-
17
- namespace middleware {
18
-
19
- class runner {
20
- public:
21
- runner() = default;
22
- virtual ~runner() = default;
23
-
24
- [[nodiscard]] virtual bool init(const std::string& config_file, const uint32_t& device_index, const uint32_t& kind) = 0;
25
- [[nodiscard]] virtual bool final() = 0;
26
-
27
- [[nodiscard]] virtual bool load(const std::string& model_path) = 0;
28
- [[nodiscard]] virtual bool prepare(const bool& input_cached, const bool& output_cached, const uint32_t& group, const uint32_t& batch) = 0;
29
-
30
- [[nodiscard]] virtual bool run(const bool& parallel) = 0;
31
-
32
- [[nodiscard]] virtual uint32_t get_input_count() const = 0;
33
- [[nodiscard]] virtual uint32_t get_output_count() const = 0;
34
- [[nodiscard]] virtual std::string get_input_name(const uint32_t& index) const = 0;
35
- [[nodiscard]] virtual std::string get_output_name(const uint32_t& index) const = 0;
36
- [[nodiscard]] virtual void *get_input_pointer(const uint32_t& index) const = 0;
37
- [[nodiscard]] virtual void *get_output_pointer(const uint32_t& index) const = 0;
38
- [[nodiscard]] virtual uintmax_t get_input_size(const uint32_t& index) const = 0;
39
- [[nodiscard]] virtual uintmax_t get_output_size(const uint32_t& index) const = 0;
40
-
41
- [[nodiscard]] virtual uintmax_t get_shape_group_count() const = 0;
42
-
43
- [[nodiscard]] virtual bool flush_input() const = 0;
44
- [[nodiscard]] virtual bool invalidate_output() const = 0;
45
-
46
- [[nodiscard]] virtual bool feed(const std::string& input_folder, const std::string& stimulus_name) const = 0;
47
- [[nodiscard]] virtual bool verify(const std::string& output_folder, const std::string& stimulus_name) const = 0;
48
- [[nodiscard]] virtual bool save(const std::string& output_folder, const std::string& stimulus_name) const = 0;
49
-
50
- [[nodiscard]] virtual std::string get_library_version() const = 0;
51
- [[nodiscard]] virtual std::string get_model_version() const = 0;
52
-
53
- [[nodiscard]] virtual int32_t get_model_type() const = 0;
54
- [[nodiscard]] virtual int32_t get_npu_type() const = 0;
55
- [[nodiscard]] virtual int32_t get_batch_size() const = 0;
56
- [[nodiscard]] virtual intmax_t get_sys_usage() const = 0;
57
- [[nodiscard]] virtual intmax_t get_cmm_usage() const = 0;
58
-
59
- virtual void sleep_for(uint32_t sleep_duration) const;
60
-
61
- [[nodiscard]] static std::vector<std::string> read(const std::string& list_file);
62
- [[nodiscard]] static bool read(const std::string& binary_file, void* address, const uintmax_t& size);
63
- [[nodiscard]] static bool write(const std::string& binary_file, const void* address, const uintmax_t& size);
64
- [[nodiscard]] static bool verify(const void* dst, const void* src, const uintmax_t& size);
65
- };
66
-
67
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/pinyin_table.hpp DELETED
The diff for this file is too large to render. See raw diff
 
cpp/src/tokenizer.cpp DELETED
@@ -1,306 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * Tokenizer implementation. Uses pinyin_table.hpp (auto-generated from pypinyin.pinyin_dict)
5
- * for Chinese character → pinyin token mapping, matching Python LocalEmiliaTokenizer output.
6
- **************************************************************************************************/
7
-
8
- #include "tokenizer.hpp"
9
- #include "src/pinyin_table.hpp"
10
-
11
- #include <fstream>
12
- #include <sstream>
13
- #include <regex>
14
- #include <cctype>
15
- #include <algorithm>
16
-
17
- Tokenizer::Tokenizer() : m_pad_id(0), m_loaded(false) {}
18
-
19
- int Tokenizer::Load(const std::string& token_file) {
20
- std::ifstream file(token_file);
21
- if (!file.is_open()) {
22
- printf("Failed to open token file: %s\n", token_file.c_str());
23
- return -1;
24
- }
25
-
26
- m_token2id.clear();
27
- std::string line;
28
- while (std::getline(file, line)) {
29
- if (line.empty()) continue;
30
- // Format: token\tid
31
- size_t tab_pos = line.rfind('\t');
32
- if (tab_pos == std::string::npos) continue;
33
-
34
- std::string token = line.substr(0, tab_pos);
35
- int id = std::stoi(line.substr(tab_pos + 1));
36
- m_token2id[token] = id;
37
- }
38
- file.close();
39
-
40
- // Build reverse mapping
41
- int max_id = 0;
42
- for (auto& kv : m_token2id) {
43
- if (kv.second > max_id) max_id = kv.second;
44
- }
45
- m_id2token.resize(max_id + 1);
46
- for (auto& kv : m_token2id) {
47
- m_id2token[kv.second] = kv.first;
48
- }
49
-
50
- auto it = m_token2id.find("_");
51
- if (it != m_token2id.end()) {
52
- m_pad_id = it->second;
53
- } else {
54
- m_pad_id = 0;
55
- printf("WARNING: pad token '_' not found in token file, using 0 as pad_id\n");
56
- }
57
-
58
- m_loaded = true;
59
- printf("Loaded %zu tokens from %s, pad_id=%d\n", m_token2id.size(), token_file.c_str(), m_pad_id);
60
- return 0;
61
- }
62
-
63
- int Tokenizer::TokenToId(const std::string& token) const {
64
- auto it = m_token2id.find(token);
65
- return (it != m_token2id.end()) ? it->second : m_pad_id;
66
- }
67
-
68
- bool Tokenizer::IsChinese(char c) {
69
- return (c >= 0x4E00 && c <= 0x9FFF);
70
- }
71
-
72
- bool Tokenizer::IsAlphabet(char c) {
73
- return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
74
- }
75
-
76
- std::string Tokenizer::MapPunctuation(const std::string& text) {
77
- // Map full-width Chinese punctuation to ASCII equivalents.
78
- // UTF-8 code points:
79
- // \xEF\xBC\x8C = U+FF0C (,) \xEF\xBC\x9A = U+FF1A (:)
80
- // \xE3\x80\x82 = U+3002 (。) \xE3\x80\x81 = U+3001 (、)
81
- // \xEF\xBC\x81 = U+FF01 (!) \xE2\x80\x9C = U+201C (")
82
- // \xEF\xBC\x9F = U+FF1F (?) \xE2\x80\x9D = U+201D (")
83
- // \xEF\xBC\x9B = U+FF1B (;) \xE2\x80\x98 = U+2018 (')
84
- // \xE2\x80\xA6 = U+2026 (…) \xE2\x80\x99 = U+2019 (')
85
- // \xE2\x8B\xAF = U+22EF (⋯)
86
- static const std::pair<std::string, std::string> replacements[] = {
87
- {"\xEF\xBC\x8C", ","}, // ,
88
- {"\xE3\x80\x82", "."}, // 。
89
- {"\xEF\xBC\x81", "!"}, // !
90
- {"\xEF\xBC\x9F", "?"}, // ?
91
- {"\xEF\xBC\x9B", ";"}, // ;
92
- {"\xEF\xBC\x9A", ":"}, // :
93
- {"\xE3\x80\x81", ","}, // 、
94
- {"\xE2\x80\x9C", "\""}, // "
95
- {"\xE2\x80\x9D", "\""}, // "
96
- {"\xE2\x80\x98", "'"}, // '
97
- {"\xE2\x80\x99", "'"}, // '
98
- {"\xE2\x80\xA6", "..."}, // …
99
- {"\xE2\x8B\xAF", "..."}, // ⋯
100
- };
101
- std::string result = text;
102
- for (auto& rep : replacements) {
103
- size_t pos = 0;
104
- while ((pos = result.find(rep.first, pos)) != std::string::npos) {
105
- result.replace(pos, rep.first.length(), rep.second);
106
- pos += rep.second.length();
107
- }
108
- }
109
- return result;
110
- }
111
-
112
- std::vector<std::pair<std::string, std::string>>
113
- Tokenizer::GetSegments(const std::string& text) const {
114
- std::vector<std::pair<std::string, std::string>> segments;
115
- if (text.empty()) return segments;
116
-
117
- std::string current;
118
- std::string current_lang;
119
-
120
- auto char_lang = [](char c) -> std::string {
121
- if (IsChinese(c)) return "zh";
122
- if (IsAlphabet(c)) return "en";
123
- return "other";
124
- };
125
-
126
- for (size_t i = 0; i < text.size(); ) {
127
- // Handle UTF-8 multi-byte characters
128
- size_t char_len = 1;
129
- unsigned char c = static_cast<unsigned char>(text[i]);
130
- if ((c & 0x80) == 0) char_len = 1;
131
- else if ((c & 0xE0) == 0xC0) char_len = 2;
132
- else if ((c & 0xF0) == 0xE0) char_len = 3;
133
- else if ((c & 0xF8) == 0xF0) char_len = 4;
134
-
135
- std::string ch = text.substr(i, char_len);
136
- std::string lang;
137
-
138
- if (char_len > 1) {
139
- lang = "zh"; // Assume multi-byte UTF-8 is Chinese
140
- } else if (IsAlphabet(ch[0])) {
141
- lang = "en";
142
- } else {
143
- lang = "other";
144
- }
145
-
146
- if (current.empty()) {
147
- current = ch;
148
- current_lang = lang;
149
- } else if (current_lang == "other" || lang == "other" || current_lang == lang) {
150
- current += ch;
151
- if (current_lang == "other" && lang != "other") current_lang = lang;
152
- } else {
153
- segments.push_back({current, current_lang});
154
- current = ch;
155
- current_lang = lang;
156
- }
157
- i += char_len;
158
- }
159
- if (!current.empty()) {
160
- segments.push_back({current, current_lang});
161
- }
162
- return segments;
163
- }
164
-
165
- std::vector<std::string> Tokenizer::TokenizeZh(const std::string& text) const {
166
- // Character-by-character pinyin tokenization using pinyin_table.hpp.
167
- // Matches Python LocalEmiliaTokenizer (without jieba word segmentation).
168
- std::vector<std::string> tokens;
169
- std::string normalized = MapPunctuation(text);
170
-
171
- for (size_t i = 0; i < normalized.size(); ) {
172
- unsigned char c = static_cast<unsigned char>(normalized[i]);
173
- size_t char_len = 1;
174
- if ((c & 0x80) == 0) char_len = 1;
175
- else if ((c & 0xE0) == 0xC0) char_len = 2;
176
- else if ((c & 0xF0) == 0xE0) char_len = 3;
177
- else if ((c & 0xF8) == 0xF0) char_len = 4;
178
-
179
- std::string ch = normalized.substr(i, char_len);
180
- i += char_len;
181
-
182
- // Punctuation or ASCII
183
- if (char_len == 1) {
184
- std::string mapped = MapPunctuation(ch);
185
- if (mapped != ch && m_token2id.find(mapped) != m_token2id.end()) {
186
- tokens.push_back(mapped);
187
- continue;
188
- }
189
- if (m_token2id.find(ch) != m_token2id.end()) {
190
- tokens.push_back(ch);
191
- continue;
192
- }
193
- }
194
-
195
- // Chinese character: lookup pinyin token IDs via generated table
196
- if (char_len == 3) {
197
- uint32_t cp = ((unsigned char)ch[0] & 0x0F) << 12
198
- | ((unsigned char)ch[1] & 0x3F) << 6
199
- | ((unsigned char)ch[2] & 0x3F);
200
- auto ids = pinyin_lookup(cp);
201
- for (int tid : ids) {
202
- if (tid >= 0 && tid < (int)m_id2token.size() && !m_id2token[tid].empty()) {
203
- tokens.push_back(m_id2token[tid]);
204
- }
205
- }
206
- }
207
- }
208
- return tokens;
209
- }
210
-
211
- std::vector<std::string> Tokenizer::TokenizeEn(const std::string& text) const {
212
- // Simplified English tokenization: character-by-character phoneme mapping
213
- // In production, use the Python tokenizer with piper_phonemize
214
- std::vector<std::string> tokens;
215
- std::string lower = text;
216
- std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
217
- lower = MapPunctuation(lower);
218
-
219
- for (size_t i = 0; i < lower.size(); ++i) {
220
- char c = lower[i];
221
- if (c == ' ') continue;
222
- if (ispunct(c)) {
223
- // Map common punctuation
224
- switch (c) {
225
- case ',': tokens.push_back(","); break;
226
- case '.': tokens.push_back("."); break;
227
- case '!': tokens.push_back("!"); break;
228
- case '?': tokens.push_back("?"); break;
229
- case ';': tokens.push_back(";"); break;
230
- case ':': tokens.push_back(":"); break;
231
- case '\'': tokens.push_back("'"); break;
232
- case '"': tokens.push_back("\""); break;
233
- default: break;
234
- }
235
- continue;
236
- }
237
- // Output character as-is (phoneme-based tokens)
238
- std::string token(1, c);
239
- if (m_token2id.find(token) != m_token2id.end()) {
240
- tokens.push_back(token);
241
- }
242
- }
243
- return tokens;
244
- }
245
-
246
- std::vector<int> Tokenizer::TextToTokenIds(const std::string& text) const {
247
- if (!m_loaded) return {};
248
-
249
- std::string normalized = MapPunctuation(text);
250
- auto segments = GetSegments(normalized);
251
-
252
- std::vector<int> token_ids;
253
- for (auto& seg : segments) {
254
- std::vector<std::string> tokens;
255
- if (seg.second == "zh") {
256
- tokens = TokenizeZh(seg.first);
257
- } else if (seg.second == "en") {
258
- tokens = TokenizeEn(seg.first);
259
- }
260
- // "other" segments: try individual chars as tokens
261
- else {
262
- for (char c : seg.first) {
263
- std::string token(1, c);
264
- if (m_token2id.find(token) != m_token2id.end()) {
265
- token_ids.push_back(m_token2id.at(token));
266
- }
267
- }
268
- continue;
269
- }
270
-
271
- for (auto& token : tokens) {
272
- auto it = m_token2id.find(token);
273
- if (it != m_token2id.end()) {
274
- token_ids.push_back(it->second);
275
- }
276
- }
277
- }
278
- return token_ids;
279
- }
280
-
281
- std::vector<std::vector<int>> Tokenizer::TextsToTokenIds(const std::vector<std::string>& texts) const {
282
- std::vector<std::vector<int>> result;
283
- result.reserve(texts.size());
284
- for (auto& text : texts) {
285
- result.push_back(TextToTokenIds(text));
286
- }
287
- return result;
288
- }
289
-
290
- void Tokenizer::BuildCatTokens(const std::vector<int>& prompt_tokens,
291
- const std::vector<int>& text_tokens,
292
- int max_tokens,
293
- std::vector<int32_t>& out_cat_tokens) const {
294
- out_cat_tokens.assign(max_tokens, static_cast<int32_t>(m_pad_id));
295
-
296
- size_t pos = 0;
297
- for (size_t i = 0; i < prompt_tokens.size() && pos < (size_t)max_tokens; ++i) {
298
- out_cat_tokens[pos++] = static_cast<int32_t>(prompt_tokens[i]);
299
- }
300
- for (size_t i = 0; i < text_tokens.size() && pos < (size_t)max_tokens; ++i) {
301
- out_cat_tokens[pos++] = static_cast<int32_t>(text_tokens[i]);
302
- }
303
- if (pos < (size_t)max_tokens) {
304
- out_cat_tokens[pos] = static_cast<int32_t>(m_pad_id);
305
- }
306
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/tokenizer.hpp DELETED
@@ -1,79 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * Tokenizer: loads tokens.txt and maps token strings to IDs.
5
- *
6
- * For board deployment, tokenization should ideally be done on a host machine
7
- * and token IDs passed directly. This class provides basic tokenization
8
- * capability for convenience.
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <string>
14
- #include <vector>
15
- #include <unordered_map>
16
- #include <cstdint>
17
-
18
- class Tokenizer {
19
- public:
20
- Tokenizer();
21
-
22
- /**
23
- * Load tokens.txt file. Format: token\tid per line.
24
- */
25
- int Load(const std::string& token_file);
26
-
27
- /**
28
- * Convert a single text to token IDs using simplified rules.
29
- * For production use, pre-compute token IDs with the Python tokenizer.
30
- */
31
- std::vector<int> TextToTokenIds(const std::string& text) const;
32
-
33
- /**
34
- * Convert multiple texts to token IDs.
35
- */
36
- std::vector<std::vector<int>> TextsToTokenIds(const std::vector<std::string>& texts) const;
37
-
38
- /**
39
- * Get the pad token ID ("_" token).
40
- */
41
- int GetPadId() const { return m_pad_id; }
42
-
43
- /**
44
- * Get vocabulary size.
45
- */
46
- int GetVocabSize() const { return static_cast<int>(m_token2id.size()); }
47
-
48
- /**
49
- * Lookup a single token. Returns pad_id if not found.
50
- */
51
- int TokenToId(const std::string& token) const;
52
-
53
- /**
54
- * Build concatenated token array [prompt_tokens + text_tokens + pad] padded to max_tokens.
55
- */
56
- void BuildCatTokens(const std::vector<int>& prompt_tokens,
57
- const std::vector<int>& text_tokens,
58
- int max_tokens,
59
- std::vector<int32_t>& out_cat_tokens) const;
60
-
61
- bool IsLoaded() const { return m_loaded; }
62
-
63
- private:
64
- std::unordered_map<std::string, int> m_token2id;
65
- std::vector<std::string> m_id2token;
66
- int m_pad_id;
67
- bool m_loaded;
68
-
69
- // Simplified text→tokens for Chinese (char-by-char pinyin-like tokens)
70
- std::vector<std::string> TokenizeZh(const std::string& text) const;
71
- // Simplified text→tokens for English (basic phoneme rules)
72
- std::vector<std::string> TokenizeEn(const std::string& text) const;
73
- // Split text into language segments
74
- std::vector<std::pair<std::string, std::string>> GetSegments(const std::string& text) const;
75
-
76
- static bool IsChinese(char c);
77
- static bool IsAlphabet(char c);
78
- static std::string MapPunctuation(const std::string& text);
79
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/file.hpp DELETED
@@ -1,251 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <fstream>
14
- #include <cctype>
15
-
16
- #if defined(ENV_HAS_STD_FILESYSTEM)
17
- #include <filesystem>
18
- #endif // ENV_HAS_STD_FILESYSTEM
19
- #if defined(ENV_HAS_POSIX_FILE_STAT)
20
- #include <sys/types.h>
21
- #include <sys/stat.h>
22
- #include <dirent.h>
23
- #include <cstring>
24
- #include "utilities/scalar_guard.hpp"
25
- #endif // ENV_HAS_POSIX_FILE_STAT
26
- #if defined(ENV_HAS_WIN_API)
27
- #include <Windows.h>
28
- #endif // ENV_HAS_WIN_API
29
-
30
- #include <string>
31
-
32
- namespace utilities {
33
- constexpr auto error_size = static_cast<uintmax_t>(-1);
34
-
35
- enum class file_type {
36
- none,
37
- not_found,
38
- regular,
39
- directory,
40
- symlink,
41
- block,
42
- character,
43
- fifo,
44
- socket,
45
- unknown,
46
- };
47
-
48
- inline bool exists(const std::string& path) {
49
- #if defined(ENV_HAS_STD_FILESYSTEM)
50
- return std::filesystem::exists(path);
51
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
52
- struct ::stat path_stat{};
53
- return 0 == ::stat(path.c_str(), &path_stat);
54
- #else
55
- #error "Unsupported platform, native file system API is required."
56
- #endif
57
- }
58
-
59
- inline uintmax_t file_size(const std::string& path) {
60
- #if defined(ENV_HAS_STD_FILESYSTEM)
61
- return std::filesystem::file_size(path);
62
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
63
- struct ::stat path_stat{};
64
- if (0 == ::stat(path.c_str(), &path_stat)) {
65
- return path_stat.st_size;
66
- }
67
- return error_size;
68
- #else
69
- #error "Unsupported platform, native file system API is required."
70
- #endif
71
- }
72
-
73
- inline file_type status(const std::string& path) {
74
- #if defined(ENV_HAS_STD_FILESYSTEM)
75
- if (!exists(path)) {
76
- return file_type::not_found;
77
- }
78
-
79
- const auto status = std::filesystem::status(path);
80
- if (std::filesystem::is_regular_file(status)) {
81
- return file_type::regular;
82
- }
83
- if (std::filesystem::is_directory(status)) {
84
- return file_type::directory;
85
- }
86
- if (std::filesystem::is_symlink(status)) {
87
- return file_type::symlink;
88
- }
89
- if (std::filesystem::is_block_file(status)) {
90
- return file_type::block;
91
- }
92
- if (std::filesystem::is_character_file(status)) {
93
- return file_type::character;
94
- }
95
- if (std::filesystem::is_fifo(status)) {
96
- return file_type::fifo;
97
- }
98
- if (std::filesystem::is_socket(status)) {
99
- return file_type::socket;
100
- }
101
- return file_type::unknown;
102
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
103
- struct ::stat path_stat{};
104
- if (0 != ::stat(path.c_str(), &path_stat)) {
105
- return file_type::not_found;
106
- }
107
-
108
- if (S_ISREG(path_stat.st_mode)) {
109
- return file_type::regular;
110
- }
111
- if (S_ISDIR(path_stat.st_mode)) {
112
- return file_type::directory;
113
- }
114
- if (S_ISLNK(path_stat.st_mode)) {
115
- return file_type::symlink;
116
- }
117
- if (S_ISBLK(path_stat.st_mode)) {
118
- return file_type::block;
119
- }
120
- if (S_ISCHR(path_stat.st_mode)) {
121
- return file_type::character;
122
- }
123
- if (S_ISFIFO(path_stat.st_mode)) {
124
- return file_type::fifo;
125
- }
126
- if (S_ISSOCK(path_stat.st_mode)) {
127
- return file_type::socket;
128
- }
129
- return file_type::unknown;
130
- #else
131
- #error "Unsupported platform, native file system API is required."
132
- #endif
133
- }
134
-
135
- inline bool is_regular_file(const std::string& path) {
136
- #if defined(ENV_HAS_STD_FILESYSTEM)
137
- return std::filesystem::is_regular_file(path);
138
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
139
- struct ::stat path_stat{};
140
- return 0 == ::stat(path.c_str(), &path_stat) && S_ISREG(path_stat.st_mode);
141
- #else
142
- #error "Unsupported platform, native file system API is required."
143
- #endif
144
- }
145
-
146
- inline bool is_directory(const std::string& path) {
147
- #if defined(ENV_HAS_STD_FILESYSTEM)
148
- return std::filesystem::is_directory(path);
149
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
150
- struct ::stat path_stat{};
151
- return 0 == ::stat(path.c_str(), &path_stat) && S_ISDIR(path_stat.st_mode);
152
- #else
153
- #error "Unsupported platform, native file system API is required."
154
- #endif
155
- }
156
-
157
- inline bool is_empty(const std::string& path) {
158
- #if defined(ENV_HAS_STD_FILESYSTEM)
159
- return std::filesystem::is_empty(path);
160
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
161
- if (!exists(path))
162
- return false;
163
-
164
- if (is_regular_file(path))
165
- return 0 == file_size(path);
166
- if (is_directory(path)) {
167
- auto dir = scalar_guard<DIR*>(::opendir(path.c_str()), ::closedir);
168
- if (nullptr == dir.get()) {
169
- return false;
170
- }
171
-
172
- struct ::dirent* entry;
173
- while ((entry = ::readdir(dir.get())) != nullptr) {
174
- if (0 != ::strcmp(entry->d_name, ".") && 0 != ::strcmp(entry->d_name, "..")) {
175
- return false;
176
- }
177
- }
178
- return true;
179
- }
180
- return false;
181
- #else
182
- #error "Unsupported platform, native file system API is required."
183
- #endif
184
- }
185
-
186
- inline bool read(const std::string& file, void* data, const uintmax_t& size) {
187
- std::ifstream stream;
188
- stream.open(file, std::ios_base::binary | std::ios_base::in);
189
- if (stream.is_open()) {
190
- stream.read(static_cast<char*>(data), static_cast<std::streamsize>(size));
191
- stream.close();
192
- return true;
193
- }
194
- return false;
195
- }
196
-
197
- inline bool write(const std::string& file, const void* data, const uintmax_t& size) {
198
- std::ofstream stream;
199
- stream.open(file, std::ios_base::binary | std::ios_base::out);
200
- if (stream.is_open()) {
201
- stream.write(static_cast<const char*>(data), static_cast<std::streamsize>(size));
202
- stream.close();
203
- return true;
204
- }
205
- return false;
206
- }
207
-
208
- inline bool create_directory(const std::string& path) {
209
- #if defined(ENV_HAS_STD_FILESYSTEM)
210
- return std::filesystem::create_directories(path);
211
- #elif defined(ENV_HAS_POSIX_FILE_STAT)
212
- return 0 == ::mkdir(path.c_str(), 0755);
213
- #else
214
- #error "Unsupported platform, native file system API is required."
215
- #endif
216
- }
217
-
218
- inline std::string get_file_name(const std::string& file) {
219
- #if defined(ENV_HAS_STD_FILESYSTEM)
220
- return std::filesystem::path(file).filename().string();
221
- #else
222
- if (const auto pos = file.find_last_of("/\\"); std::string::npos != pos) {
223
- return file.substr(pos + 1);
224
- }
225
- return file;
226
- #endif
227
- }
228
-
229
- inline std::string get_file_extension(const std::string& file) {
230
- #if defined(ENV_HAS_STD_FILESYSTEM)
231
- return std::filesystem::path(file).extension().string();
232
- #else
233
- if (const auto pos = file.find_last_of('.'); std::string::npos != pos) {
234
- return file.substr(pos + 1);
235
- }
236
- return "";
237
- #endif
238
- }
239
-
240
- inline std::string get_legal_name(const std::string& name) {
241
- std::string temp = name;
242
-
243
- size_t pos = temp.find_last_of("/\\");
244
- if (pos != std::string::npos) pos = 0;
245
-
246
- for (size_t i = pos; i < temp.size(); ++i)
247
- if (!(::isalnum(temp[i]) || '-' == temp[i] || '_' == temp[i])) temp[i] = '_';
248
- return temp;
249
- }
250
-
251
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/file_mapper.hpp DELETED
@@ -1,86 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #if defined(ENV_HAS_POSIX_FILE_STAT)
14
- #include "utilities/scalar_guard.hpp"
15
- #include <sys/mman.h>
16
- #include <fcntl.h>
17
- #include <unistd.h>
18
- #endif // ENV_HAS_POSIX_FILE_STAT
19
-
20
- #if defined(ENV_HAS_WIN_API)
21
- #include <Windows.h>
22
- #endif // ENV_HAS_WIN_API
23
-
24
- #include <utilities/file.hpp>
25
-
26
- namespace utilities {
27
-
28
- struct file_mapper {
29
- file_mapper() = delete;
30
-
31
- explicit file_mapper(const std::string& path) {
32
- #if defined(ENV_HAS_POSIX_FILE_STAT)
33
-
34
- auto fd_guard = scalar_guard<int>(
35
- ::open(path.c_str(), O_RDONLY),
36
- [](const int& fd) { if (fd != -1) ::close(fd); }
37
- );
38
-
39
- if (-1 == fd_guard.get()) {
40
- return;
41
- }
42
-
43
- auto size = file_size(path);
44
- auto map_guard = scalar_guard<void*>(
45
- ::mmap(nullptr, size, PROT_READ, MAP_SHARED, fd_guard.get(), 0),
46
- [&size](void*& addr) { if (MAP_FAILED != addr && nullptr != addr) ::munmap(addr, size); }
47
- );
48
-
49
- if (MAP_FAILED == map_guard.get()) {
50
- return;
51
- }
52
-
53
- this->size_ = size;
54
- std::swap(this->fd_, fd_guard.get());
55
- std::swap(this->buffer_, map_guard.get());
56
- #endif // ENV_HAS_POSIX_FILE_STAT
57
- }
58
-
59
- ~file_mapper() {
60
- #if defined(ENV_HAS_POSIX_FILE_STAT)
61
- if (nullptr != this->buffer_) {
62
- ::munmap(this->buffer_, this->size_);
63
- this->buffer_ = nullptr;
64
- }
65
- if (-1 != this->fd_) {
66
- ::close(this->fd_);
67
- this->fd_ = -1;
68
- }
69
- #endif // ENV_HAS_POSIX_FILE_STAT
70
- }
71
-
72
- [[nodiscard]] void* get() const {
73
- return this->buffer_;
74
- }
75
-
76
- [[nodiscard]] uint64_t size() const {
77
- return this->size_;
78
- }
79
-
80
- private:
81
- int fd_ = -1;
82
- void* buffer_ = nullptr;
83
- uint64_t size_ = 0;
84
- };
85
-
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/log.hpp DELETED
@@ -1,64 +0,0 @@
1
- /*
2
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
3
- *
4
- * This source file is the property of Axera Semiconductor Co., Ltd. and
5
- * may not be copied or distributed in any isomorphic form without the prior
6
- * written consent of Axera Semiconductor Co., Ltd.
7
- *
8
- * Author: wanglusheng@axera-tech.com
9
- */
10
-
11
- #pragma once
12
-
13
- #include <cstdarg>
14
- #include <cstdio>
15
-
16
- namespace utilities {
17
- class log
18
- {
19
- public:
20
- enum class type {
21
- debug = 0,
22
- info = 1,
23
- warn = 2,
24
- error = 3,
25
- };
26
-
27
- log() = default;
28
- explicit log(const type& mode) : type_(mode) {}
29
- ~log() = default;
30
-
31
- void print(const type& mode, const char *fmt, ...) const {
32
- if (mode >= this->type_) {
33
- switch (mode) {
34
- case type::debug:
35
- ::fprintf(stdout, "[DEBUG] ");
36
- break;
37
- case type::info:
38
- ::fprintf(stdout, "[INFO] ");
39
- break;
40
- case type::warn:
41
- ::fprintf(stdout, "[WARNING] ");
42
- break;
43
- case type::error:
44
- ::fprintf(stdout, "[ERROR] ");
45
- break;
46
- }
47
-
48
- ::va_list args;
49
- va_start(args, fmt);
50
- ::vprintf( fmt, args);
51
- va_end(args);
52
- }
53
- ::fflush(stdout);
54
- }
55
- void set_level(const type& mode) {
56
- this->type_ = mode;
57
- }
58
-
59
- private:
60
- type type_ = type::warn;
61
- };
62
-
63
- static log glog;
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/scalar_guard.hpp DELETED
@@ -1,60 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <functional>
14
- #include <vector>
15
- #include <utility>
16
- #include <stdexcept>
17
-
18
- namespace utilities {
19
-
20
- template<typename T>
21
- class scalar_guard {
22
- public:
23
- scalar_guard() = delete;
24
-
25
- scalar_guard(T resource, std::function<void(T&)> destructor)
26
- : instance_(resource), destructor_(std::move(destructor)) {}
27
-
28
- scalar_guard(std::function<T()> resource_creator, std::function<void(T&)> destructor)
29
- : instance_(resource_creator()), destructor_(std::move(destructor)) {}
30
-
31
- scalar_guard(scalar_guard&& other) noexcept
32
- : instance_(std::exchange(other.instance_, T{})), destructor_(std::move(other.destructor_)) {}
33
-
34
- scalar_guard& operator=(scalar_guard&& other) noexcept {
35
- if (this != &other) {
36
- instance_ = std::exchange(other.instance_, T{});
37
- destructor_ = std::move(other.destructor_);
38
- }
39
- return *this;
40
- }
41
-
42
- scalar_guard(const scalar_guard&) = delete;
43
- scalar_guard& operator=(const scalar_guard&) = delete;
44
-
45
- ~scalar_guard() noexcept {
46
- if (destructor_) {
47
- destructor_(instance_);
48
- }
49
- }
50
-
51
- T& get() {
52
- return instance_;
53
- }
54
-
55
- private:
56
- T instance_;
57
- std::function<void(T&)> destructor_;
58
- };
59
-
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/timer.hpp DELETED
@@ -1,84 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <chrono>
14
-
15
- namespace utilities {
16
-
17
- class timer {
18
- public:
19
- using nanoseconds = std::chrono::nanoseconds;
20
- using microseconds = std::chrono::microseconds;
21
- using milliseconds = std::chrono::milliseconds;
22
- using seconds = std::chrono::seconds;
23
- using minutes = std::chrono::minutes;
24
- using hours = std::chrono::hours;
25
-
26
- timer() {
27
- start();
28
- }
29
-
30
- void start() {
31
- stop();
32
- this->start_ = this->end_;
33
- }
34
-
35
- void stop() {
36
- #ifdef _MSC_VER
37
- this->end_ = std::chrono::system_clock::now();
38
- #else
39
- this->end_ = std::chrono::high_resolution_clock::now();
40
- #endif
41
- }
42
-
43
- template<typename T>
44
- float elapsed() {
45
- if (this->end_ <= this->start_) {
46
- this->stop();
47
- }
48
-
49
- if (std::is_same_v<T, std::chrono::nanoseconds>) {
50
- const auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(this->end_ - this->start_).count();
51
- return static_cast<float>(t);
52
- }
53
- if (std::is_same_v<T, std::chrono::microseconds>) {
54
- const auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(this->end_ - this->start_).count();
55
- return static_cast<float>(t) / 1000.f;
56
- }
57
- if (std::is_same_v<T, std::chrono::milliseconds>) {
58
- const auto t = std::chrono::duration_cast<std::chrono::microseconds>(this->end_ - this->start_).count();
59
- return static_cast<float>(t) / 1000.f;
60
- }
61
- if (std::is_same_v<T, std::chrono::seconds>) {
62
- const auto t = std::chrono::duration_cast<std::chrono::milliseconds>(this->end_ - this->start_).count();
63
- return static_cast<float>(t) / 1000.f;
64
- }
65
- if (std::is_same_v<T, std::chrono::minutes>) {
66
- const auto t = std::chrono::duration_cast<std::chrono::milliseconds>(this->end_ - this->start_).count();
67
- return static_cast<float>(t) / (60.f * 1000.f);
68
- }
69
- if (std::is_same_v<T, std::chrono::hours>) {
70
- const auto t = std::chrono::duration_cast<std::chrono::seconds>(this->end_ - this->start_).count();
71
- return static_cast<float>(t) / (60.f * 60.f);
72
- }
73
- return 0.f;
74
- }
75
-
76
- float elapsed() {
77
- return elapsed<std::chrono::milliseconds>();
78
- }
79
-
80
- private:
81
- std::chrono::system_clock::time_point start_, end_;
82
- };
83
-
84
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/utilities/vector_guard.hpp DELETED
@@ -1,64 +0,0 @@
1
- /**************************************************************************************************
2
- *
3
- * Copyright (c) 2019-2024 Axera Semiconductor Co., Ltd. All Rights Reserved.
4
- *
5
- * This source file is the property of Axera Semiconductor Co., Ltd. and
6
- * may not be copied or distributed in any isomorphic form without the prior
7
- * written consent of Axera Semiconductor Co., Ltd.
8
- *
9
- **************************************************************************************************/
10
-
11
- #pragma once
12
-
13
- #include <functional>
14
- #include <vector>
15
-
16
- namespace utilities {
17
-
18
- template<typename T>
19
- class vector_guard {
20
- public:
21
- vector_guard() = delete;
22
-
23
- vector_guard(std::vector<T> resources, std::function<void(T&)> destructor)
24
- : instance_(std::move(resources)), destructor_(std::move(destructor)) {}
25
-
26
- vector_guard(std::function<std::vector<T>()> resource_creator, std::function<void(T&)> destructor)
27
- : instance_(resource_creator()), destructor_(std::move(destructor)) {}
28
-
29
- vector_guard(vector_guard&& other) noexcept
30
- : instance_(std::exchange(other.instance_, std::vector<T>{})), destructor_(std::move(other.destructor_)) {}
31
-
32
- vector_guard& operator=(vector_guard&& other) noexcept {
33
- if (this != &other) {
34
- instance_ = std::exchange(other.instance_, std::vector<T>{});
35
- destructor_ = std::move(other.destructor_);
36
- }
37
- return *this;
38
- }
39
-
40
- vector_guard(const vector_guard&) = delete;
41
- vector_guard& operator=(const vector_guard&) = delete;
42
-
43
- ~vector_guard() noexcept {
44
- if (destructor_) {
45
- for (auto& resource : instance_) {
46
- destructor_(resource);
47
- }
48
- }
49
- }
50
-
51
- std::vector<T>& get() {
52
- return instance_;
53
- }
54
-
55
- T* data() {
56
- return instance_.data();
57
- }
58
-
59
- private:
60
- std::vector<T> instance_;
61
- std::function<void(T&)> destructor_;
62
- };
63
-
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/vocoder.cpp DELETED
@@ -1,153 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * Vocoder implementation using kissfft for fast IRFFT.
5
- **************************************************************************************************/
6
-
7
- #include "src/vocoder.hpp"
8
-
9
- #include <cmath>
10
- #include <cstring>
11
- #include <cstdio>
12
- #include <algorithm>
13
-
14
- #ifndef M_PI
15
- #define M_PI 3.14159265358979323846
16
- #endif
17
-
18
- Vocoder::Vocoder() : m_has_init(false), m_n_freqs(0) {}
19
- Vocoder::~Vocoder() {
20
- m_session.reset();
21
- if (m_fft_cfg) { rnn_fft_free(m_fft_cfg, 0); m_fft_cfg = nullptr; }
22
- m_ifft_cfg = nullptr; // shared with m_fft_cfg
23
- }
24
-
25
- int Vocoder::Init(const Config& cfg) {
26
- m_cfg = cfg;
27
- m_n_freqs = cfg.n_fft / 2 + 1; // 513
28
-
29
- BuildWindow();
30
-
31
- // Init kissfft once
32
- m_fft_cfg = rnn_fft_alloc(cfg.n_fft, NULL, NULL, 0);
33
- if (!m_fft_cfg) {
34
- printf("Failed to init kissfft for vocoder\n");
35
- return -1;
36
- }
37
- m_ifft_cfg = m_fft_cfg;
38
-
39
- // Load vocos_full.axmodel
40
- m_session = std::make_unique<EngineWrapper>();
41
- if (m_session->Init(cfg.model_path.c_str(), 0, cfg.axclConfig) != 0) {
42
- printf("Failed to load vocoder model: %s\n", cfg.model_path.c_str());
43
- return -1;
44
- }
45
-
46
- m_has_init = true;
47
- printf("Vocoder initialized: n_fft=%d, hop=%d, n_mels=%d\n",
48
- cfg.n_fft, cfg.hop_length, cfg.n_mels);
49
- return 0;
50
- }
51
-
52
- void Vocoder::BuildWindow() {
53
- int n = m_cfg.n_fft;
54
- m_window.resize(n);
55
- m_window_sq.resize(n);
56
- for (int i = 0; i < n; ++i) {
57
- m_window[i] = 0.5f * (1.0f - std::cos(2.0f * M_PI * i / (n - 1)));
58
- m_window_sq[i] = m_window[i] * m_window[i];
59
- }
60
- }
61
-
62
- int Vocoder::Decode(const std::vector<float>& mel, int T, float feat_scale, std::vector<float>& audio) {
63
- if (!m_has_init || mel.empty()) return -1;
64
-
65
- int feat_dim = m_cfg.n_mels; // 100
66
- int n_fft = m_cfg.n_fft; // 1024
67
- int n_freqs = m_n_freqs; // 513
68
- int hop = m_cfg.hop_length; // 256
69
-
70
- // 1. Undo feat_scale and transpose to [1, n_mels, T_model]
71
- float inv_scale = (feat_scale != 0.0f) ? (1.0f / feat_scale) : 1.0f;
72
- int T_model = 620;
73
- std::vector<float> mel_padded(T_model * feat_dim, 0.0f);
74
- for (int t = 0; t < T; ++t) {
75
- for (int c = 0; c < feat_dim; ++c) {
76
- mel_padded[c * T_model + t] = mel[t * feat_dim + c] * inv_scale;
77
- }
78
- }
79
-
80
- // 2. Run vocos_full.axmodel on NPU
81
- int input_idx = m_session->GetInputIndex("mel");
82
- if (input_idx < 0) input_idx = 0;
83
- m_session->SetInput(mel_padded.data(), input_idx);
84
-
85
- if (m_session->RunSync() != 0) {
86
- printf("Vocoder NPU inference failed\n");
87
- return -1;
88
- }
89
-
90
- int real_idx = m_session->GetOutputIndex("real");
91
- int imag_idx = m_session->GetOutputIndex("imag");
92
- if (real_idx < 0) real_idx = 0;
93
- if (imag_idx < 0) imag_idx = 1;
94
-
95
- int spec_size = m_session->GetOutputSize(real_idx);
96
- std::vector<float> real_spec(spec_size / sizeof(float));
97
- std::vector<float> imag_spec(spec_size / sizeof(float));
98
- m_session->GetOutput(real_spec.data(), real_idx);
99
- m_session->GetOutput(imag_spec.data(), imag_idx);
100
-
101
- // 3. kissfft IRFFT + window + overlap-add
102
- int out_len = (T - 1) * hop + n_fft;
103
- audio.assign(out_len, 0.0f);
104
- std::vector<float> envelope(out_len, 0.0f);
105
-
106
- std::vector<kiss_fft_cpx> cx_in(n_fft), cx_out(n_fft);
107
-
108
- for (int t = 0; t < T; ++t) {
109
- int spec_offset = t * n_freqs;
110
-
111
- // Build full Hermitian spectrum from [0..N/2]
112
- cx_in[0].r = real_spec[spec_offset + 0];
113
- cx_in[0].i = 0.0f;
114
- for (int k = 1; k < n_freqs - 1; ++k) {
115
- cx_in[k].r = real_spec[spec_offset + k];
116
- cx_in[k].i = imag_spec[spec_offset + k];
117
- cx_in[n_fft - k].r = real_spec[spec_offset + k];
118
- cx_in[n_fft - k].i = -imag_spec[spec_offset + k];
119
- }
120
- cx_in[n_freqs - 1].r = real_spec[spec_offset + (n_freqs - 1)];
121
- cx_in[n_freqs - 1].i = 0.0f; // Nyquist imag must be 0
122
-
123
- rnn_ifft(m_ifft_cfg, cx_in.data(), cx_out.data(), 0);
124
-
125
- // Window + overlap-add
126
- int pos = t * hop;
127
- for (int n = 0; n < n_fft; ++n) {
128
- float sample = (cx_out[n].r / n_fft) * m_window[n];
129
- int p = pos + n;
130
- if (p < out_len) {
131
- audio[p] += sample;
132
- envelope[p] += m_window_sq[n];
133
- }
134
- }
135
- }
136
-
137
- // 4. Normalize by window envelope
138
- for (int i = 0; i < out_len; ++i) {
139
- if (envelope[i] > 1e-10f) {
140
- audio[i] /= envelope[i];
141
- }
142
- }
143
-
144
- // 5. Center trim (n_fft/2 from each side, matching torch.istft center=True)
145
- int pad = n_fft / 2;
146
- int trim_len = out_len - 2 * pad;
147
- if (trim_len > 0) {
148
- std::vector<float> trimmed(audio.begin() + pad, audio.begin() + pad + trim_len);
149
- audio = std::move(trimmed);
150
- }
151
-
152
- return 0;
153
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/vocoder.hpp DELETED
@@ -1,67 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * Vocoder: mel features → audio via vocos_full.axmodel + IRFFT + overlap-add.
5
- **************************************************************************************************/
6
-
7
- #pragma once
8
-
9
- #include <vector>
10
- #include <string>
11
- #include <memory>
12
-
13
- #include "src/EngineWrapper.hpp"
14
- #include "kiss_fft.h"
15
-
16
- class Vocoder {
17
- public:
18
- struct Config {
19
- std::string model_path;
20
- const char* axclConfig = nullptr; // AXCL only: path to axcl.json. Ignored on AXERA.
21
- int n_fft = 1024;
22
- int hop_length = 256;
23
- int win_length = 1024;
24
- int n_mels = 100;
25
- int sample_rate = 24000;
26
- };
27
-
28
- Vocoder();
29
- ~Vocoder();
30
-
31
- /**
32
- * Initialize: load vocos_full.axmodel and pre-compute IRFFT basis.
33
- */
34
- int Init(const Config& cfg);
35
-
36
- /**
37
- * Decode mel features to audio waveform.
38
- * @param mel Mel features [T, n_mels] (flat, row-major)
39
- * @param T Number of mel frames
40
- * @param feat_scale Feature scaling factor to undo (Python: features/feat_scale before vocoder)
41
- * @param audio Output audio samples (24kHz float32)
42
- */
43
- int Decode(const std::vector<float>& mel, int T, float feat_scale, std::vector<float>& audio);
44
-
45
- bool HasInit() const { return m_has_init; }
46
-
47
- private:
48
- Config m_cfg;
49
- bool m_has_init;
50
- std::unique_ptr<EngineWrapper> m_session;
51
-
52
- // kissfft configs (shared forward/inverse twiddles)
53
- kiss_fft_state* m_fft_cfg = nullptr;
54
- kiss_fft_state* m_ifft_cfg = nullptr;
55
-
56
- // Hann window
57
- std::vector<float> m_window;
58
-
59
- // Window squared for envelope normalization
60
- std::vector<float> m_window_sq;
61
-
62
- int m_n_freqs;
63
-
64
- void BuildWindow();
65
-
66
- static void Fft(std::vector<float>& real, std::vector<float>& imag, bool inverse);
67
- };