HY-2012 commited on
Commit
aa48d14
·
verified ·
1 Parent(s): d0d0172

cleanup: remove legacy cpp sources (now on GitHub)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. cpp/.gitattributes +0 -2
  2. cpp/CMakeLists.txt +0 -53
  3. cpp/README.md +0 -90
  4. cpp/build_ax650.sh +0 -30
  5. cpp/build_axcl.sh +0 -34
  6. cpp/cmake/msp_dependencies.cmake +0 -68
  7. cpp/download_bsp.sh +0 -23
  8. cpp/install/ax650/zipvoice +0 -3
  9. cpp/install/ax650/zipvoice_axera +0 -3
  10. cpp/install/axcl/zipvoice +0 -3
  11. cpp/scripts/compare_vocoder.py +0 -277
  12. cpp/scripts/export_vocos_onnx.py +0 -125
  13. cpp/scripts/gen_cat_tokens.py +0 -44
  14. cpp/scripts/gen_pinyin_table.py +0 -95
  15. cpp/scripts/generate_vocoder_calib.py +0 -141
  16. cpp/scripts/py_daemon.py +0 -57
  17. cpp/scripts/quantize_vocoder.sh +0 -123
  18. cpp/src/EngineWrapper.cpp +0 -13
  19. cpp/src/EngineWrapper.hpp +0 -81
  20. cpp/src/EngineWrapper_axcl.cpp +0 -217
  21. cpp/src/EngineWrapper_axera.cpp +0 -291
  22. cpp/src/cmdline.hpp +0 -732
  23. cpp/src/fbank.cpp +0 -219
  24. cpp/src/fbank.hpp +0 -65
  25. cpp/src/middleware/ax_npu_runner.cc +0 -131
  26. cpp/src/middleware/ax_npu_runner.hpp +0 -65
  27. cpp/src/middleware/ax_npu_runner_impl.hpp +0 -640
  28. cpp/src/middleware/axcl_base.cc +0 -241
  29. cpp/src/middleware/axcl_base.hpp +0 -42
  30. cpp/src/middleware/axcl_native_runner.cc +0 -105
  31. cpp/src/middleware/axcl_native_runner.hpp +0 -57
  32. cpp/src/middleware/axcl_native_runner_impl.hpp +0 -504
  33. cpp/src/middleware/axcl_runtime_runner.cc +0 -105
  34. cpp/src/middleware/axcl_runtime_runner.hpp +0 -56
  35. cpp/src/middleware/axcl_runtime_runner_impl.hpp +0 -482
  36. cpp/src/middleware/runner.cc +0 -88
  37. cpp/src/middleware/runner.hpp +0 -67
  38. cpp/src/pinyin_table.hpp +0 -0
  39. cpp/src/tokenizer.cpp +0 -306
  40. cpp/src/tokenizer.hpp +0 -79
  41. cpp/src/utilities/file.hpp +0 -251
  42. cpp/src/utilities/file_mapper.hpp +0 -86
  43. cpp/src/utilities/log.hpp +0 -64
  44. cpp/src/utilities/scalar_guard.hpp +0 -60
  45. cpp/src/utilities/timer.hpp +0 -84
  46. cpp/src/utilities/vector_guard.hpp +0 -64
  47. cpp/src/vocoder.cpp +0 -190
  48. cpp/src/vocoder.hpp +0 -68
  49. cpp/src/wav_writer.hpp +0 -84
  50. cpp/src/zipvoice_engine.cpp +0 -616
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,90 +0,0 @@
1
- # ZipVoice C++ — AXERA & AXCL
2
-
3
- ## 性能
4
-
5
- ### Distill 模型 (num_step=4)
6
-
7
- | 场景 | 音频 | Python AX650<br>耗时 RTF | C++ AX650<br>耗时 RTF | C++ AXCL<br>耗时 RTF | Python AX630C<br>耗时 RTF | C++ AX630C<br>耗时 RTF |
8
- |------|------|-------------------------|----------------------|---------------------|--------------------------|-----------------------|
9
- | 中文句子 | 6.41s | 1.992s/0.311 | 1.057s/0.165 | 0.918s/**0.143** | 10.296s/1.606 | 4.650s/0.725 |
10
- | 中文段落 | 44.97s | 13.457s/0.301 | 7.357s/0.164 | 6.443s/**0.143** | 71.574s/1.600 | 32.590s/0.725 |
11
- | 英文句子 | 6.41s | 2.045s/0.319 | 1.067s/0.166 | 0.919s/**0.143** | 10.686s/1.667 | 4.654s/0.726 |
12
- | 英文段落 | 59.16s | 19.715s/0.305 | 10.529s/0.178 | 9.207s/**0.156** | 106.183s/1.640 | 46.541s/0.787 |
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/AXERA-TECH/ax620e_bsp_sdk.git --depth=1
36
- git clone https://github.com/Abandon-ht/axcl_bsp_sdk.git --depth=1
37
- ```
38
-
39
- 修改 `cmake/msp_dependencies.cmake` 和 `toolchains/aarch64-none-linux-gnu.toolchain.cmake` 中的路径。
40
-
41
- 英文分词需 Python 依赖(运行设备上安装):
42
- ```bash
43
- pip install jieba numpy pypinyin piper_phonemize
44
- ```
45
-
46
- ## 编译
47
-
48
- ```bash
49
- bash build_ax650.sh # → install/ax650/zipvoice
50
- bash build_ax630c.sh # → install/ax630c/zipvoice
51
- bash build_axcl.sh # → install/axcl/zipvoice
52
- ```
53
-
54
- ## 运行
55
-
56
- 在 repo 根目录(`ZipVoice.AXERA/`)执行:
57
-
58
- ```bash
59
- # 板端
60
- bash run_ax650.sh distill zh sentence
61
- bash run_ax650.sh distill zh paragraph
62
- bash run_ax650.sh standard zh sentence
63
- bash run_ax650.sh standard zh paragraph
64
- bash run_ax650.sh distill en sentence
65
- bash run_ax650.sh distill en paragraph
66
- bash run_ax650.sh standard en sentence
67
- bash run_ax650.sh standard en paragraph
68
-
69
- # 算力卡
70
- bash run_axcl.sh distill zh paragraph
71
- bash run_axcl.sh standard en sentence
72
-
73
- # AX630C (仅 distill)
74
- bash run_ax630c.sh zh sentence
75
- bash run_ax630c.sh en paragraph
76
- ...
77
- ```
78
-
79
- ## 参数
80
-
81
- | 参数 | 说明 | 默认值 |
82
- |------|------|--------|
83
- | `--model-dir` | 模型目录 | 必填 |
84
- | `--prompt-wav` | 提示音频 | 必填 |
85
- | `--prompt-text` | 提示文本 | 必填 |
86
- | `--text` / `--text-file` | 合成文本 | 二选一 |
87
- | `--vocoder-model` | vocos_full.axmodel 路径 | 必填 |
88
- | `--output-wav` | 输出 WAV | output.wav |
89
- | `--num-step` | 采样步数 | 10 (distill: 4) |
90
- | `--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,68 +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 /data/shared/huyuan/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc)
23
- endif()
24
- set(MSP_INC_DIR ${BSP_MSP_DIR}/include)
25
- set(MSP_LIB_DIR ${BSP_MSP_DIR}/lib)
26
- list(APPEND MSP_LIBS ax_sys ax_engine ax_interpreter)
27
-
28
- elseif(AX620Q)
29
- add_definitions(-DAX620Q)
30
- if(NOT BSP_MSP_DIR)
31
- set(BSP_MSP_DIR ${CMAKE_SOURCE_DIR}/ax620e_bsp_sdk/msp/out/arm_uclibc)
32
- endif()
33
- if(NOT EXISTS ${BSP_MSP_DIR})
34
- message(FATAL_ERROR "BSP_MSP_DIR ${BSP_MSP_DIR} not exist.")
35
- endif()
36
- set(MSP_INC_DIR ${BSP_MSP_DIR}/include)
37
- set(MSP_LIB_DIR ${BSP_MSP_DIR}/lib)
38
- list(APPEND MSP_LIBS ax_sys ax_engine ax_interpreter)
39
-
40
- elseif(AXCL)
41
- add_definitions(-DAXCL)
42
- add_definitions(-DENV_AXCL_RUNTIME_API_ENABLE)
43
- add_definitions(-DENV_AXCL_NATIVE_API_ENABLE)
44
- add_definitions(-DENV_HAS_STD_FILESYSTEM)
45
- add_definitions(-DENV_HAS_POSIX_FILE_STAT)
46
-
47
- # AXCL SDK at /data/shared/huyuan/toolchains/axcl_bsp_sdk/out/
48
- if(NOT AXCL_SDK_DIR)
49
- set(AXCL_SDK_DIR /data/shared/huyuan/toolchains/axcl_bsp_sdk/out)
50
- endif()
51
- if(NOT EXISTS ${AXCL_SDK_DIR})
52
- message(FATAL_ERROR "AXCL_SDK_DIR ${AXCL_SDK_DIR} not exist. Run download_bsp.sh first.")
53
- endif()
54
- set(MSP_INC_DIR ${AXCL_SDK_DIR}/include ${AXCL_SDK_DIR}/bsp)
55
- set(MSP_LIB_DIR ${AXCL_SDK_DIR}/lib)
56
- list(APPEND MSP_LIBS
57
- axcl_rt axcl_pkg axcl_comm axcl_npu spdlog
58
- axcl_token axcl_pcie_msg axcl_pcie_dma)
59
- set(CMAKE_CXX_STANDARD 17)
60
-
61
- else()
62
- message(FATAL_ERROR "Unknown platform. Set -DAX650, -DAX630C, -DAX620Q, or -DAXCL.")
63
- endif()
64
-
65
- link_directories(${MSP_LIB_DIR})
66
- message(STATUS "MSP_INC_DIR: ${MSP_INC_DIR}")
67
- message(STATUS "MSP_LIB_DIR: ${MSP_LIB_DIR}")
68
- message(STATUS "MSP_LIBS: ${MSP_LIBS}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/download_bsp.sh DELETED
@@ -1,23 +0,0 @@
1
- #!/bin/bash
2
- # Download BSP SDKs to /data/shared/huyuan/toolchains/
3
-
4
- TARGET=/data/shared/huyuan/toolchains
5
- mkdir -p $TARGET && cd $TARGET
6
-
7
- if [ ! -d ax650n_bsp_sdk ]; then
8
- echo "Downloading ax650n_bsp_sdk..."
9
- git clone https://github.com/AXERA-TECH/ax650n_bsp_sdk.git --depth=1
10
- fi
11
-
12
- if [ ! -d ax620e_bsp_sdk ]; then
13
- echo "Downloading ax620e_bsp_sdk..."
14
- git clone https://github.com/AXERA-TECH/ax620e_bsp_sdk.git --depth=1
15
- fi
16
-
17
- if [ ! -d axcl_bsp_sdk ]; then
18
- echo "Downloading axcl_bsp_sdk..."
19
- git clone https://github.com/Abandon-ht/axcl_bsp_sdk.git --depth=1
20
- fi
21
-
22
- echo "Done. SDKs at $TARGET/"
23
- ls -d ax650n_bsp_sdk ax620e_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,291 +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
- #if !defined(AX630C)
13
- static const char *strAlgoModelType[AX_ENGINE_MODEL_TYPE_BUTT] = {"3.6T", "7.2T", "10.8T"};
14
- #endif
15
-
16
- // NPU type enum
17
- typedef enum axNPU_TYPE_E {
18
- AX_NPU_DEFAULT = 0,
19
- AX_STD_VNPU_1 = (1 << 0),
20
- AX_STD_VNPU_2 = (1 << 1),
21
- AX_STD_VNPU_3 = (1 << 2),
22
- AX_BL_VNPU_1 = (1 << 3),
23
- AX_BL_VNPU_2 = (1 << 4)
24
- } AX_NPU_TYPE_E;
25
-
26
- #if !defined(AX630C)
27
- static AX_S32 CheckModelVNpu(const std::string &strModel,
28
- const AX_ENGINE_MODEL_TYPE_T &eModelType,
29
- const AX_S32 &nNpuType, AX_U32 &nNpuSet) {
30
- AX_ENGINE_NPU_ATTR_T stNpuAttr;
31
- memset(&stNpuAttr, 0x00, sizeof(stNpuAttr));
32
-
33
- auto ret = AX_ENGINE_GetVNPUAttr(&stNpuAttr);
34
- if (ret == 0) {
35
- if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_DISABLE) {
36
- nNpuSet = 0x01;
37
- } else if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_STD) {
38
- if (eModelType == AX_ENGINE_MODEL_TYPE1 || eModelType == AX_ENGINE_MODEL_TYPE2)
39
- return -1;
40
- if (nNpuType == 0) nNpuSet = 0x02;
41
- else {
42
- if (nNpuType & AX_STD_VNPU_1) nNpuSet |= 0x01;
43
- if (nNpuType & AX_STD_VNPU_2) nNpuSet |= 0x02;
44
- if (nNpuType & AX_STD_VNPU_3) nNpuSet |= 0x04;
45
- }
46
- } else if (stNpuAttr.eHardMode == AX_ENGINE_VIRTUAL_NPU_BIG_LITTLE) {
47
- if (eModelType == AX_ENGINE_MODEL_TYPE2) return -1;
48
- if (nNpuType == 0) {
49
- nNpuSet = (eModelType == AX_ENGINE_MODEL_TYPE1) ? 0x01 : 0x02;
50
- } else {
51
- if (eModelType == AX_ENGINE_MODEL_TYPE1) {
52
- if (nNpuType & AX_BL_VNPU_2) return -1;
53
- if (nNpuType & AX_BL_VNPU_1) nNpuSet |= 0x01;
54
- } else {
55
- if (nNpuType & AX_BL_VNPU_1) nNpuSet |= 0x01;
56
- if (nNpuType & AX_BL_VNPU_2) nNpuSet |= 0x02;
57
- }
58
- }
59
- }
60
- }
61
- return ret;
62
- }
63
- #endif
64
-
65
- EngineWrapper::EngineWrapper()
66
- : m_hasInit(false), m_handle(nullptr), m_io_info(nullptr),
67
- m_input_num(0), m_output_num(0) {
68
- memset(&m_io, 0, sizeof(m_io));
69
- }
70
-
71
- EngineWrapper::~EngineWrapper() {
72
- Release();
73
- }
74
-
75
- int EngineWrapper::Init(const char* strModelPath, uint32_t nNpuType, const char* axclConfig) {
76
- (void)axclConfig; // unused on AXERA
77
- // 1. Load model
78
- AX_BOOL bLoadModelUseCmm = AX_TRUE;
79
- AX_CHAR *pModelBufferVirAddr = nullptr;
80
- AX_U64 u64ModelBufferPhyAddr = 0;
81
- AX_U32 nModelBufferSize = 0;
82
-
83
- if (bLoadModelUseCmm) {
84
- if (!utils::read_file(strModelPath, (AX_VOID **)&pModelBufferVirAddr,
85
- u64ModelBufferPhyAddr, nModelBufferSize)) {
86
- printf("Read model(%s) fail\n", strModelPath);
87
- return -1;
88
- }
89
- } else {
90
- std::vector<char> model_buffer;
91
- if (!utils::read_file(strModelPath, model_buffer)) {
92
- printf("Read model(%s) fail\n", strModelPath);
93
- return -1;
94
- }
95
- pModelBufferVirAddr = model_buffer.data();
96
- nModelBufferSize = model_buffer.size();
97
- }
98
-
99
- auto freeModelBuffer = [&]() {
100
- if (bLoadModelUseCmm) {
101
- if (u64ModelBufferPhyAddr != 0)
102
- AX_SYS_MemFree(u64ModelBufferPhyAddr, &pModelBufferVirAddr);
103
- }
104
- };
105
-
106
- // 1.1 Get Model Type & Check VNPU (AX650 only)
107
- #if !defined(AX630C)
108
- AX_ENGINE_MODEL_TYPE_T eModelType = AX_ENGINE_MODEL_TYPE0;
109
- AX_S32 ret = AX_ENGINE_GetModelType(pModelBufferVirAddr, nModelBufferSize, &eModelType);
110
- if (0 != ret || eModelType >= AX_ENGINE_MODEL_TYPE_BUTT) {
111
- printf("%s AX_ENGINE_GetModelType fail ret=%x\n", strModelPath, ret);
112
- freeModelBuffer();
113
- return -1;
114
- }
115
-
116
- AX_U32 nNpuSet = 0;
117
- ret = CheckModelVNpu(strModelPath, eModelType, nNpuType, nNpuSet);
118
- if (0 != ret) {
119
- printf("CheckModelVNpu fail\n");
120
- freeModelBuffer();
121
- return -1;
122
- }
123
- #endif
124
- #if defined(AX630C)
125
- AX_S32 ret = 0;
126
- #endif
127
-
128
- // 2. Create handle
129
- AX_ENGINE_HANDLE handle = nullptr;
130
- ret = AX_ENGINE_CreateHandle(&handle, pModelBufferVirAddr, nModelBufferSize);
131
- freeModelBuffer();
132
-
133
- auto deinit_handle = [&handle]() {
134
- if (handle) { AX_ENGINE_DestroyHandle(handle); }
135
- return -1;
136
- };
137
-
138
- if (0 != ret || !handle) {
139
- printf("Create model(%s) handle fail\n", strModelPath);
140
- return deinit_handle();
141
- }
142
-
143
- // 3. Create context
144
- ret = AX_ENGINE_CreateContext(handle);
145
- if (0 != ret) return deinit_handle();
146
-
147
- // 4. Get IO info
148
- m_io_info = nullptr;
149
- ret = AX_ENGINE_GetIOInfo(handle, &m_io_info);
150
- if (0 != ret) return deinit_handle();
151
-
152
- m_input_num = m_io_info->nInputSize;
153
- m_output_num = m_io_info->nOutputSize;
154
-
155
- // Build name-to-index maps
156
- m_input_name_to_idx.clear();
157
- for (int i = 0; i < m_input_num; ++i) {
158
- m_input_name_to_idx[std::string(m_io_info->pInputs[i].pName)] = i;
159
- }
160
- m_output_name_to_idx.clear();
161
- for (int i = 0; i < m_output_num; ++i) {
162
- m_output_name_to_idx[std::string(m_io_info->pOutputs[i].pName)] = i;
163
- }
164
-
165
- // 5. Prepare IO buffers
166
- ret = utils::prepare_io("enc", m_io_info, m_io, utils::IO_BUFFER_STRATEGY_DEFAULT);
167
- if (0 != ret) {
168
- printf("prepare io failed!\n");
169
- utils::free_io(m_io);
170
- return deinit_handle();
171
- }
172
-
173
- m_handle = handle;
174
- m_hasInit = true;
175
- return 0;
176
- }
177
-
178
- int EngineWrapper::SetInput(void* pInput, int index) {
179
- if (!m_hasInit || index < 0 || index >= m_input_num) return -1;
180
- return utils::push_io_input(pInput, index, m_io);
181
- }
182
-
183
- int EngineWrapper::RunSync() {
184
- if (!m_hasInit) return -1;
185
- auto ret = AX_ENGINE_RunSync(m_handle, &m_io);
186
- if (0 != ret) {
187
- printf("AX_ENGINE_RunSync failed. ret=0x%x\n", ret);
188
- }
189
- return ret;
190
- }
191
-
192
- int EngineWrapper::GetOutput(void* pOutput, int index) {
193
- if (!m_hasInit || index < 0 || index >= m_output_num) return -1;
194
- return utils::push_io_output(pOutput, index, m_io);
195
- }
196
-
197
- int EngineWrapper::SetInputByName(const char* name, void* pInput) {
198
- auto it = m_input_name_to_idx.find(std::string(name));
199
- if (it == m_input_name_to_idx.end()) {
200
- printf("Input '%s' not found in model\n", name);
201
- return -1;
202
- }
203
- return SetInput(pInput, it->second);
204
- }
205
-
206
- int EngineWrapper::GetOutputByName(const char* name, void* pOutput) {
207
- auto it = m_output_name_to_idx.find(std::string(name));
208
- if (it == m_output_name_to_idx.end()) {
209
- printf("Output '%s' not found in model\n", name);
210
- return -1;
211
- }
212
- return GetOutput(pOutput, it->second);
213
- }
214
-
215
- int EngineWrapper::GetInputSize(int index) {
216
- if (index < 0 || index >= m_input_num) return -1;
217
- return m_io.pInputs[index].nSize;
218
- }
219
-
220
- int EngineWrapper::GetOutputSize(int index) {
221
- if (index < 0 || index >= m_output_num) return -1;
222
- return m_io.pOutputs[index].nSize;
223
- }
224
-
225
- int EngineWrapper::GetInputSizeByName(const char* name) {
226
- int idx = GetInputIndex(name);
227
- if (idx < 0) return -1;
228
- return GetInputSize(idx);
229
- }
230
-
231
- int EngineWrapper::GetOutputSizeByName(const char* name) {
232
- int idx = GetOutputIndex(name);
233
- if (idx < 0) return -1;
234
- return GetOutputSize(idx);
235
- }
236
-
237
- int EngineWrapper::GetInputIndex(const char* name) {
238
- auto it = m_input_name_to_idx.find(std::string(name));
239
- return (it != m_input_name_to_idx.end()) ? it->second : -1;
240
- }
241
-
242
- int EngineWrapper::GetOutputIndex(const char* name) {
243
- auto it = m_output_name_to_idx.find(std::string(name));
244
- return (it != m_output_name_to_idx.end()) ? it->second : -1;
245
- }
246
-
247
- const char* EngineWrapper::GetInputName(int index) const {
248
- if (index < 0 || index >= m_input_num) return nullptr;
249
- return m_io_info->pInputs[index].pName;
250
- }
251
-
252
- const char* EngineWrapper::GetOutputName(int index) const {
253
- if (index < 0 || index >= m_output_num) return nullptr;
254
- return m_io_info->pOutputs[index].pName;
255
- }
256
-
257
- static const char* dtype_str(AX_ENGINE_DATA_TYPE_T t) {
258
- switch (t) {
259
- case AX_ENGINE_DT_FLOAT32: return "float32";
260
- case AX_ENGINE_DT_FLOAT64: return "float64";
261
- case AX_ENGINE_DT_SINT8: return "sint8";
262
- case AX_ENGINE_DT_UINT8: return "uint8";
263
- case AX_ENGINE_DT_SINT16: return "sint16";
264
- case AX_ENGINE_DT_UINT16: return "uint16";
265
- case AX_ENGINE_DT_SINT32: return "sint32";
266
- case AX_ENGINE_DT_UINT32: return "uint32";
267
- default: return "unknown";
268
- }
269
- }
270
-
271
- const char* EngineWrapper::GetInputDtypeStr(int index) const {
272
- if (index < 0 || index >= m_input_num) return "?";
273
- return dtype_str(m_io_info->pInputs[index].eDataType);
274
- }
275
-
276
- const char* EngineWrapper::GetOutputDtypeStr(int index) const {
277
- if (index < 0 || index >= m_output_num) return "?";
278
- return dtype_str(m_io_info->pOutputs[index].eDataType);
279
- }
280
-
281
- int EngineWrapper::Release() {
282
- if (m_handle) {
283
- utils::free_io(m_io);
284
- AX_ENGINE_DestroyHandle(m_handle);
285
- m_handle = nullptr;
286
- }
287
- m_hasInit = false;
288
- m_input_name_to_idx.clear();
289
- m_output_name_to_idx.clear();
290
- return 0;
291
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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,190 +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 backbone (or full) model
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
- // Load head_linear model (optional, for split mode)
47
- if (!cfg.head_model_path.empty()) {
48
- m_session_head = std::make_unique<EngineWrapper>();
49
- if (m_session_head->Init(cfg.head_model_path.c_str(), 0, cfg.axclConfig) != 0) {
50
- printf("Failed to load vocoder head model: %s\n", cfg.head_model_path.c_str());
51
- return -1;
52
- }
53
- }
54
-
55
- m_has_init = true;
56
- printf("Vocoder initialized: n_fft=%d, hop=%d, n_mels=%d%s\n",
57
- cfg.n_fft, cfg.hop_length, cfg.n_mels,
58
- m_session_head ? " (split mode)" : "");
59
- return 0;
60
- }
61
-
62
- void Vocoder::BuildWindow() {
63
- int n = m_cfg.n_fft;
64
- m_window.resize(n);
65
- m_window_sq.resize(n);
66
- for (int i = 0; i < n; ++i) {
67
- m_window[i] = 0.5f * (1.0f - std::cos(2.0f * M_PI * i / (n - 1)));
68
- m_window_sq[i] = m_window[i] * m_window[i];
69
- }
70
- }
71
-
72
- int Vocoder::Decode(const std::vector<float>& mel, int T, float feat_scale, std::vector<float>& audio) {
73
- if (!m_has_init || mel.empty()) return -1;
74
-
75
- int feat_dim = m_cfg.n_mels; // 100
76
- int n_fft = m_cfg.n_fft; // 1024
77
- int n_freqs = m_n_freqs; // 513
78
- int hop = m_cfg.hop_length; // 256
79
-
80
- // 1. Undo feat_scale and transpose to [1, n_mels, T_model]
81
- float inv_scale = (feat_scale != 0.0f) ? (1.0f / feat_scale) : 1.0f;
82
- int T_model = 620;
83
- std::vector<float> mel_padded(T_model * feat_dim, 0.0f);
84
- for (int t = 0; t < T; ++t) {
85
- for (int c = 0; c < feat_dim; ++c) {
86
- mel_padded[c * T_model + t] = mel[t * feat_dim + c] * inv_scale;
87
- }
88
- }
89
-
90
- // 2. Run NPU inference
91
- std::vector<float> real_spec, imag_spec;
92
- int spec_size;
93
-
94
- if (m_session_head) {
95
- // Split mode: backbone → features → head_linear → (real, imag)
96
- int in_idx = m_session->GetInputIndex("mel");
97
- if (in_idx < 0) in_idx = 0;
98
- m_session->SetInput(mel_padded.data(), in_idx);
99
- if (m_session->RunSync() != 0) { printf("Vocoder backbone failed\n"); return -1; }
100
-
101
- int feat_idx = m_session->GetOutputIndex("features");
102
- if (feat_idx < 0) feat_idx = 0;
103
- std::vector<float> features(m_session->GetOutputSize(feat_idx) / sizeof(float));
104
- m_session->GetOutput(features.data(), feat_idx);
105
-
106
- int h_in = m_session_head->GetInputIndex("features");
107
- if (h_in < 0) h_in = 0;
108
- m_session_head->SetInput(features.data(), h_in);
109
- if (m_session_head->RunSync() != 0) { printf("Vocoder head failed\n"); return -1; }
110
-
111
- int real_idx = m_session_head->GetOutputIndex("real");
112
- int imag_idx = m_session_head->GetOutputIndex("imag");
113
- if (real_idx < 0) real_idx = 0;
114
- if (imag_idx < 0) imag_idx = 1;
115
- spec_size = m_session_head->GetOutputSize(real_idx);
116
- real_spec.resize(spec_size / sizeof(float));
117
- imag_spec.resize(spec_size / sizeof(float));
118
- m_session_head->GetOutput(real_spec.data(), real_idx);
119
- m_session_head->GetOutput(imag_spec.data(), imag_idx);
120
- } else {
121
- // Full model: mel → (real, imag)
122
- int in_idx = m_session->GetInputIndex("mel");
123
- if (in_idx < 0) in_idx = 0;
124
- m_session->SetInput(mel_padded.data(), in_idx);
125
- if (m_session->RunSync() != 0) { printf("Vocoder NPU inference failed\n"); return -1; }
126
-
127
- int real_idx = m_session->GetOutputIndex("real");
128
- int imag_idx = m_session->GetOutputIndex("imag");
129
- if (real_idx < 0) real_idx = 0;
130
- if (imag_idx < 0) imag_idx = 1;
131
- spec_size = m_session->GetOutputSize(real_idx);
132
- real_spec.resize(spec_size / sizeof(float));
133
- imag_spec.resize(spec_size / sizeof(float));
134
- m_session->GetOutput(real_spec.data(), real_idx);
135
- m_session->GetOutput(imag_spec.data(), imag_idx);
136
- }
137
-
138
- // 3. kissfft IRFFT + window + overlap-add
139
- int out_len = (T - 1) * hop + n_fft;
140
- audio.assign(out_len, 0.0f);
141
- std::vector<float> envelope(out_len, 0.0f);
142
-
143
- std::vector<kiss_fft_cpx> cx_in(n_fft), cx_out(n_fft);
144
-
145
- for (int t = 0; t < T; ++t) {
146
- int spec_offset = t * n_freqs;
147
-
148
- // Build full Hermitian spectrum from [0..N/2]
149
- cx_in[0].r = real_spec[spec_offset + 0];
150
- cx_in[0].i = 0.0f;
151
- for (int k = 1; k < n_freqs - 1; ++k) {
152
- cx_in[k].r = real_spec[spec_offset + k];
153
- cx_in[k].i = imag_spec[spec_offset + k];
154
- cx_in[n_fft - k].r = real_spec[spec_offset + k];
155
- cx_in[n_fft - k].i = -imag_spec[spec_offset + k];
156
- }
157
- cx_in[n_freqs - 1].r = real_spec[spec_offset + (n_freqs - 1)];
158
- cx_in[n_freqs - 1].i = 0.0f; // Nyquist imag must be 0
159
-
160
- rnn_ifft(m_ifft_cfg, cx_in.data(), cx_out.data(), 0);
161
-
162
- // Window + overlap-add
163
- int pos = t * hop;
164
- for (int n = 0; n < n_fft; ++n) {
165
- float sample = (cx_out[n].r / n_fft) * m_window[n];
166
- int p = pos + n;
167
- if (p < out_len) {
168
- audio[p] += sample;
169
- envelope[p] += m_window_sq[n];
170
- }
171
- }
172
- }
173
-
174
- // 4. Normalize by window envelope
175
- for (int i = 0; i < out_len; ++i) {
176
- if (envelope[i] > 1e-10f) {
177
- audio[i] /= envelope[i];
178
- }
179
- }
180
-
181
- // 5. Center trim (n_fft/2 from each side, matching torch.istft center=True)
182
- int pad = n_fft / 2;
183
- int trim_len = out_len - 2 * pad;
184
- if (trim_len > 0) {
185
- std::vector<float> trimmed(audio.begin() + pad, audio.begin() + pad + trim_len);
186
- audio = std::move(trimmed);
187
- }
188
-
189
- return 0;
190
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/vocoder.hpp DELETED
@@ -1,68 +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; // full model (or backbone in split mode)
20
- std::string head_model_path; // head_linear model (optional, for split mode)
21
- const char* axclConfig = nullptr;
22
- int n_fft = 1024;
23
- int hop_length = 256;
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
- std::unique_ptr<EngineWrapper> m_session_head; // optional, for split mode
52
-
53
- // kissfft configs (shared forward/inverse twiddles)
54
- kiss_fft_state* m_fft_cfg = nullptr;
55
- kiss_fft_state* m_ifft_cfg = nullptr;
56
-
57
- // Hann window
58
- std::vector<float> m_window;
59
-
60
- // Window squared for envelope normalization
61
- std::vector<float> m_window_sq;
62
-
63
- int m_n_freqs;
64
-
65
- void BuildWindow();
66
-
67
- static void Fft(std::vector<float>& real, std::vector<float>& imag, bool inverse);
68
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/wav_writer.hpp DELETED
@@ -1,84 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * Simple WAV file writer for float32 mono audio.
5
- **************************************************************************************************/
6
-
7
- #pragma once
8
-
9
- #include <vector>
10
- #include <string>
11
- #include <fstream>
12
- #include <cstdint>
13
- #include <cstring>
14
-
15
- class WavWriter {
16
- public:
17
- /**
18
- * Write float32 mono audio samples to a WAV file.
19
- *
20
- * @param path Output file path
21
- * @param samples Float32 audio samples in range [-1.0, 1.0]
22
- * @param sample_rate Sample rate in Hz (e.g., 24000)
23
- * @return true on success
24
- */
25
- static bool Write(const std::string& path,
26
- const std::vector<float>& samples,
27
- int sample_rate) {
28
- std::ofstream file(path, std::ios::binary);
29
- if (!file.is_open()) return false;
30
-
31
- int num_samples = static_cast<int>(samples.size());
32
- int byte_rate = sample_rate * 2; // 16-bit mono
33
- int data_size = num_samples * 2;
34
- int chunk_size = 36 + data_size;
35
-
36
- // RIFF header
37
- Write4CC(file, "RIFF");
38
- WriteU32LE(file, chunk_size);
39
- Write4CC(file, "WAVE");
40
-
41
- // fmt chunk
42
- Write4CC(file, "fmt ");
43
- WriteU32LE(file, 16); // chunk size
44
- WriteU16LE(file, 1); // PCM format
45
- WriteU16LE(file, 1); // mono
46
- WriteU32LE(file, sample_rate);
47
- WriteU32LE(file, byte_rate);
48
- WriteU16LE(file, 2); // block align
49
- WriteU16LE(file, 16); // bits per sample
50
-
51
- // data chunk
52
- Write4CC(file, "data");
53
- WriteU32LE(file, data_size);
54
-
55
- // Convert float32 to int16 (with clipping)
56
- for (float sample : samples) {
57
- // Clamp to [-1, 1]
58
- if (sample > 1.0f) sample = 1.0f;
59
- if (sample < -1.0f) sample = -1.0f;
60
- int16_t val = static_cast<int16_t>(sample * 32767.0f);
61
- WriteU16LE(file, static_cast<uint16_t>(val));
62
- }
63
-
64
- file.close();
65
- return true;
66
- }
67
-
68
- private:
69
- static void WriteU16LE(std::ofstream& f, uint16_t v) {
70
- f.put(v & 0xFF);
71
- f.put((v >> 8) & 0xFF);
72
- }
73
-
74
- static void WriteU32LE(std::ofstream& f, uint32_t v) {
75
- f.put(v & 0xFF);
76
- f.put((v >> 8) & 0xFF);
77
- f.put((v >> 16) & 0xFF);
78
- f.put((v >> 24) & 0xFF);
79
- }
80
-
81
- static void Write4CC(std::ofstream& f, const char* s) {
82
- f.write(s, 4);
83
- }
84
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/zipvoice_engine.cpp DELETED
@@ -1,616 +0,0 @@
1
- /**************************************************************************************************
2
- * ZipVoice AXERA C++ Port
3
- *
4
- * ZipVoiceEngine implementation.
5
- **************************************************************************************************/
6
-
7
- #include "zipvoice_engine.hpp"
8
-
9
- #include <fstream>
10
- #include <sstream>
11
- #include <cmath>
12
- #include <cstring>
13
- #include <algorithm>
14
- #include <sys/time.h>
15
-
16
- #ifndef M_PI
17
- #define M_PI 3.14159265358979323846
18
- #endif
19
-
20
- // Simple JSON value parser (no external dependency)
21
- // Only parses the simple structures needed by manifest.json and runtime_config.json
22
- namespace {
23
-
24
- std::string json_get_string(const std::string& json, const std::string& key) {
25
- std::string search = "\"" + key + "\"";
26
- size_t pos = json.find(search);
27
- if (pos == std::string::npos) return "";
28
-
29
- pos = json.find(':', pos + search.length());
30
- if (pos == std::string::npos) return "";
31
-
32
- pos = json.find('"', pos + 1);
33
- if (pos == std::string::npos) return "";
34
-
35
- size_t end = json.find('"', pos + 1);
36
- if (end == std::string::npos) return "";
37
-
38
- return json.substr(pos + 1, end - pos - 1);
39
- }
40
-
41
- int json_get_int(const std::string& json, const std::string& key, int default_val = 0) {
42
- std::string search = "\"" + key + "\"";
43
- size_t pos = json.find(search);
44
- if (pos == std::string::npos) return default_val;
45
-
46
- pos = json.find(':', pos + search.length());
47
- if (pos == std::string::npos) return default_val;
48
-
49
- // Skip whitespace
50
- pos++;
51
- while (pos < json.length() && (json[pos] == ' ' || json[pos] == '\t' || json[pos] == '\n')) pos++;
52
- if (pos >= json.length()) return default_val;
53
-
54
- // Parse number
55
- std::string num_str;
56
- while (pos < json.length() && (std::isdigit(json[pos]) || json[pos] == '-' || json[pos] == '.')) {
57
- num_str += json[pos];
58
- pos++;
59
- }
60
- if (num_str.empty()) return default_val;
61
-
62
- // Check if float
63
- if (num_str.find('.') != std::string::npos) {
64
- return static_cast<int>(std::stof(num_str));
65
- }
66
- return std::stoi(num_str);
67
- }
68
-
69
- float json_get_float(const std::string& json, const std::string& key, float default_val = 0.0f) {
70
- std::string search = "\"" + key + "\"";
71
- size_t pos = json.find(search);
72
- if (pos == std::string::npos) return default_val;
73
-
74
- pos = json.find(':', pos + search.length());
75
- if (pos == std::string::npos) return default_val;
76
-
77
- pos++;
78
- while (pos < json.length() && (json[pos] == ' ' || json[pos] == '\t' || json[pos] == '\n')) pos++;
79
- if (pos >= json.length()) return default_val;
80
-
81
- std::string num_str;
82
- while (pos < json.length() && (std::isdigit(json[pos]) || json[pos] == '-' || json[pos] == '.')) {
83
- num_str += json[pos];
84
- pos++;
85
- }
86
- if (num_str.empty()) return default_val;
87
- return std::stof(num_str);
88
- }
89
-
90
- std::vector<std::string> json_get_string_array(const std::string& json, const std::string& key) {
91
- std::vector<std::string> result;
92
- std::string search = "\"" + key + "\"";
93
- size_t pos = json.find(search);
94
- if (pos == std::string::npos) return result;
95
-
96
- pos = json.find('[', pos + search.length());
97
- if (pos == std::string::npos) return result;
98
-
99
- size_t end = json.find(']', pos);
100
- if (end == std::string::npos) return result;
101
-
102
- std::string array_str = json.substr(pos + 1, end - pos - 1);
103
-
104
- size_t start = 0;
105
- while (start < array_str.length()) {
106
- size_t q1 = array_str.find('"', start);
107
- if (q1 == std::string::npos) break;
108
- size_t q2 = array_str.find('"', q1 + 1);
109
- if (q2 == std::string::npos) break;
110
- result.push_back(array_str.substr(q1 + 1, q2 - q1 - 1));
111
- start = q2 + 1;
112
- }
113
- return result;
114
- }
115
-
116
- std::string read_file_content(const std::string& path) {
117
- std::ifstream file(path);
118
- if (!file.is_open()) return "";
119
- std::stringstream ss;
120
- ss << file.rdbuf();
121
- return ss.str();
122
- }
123
-
124
- } // anonymous namespace
125
-
126
- ZipVoiceEngine::ZipVoiceEngine()
127
- : m_has_init(false), m_decoder_seq_len(0), m_decoder_has_padding_mask(false) {}
128
-
129
- ZipVoiceEngine::~ZipVoiceEngine() {
130
- m_sessions.clear();
131
- }
132
-
133
- double ZipVoiceEngine::GetCurrentTimeMs() {
134
- struct timeval tv;
135
- gettimeofday(&tv, nullptr);
136
- return tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
137
- }
138
-
139
- int ZipVoiceEngine::Init(const std::string& model_dir, const char* axclConfig) {
140
- if (LoadConfig(model_dir) != 0) return -1;
141
- if (LoadManifest(model_dir) != 0) return -1;
142
- if (LoadModels(model_dir, axclConfig) != 0) return -1;
143
- if (LoadDecoderMetadata() != 0) return -1;
144
-
145
- m_has_init = true;
146
- printf("ZipVoiceEngine initialized: max_tokens=%d, max_feat_len=%d, feat_dim=%d, num_step=%d\n",
147
- m_config.max_tokens, m_config.max_feat_len, m_config.feat_dim, m_config.num_step);
148
- return 0;
149
- }
150
-
151
- int ZipVoiceEngine::LoadConfig(const std::string& model_dir) {
152
- std::string config_path = model_dir + "/runtime_config.json";
153
- std::string json = read_file_content(config_path);
154
- if (!json.empty()) {
155
- m_config.max_tokens = json_get_int(json, "max_tokens", 384);
156
- m_config.max_feat_len = json_get_int(json, "max_feat_len", 1024);
157
- m_config.feat_dim = json_get_int(json, "feat_dim", 100);
158
- m_config.sampling_rate = json_get_int(json, "sampling_rate", 24000);
159
- m_config.hop_length = json_get_int(json, "hop_length", 256);
160
- m_config.num_step = json_get_int(json, "num_step", 10);
161
- m_config.t_shift = json_get_float(json, "t_shift", 0.5f);
162
- m_config.guidance_scale = json_get_float(json, "guidance_scale", 1.0f);
163
- }
164
- m_config.model_dir = model_dir;
165
- return 0;
166
- }
167
-
168
- int ZipVoiceEngine::LoadManifest(const std::string& model_dir) {
169
- std::string manifest_path = model_dir + "/decoder4_split_manifest.json";
170
- std::string json = read_file_content(manifest_path);
171
- if (json.empty()) {
172
- printf("Failed to read manifest: %s\n", manifest_path.c_str());
173
- return -1;
174
- }
175
-
176
- // Parse encoder info
177
- m_encoder_info.name = json_get_string(json, "name");
178
- // Need to parse the nested "encoder" object
179
- size_t enc_pos = json.find("\"encoder\"");
180
- if (enc_pos != std::string::npos) {
181
- size_t obj_start = json.find('{', enc_pos);
182
- size_t obj_end = json.find('}', obj_start);
183
- if (obj_start != std::string::npos && obj_end != std::string::npos) {
184
- std::string enc_json = json.substr(obj_start, obj_end - obj_start + 1);
185
- m_encoder_info.name = json_get_string(enc_json, "name");
186
- m_encoder_info.file = json_get_string(enc_json, "file");
187
- m_encoder_info.inputs = json_get_string_array(enc_json, "inputs");
188
- m_encoder_info.outputs = json_get_string_array(enc_json, "outputs");
189
- }
190
- }
191
-
192
- // Parse decoder_parts array
193
- size_t dec_pos = json.find("\"decoder_parts\"");
194
- if (dec_pos != std::string::npos) {
195
- size_t arr_start = json.find('[', dec_pos);
196
- if (arr_start != std::string::npos) {
197
- m_decoder_parts.clear();
198
- size_t pos = arr_start + 1;
199
- int depth = 0;
200
- std::string part_json;
201
- for (; pos < json.length(); ++pos) {
202
- if (json[pos] == '{') depth++;
203
- if (depth > 0) part_json += json[pos];
204
- if (json[pos] == '}') {
205
- depth--;
206
- if (depth == 0) {
207
- // Parse this part
208
- ModelInfo info;
209
- info.name = json_get_string(part_json, "name");
210
- info.file = json_get_string(part_json, "file");
211
- info.inputs = json_get_string_array(part_json, "inputs");
212
- info.outputs = json_get_string_array(part_json, "outputs");
213
- m_decoder_parts.push_back(info);
214
- part_json.clear();
215
- }
216
- }
217
- }
218
- }
219
- }
220
-
221
- printf("Manifest: encoder=%s, decoder_parts=%zu\n",
222
- m_encoder_info.name.c_str(), m_decoder_parts.size());
223
- for (size_t i = 0; i < m_decoder_parts.size(); ++i) {
224
- printf(" part%zu: %s (%s) in=%zu out=%zu\n", i,
225
- m_decoder_parts[i].name.c_str(), m_decoder_parts[i].file.c_str(),
226
- m_decoder_parts[i].inputs.size(), m_decoder_parts[i].outputs.size());
227
- }
228
- return 0;
229
- }
230
-
231
- int ZipVoiceEngine::LoadModels(const std::string& model_dir, const char* axclConfig) {
232
- // Load encoder
233
- std::string enc_path = model_dir + "/" + m_encoder_info.file;
234
- auto enc = std::make_unique<EngineWrapper>();
235
- if (enc->Init(enc_path.c_str(), 0, axclConfig) != 0) {
236
- printf("Failed to load encoder: %s\n", enc_path.c_str());
237
- return -1;
238
- }
239
- m_sessions[m_encoder_info.name] = std::move(enc);
240
-
241
- // Load decoder parts
242
- for (auto& part : m_decoder_parts) {
243
- std::string path = model_dir + "/" + part.file;
244
- auto sess = std::make_unique<EngineWrapper>();
245
- if (sess->Init(path.c_str(), 0, axclConfig) != 0) {
246
- printf("Failed to load decoder part: %s\n", path.c_str());
247
- return -1;
248
- }
249
- m_sessions[part.name] = std::move(sess);
250
- }
251
-
252
- printf("Loaded %zu models\n", m_sessions.size());
253
- return 0;
254
- }
255
-
256
- int ZipVoiceEngine::LoadDecoderMetadata() {
257
- if (m_decoder_parts.empty()) return -1;
258
-
259
- auto& part0 = m_decoder_parts[0];
260
- auto it = m_sessions.find(part0.name);
261
- if (it == m_sessions.end()) return -1;
262
-
263
- auto& sess = it->second;
264
-
265
- // Check if padding_mask is an input
266
- int pad_idx = sess->GetInputIndex("padding_mask");
267
- m_decoder_has_padding_mask = (pad_idx >= 0);
268
-
269
- // Get sequence length from x input shape
270
- m_decoder_seq_len = m_config.max_feat_len;
271
-
272
- // Try to get seq_len from model metadata
273
- // The shape info is in the AX engine io_info; for simplicity we use config value
274
-
275
- printf("Decoder metadata: seq_len=%d, has_padding_mask=%d\n",
276
- m_decoder_seq_len, m_decoder_has_padding_mask ? 1 : 0);
277
- return 0;
278
- }
279
-
280
- std::vector<float> ZipVoiceEngine::GetTimesteps(int num_step, float t_shift) const {
281
- std::vector<float> ts(num_step + 1);
282
- for (int i = 0; i <= num_step; ++i) {
283
- float t = static_cast<float>(i) / num_step;
284
- ts[i] = t_shift * t / (1.0f + (t_shift - 1.0f) * t);
285
- }
286
- return ts;
287
- }
288
-
289
- int ZipVoiceEngine::RunEncoder(const std::vector<int32_t>& cat_tokens,
290
- std::vector<float>& out_encoded) {
291
- auto it = m_sessions.find(m_encoder_info.name);
292
- if (it == m_sessions.end()) return -1;
293
-
294
- auto& sess = it->second;
295
-
296
- // Set input
297
- int input_idx = sess->GetInputIndex(m_encoder_info.inputs[0].c_str());
298
- if (input_idx < 0) input_idx = 0;
299
-
300
- // Need to copy to non-const buffer for the engine API
301
- std::vector<int32_t> input_copy = cat_tokens;
302
- sess->SetInput(input_copy.data(), input_idx);
303
-
304
- // Run
305
- if (sess->RunSync() != 0) return -1;
306
-
307
- // Get output
308
- int output_idx = sess->GetOutputIndex(m_encoder_info.outputs[0].c_str());
309
- if (output_idx < 0) output_idx = 0;
310
-
311
- int output_size = sess->GetOutputSize(output_idx);
312
- out_encoded.resize(output_size / sizeof(float));
313
- sess->GetOutput(out_encoded.data(), output_idx);
314
-
315
- return 0;
316
- }
317
-
318
- int ZipVoiceEngine::DurationExpand(const std::vector<float>& encoded,
319
- int prompt_tokens_len,
320
- int text_tokens_len,
321
- int prompt_features_len,
322
- float speed,
323
- std::vector<float>& out_text_condition,
324
- int& out_features_len) {
325
- int total_tokens_len = prompt_tokens_len + text_tokens_len;
326
- if (total_tokens_len <= 0) return -1;
327
-
328
- // Compute target features length
329
- int features_len = static_cast<int>(
330
- std::ceil(static_cast<float>(prompt_features_len) / prompt_tokens_len
331
- * total_tokens_len / speed)
332
- );
333
- if (features_len > m_config.max_feat_len) {
334
- features_len = m_config.max_feat_len;
335
- }
336
-
337
- int feat_dim = m_config.feat_dim;
338
-
339
- // encoded shape: [1, max_tokens, feat_dim] (flat array)
340
- // Extract the no-pad portion
341
- int token_dur = features_len / total_tokens_len;
342
- int max_tokens = m_config.max_tokens;
343
-
344
- // out_text_condition: [1, features_len, feat_dim]
345
- out_text_condition.assign(features_len * feat_dim, 0.0f);
346
-
347
- // Repeat each token embedding token_dur times
348
- for (int t = 0; t < total_tokens_len; ++t) {
349
- int base_idx = t * feat_dim;
350
- for (int d = 0; d < token_dur; ++d) {
351
- int frame_idx = t * token_dur + d;
352
- if (frame_idx >= features_len) break;
353
- int dst_idx = frame_idx * feat_dim;
354
- std::copy(encoded.begin() + base_idx,
355
- encoded.begin() + base_idx + feat_dim,
356
- out_text_condition.begin() + dst_idx);
357
- }
358
- }
359
-
360
- // Fill residual frames with last token embedding
361
- int filled = total_tokens_len * token_dur;
362
- int residual = features_len - filled;
363
- if (residual > 0) {
364
- int last_base = total_tokens_len * feat_dim;
365
- for (int d = 0; d < residual; ++d) {
366
- int dst_idx = (filled + d) * feat_dim;
367
- std::copy(encoded.begin() + last_base,
368
- encoded.begin() + last_base + feat_dim,
369
- out_text_condition.begin() + dst_idx);
370
- }
371
- }
372
-
373
- out_features_len = features_len;
374
- return 0;
375
- }
376
-
377
- int ZipVoiceEngine::RunDecoderPart(const ModelInfo& part,
378
- std::map<std::string, std::vector<float>>& values,
379
- const std::vector<uint8_t>* padding_mask_data,
380
- std::vector<uint8_t>* padding_mask2_out) {
381
- auto it = m_sessions.find(part.name);
382
- if (it == m_sessions.end()) return -1;
383
- auto& sess = it->second;
384
-
385
- // Set inputs in order
386
- for (size_t i = 0; i < part.inputs.size(); ++i) {
387
- const std::string& expected_name = part.inputs[i];
388
-
389
- int input_idx = sess->GetInputIndex(expected_name.c_str());
390
- if (input_idx < 0) input_idx = static_cast<int>(i);
391
-
392
- // padding_mask: use uint8 data from caller (part0 only)
393
- if (expected_name == "padding_mask") {
394
- if (padding_mask_data) {
395
- sess->SetInput((void*)padding_mask_data->data(), input_idx);
396
- continue;
397
- }
398
- }
399
- // padding_mask2: use raw uint8 data from part0's output
400
- if (expected_name == "padding_mask2") {
401
- if (padding_mask2_out && !padding_mask2_out->empty()) {
402
- sess->SetInput((void*)padding_mask2_out->data(), input_idx);
403
- continue;
404
- }
405
- printf("ERROR: padding_mask2 not available for '%s'\n", part.name.c_str());
406
- return -1;
407
- }
408
-
409
- // Find the value in float map
410
- auto val_it = values.find(expected_name);
411
- if (val_it == values.end()) {
412
- printf("Missing input '%s' for model '%s'\n",
413
- expected_name.c_str(), part.name.c_str());
414
- return -1;
415
- }
416
-
417
- sess->SetInput((void*)val_it->second.data(), input_idx);
418
- }
419
-
420
- // Run
421
- if (sess->RunSync() != 0) return -1;
422
-
423
- // Get outputs
424
- for (size_t i = 0; i < part.outputs.size(); ++i) {
425
- const std::string& name = part.outputs[i];
426
-
427
- int output_idx = sess->GetOutputIndex(name.c_str());
428
- if (output_idx < 0) output_idx = static_cast<int>(i);
429
-
430
- int size = sess->GetOutputSize(output_idx);
431
- if (size <= 0) {
432
- printf("Invalid output size for '%s' in '%s'\n",
433
- name.c_str(), part.name.c_str());
434
- return -1;
435
- }
436
-
437
- // padding_mask2 is uint8 — read raw bytes, don't convert to float
438
- if (name == "padding_mask2" && padding_mask2_out) {
439
- padding_mask2_out->resize(size);
440
- sess->GetOutput(padding_mask2_out->data(), output_idx);
441
- continue;
442
- }
443
-
444
- std::vector<float> output_data(size / sizeof(float));
445
- sess->GetOutput(output_data.data(), output_idx);
446
- values[name] = std::move(output_data);
447
- }
448
-
449
- return 0;
450
- }
451
-
452
- int ZipVoiceEngine::Sample(const std::vector<int32_t>& cat_tokens,
453
- int prompt_tokens_len,
454
- int text_tokens_len,
455
- const std::vector<float>& prompt_features,
456
- int prompt_features_len,
457
- float speed,
458
- float guidance_scale,
459
- int seed,
460
- std::vector<float>& out_features,
461
- Timing& out_timing) {
462
- double t_total_start = GetCurrentTimeMs();
463
-
464
- // 1. Run encoder
465
- double t_start = GetCurrentTimeMs();
466
- std::vector<float> encoded;
467
- if (RunEncoder(cat_tokens, encoded) != 0) return -1;
468
- out_timing.encoder_time_sec = static_cast<float>(GetCurrentTimeMs() - t_start) / 1000.0f;
469
-
470
- // encoded shape: [max_tokens * feat_dim] (flattened, batch=1)
471
- int feat_dim = m_config.feat_dim;
472
-
473
- // 2. Duration expand
474
- t_start = GetCurrentTimeMs();
475
- std::vector<float> text_condition;
476
- int features_len;
477
- if (DurationExpand(encoded, prompt_tokens_len, text_tokens_len,
478
- prompt_features_len, speed,
479
- text_condition, features_len) != 0) return -1;
480
- out_timing.duration_expand_time_sec = static_cast<float>(GetCurrentTimeMs() - t_start) / 1000.0f;
481
-
482
- // 3. Prepare decoder inputs
483
- int seq_len = m_decoder_seq_len > 0 ? m_decoder_seq_len : m_config.max_feat_len;
484
-
485
- if (features_len > seq_len) {
486
- printf("features_len=%d exceeds decoder seq_len=%d\n", features_len, seq_len);
487
- return -1;
488
- }
489
- if (prompt_features_len > seq_len) {
490
- printf("prompt_features_len=%d exceeds decoder seq_len=%d\n", prompt_features_len, seq_len);
491
- return -1;
492
- }
493
-
494
- // text_cond_padded: [1, seq_len, feat_dim] (zeros, filled up to features_len)
495
- std::vector<float> text_cond_padded(seq_len * feat_dim, 0.0f);
496
- std::copy(text_condition.begin(),
497
- text_condition.begin() + features_len * feat_dim,
498
- text_cond_padded.begin());
499
-
500
- // speech_cond_padded: [1, seq_len, feat_dim]
501
- std::vector<float> speech_cond_padded(seq_len * feat_dim, 0.0f);
502
- std::copy(prompt_features.begin(),
503
- prompt_features.begin() + prompt_features_len * feat_dim,
504
- speech_cond_padded.begin());
505
- // DEBUG
506
-
507
- // padding_mask: [1, seq_len] as uint8_t (bool), NOT float32!
508
- // Python: np.zeros((1, seq_len), dtype=np.bool_)
509
- std::vector<uint8_t> padding_mask(seq_len, 0);
510
- for (int i = features_len; i < seq_len; ++i) {
511
- padding_mask[i] = 1;
512
- }
513
-
514
- // x: random init [1, seq_len, feat_dim]
515
- std::vector<float> x(seq_len * feat_dim, 0.0f);
516
- // Simple LCG random
517
- uint32_t rng_state = static_cast<uint32_t>(seed > 0 ? seed : 42);
518
- for (int i = 0; i < features_len * feat_dim; ++i) {
519
- rng_state = rng_state * 1103515245 + 12345;
520
- // Box-Muller for normal distribution
521
- float u1 = static_cast<float>(rng_state & 0x7FFFFFFF) / 0x7FFFFFFF;
522
- rng_state = rng_state * 1103515245 + 12345;
523
- float u2 = static_cast<float>(rng_state & 0x7FFFFFFF) / 0x7FFFFFFF;
524
- x[i] = std::sqrt(-2.0f * std::log(std::max(u1, 1e-10f)))
525
- * std::cos(2.0f * M_PI * u2);
526
- }
527
-
528
- // Time steps
529
- std::vector<float> timesteps = GetTimesteps(m_config.num_step, m_config.t_shift);
530
-
531
- // Guidance scale as single float array
532
- std::vector<float> gs = { guidance_scale };
533
-
534
- // 4. Flow-matching decoder
535
- double t_dec_total = 0.0;
536
- for (int step = 0; step < m_config.num_step; ++step) {
537
- double t_step_start = GetCurrentTimeMs();
538
-
539
- // Prepare inputs for this step
540
- std::map<std::string, std::vector<float>> values;
541
-
542
- // t: scalar
543
- std::vector<float> t_val = { timesteps[step] };
544
- values["t"] = t_val;
545
-
546
- // x: [1, seq_len, feat_dim]
547
- values["x"] = x;
548
-
549
- // text_condition
550
- values["text_condition"] = text_cond_padded;
551
-
552
- // speech_condition
553
- values["speech_condition"] = speech_cond_padded;
554
-
555
- // guidance_scale: scalar
556
- values["guidance_scale"] = gs;
557
-
558
- // padding_mask is passed separately as uint8_t (bool), not in values map
559
- std::vector<uint8_t> padding_mask2_data; // populated by part0, used by parts 1-3
560
-
561
- // Run all decoder parts in sequence
562
- for (auto& part : m_decoder_parts) {
563
- if (RunDecoderPart(part, values, &padding_mask, &padding_mask2_data) != 0) return -1;
564
- }
565
-
566
- t_dec_total += GetCurrentTimeMs() - t_step_start;
567
-
568
- // Get v (velocity) from last part output
569
- const std::string& final_output_name = m_decoder_parts.back().outputs[0];
570
- auto vit = values.find(final_output_name);
571
- if (vit == values.end()) {
572
- printf("Missing final output '%s'\n", final_output_name.c_str());
573
- return -1;
574
- }
575
-
576
- const std::vector<float>& v = vit->second;
577
-
578
- // Euler step: x = x + v * dt
579
- float dt = timesteps[step + 1] - timesteps[step];
580
- for (size_t i = 0; i < x.size(); ++i) {
581
- x[i] += v[i] * dt;
582
- }
583
-
584
- // Zero out padding region
585
- for (int i = features_len * feat_dim; i < seq_len * feat_dim; ++i) {
586
- x[i] = 0.0f;
587
- }
588
- }
589
-
590
- out_timing.decoder_time_sec = static_cast<float>(t_dec_total) / 1000.0f;
591
-
592
- // 5. Extract generated features (excluding prompt region)
593
- int generated_frames = features_len - prompt_features_len;
594
- if (generated_frames <= 0) {
595
- generated_frames = features_len;
596
- out_features.assign(x.begin(), x.begin() + features_len * feat_dim);
597
- } else {
598
- int offset = prompt_features_len * feat_dim;
599
- out_features.assign(x.begin() + offset,
600
- x.begin() + features_len * feat_dim);
601
- }
602
-
603
- out_timing.generated_frames = generated_frames;
604
- out_timing.features_len = features_len;
605
- out_timing.total_time_sec = static_cast<float>(GetCurrentTimeMs() - t_total_start) / 1000.0f;
606
-
607
- printf(" encoder: %.3f s dur_expand: %.3f s decoder(%d steps): %.3f s (avg %.3f ms/step) total: %.3f s\n",
608
- out_timing.encoder_time_sec,
609
- out_timing.duration_expand_time_sec,
610
- m_config.num_step,
611
- out_timing.decoder_time_sec,
612
- out_timing.decoder_time_sec / m_config.num_step * 1000.0f,
613
- out_timing.total_time_sec);
614
-
615
- return 0;
616
- }