Research zipvoice
#1
by inoryQwQ - opened
This view is limited to 50 files because it contains too many changes. See the raw diff here.
- .gitattributes +12 -13
- README.md +11 -44
- cpp/.gitattributes +0 -2
- cpp/CMakeLists.txt +0 -53
- cpp/README.md +0 -84
- cpp/build_ax650.sh +0 -30
- cpp/build_axcl.sh +0 -34
- cpp/cmake/msp_dependencies.cmake +0 -71
- cpp/download_bsp.sh +0 -19
- cpp/install/ax650/zipvoice +0 -3
- cpp/install/ax650/zipvoice_axera +0 -3
- cpp/install/axcl/zipvoice +0 -3
- cpp/scripts/compare_vocoder.py +0 -277
- cpp/scripts/export_vocos_onnx.py +0 -125
- cpp/scripts/gen_cat_tokens.py +0 -44
- cpp/scripts/gen_pinyin_table.py +0 -95
- cpp/scripts/generate_vocoder_calib.py +0 -141
- cpp/scripts/py_daemon.py +0 -57
- cpp/scripts/quantize_vocoder.sh +0 -123
- cpp/src/EngineWrapper.cpp +0 -13
- cpp/src/EngineWrapper.hpp +0 -81
- cpp/src/EngineWrapper_axcl.cpp +0 -217
- cpp/src/EngineWrapper_axera.cpp +0 -283
- cpp/src/cmdline.hpp +0 -732
- cpp/src/fbank.cpp +0 -219
- cpp/src/fbank.hpp +0 -65
- cpp/src/middleware/ax_npu_runner.cc +0 -131
- cpp/src/middleware/ax_npu_runner.hpp +0 -65
- cpp/src/middleware/ax_npu_runner_impl.hpp +0 -640
- cpp/src/middleware/axcl_base.cc +0 -241
- cpp/src/middleware/axcl_base.hpp +0 -42
- cpp/src/middleware/axcl_native_runner.cc +0 -105
- cpp/src/middleware/axcl_native_runner.hpp +0 -57
- cpp/src/middleware/axcl_native_runner_impl.hpp +0 -504
- cpp/src/middleware/axcl_runtime_runner.cc +0 -105
- cpp/src/middleware/axcl_runtime_runner.hpp +0 -56
- cpp/src/middleware/axcl_runtime_runner_impl.hpp +0 -482
- cpp/src/middleware/runner.cc +0 -88
- cpp/src/middleware/runner.hpp +0 -67
- cpp/src/pinyin_table.hpp +0 -0
- cpp/src/tokenizer.cpp +0 -306
- cpp/src/tokenizer.hpp +0 -79
- cpp/src/utilities/file.hpp +0 -251
- cpp/src/utilities/file_mapper.hpp +0 -86
- cpp/src/utilities/log.hpp +0 -64
- cpp/src/utilities/scalar_guard.hpp +0 -60
- cpp/src/utilities/timer.hpp +0 -84
- cpp/src/utilities/vector_guard.hpp +0 -64
- cpp/src/vocoder.cpp +0 -153
- 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/
|
| 63 |
outputs/en_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
|
| 64 |
-
outputs/
|
| 65 |
outputs/en_sentence_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
|
| 66 |
-
outputs/
|
| 67 |
outputs/zh_long_paragraph_distill_ax650.wav filter=lfs diff=lfs merge=lfs -text
|
| 68 |
-
outputs/
|
| 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 板端
|
| 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.
|
| 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
|
| 70 |
-
├── run_ax650.sh # AXERA 板端一键运行
|
| 71 |
-
├── run_axcl.sh # AXCL 算力卡一键运行
|
| 72 |
├── requirements.txt
|
| 73 |
└── README.md
|
| 74 |
```
|
| 75 |
|
| 76 |
-
##
|
| 77 |
-
|
| 78 |
-
### 环境
|
| 79 |
|
| 80 |
安装 pyaxengine:
|
| 81 |
-
|
| 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 |
-
###
|
| 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 |
-
###
|
| 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 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|