First commit
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +16 -1
- README.md +125 -3
- audio/openwakeword/alexa_test.wav +0 -0
- audio/openwakeword/hey_jane.wav +0 -0
- audio/openwakeword/hey_mycroft_test.wav +0 -0
- config.json +9 -0
- config/openwakeword_mel_weights.bin +3 -0
- config/openwakeword_mel_weights.npz +3 -0
- cpp/CMakeLists.txt +57 -0
- cpp/README.md +89 -0
- cpp/bin/openwakeword_ax630c +0 -0
- cpp/bin/openwakeword_ax650 +0 -0
- cpp/build_ax630c.sh +32 -0
- cpp/build_ax650.sh +32 -0
- cpp/download_bsp.sh +45 -0
- cpp/openwakeword_ax.cpp +379 -0
- cpp/run_batch_openwakeword_ax.sh +122 -0
- cpp/run_batch_openwakeword_ax630c.sh +5 -0
- cpp/run_batch_openwakeword_ax650.sh +5 -0
- cpp/run_openwakeword_ax.sh +46 -0
- cpp/run_openwakeword_ax630c.sh +5 -0
- cpp/run_openwakeword_ax650.sh +5 -0
- cpp/src/engine_wrapper.cpp +197 -0
- cpp/src/engine_wrapper.hpp +43 -0
- cpp/src/wav_reader.hpp +80 -0
- manifest.json +217 -0
- models/630C/.gitkeep +1 -0
- models/630C/openwakeword__alexa_v0.1.axmodel +3 -0
- models/630C/openwakeword__embedding_model.axmodel +3 -0
- models/630C/openwakeword__hey_jarvis_v0.1.axmodel +3 -0
- models/630C/openwakeword__hey_mycroft_v0.1.axmodel +3 -0
- models/630C/openwakeword__hey_rhasspy_v0.1.axmodel +3 -0
- models/630C/openwakeword__melspectrogram.axmodel +3 -0
- models/630C/openwakeword__timer_v0.1.axmodel +3 -0
- models/630C/openwakeword__weather_v0.1.axmodel +3 -0
- models/650/openwakeword__alexa_v0.1.axmodel +3 -0
- models/650/openwakeword__embedding_model.axmodel +3 -0
- models/650/openwakeword__hey_jarvis_v0.1.axmodel +3 -0
- models/650/openwakeword__hey_mycroft_v0.1.axmodel +3 -0
- models/650/openwakeword__hey_rhasspy_v0.1.axmodel +3 -0
- models/650/openwakeword__melspectrogram.axmodel +3 -0
- models/650/openwakeword__timer_v0.1.axmodel +3 -0
- models/650/openwakeword__weather_v0.1.axmodel +3 -0
- outputs/.gitkeep +1 -0
- outputs/cpp_batch/logs/alexa_test.log +25 -0
- outputs/cpp_batch/logs/hey_jane.log +25 -0
- outputs/cpp_batch/logs/hey_mycroft_test.log +25 -0
- outputs/cpp_batch/results.tsv +4 -0
- outputs/cpp_batch/summary.txt +7 -0
- reference/local_inference_results.json +497 -0
.gitattributes
CHANGED
|
@@ -10,7 +10,6 @@
|
|
| 10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 14 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 15 |
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 16 |
*.npz filter=lfs diff=lfs merge=lfs -text
|
|
@@ -34,3 +33,19 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 36 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
*.model filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 13 |
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
*.npz filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
models/630C/openwakeword__alexa_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
models/630C/openwakeword__embedding_model.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
models/630C/openwakeword__hey_jarvis_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
models/630C/openwakeword__hey_mycroft_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
models/630C/openwakeword__hey_rhasspy_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
models/630C/openwakeword__melspectrogram.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
models/630C/openwakeword__timer_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
models/630C/openwakeword__weather_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
models/650/openwakeword__alexa_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
models/650/openwakeword__embedding_model.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
models/650/openwakeword__hey_jarvis_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
models/650/openwakeword__hey_mycroft_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
models/650/openwakeword__hey_rhasspy_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
models/650/openwakeword__melspectrogram.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
models/650/openwakeword__timer_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
models/650/openwakeword__weather_v0.1.axmodel filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,3 +1,125 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# openWakeWord.AXERA
|
| 2 |
+
|
| 3 |
+
[openWakeWord](https://github.com/dscripka/openWakeWord) 语音唤醒 AXERA 推理 demo。
|
| 4 |
+
|
| 5 |
+
## 功能
|
| 6 |
+
|
| 7 |
+
- 支持 AX650 和 AX630C;
|
| 8 |
+
- 支持 Python 和 C++ 板端推理;
|
| 9 |
+
|
| 10 |
+
## 目录结构
|
| 11 |
+
|
| 12 |
+
```text
|
| 13 |
+
OpenWakeWord.AXERA/
|
| 14 |
+
├── models/
|
| 15 |
+
│ ├── 650/ # AX650 axmodel
|
| 16 |
+
│ └── 630C/ # AX630C axmodel
|
| 17 |
+
├── config/ # STFT/mel 权重
|
| 18 |
+
├── audio/openwakeword/
|
| 19 |
+
├── scripts/ # Python 推理代码
|
| 20 |
+
├── cpp/ # C++ 源码、编译和运行脚本
|
| 21 |
+
└── README.md
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
## Python
|
| 26 |
+
|
| 27 |
+
```bash
|
| 28 |
+
创建虚拟环境
|
| 29 |
+
conda create -n OpenWakeWord python=3.10
|
| 30 |
+
conda activate OpenWakeWord
|
| 31 |
+
|
| 32 |
+
安装 [pyaxengine](https://github.com/AXERA-TECH/pyaxengine/releases/latest):
|
| 33 |
+
pip install axengine-x.x.x-py3-none-any.whl
|
| 34 |
+
|
| 35 |
+
pip install -r requirements.txt
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
AX650:
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
python scripts/openwakeword_ax650.py
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
AX630C:
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
python scripts/openwakeword_ax630c.py
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
自定义音频目录、阈值和输出文件:
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
python scripts/openwakeword_ax630c.py \
|
| 54 |
+
--audio-dir audio/openwakeword \
|
| 55 |
+
--threshold 0.5 \
|
| 56 |
+
--output outputs/openwakeword_ax630c.json
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
## C++
|
| 60 |
+
|
| 61 |
+
### 编译环境
|
| 62 |
+
|
| 63 |
+
AX650 和 AX630C 共用 Arm GNU 9.2 AArch64 交叉编译器:
|
| 64 |
+
|
| 65 |
+
<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>
|
| 66 |
+
|
| 67 |
+
```bash
|
| 68 |
+
mkdir -p cpp/toolchains
|
| 69 |
+
wget -P cpp/toolchains \
|
| 70 |
+
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
|
| 71 |
+
tar -xf cpp/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz \
|
| 72 |
+
-C cpp/toolchains
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
BSP SDK 下载地址:
|
| 76 |
+
|
| 77 |
+
| 平台 | BSP SDK |
|
| 78 |
+
| --- | --- |
|
| 79 |
+
| AX650 | <https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_50_3.10.2.zip> |
|
| 80 |
+
| AX630C | <https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_20e_3.0.0.zip> |
|
| 81 |
+
|
| 82 |
+
下载并整理到 `cpp/toolchains/`:
|
| 83 |
+
|
| 84 |
+
```bash
|
| 85 |
+
bash cpp/download_bsp.sh all
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### 交叉编译
|
| 89 |
+
|
| 90 |
+
```bash
|
| 91 |
+
export TOOLCHAIN_ROOT="cpp/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu"
|
| 92 |
+
|
| 93 |
+
bash cpp/build_ax650.sh
|
| 94 |
+
bash cpp/build_ax630c.sh
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
编译结果:
|
| 98 |
+
|
| 99 |
+
```text
|
| 100 |
+
cpp/bin/openwakeword_ax650
|
| 101 |
+
cpp/bin/openwakeword_ax630c
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
### 板端批量测试
|
| 105 |
+
|
| 106 |
+
AX650:
|
| 107 |
+
|
| 108 |
+
```bash
|
| 109 |
+
THRESHOLD=0.5 bash cpp/run_batch_openwakeword_ax650.sh
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
AX630C:
|
| 113 |
+
|
| 114 |
+
```bash
|
| 115 |
+
THRESHOLD=0.5 bash cpp/run_batch_openwakeword_ax630c.sh
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
结果分别写入 `outputs/cpp_ax650_batch/` 和 `outputs/cpp_ax630c_batch/`。
|
| 119 |
+
|
| 120 |
+
详细 C++ 说明见 `cpp/README.md`。
|
| 121 |
+
|
| 122 |
+
## 参考
|
| 123 |
+
|
| 124 |
+
- [openWakeWord](https://github.com/dscripka/openWakeWord)
|
| 125 |
+
- [Pulsar2](https://pulsar2-docs.readthedocs.io/en/latest/pulsar2/introduction.html)
|
audio/openwakeword/alexa_test.wav
ADDED
|
Binary file (20 kB). View file
|
|
|
audio/openwakeword/hey_jane.wav
ADDED
|
Binary file (75.8 kB). View file
|
|
|
audio/openwakeword/hey_mycroft_test.wav
ADDED
|
Binary file (30.5 kB). View file
|
|
|
config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "keyword-spotting",
|
| 3 |
+
"source": "openWakeWord",
|
| 4 |
+
"target_hardware": "AX630C/AX650",
|
| 5 |
+
"runtime": "axengine",
|
| 6 |
+
"sample_rate": 16000,
|
| 7 |
+
"default_threshold": 0.5,
|
| 8 |
+
"mel_backend": "numpy"
|
| 9 |
+
}
|
config/openwakeword_mel_weights.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f5d3a5bafe0def6c1efb4874d724c272d78edadada6652ef885059db2ba147a7
|
| 3 |
+
size 1085608
|
config/openwakeword_mel_weights.npz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a3de443a7383dc51a4bf8b1d2dc9bbc767f7e33e17af617d993700a5f9947ed6
|
| 3 |
+
size 1086554
|
cpp/CMakeLists.txt
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cmake_minimum_required(VERSION 3.13)
|
| 2 |
+
project(openwakeword_axera_cpp LANGUAGES C CXX)
|
| 3 |
+
|
| 4 |
+
set(CMAKE_CXX_STANDARD 17)
|
| 5 |
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
| 6 |
+
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
|
| 7 |
+
|
| 8 |
+
set(AXERA_TARGET "AX650" CACHE STRING "AXERA target: AX650 or AX630C")
|
| 9 |
+
set_property(CACHE AXERA_TARGET PROPERTY STRINGS AX650 AX630C)
|
| 10 |
+
string(TOUPPER "${AXERA_TARGET}" AXERA_TARGET)
|
| 11 |
+
if(AXERA_TARGET STREQUAL "AX650")
|
| 12 |
+
set(KWS_EXECUTABLE openwakeword_ax650)
|
| 13 |
+
set(DEFAULT_BSP_MSP_DIR
|
| 14 |
+
"${CMAKE_SOURCE_DIR}/toolchains/ax650n_bsp_sdk/msp/out")
|
| 15 |
+
elseif(AXERA_TARGET STREQUAL "AX630C")
|
| 16 |
+
set(KWS_EXECUTABLE openwakeword_ax630c)
|
| 17 |
+
set(DEFAULT_BSP_MSP_DIR
|
| 18 |
+
"${CMAKE_SOURCE_DIR}/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc")
|
| 19 |
+
else()
|
| 20 |
+
message(FATAL_ERROR "AXERA_TARGET must be AX650 or AX630C")
|
| 21 |
+
endif()
|
| 22 |
+
|
| 23 |
+
set(BSP_MSP_DIR "${DEFAULT_BSP_MSP_DIR}" CACHE PATH
|
| 24 |
+
"BSP directory containing include/ and lib/")
|
| 25 |
+
if(NOT EXISTS "${BSP_MSP_DIR}/include/ax_engine_api.h")
|
| 26 |
+
message(FATAL_ERROR
|
| 27 |
+
"${AXERA_TARGET} BSP not found: ${BSP_MSP_DIR}. "
|
| 28 |
+
"Set BSP_MSP_DIR to the directory containing include/ and lib/.")
|
| 29 |
+
endif()
|
| 30 |
+
|
| 31 |
+
add_executable(${KWS_EXECUTABLE}
|
| 32 |
+
openwakeword_ax.cpp
|
| 33 |
+
src/engine_wrapper.cpp
|
| 34 |
+
)
|
| 35 |
+
target_include_directories(${KWS_EXECUTABLE} PRIVATE
|
| 36 |
+
${CMAKE_SOURCE_DIR}
|
| 37 |
+
${CMAKE_SOURCE_DIR}/src
|
| 38 |
+
${BSP_MSP_DIR}/include
|
| 39 |
+
)
|
| 40 |
+
target_link_directories(${KWS_EXECUTABLE} PRIVATE ${BSP_MSP_DIR}/lib)
|
| 41 |
+
target_compile_definitions(${KWS_EXECUTABLE} PRIVATE
|
| 42 |
+
AXERA_TARGET_NAME="${AXERA_TARGET}"
|
| 43 |
+
)
|
| 44 |
+
target_compile_options(${KWS_EXECUTABLE} PRIVATE
|
| 45 |
+
-O3 -Wall -Wextra -Wpedantic
|
| 46 |
+
-fvisibility=hidden -fdata-sections -ffunction-sections
|
| 47 |
+
)
|
| 48 |
+
target_link_libraries(${KWS_EXECUTABLE} PRIVATE
|
| 49 |
+
ax_sys ax_engine ax_interpreter pthread dl m
|
| 50 |
+
)
|
| 51 |
+
target_link_options(${KWS_EXECUTABLE} PRIVATE
|
| 52 |
+
-Wl,--enable-new-dtags -Wl,--allow-shlib-undefined
|
| 53 |
+
)
|
| 54 |
+
set_target_properties(${KWS_EXECUTABLE} PROPERTIES
|
| 55 |
+
BUILD_WITH_INSTALL_RPATH TRUE
|
| 56 |
+
INSTALL_RPATH "$ORIGIN"
|
| 57 |
+
)
|
cpp/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# openWakeWord C++ 推理
|
| 2 |
+
|
| 3 |
+
本目录提供 AX650 和 AX630C C++ 推理程序。WAV、STFT、mel 和缓存更新在 CPU
|
| 4 |
+
端完成,embedding 与 classifier 使用对应平台的 `axmodel`。
|
| 5 |
+
|
| 6 |
+
## 编译环境
|
| 7 |
+
|
| 8 |
+
AX650 与 AX630C 共用 Arm GNU 9.2 AArch64 交叉编译器:
|
| 9 |
+
|
| 10 |
+
```bash
|
| 11 |
+
mkdir -p cpp/toolchains
|
| 12 |
+
wget -P cpp/toolchains \
|
| 13 |
+
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
|
| 14 |
+
tar -xf cpp/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz \
|
| 15 |
+
-C cpp/toolchains
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
下载 BSP:
|
| 19 |
+
|
| 20 |
+
```bash
|
| 21 |
+
bash cpp/download_bsp.sh all
|
| 22 |
+
```
|
| 23 |
+
|
| 24 |
+
| 平台 | BSP 压缩包 | 编译目录 |
|
| 25 |
+
| --- | --- | --- |
|
| 26 |
+
| AX650 | `msp_50_3.10.2.zip` | `cpp/toolchains/ax650n_bsp_sdk/msp/out` |
|
| 27 |
+
| AX630C | `msp_20e_3.0.0.zip` | `cpp/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc` |
|
| 28 |
+
|
| 29 |
+
## 交叉编译
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
export TOOLCHAIN_ROOT="cpp/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu"
|
| 33 |
+
|
| 34 |
+
bash cpp/build_ax650.sh
|
| 35 |
+
bash cpp/build_ax630c.sh
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
生成:
|
| 39 |
+
|
| 40 |
+
```text
|
| 41 |
+
cpp/bin/openwakeword_ax650
|
| 42 |
+
cpp/bin/openwakeword_ax630c
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
如 BSP 放在其他位置,可设置 `BSP_MSP_DIR`。AX650 应指向包含 `include/` 和
|
| 46 |
+
`lib/` 的 `msp/out`;AX630C 应指向 `msp/out/arm64_glibc`。
|
| 47 |
+
|
| 48 |
+
## 板端运行
|
| 49 |
+
|
| 50 |
+
AX650 单条推理:
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
AUDIO=audio/openwakeword/alexa_test.wav \
|
| 54 |
+
bash cpp/run_openwakeword_ax650.sh
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
AX630C 单条推理:
|
| 58 |
+
|
| 59 |
+
```bash
|
| 60 |
+
AUDIO=audio/openwakeword/alexa_test.wav \
|
| 61 |
+
bash cpp/run_openwakeword_ax630c.sh
|
| 62 |
+
```
|
| 63 |
+
|
| 64 |
+
批量测试:
|
| 65 |
+
|
| 66 |
+
```bash
|
| 67 |
+
THRESHOLD=0.5 bash cpp/run_batch_openwakeword_ax650.sh
|
| 68 |
+
THRESHOLD=0.5 bash cpp/run_batch_openwakeword_ax630c.sh
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
模型目录必须与平台对应:
|
| 72 |
+
|
| 73 |
+
```text
|
| 74 |
+
models/650/
|
| 75 |
+
models/630C/
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
运行脚本会检查 embedding 和 6 个 classifier 模型,避免误用其他平台的 axmodel。
|
| 79 |
+
输入音频必须为 16 kHz、单声道、16-bit PCM WAV。
|
| 80 |
+
|
| 81 |
+
单条推理会输出 classifier 分数和 `WAKEUP`,并只输出一个 `rtf`。`rtf` 包含
|
| 82 |
+
CPU mel 和 NPU 推理,不包含一次性模型加载与初始化。
|
| 83 |
+
|
| 84 |
+
阈值可通过环境变量调整:
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
THRESHOLD=0.6 AUDIO=audio/openwakeword/hey_mycroft_test.wav \
|
| 88 |
+
bash cpp/run_openwakeword_ax630c.sh
|
| 89 |
+
```
|
cpp/bin/openwakeword_ax630c
ADDED
|
Binary file (39.7 kB). View file
|
|
|
cpp/bin/openwakeword_ax650
ADDED
|
Binary file (39.7 kB). View file
|
|
|
cpp/build_ax630c.sh
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
CPP_DIR="${ROOT}/cpp"
|
| 6 |
+
TOOLCHAIN_ROOT="${TOOLCHAIN_ROOT:-${CPP_DIR}/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu}"
|
| 7 |
+
BSP_MSP_DIR="${BSP_MSP_DIR:-${CPP_DIR}/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc}"
|
| 8 |
+
BUILD_DIR="${CPP_DIR}/build/ax630c"
|
| 9 |
+
|
| 10 |
+
if [[ ! -x "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" ]]; then
|
| 11 |
+
echo "ERROR: AArch64 toolchain not found: ${TOOLCHAIN_ROOT}" >&2
|
| 12 |
+
exit 2
|
| 13 |
+
fi
|
| 14 |
+
if [[ ! -f "${BSP_MSP_DIR}/include/ax_engine_api.h" ]]; then
|
| 15 |
+
echo "ERROR: AX630C BSP arm64_glibc directory not found: ${BSP_MSP_DIR}" >&2
|
| 16 |
+
exit 2
|
| 17 |
+
fi
|
| 18 |
+
|
| 19 |
+
mkdir -p "${BUILD_DIR}" "${CPP_DIR}/bin"
|
| 20 |
+
cmake -S "${CPP_DIR}" -B "${BUILD_DIR}" \
|
| 21 |
+
-DCMAKE_BUILD_TYPE=Release \
|
| 22 |
+
-DCMAKE_SYSTEM_NAME=Linux \
|
| 23 |
+
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
|
| 24 |
+
-DCMAKE_C_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-gcc" \
|
| 25 |
+
-DCMAKE_CXX_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" \
|
| 26 |
+
-DAXERA_TARGET=AX630C \
|
| 27 |
+
-DBSP_MSP_DIR="${BSP_MSP_DIR}"
|
| 28 |
+
cmake --build "${BUILD_DIR}" -j"$(nproc)"
|
| 29 |
+
cp "${BUILD_DIR}/openwakeword_ax630c" "${CPP_DIR}/bin/"
|
| 30 |
+
"${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-strip" --strip-unneeded \
|
| 31 |
+
"${CPP_DIR}/bin/openwakeword_ax630c"
|
| 32 |
+
echo "Built ${CPP_DIR}/bin/openwakeword_ax630c"
|
cpp/build_ax650.sh
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
CPP_DIR="${ROOT}/cpp"
|
| 6 |
+
TOOLCHAIN_ROOT="${TOOLCHAIN_ROOT:-${CPP_DIR}/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu}"
|
| 7 |
+
BSP_MSP_DIR="${BSP_MSP_DIR:-${CPP_DIR}/toolchains/ax650n_bsp_sdk/msp/out}"
|
| 8 |
+
BUILD_DIR="${CPP_DIR}/build/ax650"
|
| 9 |
+
|
| 10 |
+
if [[ ! -x "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" ]]; then
|
| 11 |
+
echo "ERROR: AArch64 toolchain not found: ${TOOLCHAIN_ROOT}" >&2
|
| 12 |
+
exit 2
|
| 13 |
+
fi
|
| 14 |
+
if [[ ! -f "${BSP_MSP_DIR}/include/ax_engine_api.h" ]]; then
|
| 15 |
+
echo "ERROR: AX650 BSP msp/out not found: ${BSP_MSP_DIR}" >&2
|
| 16 |
+
exit 2
|
| 17 |
+
fi
|
| 18 |
+
|
| 19 |
+
mkdir -p "${BUILD_DIR}" "${CPP_DIR}/bin"
|
| 20 |
+
cmake -S "${CPP_DIR}" -B "${BUILD_DIR}" \
|
| 21 |
+
-DCMAKE_BUILD_TYPE=Release \
|
| 22 |
+
-DCMAKE_SYSTEM_NAME=Linux \
|
| 23 |
+
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
|
| 24 |
+
-DCMAKE_C_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-gcc" \
|
| 25 |
+
-DCMAKE_CXX_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" \
|
| 26 |
+
-DAXERA_TARGET=AX650 \
|
| 27 |
+
-DBSP_MSP_DIR="${BSP_MSP_DIR}"
|
| 28 |
+
cmake --build "${BUILD_DIR}" -j"$(nproc)"
|
| 29 |
+
cp "${BUILD_DIR}/openwakeword_ax650" "${CPP_DIR}/bin/"
|
| 30 |
+
"${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-strip" --strip-unneeded \
|
| 31 |
+
"${CPP_DIR}/bin/openwakeword_ax650"
|
| 32 |
+
echo "Built ${CPP_DIR}/bin/openwakeword_ax650"
|
cpp/download_bsp.sh
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
CPP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
TOOLCHAINS_DIR="${CPP_DIR}/toolchains"
|
| 6 |
+
PLATFORM="${1:-all}"
|
| 7 |
+
|
| 8 |
+
download_sdk() {
|
| 9 |
+
local directory="$1"
|
| 10 |
+
local archive_name="$2"
|
| 11 |
+
local extracted_name="$3"
|
| 12 |
+
local url="$4"
|
| 13 |
+
|
| 14 |
+
if [[ -d "${TOOLCHAINS_DIR}/${directory}" ]]; then
|
| 15 |
+
echo "Found ${TOOLCHAINS_DIR}/${directory}"
|
| 16 |
+
return
|
| 17 |
+
fi
|
| 18 |
+
mkdir -p "${TOOLCHAINS_DIR}"
|
| 19 |
+
wget -c "${url}" -O "${TOOLCHAINS_DIR}/${archive_name}"
|
| 20 |
+
unzip -q "${TOOLCHAINS_DIR}/${archive_name}" -d "${TOOLCHAINS_DIR}"
|
| 21 |
+
mv "${TOOLCHAINS_DIR}/${extracted_name}" "${TOOLCHAINS_DIR}/${directory}"
|
| 22 |
+
rm -f "${TOOLCHAINS_DIR}/${archive_name}"
|
| 23 |
+
echo "Downloaded ${TOOLCHAINS_DIR}/${directory}"
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
case "${PLATFORM}" in
|
| 27 |
+
650|AX650|ax650)
|
| 28 |
+
download_sdk \
|
| 29 |
+
ax650n_bsp_sdk msp_50_3.10.2.zip msp_50_3.10.2 \
|
| 30 |
+
https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_50_3.10.2.zip
|
| 31 |
+
;;
|
| 32 |
+
630C|AX630C|ax630c)
|
| 33 |
+
download_sdk \
|
| 34 |
+
ax620e_bsp_sdk msp_20e_3.0.0.zip msp_20e_3.0.0 \
|
| 35 |
+
https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_20e_3.0.0.zip
|
| 36 |
+
;;
|
| 37 |
+
all)
|
| 38 |
+
bash "${BASH_SOURCE[0]}" 650
|
| 39 |
+
bash "${BASH_SOURCE[0]}" 630C
|
| 40 |
+
;;
|
| 41 |
+
*)
|
| 42 |
+
echo "Usage: bash cpp/download_bsp.sh [650|630C|all]" >&2
|
| 43 |
+
exit 2
|
| 44 |
+
;;
|
| 45 |
+
esac
|
cpp/openwakeword_ax.cpp
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <algorithm>
|
| 2 |
+
#include <array>
|
| 3 |
+
#include <chrono>
|
| 4 |
+
#include <cmath>
|
| 5 |
+
#include <cstdint>
|
| 6 |
+
#include <cstdio>
|
| 7 |
+
#include <cstring>
|
| 8 |
+
#include <fstream>
|
| 9 |
+
#include <limits>
|
| 10 |
+
#include <stdexcept>
|
| 11 |
+
#include <string>
|
| 12 |
+
#include <vector>
|
| 13 |
+
|
| 14 |
+
#include "ax_engine_api.h"
|
| 15 |
+
#include "ax_sys_api.h"
|
| 16 |
+
#include "src/engine_wrapper.hpp"
|
| 17 |
+
#include "src/wav_reader.hpp"
|
| 18 |
+
|
| 19 |
+
#ifndef AXERA_TARGET_NAME
|
| 20 |
+
#define AXERA_TARGET_NAME "AXERA"
|
| 21 |
+
#endif
|
| 22 |
+
|
| 23 |
+
namespace {
|
| 24 |
+
constexpr int kSampleRate = 16000;
|
| 25 |
+
constexpr int kChunkSamples = 1280;
|
| 26 |
+
constexpr int kHistorySamples = 480;
|
| 27 |
+
constexpr int kFftSize = 512;
|
| 28 |
+
constexpr int kSpectrumBins = 257;
|
| 29 |
+
constexpr int kMelBins = 32;
|
| 30 |
+
constexpr int kMelFrames = 8;
|
| 31 |
+
constexpr int kEmbeddingFrames = 76;
|
| 32 |
+
constexpr int kEmbeddingSize = 96;
|
| 33 |
+
constexpr int kFeatureFrames = 34;
|
| 34 |
+
using Clock = std::chrono::steady_clock;
|
| 35 |
+
|
| 36 |
+
double ElapsedSeconds(Clock::time_point begin, Clock::time_point end) {
|
| 37 |
+
return std::chrono::duration<double>(end - begin).count();
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
struct Args {
|
| 41 |
+
std::string models_dir = "models";
|
| 42 |
+
std::string weights = "config/openwakeword_mel_weights.bin";
|
| 43 |
+
std::string audio = "audio/openwakeword/alexa_test.wav";
|
| 44 |
+
float threshold = 0.5f;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
void Usage(const char *program) {
|
| 48 |
+
std::printf(
|
| 49 |
+
"Usage: %s [--models-dir DIR] [--mel-weights FILE] [--audio WAV] "
|
| 50 |
+
"[--threshold VALUE]\n",
|
| 51 |
+
program);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
Args ParseArgs(int argc, char **argv) {
|
| 55 |
+
Args args;
|
| 56 |
+
for (int i = 1; i < argc; ++i) {
|
| 57 |
+
const std::string key = argv[i];
|
| 58 |
+
auto value = [&]() -> std::string {
|
| 59 |
+
if (++i >= argc) throw std::runtime_error("Missing value for " + key);
|
| 60 |
+
return argv[i];
|
| 61 |
+
};
|
| 62 |
+
if (key == "--models-dir") {
|
| 63 |
+
args.models_dir = value();
|
| 64 |
+
} else if (key == "--mel-weights") {
|
| 65 |
+
args.weights = value();
|
| 66 |
+
} else if (key == "--audio") {
|
| 67 |
+
args.audio = value();
|
| 68 |
+
} else if (key == "--threshold") {
|
| 69 |
+
args.threshold = std::stof(value());
|
| 70 |
+
} else if (key == "-h" || key == "--help") {
|
| 71 |
+
Usage(argv[0]);
|
| 72 |
+
std::exit(0);
|
| 73 |
+
} else {
|
| 74 |
+
throw std::runtime_error("Unknown argument: " + key);
|
| 75 |
+
}
|
| 76 |
+
}
|
| 77 |
+
return args;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
std::string Join(const std::string &left, const std::string &right) {
|
| 81 |
+
return left.empty() || left.back() == '/' ? left + right
|
| 82 |
+
: left + "/" + right;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
class AxRuntime {
|
| 86 |
+
public:
|
| 87 |
+
AxRuntime() {
|
| 88 |
+
if (AX_SYS_Init() != 0) throw std::runtime_error("AX_SYS_Init failed");
|
| 89 |
+
sys_initialized_ = true;
|
| 90 |
+
AX_ENGINE_NPU_ATTR_T attr{};
|
| 91 |
+
if (AX_ENGINE_Init(&attr) != 0) {
|
| 92 |
+
AX_SYS_Deinit();
|
| 93 |
+
sys_initialized_ = false;
|
| 94 |
+
throw std::runtime_error("AX_ENGINE_Init failed");
|
| 95 |
+
}
|
| 96 |
+
engine_initialized_ = true;
|
| 97 |
+
}
|
| 98 |
+
~AxRuntime() {
|
| 99 |
+
if (engine_initialized_) AX_ENGINE_Deinit();
|
| 100 |
+
if (sys_initialized_) AX_SYS_Deinit();
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
private:
|
| 104 |
+
bool sys_initialized_ = false;
|
| 105 |
+
bool engine_initialized_ = false;
|
| 106 |
+
};
|
| 107 |
+
|
| 108 |
+
template <typename T>
|
| 109 |
+
T ReadScalar(std::istream &input) {
|
| 110 |
+
T value{};
|
| 111 |
+
input.read(reinterpret_cast<char *>(&value), sizeof(value));
|
| 112 |
+
if (!input) throw std::runtime_error("Truncated mel weight file");
|
| 113 |
+
return value;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
struct MelWeights {
|
| 117 |
+
std::vector<float> real;
|
| 118 |
+
std::vector<float> imag;
|
| 119 |
+
std::vector<float> mel;
|
| 120 |
+
float floor = 0.0f;
|
| 121 |
+
|
| 122 |
+
static MelWeights Load(const std::string &path) {
|
| 123 |
+
std::ifstream input(path, std::ios::binary);
|
| 124 |
+
if (!input) throw std::runtime_error("Cannot open mel weights: " + path);
|
| 125 |
+
char magic[8]{};
|
| 126 |
+
input.read(magic, 8);
|
| 127 |
+
if (std::memcmp(magic, "OWWMEL1", 7) != 0 ||
|
| 128 |
+
ReadScalar<uint32_t>(input) != 1) {
|
| 129 |
+
throw std::runtime_error("Invalid openWakeWord mel weight file");
|
| 130 |
+
}
|
| 131 |
+
const uint32_t real_rows = ReadScalar<uint32_t>(input);
|
| 132 |
+
const uint32_t real_cols = ReadScalar<uint32_t>(input);
|
| 133 |
+
const uint32_t imag_rows = ReadScalar<uint32_t>(input);
|
| 134 |
+
const uint32_t imag_cols = ReadScalar<uint32_t>(input);
|
| 135 |
+
const uint32_t mel_rows = ReadScalar<uint32_t>(input);
|
| 136 |
+
const uint32_t mel_cols = ReadScalar<uint32_t>(input);
|
| 137 |
+
MelWeights result;
|
| 138 |
+
result.floor = ReadScalar<float>(input);
|
| 139 |
+
if (real_rows != kSpectrumBins || real_cols != kFftSize ||
|
| 140 |
+
imag_rows != kSpectrumBins || imag_cols != kFftSize ||
|
| 141 |
+
mel_rows != kSpectrumBins || mel_cols != kMelBins) {
|
| 142 |
+
throw std::runtime_error("Unexpected openWakeWord mel weight shapes");
|
| 143 |
+
}
|
| 144 |
+
result.real.resize(static_cast<std::size_t>(real_rows) * real_cols);
|
| 145 |
+
result.imag.resize(static_cast<std::size_t>(imag_rows) * imag_cols);
|
| 146 |
+
result.mel.resize(static_cast<std::size_t>(mel_rows) * mel_cols);
|
| 147 |
+
input.read(reinterpret_cast<char *>(result.real.data()),
|
| 148 |
+
result.real.size() * sizeof(float));
|
| 149 |
+
input.read(reinterpret_cast<char *>(result.imag.data()),
|
| 150 |
+
result.imag.size() * sizeof(float));
|
| 151 |
+
input.read(reinterpret_cast<char *>(result.mel.data()),
|
| 152 |
+
result.mel.size() * sizeof(float));
|
| 153 |
+
if (!input) throw std::runtime_error("Truncated openWakeWord mel weights");
|
| 154 |
+
return result;
|
| 155 |
+
}
|
| 156 |
+
};
|
| 157 |
+
|
| 158 |
+
std::array<float, kMelFrames * kMelBins> ComputeMel(
|
| 159 |
+
const std::array<float, kHistorySamples + kChunkSamples> &samples,
|
| 160 |
+
const MelWeights &weights) {
|
| 161 |
+
std::array<float, kMelFrames * kMelBins> result{};
|
| 162 |
+
std::array<float, kSpectrumBins> power{};
|
| 163 |
+
float max_db = -std::numeric_limits<float>::infinity();
|
| 164 |
+
for (int frame = 0; frame < kMelFrames; ++frame) {
|
| 165 |
+
const float *frame_samples = samples.data() + frame * 160;
|
| 166 |
+
for (int frequency = 0; frequency < kSpectrumBins; ++frequency) {
|
| 167 |
+
const float *real = weights.real.data() + frequency * kFftSize;
|
| 168 |
+
const float *imag = weights.imag.data() + frequency * kFftSize;
|
| 169 |
+
float real_sum = 0.0f;
|
| 170 |
+
float imag_sum = 0.0f;
|
| 171 |
+
for (int n = 0; n < kFftSize; ++n) {
|
| 172 |
+
real_sum += frame_samples[n] * real[n];
|
| 173 |
+
imag_sum += frame_samples[n] * imag[n];
|
| 174 |
+
}
|
| 175 |
+
power[frequency] = real_sum * real_sum + imag_sum * imag_sum;
|
| 176 |
+
}
|
| 177 |
+
for (int bin = 0; bin < kMelBins; ++bin) {
|
| 178 |
+
float value = 0.0f;
|
| 179 |
+
for (int frequency = 0; frequency < kSpectrumBins; ++frequency) {
|
| 180 |
+
value += power[frequency] *
|
| 181 |
+
weights.mel[frequency * kMelBins + bin];
|
| 182 |
+
}
|
| 183 |
+
value = std::max(value, weights.floor);
|
| 184 |
+
const float db = std::log(value) * 10.0f / 2.3025851249694824f;
|
| 185 |
+
result[frame * kMelBins + bin] = db;
|
| 186 |
+
max_db = std::max(max_db, db);
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
const float minimum = max_db - 80.0f;
|
| 190 |
+
for (float &value : result) {
|
| 191 |
+
value = std::max(value, minimum) / 10.0f + 2.0f;
|
| 192 |
+
}
|
| 193 |
+
return result;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
struct Classifier {
|
| 197 |
+
std::string name;
|
| 198 |
+
int frames;
|
| 199 |
+
EngineWrapper engine;
|
| 200 |
+
std::vector<float> maximum;
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
void Run(const Args &args) {
|
| 204 |
+
const PcmWav wav = ReadPcmWav(args.audio);
|
| 205 |
+
if (wav.sample_rate != kSampleRate) {
|
| 206 |
+
throw std::runtime_error("Input WAV must use 16 kHz sample rate");
|
| 207 |
+
}
|
| 208 |
+
const double audio_seconds =
|
| 209 |
+
static_cast<double>(wav.samples.size()) / kSampleRate;
|
| 210 |
+
if (audio_seconds <= 0.0) {
|
| 211 |
+
throw std::runtime_error("Input WAV contains no samples");
|
| 212 |
+
}
|
| 213 |
+
const MelWeights weights = MelWeights::Load(args.weights);
|
| 214 |
+
const auto model_load_begin = Clock::now();
|
| 215 |
+
AxRuntime runtime;
|
| 216 |
+
|
| 217 |
+
EngineWrapper embedding;
|
| 218 |
+
if (embedding.Init(Join(args.models_dir,
|
| 219 |
+
"openwakeword__embedding_model.axmodel")) != 0) {
|
| 220 |
+
throw std::runtime_error("Failed to load embedding model");
|
| 221 |
+
}
|
| 222 |
+
const std::array<std::pair<const char *, int>, 6> definitions{{
|
| 223 |
+
{"alexa_v0.1", 16},
|
| 224 |
+
{"hey_jarvis_v0.1", 16},
|
| 225 |
+
{"hey_mycroft_v0.1", 16},
|
| 226 |
+
{"hey_rhasspy_v0.1", 16},
|
| 227 |
+
{"timer_v0.1", 34},
|
| 228 |
+
{"weather_v0.1", 22},
|
| 229 |
+
}};
|
| 230 |
+
std::array<Classifier, 6> classifiers;
|
| 231 |
+
for (std::size_t classifier_index = 0;
|
| 232 |
+
classifier_index < definitions.size(); ++classifier_index) {
|
| 233 |
+
const auto &definition = definitions[classifier_index];
|
| 234 |
+
Classifier &classifier = classifiers[classifier_index];
|
| 235 |
+
classifier.name = definition.first;
|
| 236 |
+
classifier.frames = definition.second;
|
| 237 |
+
const std::string model =
|
| 238 |
+
Join(args.models_dir, "openwakeword__" + classifier.name + ".axmodel");
|
| 239 |
+
if (classifier.engine.Init(model) != 0) {
|
| 240 |
+
throw std::runtime_error("Failed to load classifier: " + classifier.name);
|
| 241 |
+
}
|
| 242 |
+
const int output_bytes = classifier.engine.GetOutputSizeByName(
|
| 243 |
+
classifier.engine.OutputName(0));
|
| 244 |
+
if (output_bytes <= 0 || output_bytes % sizeof(float) != 0) {
|
| 245 |
+
throw std::runtime_error("Unexpected classifier output: " +
|
| 246 |
+
classifier.name);
|
| 247 |
+
}
|
| 248 |
+
classifier.maximum.assign(output_bytes / sizeof(float),
|
| 249 |
+
-std::numeric_limits<float>::infinity());
|
| 250 |
+
}
|
| 251 |
+
const double model_load_seconds =
|
| 252 |
+
ElapsedSeconds(model_load_begin, Clock::now());
|
| 253 |
+
|
| 254 |
+
std::vector<int16_t> padded = wav.samples;
|
| 255 |
+
const std::size_t remainder = padded.size() % kChunkSamples;
|
| 256 |
+
if (remainder != 0) padded.resize(padded.size() + kChunkSamples - remainder);
|
| 257 |
+
std::array<int16_t, kHistorySamples> history{};
|
| 258 |
+
std::array<float, kEmbeddingFrames * kMelBins> mel_buffer{};
|
| 259 |
+
mel_buffer.fill(1.0f);
|
| 260 |
+
std::array<float, kFeatureFrames * kEmbeddingSize> feature_buffer{};
|
| 261 |
+
int chunks = 0;
|
| 262 |
+
double feature_seconds = 0.0;
|
| 263 |
+
double npu_seconds = 0.0;
|
| 264 |
+
const auto inference_begin = Clock::now();
|
| 265 |
+
|
| 266 |
+
for (std::size_t start = 0; start < padded.size(); start += kChunkSamples) {
|
| 267 |
+
std::array<float, kHistorySamples + kChunkSamples> mel_input{};
|
| 268 |
+
for (int i = 0; i < kHistorySamples; ++i) mel_input[i] = history[i];
|
| 269 |
+
for (int i = 0; i < kChunkSamples; ++i) {
|
| 270 |
+
mel_input[kHistorySamples + i] = padded[start + i];
|
| 271 |
+
}
|
| 272 |
+
for (int i = 0; i < kHistorySamples; ++i) {
|
| 273 |
+
history[i] = padded[start + kChunkSamples - kHistorySamples + i];
|
| 274 |
+
}
|
| 275 |
+
const auto feature_begin = Clock::now();
|
| 276 |
+
const auto mel = ComputeMel(mel_input, weights);
|
| 277 |
+
feature_seconds += ElapsedSeconds(feature_begin, Clock::now());
|
| 278 |
+
std::memmove(mel_buffer.data(), mel_buffer.data() + kMelFrames * kMelBins,
|
| 279 |
+
(kEmbeddingFrames - kMelFrames) * kMelBins * sizeof(float));
|
| 280 |
+
std::memcpy(mel_buffer.data() +
|
| 281 |
+
(kEmbeddingFrames - kMelFrames) * kMelBins,
|
| 282 |
+
mel.data(), mel.size() * sizeof(float));
|
| 283 |
+
|
| 284 |
+
const std::string &embedding_input = embedding.InputName(0);
|
| 285 |
+
if (embedding.SetInputByName(embedding_input, mel_buffer.data(),
|
| 286 |
+
mel_buffer.size() * sizeof(float)) != 0) {
|
| 287 |
+
throw std::runtime_error("Failed to set embedding input");
|
| 288 |
+
}
|
| 289 |
+
const auto embedding_begin = Clock::now();
|
| 290 |
+
const int embedding_ret = embedding.RunSync();
|
| 291 |
+
npu_seconds += ElapsedSeconds(embedding_begin, Clock::now());
|
| 292 |
+
if (embedding_ret != 0) {
|
| 293 |
+
throw std::runtime_error("Embedding inference failed");
|
| 294 |
+
}
|
| 295 |
+
std::array<float, kEmbeddingSize> feature{};
|
| 296 |
+
if (embedding.GetOutputByName(embedding.OutputName(0), feature.data(),
|
| 297 |
+
feature.size() * sizeof(float)) != 0) {
|
| 298 |
+
throw std::runtime_error("Failed to read embedding output");
|
| 299 |
+
}
|
| 300 |
+
std::memmove(feature_buffer.data(), feature_buffer.data() + kEmbeddingSize,
|
| 301 |
+
(kFeatureFrames - 1) * kEmbeddingSize * sizeof(float));
|
| 302 |
+
std::memcpy(feature_buffer.data() +
|
| 303 |
+
(kFeatureFrames - 1) * kEmbeddingSize,
|
| 304 |
+
feature.data(), feature.size() * sizeof(float));
|
| 305 |
+
|
| 306 |
+
for (Classifier &classifier : classifiers) {
|
| 307 |
+
const float *input =
|
| 308 |
+
feature_buffer.data() +
|
| 309 |
+
(kFeatureFrames - classifier.frames) * kEmbeddingSize;
|
| 310 |
+
const std::string &input_name = classifier.engine.InputName(0);
|
| 311 |
+
if (classifier.engine.SetInputByName(
|
| 312 |
+
input_name, input,
|
| 313 |
+
classifier.frames * kEmbeddingSize * sizeof(float)) != 0) {
|
| 314 |
+
throw std::runtime_error("Failed to set classifier input: " +
|
| 315 |
+
classifier.name);
|
| 316 |
+
}
|
| 317 |
+
const auto classifier_begin = Clock::now();
|
| 318 |
+
const int classifier_ret = classifier.engine.RunSync();
|
| 319 |
+
npu_seconds += ElapsedSeconds(classifier_begin, Clock::now());
|
| 320 |
+
if (classifier_ret != 0) {
|
| 321 |
+
throw std::runtime_error("Classifier inference failed: " +
|
| 322 |
+
classifier.name);
|
| 323 |
+
}
|
| 324 |
+
std::vector<float> output(classifier.maximum.size());
|
| 325 |
+
if (classifier.engine.GetOutputByName(
|
| 326 |
+
classifier.engine.OutputName(0), output.data(),
|
| 327 |
+
output.size() * sizeof(float)) != 0) {
|
| 328 |
+
throw std::runtime_error("Failed to read classifier output");
|
| 329 |
+
}
|
| 330 |
+
for (std::size_t i = 0; i < output.size(); ++i) {
|
| 331 |
+
classifier.maximum[i] = std::max(classifier.maximum[i], output[i]);
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
++chunks;
|
| 335 |
+
}
|
| 336 |
+
const double inference_seconds =
|
| 337 |
+
ElapsedSeconds(inference_begin, Clock::now());
|
| 338 |
+
const double rtf = inference_seconds / audio_seconds;
|
| 339 |
+
|
| 340 |
+
std::printf("\nopenWakeWord C++ inference complete\n");
|
| 341 |
+
std::printf("target: %s\naudio: %s\nchunks: %d\nthreshold: %.3f\n",
|
| 342 |
+
AXERA_TARGET_NAME, args.audio.c_str(), chunks, args.threshold);
|
| 343 |
+
bool detected = false;
|
| 344 |
+
for (const Classifier &classifier : classifiers) {
|
| 345 |
+
std::printf("%-22s", classifier.name.c_str());
|
| 346 |
+
float score = -std::numeric_limits<float>::infinity();
|
| 347 |
+
for (std::size_t i = 0; i < classifier.maximum.size(); ++i) {
|
| 348 |
+
const float value = classifier.maximum[i];
|
| 349 |
+
std::printf(" %.6f", value);
|
| 350 |
+
if (classifier.name != "timer_v0.1" || i != 0) {
|
| 351 |
+
score = std::max(score, value);
|
| 352 |
+
}
|
| 353 |
+
}
|
| 354 |
+
if (score >= args.threshold) {
|
| 355 |
+
std::printf(" WAKEUP");
|
| 356 |
+
detected = true;
|
| 357 |
+
}
|
| 358 |
+
std::printf("\n");
|
| 359 |
+
}
|
| 360 |
+
std::printf("detected: %s\n", detected ? "true" : "false");
|
| 361 |
+
std::printf("audio_seconds: %.6f\n", audio_seconds);
|
| 362 |
+
std::printf("feature_seconds: %.6f\n", feature_seconds);
|
| 363 |
+
std::printf("npu_seconds: %.6f\n", npu_seconds);
|
| 364 |
+
std::printf("model_load_seconds: %.6f\n", model_load_seconds);
|
| 365 |
+
std::printf("inference_seconds: %.6f\n", inference_seconds);
|
| 366 |
+
std::printf("rtf: %.6f\n", rtf);
|
| 367 |
+
}
|
| 368 |
+
} // namespace
|
| 369 |
+
|
| 370 |
+
int main(int argc, char **argv) {
|
| 371 |
+
try {
|
| 372 |
+
const Args args = ParseArgs(argc, argv);
|
| 373 |
+
Run(args);
|
| 374 |
+
return 0;
|
| 375 |
+
} catch (const std::exception &error) {
|
| 376 |
+
std::fprintf(stderr, "ERROR: %s\n", error.what());
|
| 377 |
+
return 1;
|
| 378 |
+
}
|
| 379 |
+
}
|
cpp/run_batch_openwakeword_ax.sh
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
TARGET="${AXERA_TARGET:-AX650}"
|
| 6 |
+
AUDIO_DIR="${AUDIO_DIR:-${ROOT}/audio/openwakeword}"
|
| 7 |
+
THRESHOLD="${THRESHOLD:-0.5}"
|
| 8 |
+
|
| 9 |
+
case "${TARGET}" in
|
| 10 |
+
AX650)
|
| 11 |
+
TARGET_SLUG="ax650"
|
| 12 |
+
BINARY="${ROOT}/cpp/bin/openwakeword_ax650"
|
| 13 |
+
MODELS_DIR="${MODELS_DIR:-${ROOT}/models/650}"
|
| 14 |
+
BSP_LIB_DIR="${AXERA_BSP_LIB_DIR:-${AX650_BSP_LIB_DIR:-${ROOT}/cpp/toolchains/ax650n_bsp_sdk/msp/out/lib}}"
|
| 15 |
+
BUILD_SCRIPT="cpp/build_ax650.sh"
|
| 16 |
+
;;
|
| 17 |
+
AX630C)
|
| 18 |
+
TARGET_SLUG="ax630c"
|
| 19 |
+
BINARY="${ROOT}/cpp/bin/openwakeword_ax630c"
|
| 20 |
+
MODELS_DIR="${MODELS_DIR:-${ROOT}/models/630C}"
|
| 21 |
+
BSP_LIB_DIR="${AXERA_BSP_LIB_DIR:-${AX630C_BSP_LIB_DIR:-${ROOT}/cpp/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc/lib}}"
|
| 22 |
+
BUILD_SCRIPT="cpp/build_ax630c.sh"
|
| 23 |
+
;;
|
| 24 |
+
*)
|
| 25 |
+
echo "ERROR: AXERA_TARGET must be AX650 or AX630C" >&2
|
| 26 |
+
exit 2
|
| 27 |
+
;;
|
| 28 |
+
esac
|
| 29 |
+
|
| 30 |
+
OUTPUT_DIR="${OUTPUT_DIR:-${ROOT}/outputs/cpp_${TARGET_SLUG}_batch}"
|
| 31 |
+
if [[ ! -x "${BINARY}" ]]; then
|
| 32 |
+
echo "ERROR: ${BINARY} is missing; run bash ${BUILD_SCRIPT} first" >&2
|
| 33 |
+
exit 2
|
| 34 |
+
fi
|
| 35 |
+
if [[ ! -d "${AUDIO_DIR}" ]]; then
|
| 36 |
+
echo "ERROR: audio directory does not exist: ${AUDIO_DIR}" >&2
|
| 37 |
+
exit 2
|
| 38 |
+
fi
|
| 39 |
+
for name in embedding_model alexa_v0.1 hey_jarvis_v0.1 hey_mycroft_v0.1 \
|
| 40 |
+
hey_rhasspy_v0.1 timer_v0.1 weather_v0.1; do
|
| 41 |
+
model="${MODELS_DIR}/openwakeword__${name}.axmodel"
|
| 42 |
+
if [[ ! -f "${model}" ]]; then
|
| 43 |
+
echo "ERROR: ${TARGET} model is missing: ${model}" >&2
|
| 44 |
+
exit 2
|
| 45 |
+
fi
|
| 46 |
+
done
|
| 47 |
+
|
| 48 |
+
mapfile -d '' AUDIO_FILES < <(
|
| 49 |
+
find "${AUDIO_DIR}" -maxdepth 1 -type f -iname '*.wav' -print0 | sort -z
|
| 50 |
+
)
|
| 51 |
+
if [[ "${#AUDIO_FILES[@]}" -eq 0 ]]; then
|
| 52 |
+
echo "ERROR: no WAV files found under ${AUDIO_DIR}" >&2
|
| 53 |
+
exit 2
|
| 54 |
+
fi
|
| 55 |
+
|
| 56 |
+
mkdir -p "${OUTPUT_DIR}/logs"
|
| 57 |
+
RESULTS="${OUTPUT_DIR}/results.tsv"
|
| 58 |
+
SUMMARY="${OUTPUT_DIR}/summary.txt"
|
| 59 |
+
printf 'file\taudio_seconds\tfeature_seconds\tnpu_seconds\tinference_seconds\trtf\tmodel_load_seconds\tdetections\n' > "${RESULTS}"
|
| 60 |
+
|
| 61 |
+
export LD_LIBRARY_PATH="${BSP_LIB_DIR}:${LD_LIBRARY_PATH:-}"
|
| 62 |
+
for audio in "${AUDIO_FILES[@]}"; do
|
| 63 |
+
name="$(basename "${audio}")"
|
| 64 |
+
stem="${name%.*}"
|
| 65 |
+
log="${OUTPUT_DIR}/logs/${stem}.log"
|
| 66 |
+
echo "[RUN] target=${TARGET} ${name} threshold=${THRESHOLD}"
|
| 67 |
+
"${BINARY}" \
|
| 68 |
+
--models-dir "${MODELS_DIR}" \
|
| 69 |
+
--mel-weights "${ROOT}/config/openwakeword_mel_weights.bin" \
|
| 70 |
+
--audio "${audio}" \
|
| 71 |
+
--threshold "${THRESHOLD}" > "${log}" 2>&1
|
| 72 |
+
cat "${log}"
|
| 73 |
+
|
| 74 |
+
field() {
|
| 75 |
+
awk -F': ' -v key="$1" '$1 == key {print $2; exit}' "${log}"
|
| 76 |
+
}
|
| 77 |
+
audio_seconds="$(field audio_seconds)"
|
| 78 |
+
feature_seconds="$(field feature_seconds)"
|
| 79 |
+
npu_seconds="$(field npu_seconds)"
|
| 80 |
+
inference_seconds="$(field inference_seconds)"
|
| 81 |
+
rtf="$(field rtf)"
|
| 82 |
+
model_load_seconds="$(field model_load_seconds)"
|
| 83 |
+
detections="$(awk '$NF == "WAKEUP" {print $1}' "${log}" | paste -sd ',' -)"
|
| 84 |
+
detections="${detections:-none}"
|
| 85 |
+
|
| 86 |
+
for value in "${audio_seconds}" "${feature_seconds}" "${npu_seconds}" \
|
| 87 |
+
"${inference_seconds}" "${rtf}" "${model_load_seconds}"; do
|
| 88 |
+
if [[ -z "${value}" ]]; then
|
| 89 |
+
echo "ERROR: timing field missing from ${log}" >&2
|
| 90 |
+
exit 1
|
| 91 |
+
fi
|
| 92 |
+
done
|
| 93 |
+
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
| 94 |
+
"${name}" "${audio_seconds}" "${feature_seconds}" "${npu_seconds}" \
|
| 95 |
+
"${inference_seconds}" "${rtf}" "${model_load_seconds}" "${detections}" \
|
| 96 |
+
>> "${RESULTS}"
|
| 97 |
+
done
|
| 98 |
+
|
| 99 |
+
awk -F'\t' '
|
| 100 |
+
NR > 1 {
|
| 101 |
+
files += 1
|
| 102 |
+
audio += $2
|
| 103 |
+
feature += $3
|
| 104 |
+
npu += $4
|
| 105 |
+
inference += $5
|
| 106 |
+
model_load += $7
|
| 107 |
+
}
|
| 108 |
+
END {
|
| 109 |
+
printf "files: %d\n", files
|
| 110 |
+
printf "total_audio_seconds: %.6f\n", audio
|
| 111 |
+
printf "total_feature_seconds: %.6f\n", feature
|
| 112 |
+
printf "total_npu_seconds: %.6f\n", npu
|
| 113 |
+
printf "total_inference_seconds: %.6f\n", inference
|
| 114 |
+
printf "total_model_load_seconds: %.6f\n", model_load
|
| 115 |
+
printf "rtf: %.6f\n", inference / audio
|
| 116 |
+
}
|
| 117 |
+
' "${RESULTS}" > "${SUMMARY}"
|
| 118 |
+
|
| 119 |
+
echo "[SUMMARY]"
|
| 120 |
+
cat "${SUMMARY}"
|
| 121 |
+
echo "results: ${RESULTS}"
|
| 122 |
+
echo "logs: ${OUTPUT_DIR}/logs"
|
cpp/run_batch_openwakeword_ax630c.sh
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
AXERA_TARGET=AX630C exec bash "${ROOT}/cpp/run_batch_openwakeword_ax.sh"
|
cpp/run_batch_openwakeword_ax650.sh
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
AXERA_TARGET=AX650 exec bash "${ROOT}/cpp/run_batch_openwakeword_ax.sh"
|
cpp/run_openwakeword_ax.sh
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
TARGET="${AXERA_TARGET:-AX650}"
|
| 6 |
+
AUDIO="${AUDIO:-${ROOT}/audio/openwakeword/alexa_test.wav}"
|
| 7 |
+
THRESHOLD="${THRESHOLD:-0.5}"
|
| 8 |
+
|
| 9 |
+
case "${TARGET}" in
|
| 10 |
+
AX650)
|
| 11 |
+
BINARY="${ROOT}/cpp/bin/openwakeword_ax650"
|
| 12 |
+
MODELS_DIR="${MODELS_DIR:-${ROOT}/models/650}"
|
| 13 |
+
BSP_LIB_DIR="${AXERA_BSP_LIB_DIR:-${AX650_BSP_LIB_DIR:-${ROOT}/cpp/toolchains/ax650n_bsp_sdk/msp/out/lib}}"
|
| 14 |
+
BUILD_SCRIPT="cpp/build_ax650.sh"
|
| 15 |
+
;;
|
| 16 |
+
AX630C)
|
| 17 |
+
BINARY="${ROOT}/cpp/bin/openwakeword_ax630c"
|
| 18 |
+
MODELS_DIR="${MODELS_DIR:-${ROOT}/models/630C}"
|
| 19 |
+
BSP_LIB_DIR="${AXERA_BSP_LIB_DIR:-${AX630C_BSP_LIB_DIR:-${ROOT}/cpp/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc/lib}}"
|
| 20 |
+
BUILD_SCRIPT="cpp/build_ax630c.sh"
|
| 21 |
+
;;
|
| 22 |
+
*)
|
| 23 |
+
echo "ERROR: AXERA_TARGET must be AX650 or AX630C" >&2
|
| 24 |
+
exit 2
|
| 25 |
+
;;
|
| 26 |
+
esac
|
| 27 |
+
|
| 28 |
+
if [[ ! -x "${BINARY}" ]]; then
|
| 29 |
+
echo "ERROR: ${BINARY} is missing; run bash ${BUILD_SCRIPT} first" >&2
|
| 30 |
+
exit 2
|
| 31 |
+
fi
|
| 32 |
+
for name in embedding_model alexa_v0.1 hey_jarvis_v0.1 hey_mycroft_v0.1 \
|
| 33 |
+
hey_rhasspy_v0.1 timer_v0.1 weather_v0.1; do
|
| 34 |
+
model="${MODELS_DIR}/openwakeword__${name}.axmodel"
|
| 35 |
+
if [[ ! -f "${model}" ]]; then
|
| 36 |
+
echo "ERROR: ${TARGET} model is missing: ${model}" >&2
|
| 37 |
+
exit 2
|
| 38 |
+
fi
|
| 39 |
+
done
|
| 40 |
+
|
| 41 |
+
export LD_LIBRARY_PATH="${BSP_LIB_DIR}:${LD_LIBRARY_PATH:-}"
|
| 42 |
+
exec "${BINARY}" \
|
| 43 |
+
--models-dir "${MODELS_DIR}" \
|
| 44 |
+
--mel-weights "${ROOT}/config/openwakeword_mel_weights.bin" \
|
| 45 |
+
--audio "${AUDIO}" \
|
| 46 |
+
--threshold "${THRESHOLD}"
|
cpp/run_openwakeword_ax630c.sh
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
AXERA_TARGET=AX630C exec bash "${ROOT}/cpp/run_openwakeword_ax.sh"
|
cpp/run_openwakeword_ax650.sh
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
| 5 |
+
AXERA_TARGET=AX650 exec bash "${ROOT}/cpp/run_openwakeword_ax.sh"
|
cpp/src/engine_wrapper.cpp
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "engine_wrapper.hpp"
|
| 2 |
+
|
| 3 |
+
#include <cstdio>
|
| 4 |
+
#include <cstring>
|
| 5 |
+
#include <fstream>
|
| 6 |
+
#include <vector>
|
| 7 |
+
|
| 8 |
+
#include "ax_sys_api.h"
|
| 9 |
+
|
| 10 |
+
namespace {
|
| 11 |
+
constexpr int kAlignment = 128;
|
| 12 |
+
|
| 13 |
+
void FreeIo(AX_ENGINE_IO_T *io) {
|
| 14 |
+
for (AX_U32 i = 0; io->pInputs && i < io->nInputSize; ++i) {
|
| 15 |
+
if (io->pInputs[i].pVirAddr) {
|
| 16 |
+
AX_SYS_MemFree(io->pInputs[i].phyAddr, io->pInputs[i].pVirAddr);
|
| 17 |
+
}
|
| 18 |
+
}
|
| 19 |
+
for (AX_U32 i = 0; io->pOutputs && i < io->nOutputSize; ++i) {
|
| 20 |
+
if (io->pOutputs[i].pVirAddr) {
|
| 21 |
+
AX_SYS_MemFree(io->pOutputs[i].phyAddr, io->pOutputs[i].pVirAddr);
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
delete[] io->pInputs;
|
| 25 |
+
delete[] io->pOutputs;
|
| 26 |
+
std::memset(io, 0, sizeof(*io));
|
| 27 |
+
}
|
| 28 |
+
} // namespace
|
| 29 |
+
|
| 30 |
+
EngineWrapper::~EngineWrapper() { Release(); }
|
| 31 |
+
|
| 32 |
+
int EngineWrapper::Init(const std::string &path) {
|
| 33 |
+
std::ifstream input(path, std::ios::binary);
|
| 34 |
+
if (!input) {
|
| 35 |
+
std::fprintf(stderr, "Failed to read model: %s\n", path.c_str());
|
| 36 |
+
return -1;
|
| 37 |
+
}
|
| 38 |
+
input.seekg(0, std::ios::end);
|
| 39 |
+
const std::streamoff model_size = input.tellg();
|
| 40 |
+
if (model_size <= 0 || model_size > static_cast<std::streamoff>(UINT32_MAX)) {
|
| 41 |
+
std::fprintf(stderr, "Invalid model size: %s\n", path.c_str());
|
| 42 |
+
return -1;
|
| 43 |
+
}
|
| 44 |
+
input.seekg(0, std::ios::beg);
|
| 45 |
+
std::vector<char> model(static_cast<std::size_t>(model_size));
|
| 46 |
+
input.read(model.data(), model_size);
|
| 47 |
+
if (!input) {
|
| 48 |
+
std::fprintf(stderr, "Failed to read model: %s\n", path.c_str());
|
| 49 |
+
return -1;
|
| 50 |
+
}
|
| 51 |
+
const AX_S32 create_ret = AX_ENGINE_CreateHandle(
|
| 52 |
+
&handle_, model.data(), static_cast<AX_U32>(model.size()));
|
| 53 |
+
if (create_ret != 0 || !handle_) {
|
| 54 |
+
std::fprintf(stderr, "AX_ENGINE_CreateHandle failed: %s ret=0x%x\n",
|
| 55 |
+
path.c_str(), static_cast<unsigned>(create_ret));
|
| 56 |
+
return -1;
|
| 57 |
+
}
|
| 58 |
+
if (AX_ENGINE_CreateContext(handle_) != 0 ||
|
| 59 |
+
AX_ENGINE_GetIOInfo(handle_, &info_) != 0 || !info_) {
|
| 60 |
+
Release();
|
| 61 |
+
return -1;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
io_.nInputSize = info_->nInputSize;
|
| 65 |
+
io_.nOutputSize = info_->nOutputSize;
|
| 66 |
+
io_.pInputs = new AX_ENGINE_IO_BUFFER_T[io_.nInputSize]{};
|
| 67 |
+
io_.pOutputs = new AX_ENGINE_IO_BUFFER_T[io_.nOutputSize]{};
|
| 68 |
+
AX_S8 input_tag[] = "KWS-INPUT";
|
| 69 |
+
AX_S8 output_tag[] = "KWS-OUTPUT";
|
| 70 |
+
for (AX_U32 i = 0; i < io_.nInputSize; ++i) {
|
| 71 |
+
io_.pInputs[i].nSize = info_->pInputs[i].nSize;
|
| 72 |
+
if (AX_SYS_MemAlloc(&io_.pInputs[i].phyAddr,
|
| 73 |
+
&io_.pInputs[i].pVirAddr, io_.pInputs[i].nSize,
|
| 74 |
+
kAlignment, input_tag) != 0) {
|
| 75 |
+
Release();
|
| 76 |
+
return -1;
|
| 77 |
+
}
|
| 78 |
+
const std::string name = info_->pInputs[i].pName;
|
| 79 |
+
inputs_[name] = static_cast<int>(i);
|
| 80 |
+
input_names_.push_back(name);
|
| 81 |
+
}
|
| 82 |
+
for (AX_U32 i = 0; i < io_.nOutputSize; ++i) {
|
| 83 |
+
io_.pOutputs[i].nSize = info_->pOutputs[i].nSize;
|
| 84 |
+
if (AX_SYS_MemAlloc(&io_.pOutputs[i].phyAddr,
|
| 85 |
+
&io_.pOutputs[i].pVirAddr, io_.pOutputs[i].nSize,
|
| 86 |
+
kAlignment, output_tag) != 0) {
|
| 87 |
+
Release();
|
| 88 |
+
return -1;
|
| 89 |
+
}
|
| 90 |
+
const std::string name = info_->pOutputs[i].pName;
|
| 91 |
+
outputs_[name] = static_cast<int>(i);
|
| 92 |
+
output_names_.push_back(name);
|
| 93 |
+
}
|
| 94 |
+
initialized_ = true;
|
| 95 |
+
std::printf("Loaded %s (inputs=%u outputs=%u)\n", path.c_str(),
|
| 96 |
+
io_.nInputSize, io_.nOutputSize);
|
| 97 |
+
return 0;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
void EngineWrapper::Release() {
|
| 101 |
+
FreeIo(&io_);
|
| 102 |
+
if (handle_) AX_ENGINE_DestroyHandle(handle_);
|
| 103 |
+
initialized_ = false;
|
| 104 |
+
handle_ = nullptr;
|
| 105 |
+
info_ = nullptr;
|
| 106 |
+
inputs_.clear();
|
| 107 |
+
outputs_.clear();
|
| 108 |
+
input_names_.clear();
|
| 109 |
+
output_names_.clear();
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
int EngineWrapper::InputIndex(const std::string &name) const {
|
| 113 |
+
const auto it = inputs_.find(name);
|
| 114 |
+
return it == inputs_.end() ? -1 : it->second;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
int EngineWrapper::OutputIndex(const std::string &name) const {
|
| 118 |
+
const auto it = outputs_.find(name);
|
| 119 |
+
return it == outputs_.end() ? -1 : it->second;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
int EngineWrapper::SetInputByName(const std::string &name, const void *data,
|
| 123 |
+
std::size_t size) {
|
| 124 |
+
const int index = InputIndex(name);
|
| 125 |
+
if (!initialized_ || index < 0 || !data) return -1;
|
| 126 |
+
const std::size_t expected = io_.pInputs[index].nSize;
|
| 127 |
+
if (size != 0 && size != expected) return -1;
|
| 128 |
+
std::memcpy(io_.pInputs[index].pVirAddr, data, expected);
|
| 129 |
+
return 0;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
int EngineWrapper::ZeroInputByName(const std::string &name) {
|
| 133 |
+
const int index = InputIndex(name);
|
| 134 |
+
if (!initialized_ || index < 0) return -1;
|
| 135 |
+
std::memset(io_.pInputs[index].pVirAddr, 0, io_.pInputs[index].nSize);
|
| 136 |
+
return 0;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
int EngineWrapper::RunSync() {
|
| 140 |
+
if (!initialized_) return -1;
|
| 141 |
+
for (AX_U32 i = 0; i < io_.nInputSize; ++i) {
|
| 142 |
+
const AX_S32 flush_ret = AX_SYS_MflushCache(
|
| 143 |
+
io_.pInputs[i].phyAddr, io_.pInputs[i].pVirAddr,
|
| 144 |
+
io_.pInputs[i].nSize);
|
| 145 |
+
if (flush_ret != 0) {
|
| 146 |
+
std::fprintf(stderr, "AX_SYS_MflushCache failed input=%u ret=0x%x\n", i,
|
| 147 |
+
static_cast<unsigned>(flush_ret));
|
| 148 |
+
return flush_ret;
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
const AX_S32 ret = AX_ENGINE_RunSync(handle_, &io_);
|
| 152 |
+
if (ret != 0) {
|
| 153 |
+
std::fprintf(stderr, "AX_ENGINE_RunSync failed ret=0x%x\n",
|
| 154 |
+
static_cast<unsigned>(ret));
|
| 155 |
+
return ret;
|
| 156 |
+
}
|
| 157 |
+
for (AX_U32 i = 0; i < io_.nOutputSize; ++i) {
|
| 158 |
+
const AX_S32 invalidate_ret = AX_SYS_MinvalidateCache(
|
| 159 |
+
io_.pOutputs[i].phyAddr, io_.pOutputs[i].pVirAddr,
|
| 160 |
+
io_.pOutputs[i].nSize);
|
| 161 |
+
if (invalidate_ret != 0) {
|
| 162 |
+
std::fprintf(stderr,
|
| 163 |
+
"AX_SYS_MinvalidateCache failed output=%u ret=0x%x\n", i,
|
| 164 |
+
static_cast<unsigned>(invalidate_ret));
|
| 165 |
+
return invalidate_ret;
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
return 0;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
int EngineWrapper::GetOutputByName(const std::string &name, void *data,
|
| 172 |
+
std::size_t size) const {
|
| 173 |
+
const int index = OutputIndex(name);
|
| 174 |
+
if (!initialized_ || index < 0 || !data) return -1;
|
| 175 |
+
const std::size_t expected = io_.pOutputs[index].nSize;
|
| 176 |
+
if (size != 0 && size != expected) return -1;
|
| 177 |
+
std::memcpy(data, io_.pOutputs[index].pVirAddr, expected);
|
| 178 |
+
return 0;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
int EngineWrapper::GetInputSizeByName(const std::string &name) const {
|
| 182 |
+
const int index = InputIndex(name);
|
| 183 |
+
return index < 0 ? -1 : static_cast<int>(io_.pInputs[index].nSize);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
int EngineWrapper::GetOutputSizeByName(const std::string &name) const {
|
| 187 |
+
const int index = OutputIndex(name);
|
| 188 |
+
return index < 0 ? -1 : static_cast<int>(io_.pOutputs[index].nSize);
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
const std::string &EngineWrapper::InputName(std::size_t index) const {
|
| 192 |
+
return input_names_.at(index);
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
const std::string &EngineWrapper::OutputName(std::size_t index) const {
|
| 196 |
+
return output_names_.at(index);
|
| 197 |
+
}
|
cpp/src/engine_wrapper.hpp
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <cstddef>
|
| 4 |
+
#include <string>
|
| 5 |
+
#include <unordered_map>
|
| 6 |
+
#include <vector>
|
| 7 |
+
|
| 8 |
+
#include "ax_engine_api.h"
|
| 9 |
+
|
| 10 |
+
class EngineWrapper {
|
| 11 |
+
public:
|
| 12 |
+
EngineWrapper() = default;
|
| 13 |
+
~EngineWrapper();
|
| 14 |
+
|
| 15 |
+
EngineWrapper(const EngineWrapper &) = delete;
|
| 16 |
+
EngineWrapper &operator=(const EngineWrapper &) = delete;
|
| 17 |
+
|
| 18 |
+
int Init(const std::string &model_path);
|
| 19 |
+
void Release();
|
| 20 |
+
int SetInputByName(const std::string &name, const void *data,
|
| 21 |
+
std::size_t size = 0);
|
| 22 |
+
int ZeroInputByName(const std::string &name);
|
| 23 |
+
int RunSync();
|
| 24 |
+
int GetOutputByName(const std::string &name, void *data,
|
| 25 |
+
std::size_t size = 0) const;
|
| 26 |
+
int GetInputSizeByName(const std::string &name) const;
|
| 27 |
+
int GetOutputSizeByName(const std::string &name) const;
|
| 28 |
+
const std::string &InputName(std::size_t index) const;
|
| 29 |
+
const std::string &OutputName(std::size_t index) const;
|
| 30 |
+
|
| 31 |
+
private:
|
| 32 |
+
int InputIndex(const std::string &name) const;
|
| 33 |
+
int OutputIndex(const std::string &name) const;
|
| 34 |
+
|
| 35 |
+
bool initialized_ = false;
|
| 36 |
+
AX_ENGINE_HANDLE handle_ = nullptr;
|
| 37 |
+
AX_ENGINE_IO_INFO_T *info_ = nullptr;
|
| 38 |
+
AX_ENGINE_IO_T io_{};
|
| 39 |
+
std::unordered_map<std::string, int> inputs_;
|
| 40 |
+
std::unordered_map<std::string, int> outputs_;
|
| 41 |
+
std::vector<std::string> input_names_;
|
| 42 |
+
std::vector<std::string> output_names_;
|
| 43 |
+
};
|
cpp/src/wav_reader.hpp
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <cstdint>
|
| 4 |
+
#include <cstring>
|
| 5 |
+
#include <fstream>
|
| 6 |
+
#include <stdexcept>
|
| 7 |
+
#include <string>
|
| 8 |
+
#include <vector>
|
| 9 |
+
|
| 10 |
+
struct PcmWav {
|
| 11 |
+
int sample_rate = 0;
|
| 12 |
+
std::vector<int16_t> samples;
|
| 13 |
+
};
|
| 14 |
+
|
| 15 |
+
inline uint16_t ReadLe16(std::istream &input) {
|
| 16 |
+
uint8_t bytes[2]{};
|
| 17 |
+
input.read(reinterpret_cast<char *>(bytes), 2);
|
| 18 |
+
return static_cast<uint16_t>(bytes[0]) |
|
| 19 |
+
(static_cast<uint16_t>(bytes[1]) << 8);
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
inline uint32_t ReadLe32(std::istream &input) {
|
| 23 |
+
uint8_t bytes[4]{};
|
| 24 |
+
input.read(reinterpret_cast<char *>(bytes), 4);
|
| 25 |
+
return static_cast<uint32_t>(bytes[0]) |
|
| 26 |
+
(static_cast<uint32_t>(bytes[1]) << 8) |
|
| 27 |
+
(static_cast<uint32_t>(bytes[2]) << 16) |
|
| 28 |
+
(static_cast<uint32_t>(bytes[3]) << 24);
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
inline PcmWav ReadPcmWav(const std::string &path) {
|
| 32 |
+
std::ifstream input(path, std::ios::binary);
|
| 33 |
+
if (!input) throw std::runtime_error("Cannot open WAV: " + path);
|
| 34 |
+
char riff[4]{};
|
| 35 |
+
char wave[4]{};
|
| 36 |
+
input.read(riff, 4);
|
| 37 |
+
ReadLe32(input);
|
| 38 |
+
input.read(wave, 4);
|
| 39 |
+
if (std::memcmp(riff, "RIFF", 4) != 0 ||
|
| 40 |
+
std::memcmp(wave, "WAVE", 4) != 0) {
|
| 41 |
+
throw std::runtime_error("Invalid RIFF/WAVE file: " + path);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
uint16_t format = 0;
|
| 45 |
+
uint16_t channels = 0;
|
| 46 |
+
uint16_t bits = 0;
|
| 47 |
+
uint32_t sample_rate = 0;
|
| 48 |
+
std::vector<uint8_t> data;
|
| 49 |
+
while (input && (!format || data.empty())) {
|
| 50 |
+
char id[4]{};
|
| 51 |
+
input.read(id, 4);
|
| 52 |
+
if (!input) break;
|
| 53 |
+
const uint32_t size = ReadLe32(input);
|
| 54 |
+
if (std::memcmp(id, "fmt ", 4) == 0) {
|
| 55 |
+
if (size < 16) throw std::runtime_error("Invalid WAV fmt chunk");
|
| 56 |
+
format = ReadLe16(input);
|
| 57 |
+
channels = ReadLe16(input);
|
| 58 |
+
sample_rate = ReadLe32(input);
|
| 59 |
+
ReadLe32(input);
|
| 60 |
+
ReadLe16(input);
|
| 61 |
+
bits = ReadLe16(input);
|
| 62 |
+
input.seekg(size - 16, std::ios::cur);
|
| 63 |
+
} else if (std::memcmp(id, "data", 4) == 0) {
|
| 64 |
+
data.resize(size);
|
| 65 |
+
input.read(reinterpret_cast<char *>(data.data()), size);
|
| 66 |
+
} else {
|
| 67 |
+
input.seekg(size, std::ios::cur);
|
| 68 |
+
}
|
| 69 |
+
if (size & 1U) input.seekg(1, std::ios::cur);
|
| 70 |
+
}
|
| 71 |
+
if (format != 1 || channels != 1 || bits != 16 || sample_rate == 0 ||
|
| 72 |
+
data.empty() || data.size() % sizeof(int16_t) != 0) {
|
| 73 |
+
throw std::runtime_error("Expected mono 16-bit PCM WAV: " + path);
|
| 74 |
+
}
|
| 75 |
+
PcmWav result;
|
| 76 |
+
result.sample_rate = static_cast<int>(sample_rate);
|
| 77 |
+
result.samples.resize(data.size() / sizeof(int16_t));
|
| 78 |
+
std::memcpy(result.samples.data(), data.data(), data.size());
|
| 79 |
+
return result;
|
| 80 |
+
}
|
manifest.json
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"target_hardware": "AX630C/AX650",
|
| 3 |
+
"runtime": "axengine",
|
| 4 |
+
"axmodel_count": 8,
|
| 5 |
+
"files": [
|
| 6 |
+
{
|
| 7 |
+
"path": ".gitattributes",
|
| 8 |
+
"size_bytes": 179,
|
| 9 |
+
"sha256": "7b33e03d32f81ffc4bf98649921ff61fdbdfcff7477345dffc00bd5472351478"
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"path": ".gitignore",
|
| 13 |
+
"size_bytes": 74,
|
| 14 |
+
"sha256": "496c11fcbfe22bd803d39235e6539b04e2fc8b0e7d747479302176ae84ae181a"
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"path": "README.md",
|
| 18 |
+
"size_bytes": 3689,
|
| 19 |
+
"sha256": "7d609fad6c1e359a68551ce097e64e047056739be92a6311fd701ead738f5cd4"
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"path": "audio/openwakeword/alexa_test.wav",
|
| 23 |
+
"size_bytes": 20044,
|
| 24 |
+
"sha256": "915dba88a2b936f3ba3ee91affcdbe9041ffbe532613d3aca58d8a15447fbd81"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"path": "audio/openwakeword/hey_jane.wav",
|
| 28 |
+
"size_bytes": 75820,
|
| 29 |
+
"sha256": "cf1b938bd8ca1a7e9bb042665b9cf92a772a6673c6b98e264b27176ea4d3f443"
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"path": "audio/openwakeword/hey_mycroft_test.wav",
|
| 33 |
+
"size_bytes": 30508,
|
| 34 |
+
"sha256": "8d728ce1dbd54a97c6cddf0c80acec3113285407a967368f4abe476119c1a8c6"
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"path": "config.json",
|
| 38 |
+
"size_bytes": 207,
|
| 39 |
+
"sha256": "67d68940a1ef8586cad523779ea86876b3bd2362c593c2d4e74ef6dd0557f892"
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"path": "config/openwakeword_mel_weights.bin",
|
| 43 |
+
"size_bytes": 1085608,
|
| 44 |
+
"sha256": "f5d3a5bafe0def6c1efb4874d724c272d78edadada6652ef885059db2ba147a7"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"path": "config/openwakeword_mel_weights.npz",
|
| 48 |
+
"size_bytes": 1086554,
|
| 49 |
+
"sha256": "a3de443a7383dc51a4bf8b1d2dc9bbc767f7e33e17af617d993700a5f9947ed6"
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"path": "cpp/CMakeLists.txt",
|
| 53 |
+
"size_bytes": 1948,
|
| 54 |
+
"sha256": "89980c1323031f9b1689562f493325b5ad1e1bd7960f85bd1e932ba097d42360"
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"path": "cpp/README.md",
|
| 58 |
+
"size_bytes": 2197,
|
| 59 |
+
"sha256": "8b1abab04850f18bbd980b6f4de0f42334bfc1086fac97607606c7f6c914422f"
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"path": "cpp/bin/openwakeword_ax630c",
|
| 63 |
+
"size_bytes": 39688,
|
| 64 |
+
"sha256": "309405a685c6928975ec732525ab069316bf43a3495de80c99d6aa566e6c37a3"
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"path": "cpp/bin/openwakeword_ax650",
|
| 68 |
+
"size_bytes": 39688,
|
| 69 |
+
"sha256": "cea03dc9b00f40c4508bb82ee8e1dfa2a8775088f4e193fc413ba781e4607984"
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"path": "cpp/build_ax630c.sh",
|
| 73 |
+
"size_bytes": 1299,
|
| 74 |
+
"sha256": "4d594ea058d6563fa9177698f0af0e3409959672f399d9729a378de2a47ebc09"
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"path": "cpp/build_ax650.sh",
|
| 78 |
+
"size_bytes": 1267,
|
| 79 |
+
"sha256": "fbf962de8ed6433fef6b2aac7332bf84e18720f01b6bf7955e9d32eb409f8e01"
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"path": "cpp/download_bsp.sh",
|
| 83 |
+
"size_bytes": 1290,
|
| 84 |
+
"sha256": "0c5afbc290c6d8341df2e8b356626642935a5c9971b0b6b603d30a9b32e69f7a"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"path": "cpp/openwakeword_ax.cpp",
|
| 88 |
+
"size_bytes": 14122,
|
| 89 |
+
"sha256": "6c4ef28769f1321624819a6c915e43d2127989cefc58a39e8600631d57f98d8d"
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
"path": "cpp/run_batch_openwakeword_ax.sh",
|
| 93 |
+
"size_bytes": 3938,
|
| 94 |
+
"sha256": "5c4a4d3d9e399fb98d0a9b794389fb03ce585cfe9e24d884772052fd1f948c88"
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"path": "cpp/run_batch_openwakeword_ax630c.sh",
|
| 98 |
+
"size_bytes": 168,
|
| 99 |
+
"sha256": "f6545c7db37deb52ea727c8f641f000a2c7c1805fc7b40fbc06ec6841b3a259c"
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"path": "cpp/run_batch_openwakeword_ax650.sh",
|
| 103 |
+
"size_bytes": 167,
|
| 104 |
+
"sha256": "8711184e6284d9de1ac5b11fdfb23de7c02b9667596d3cb060be702b38b6a858"
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"path": "cpp/run_openwakeword_ax.sh",
|
| 108 |
+
"size_bytes": 1510,
|
| 109 |
+
"sha256": "2cf5332a4a6457b1356609fd66e8777d3cc89cc871aa176695cd868d4667f948"
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"path": "cpp/run_openwakeword_ax630c.sh",
|
| 113 |
+
"size_bytes": 162,
|
| 114 |
+
"sha256": "f2bd3486e9e8db53835a6d09f9f6a73769342f2a032939842559268342264cc8"
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"path": "cpp/run_openwakeword_ax650.sh",
|
| 118 |
+
"size_bytes": 161,
|
| 119 |
+
"sha256": "4ac47b1d3535d6351e595ec8c4594d9a696ae22e4224076f654bb2969f9e7dd8"
|
| 120 |
+
},
|
| 121 |
+
{
|
| 122 |
+
"path": "cpp/src/engine_wrapper.cpp",
|
| 123 |
+
"size_bytes": 6489,
|
| 124 |
+
"sha256": "d5ee6d04eaaa6cff492b1b2cd8c60d8519b630b1fc66fd93ee4085cf2121f4ea"
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"path": "cpp/src/engine_wrapper.hpp",
|
| 128 |
+
"size_bytes": 1313,
|
| 129 |
+
"sha256": "6a160d748e4fda7c4a69cd2113c36f36c66bf7292e32ffe3df966d24eac51ede"
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"path": "cpp/src/wav_reader.hpp",
|
| 133 |
+
"size_bytes": 2447,
|
| 134 |
+
"sha256": "c4890925751e81c78a8429e06fd7fc1e35673d4c9b84989d0f9fd64a364b4d34"
|
| 135 |
+
},
|
| 136 |
+
{
|
| 137 |
+
"path": "models/630C/.gitkeep",
|
| 138 |
+
"size_bytes": 1,
|
| 139 |
+
"sha256": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"
|
| 140 |
+
},
|
| 141 |
+
{
|
| 142 |
+
"path": "models/650/openwakeword__alexa_v0.1.axmodel",
|
| 143 |
+
"size_bytes": 241041,
|
| 144 |
+
"sha256": "3595cd242ddf38aca019042d593c45ac1e90107a6d54836ea5593e3dc55f9784"
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"path": "models/650/openwakeword__embedding_model.axmodel",
|
| 148 |
+
"size_bytes": 451068,
|
| 149 |
+
"sha256": "a9c579200c4e9c076d86181343cdbe5cf2c786016cd60b333463784b5c2fa9b4"
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"path": "models/650/openwakeword__hey_jarvis_v0.1.axmodel",
|
| 153 |
+
"size_bytes": 365733,
|
| 154 |
+
"sha256": "c878a73a9f187505a9496c0b12c479c94de9102d7851bc31a7d75de15a7298ef"
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"path": "models/650/openwakeword__hey_mycroft_v0.1.axmodel",
|
| 158 |
+
"size_bytes": 247553,
|
| 159 |
+
"sha256": "1ff391da1aefc04f20df5a24be0d063941459caeef0d5e6d6892c5561049fdf2"
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"path": "models/650/openwakeword__hey_rhasspy_v0.1.axmodel",
|
| 163 |
+
"size_bytes": 64073,
|
| 164 |
+
"sha256": "4e13babcf713a3b62ca871bd6d7df50315a09da17ab35c294fa41034baed4a69"
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"path": "models/650/openwakeword__melspectrogram.axmodel",
|
| 168 |
+
"size_bytes": 340028,
|
| 169 |
+
"sha256": "9ea2c5293ef3c05c3c5681b947f270d3fe77a0464308d67cf43d9090e9e7fb5f"
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"path": "models/650/openwakeword__timer_v0.1.axmodel",
|
| 173 |
+
"size_bytes": 482100,
|
| 174 |
+
"sha256": "4b7c243daadeed2e7ac2b398e5ee13fd7a3c40a5a857ad835809cbfc5d687b5a"
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"path": "models/650/openwakeword__weather_v0.1.axmodel",
|
| 178 |
+
"size_bytes": 320785,
|
| 179 |
+
"sha256": "f94fe025de680f18cfb55b7ca8f7cfabb94624f96b9f51424d73e75a9e0b471c"
|
| 180 |
+
},
|
| 181 |
+
{
|
| 182 |
+
"path": "outputs/.gitkeep",
|
| 183 |
+
"size_bytes": 1,
|
| 184 |
+
"sha256": "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b"
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"path": "reference/local_inference_results.json",
|
| 188 |
+
"size_bytes": 15035,
|
| 189 |
+
"sha256": "3e4319055ee7b4a7fae93203411acdf71d5596427c63beb2ee07b749ca090a1f"
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"path": "requirements.txt",
|
| 193 |
+
"size_bytes": 12,
|
| 194 |
+
"sha256": "a83a2a4ed7ab2e022b9b8a83cfa2b8cf52cc243006c597e8b96f90a8365590ac"
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"path": "scripts/openwakeword_ax.py",
|
| 198 |
+
"size_bytes": 11767,
|
| 199 |
+
"sha256": "4ad53f63027b7a650cbd95c6a038cde28d7a047b16cc25b5b54aa4b3b1ec865d"
|
| 200 |
+
},
|
| 201 |
+
{
|
| 202 |
+
"path": "scripts/openwakeword_ax630c.py",
|
| 203 |
+
"size_bytes": 327,
|
| 204 |
+
"sha256": "8f00e9bb9edc80dcff413c652eb1878b5174529a6d33a83e1a4f39eab52e6ed2"
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"path": "scripts/openwakeword_ax650.py",
|
| 208 |
+
"size_bytes": 324,
|
| 209 |
+
"sha256": "c9b37219849cca038434abeae54d3a5d2f0fdf585126fb8649e7ecffaa643ee4"
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"path": "scripts/runtime.py",
|
| 213 |
+
"size_bytes": 5296,
|
| 214 |
+
"sha256": "99b9f762b630a186cf3b010f57b11987564cb76e41ab403e78d3ada57729b0fb"
|
| 215 |
+
}
|
| 216 |
+
]
|
| 217 |
+
}
|
models/630C/.gitkeep
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
models/630C/openwakeword__alexa_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7115c3e39908999edc3af0dd15baddc6c6e3093f25007a3dcebf18320ef81177
|
| 3 |
+
size 226487
|
models/630C/openwakeword__embedding_model.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1dd2250f109865d94aa81c56f0aebdc90ca7dc36c5a80f2c13cce220b9ddd554
|
| 3 |
+
size 376612
|
models/630C/openwakeword__hey_jarvis_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f2d5ab8698daf6ea715b2189a71b0cae3593191780cd29fc703d896aa67b0789
|
| 3 |
+
size 338337
|
models/630C/openwakeword__hey_mycroft_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:34627c22ef7aaf915b88516a3a17d18631fe92f8945c734b57ef6b1232307b73
|
| 3 |
+
size 229479
|
models/630C/openwakeword__hey_rhasspy_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:721f58b213a2951e52a80e45e3a1bb96fb761f631157dacb8e5f3aa7591aac26
|
| 3 |
+
size 61607
|
models/630C/openwakeword__melspectrogram.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d3bb40d15f6af7ba3b0aa06702a8bd428ab7a871e28dc6557487fae7cd35e2b7
|
| 3 |
+
size 321576
|
models/630C/openwakeword__timer_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:954b46936f4fcee8694379812e0f89d00cea4b8d4f9ec0cb0632ce41a22d3c5b
|
| 3 |
+
size 450738
|
models/630C/openwakeword__weather_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2e597cc394a4ab34c5b1d9f777d366cb19053b07ec6ff873b163f306fb57a215
|
| 3 |
+
size 300175
|
models/650/openwakeword__alexa_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3595cd242ddf38aca019042d593c45ac1e90107a6d54836ea5593e3dc55f9784
|
| 3 |
+
size 241041
|
models/650/openwakeword__embedding_model.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a9c579200c4e9c076d86181343cdbe5cf2c786016cd60b333463784b5c2fa9b4
|
| 3 |
+
size 451068
|
models/650/openwakeword__hey_jarvis_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c878a73a9f187505a9496c0b12c479c94de9102d7851bc31a7d75de15a7298ef
|
| 3 |
+
size 365733
|
models/650/openwakeword__hey_mycroft_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1ff391da1aefc04f20df5a24be0d063941459caeef0d5e6d6892c5561049fdf2
|
| 3 |
+
size 247553
|
models/650/openwakeword__hey_rhasspy_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4e13babcf713a3b62ca871bd6d7df50315a09da17ab35c294fa41034baed4a69
|
| 3 |
+
size 64073
|
models/650/openwakeword__melspectrogram.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9ea2c5293ef3c05c3c5681b947f270d3fe77a0464308d67cf43d9090e9e7fb5f
|
| 3 |
+
size 340028
|
models/650/openwakeword__timer_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4b7c243daadeed2e7ac2b398e5ee13fd7a3c40a5a857ad835809cbfc5d687b5a
|
| 3 |
+
size 482100
|
models/650/openwakeword__weather_v0.1.axmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f94fe025de680f18cfb55b7ca8f7cfabb94624f96b9f51424d73e75a9e0b471c
|
| 3 |
+
size 320785
|
outputs/.gitkeep
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
outputs/cpp_batch/logs/alexa_test.log
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__embedding_model.axmodel (inputs=1 outputs=1)
|
| 2 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__alexa_v0.1.axmodel (inputs=1 outputs=1)
|
| 3 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_jarvis_v0.1.axmodel (inputs=1 outputs=1)
|
| 4 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_mycroft_v0.1.axmodel (inputs=1 outputs=1)
|
| 5 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_rhasspy_v0.1.axmodel (inputs=1 outputs=1)
|
| 6 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__timer_v0.1.axmodel (inputs=1 outputs=1)
|
| 7 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__weather_v0.1.axmodel (inputs=1 outputs=1)
|
| 8 |
+
|
| 9 |
+
openWakeWord C++ inference complete
|
| 10 |
+
audio: audio/openwakeword/alexa_test.wav
|
| 11 |
+
chunks: 8
|
| 12 |
+
threshold: 0.500
|
| 13 |
+
alexa_v0.1 1.000000 WAKEUP
|
| 14 |
+
hey_jarvis_v0.1 0.000005
|
| 15 |
+
hey_mycroft_v0.1 0.000839
|
| 16 |
+
hey_rhasspy_v0.1 0.001408
|
| 17 |
+
timer_v0.1 0.997989 0.011197 0.011197 0.012590 0.011609 0.011197 0.011197
|
| 18 |
+
weather_v0.1 0.010740
|
| 19 |
+
detected: true
|
| 20 |
+
audio_seconds: 0.625000
|
| 21 |
+
feature_seconds: 0.038823
|
| 22 |
+
npu_seconds: 0.005308
|
| 23 |
+
model_load_seconds: 0.310009
|
| 24 |
+
inference_seconds: 0.044567
|
| 25 |
+
rtf: 0.071308
|
outputs/cpp_batch/logs/hey_jane.log
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__embedding_model.axmodel (inputs=1 outputs=1)
|
| 2 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__alexa_v0.1.axmodel (inputs=1 outputs=1)
|
| 3 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_jarvis_v0.1.axmodel (inputs=1 outputs=1)
|
| 4 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_mycroft_v0.1.axmodel (inputs=1 outputs=1)
|
| 5 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_rhasspy_v0.1.axmodel (inputs=1 outputs=1)
|
| 6 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__timer_v0.1.axmodel (inputs=1 outputs=1)
|
| 7 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__weather_v0.1.axmodel (inputs=1 outputs=1)
|
| 8 |
+
|
| 9 |
+
openWakeWord C++ inference complete
|
| 10 |
+
audio: audio/openwakeword/hey_jane.wav
|
| 11 |
+
chunks: 30
|
| 12 |
+
threshold: 0.500
|
| 13 |
+
alexa_v0.1 0.001312
|
| 14 |
+
hey_jarvis_v0.1 0.017346
|
| 15 |
+
hey_mycroft_v0.1 0.000000
|
| 16 |
+
hey_rhasspy_v0.1 0.004955
|
| 17 |
+
timer_v0.1 1.000000 0.009932 0.008854 0.009936 0.009849 0.008854 0.021674
|
| 18 |
+
weather_v0.1 0.387996
|
| 19 |
+
detected: false
|
| 20 |
+
audio_seconds: 2.368000
|
| 21 |
+
feature_seconds: 0.145612
|
| 22 |
+
npu_seconds: 0.022135
|
| 23 |
+
model_load_seconds: 0.653880
|
| 24 |
+
inference_seconds: 0.169402
|
| 25 |
+
rtf: 0.071538
|
outputs/cpp_batch/logs/hey_mycroft_test.log
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__embedding_model.axmodel (inputs=1 outputs=1)
|
| 2 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__alexa_v0.1.axmodel (inputs=1 outputs=1)
|
| 3 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_jarvis_v0.1.axmodel (inputs=1 outputs=1)
|
| 4 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_mycroft_v0.1.axmodel (inputs=1 outputs=1)
|
| 5 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__hey_rhasspy_v0.1.axmodel (inputs=1 outputs=1)
|
| 6 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__timer_v0.1.axmodel (inputs=1 outputs=1)
|
| 7 |
+
Loaded /mnt/huyuan/workspace/kws_quant/huggingface/openwakeword-axera-inference/models/openwakeword__weather_v0.1.axmodel (inputs=1 outputs=1)
|
| 8 |
+
|
| 9 |
+
openWakeWord C++ inference complete
|
| 10 |
+
audio: audio/openwakeword/hey_mycroft_test.wav
|
| 11 |
+
chunks: 12
|
| 12 |
+
threshold: 0.500
|
| 13 |
+
alexa_v0.1 0.001801
|
| 14 |
+
hey_jarvis_v0.1 0.000025
|
| 15 |
+
hey_mycroft_v0.1 1.000000 WAKEUP
|
| 16 |
+
hey_rhasspy_v0.1 0.002780
|
| 17 |
+
timer_v0.1 0.998750 0.010560 0.010560 0.011588 0.011225 0.010560 0.010560
|
| 18 |
+
weather_v0.1 0.279959
|
| 19 |
+
detected: true
|
| 20 |
+
audio_seconds: 0.952000
|
| 21 |
+
feature_seconds: 0.058748
|
| 22 |
+
npu_seconds: 0.007945
|
| 23 |
+
model_load_seconds: 0.862838
|
| 24 |
+
inference_seconds: 0.067336
|
| 25 |
+
rtf: 0.070731
|
outputs/cpp_batch/results.tsv
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
file audio_seconds feature_seconds npu_seconds inference_seconds rtf model_load_seconds detections
|
| 2 |
+
alexa_test.wav 0.625000 0.038823 0.005308 0.044567 0.071308 0.310009 alexa_v0.1
|
| 3 |
+
hey_jane.wav 2.368000 0.145612 0.022135 0.169402 0.071538 0.653880 none
|
| 4 |
+
hey_mycroft_test.wav 0.952000 0.058748 0.007945 0.067336 0.070731 0.862838 hey_mycroft_v0.1
|
outputs/cpp_batch/summary.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
files: 3
|
| 2 |
+
total_audio_seconds: 3.945000
|
| 3 |
+
total_feature_seconds: 0.243183
|
| 4 |
+
total_npu_seconds: 0.035388
|
| 5 |
+
total_inference_seconds: 0.281305
|
| 6 |
+
total_model_load_seconds: 1.826727
|
| 7 |
+
rtf: 0.071307
|
reference/local_inference_results.json
ADDED
|
@@ -0,0 +1,497 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"environment": {
|
| 3 |
+
"python": "3.12.0",
|
| 4 |
+
"numpy": "1.26.4",
|
| 5 |
+
"onnxruntime": "1.23.1",
|
| 6 |
+
"platform": "Linux-5.15.0-94-generic-x86_64-with-glibc2.35"
|
| 7 |
+
},
|
| 8 |
+
"openwakeword": {
|
| 9 |
+
"pipeline": "fixed 80 ms streaming chunks with 30 ms PCM history",
|
| 10 |
+
"clips": [
|
| 11 |
+
{
|
| 12 |
+
"audio": "openWakeWord/tests/data/alexa_test.wav",
|
| 13 |
+
"sample_rate": 16000,
|
| 14 |
+
"sample_count": 10240,
|
| 15 |
+
"frame_count": 8,
|
| 16 |
+
"initial_context": "480 zero PCM samples for fixed [1,1760] mel input",
|
| 17 |
+
"stage_metrics": {
|
| 18 |
+
"melspectrogram": {
|
| 19 |
+
"shape_match": true,
|
| 20 |
+
"comparisons": 8,
|
| 21 |
+
"minimum_cosine": 0.9999999999999984,
|
| 22 |
+
"maximum_mse": 2.3590018827235326e-11,
|
| 23 |
+
"maximum_abs": 1.52587890625e-05
|
| 24 |
+
},
|
| 25 |
+
"embedding": {
|
| 26 |
+
"shape_match": true,
|
| 27 |
+
"comparisons": 8,
|
| 28 |
+
"minimum_cosine": 0.9999999999996391,
|
| 29 |
+
"maximum_mse": 2.417571698387633e-10,
|
| 30 |
+
"maximum_abs": 3.814697265625e-05
|
| 31 |
+
},
|
| 32 |
+
"classifiers": {
|
| 33 |
+
"shape_match": true,
|
| 34 |
+
"comparisons": 48,
|
| 35 |
+
"minimum_cosine": 0.9999999999999992,
|
| 36 |
+
"maximum_mse": 7.993605777301127e-15,
|
| 37 |
+
"maximum_abs": 1.1920928955078125e-07
|
| 38 |
+
}
|
| 39 |
+
},
|
| 40 |
+
"source_max_scores": {
|
| 41 |
+
"alexa_v0.1.onnx": [
|
| 42 |
+
1.0
|
| 43 |
+
],
|
| 44 |
+
"hey_jarvis_v0.1.onnx": [
|
| 45 |
+
4.9173831939697266e-06
|
| 46 |
+
],
|
| 47 |
+
"hey_mycroft_v0.1.onnx": [
|
| 48 |
+
0.0007033348083496094
|
| 49 |
+
],
|
| 50 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 51 |
+
0.0013944804668426514
|
| 52 |
+
],
|
| 53 |
+
"timer_v0.1.onnx": [
|
| 54 |
+
0.9979174733161926,
|
| 55 |
+
0.011717854999005795,
|
| 56 |
+
0.011717854999005795,
|
| 57 |
+
0.01298792939633131,
|
| 58 |
+
0.012006871402263641,
|
| 59 |
+
0.011717854999005795,
|
| 60 |
+
0.011717854999005795
|
| 61 |
+
],
|
| 62 |
+
"weather_v0.1.onnx": [
|
| 63 |
+
0.011630207300186157
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
"static_max_scores": {
|
| 67 |
+
"alexa_v0.1.onnx": [
|
| 68 |
+
1.0
|
| 69 |
+
],
|
| 70 |
+
"hey_jarvis_v0.1.onnx": [
|
| 71 |
+
4.947185516357422e-06
|
| 72 |
+
],
|
| 73 |
+
"hey_mycroft_v0.1.onnx": [
|
| 74 |
+
0.0007033348083496094
|
| 75 |
+
],
|
| 76 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 77 |
+
0.0013944804668426514
|
| 78 |
+
],
|
| 79 |
+
"timer_v0.1.onnx": [
|
| 80 |
+
0.9979174733161926,
|
| 81 |
+
0.011717865243554115,
|
| 82 |
+
0.011717865243554115,
|
| 83 |
+
0.012987940572202206,
|
| 84 |
+
0.012006882578134537,
|
| 85 |
+
0.011717865243554115,
|
| 86 |
+
0.011717865243554115
|
| 87 |
+
],
|
| 88 |
+
"weather_v0.1.onnx": [
|
| 89 |
+
0.011630237102508545
|
| 90 |
+
]
|
| 91 |
+
},
|
| 92 |
+
"expected_model": "alexa_v0.1.onnx",
|
| 93 |
+
"expected_score": 1.0,
|
| 94 |
+
"expected_detected": true,
|
| 95 |
+
"numerical_match": true,
|
| 96 |
+
"passed": true
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"audio": "openWakeWord/tests/data/hey_mycroft_test.wav",
|
| 100 |
+
"sample_rate": 16000,
|
| 101 |
+
"sample_count": 15360,
|
| 102 |
+
"frame_count": 12,
|
| 103 |
+
"initial_context": "480 zero PCM samples for fixed [1,1760] mel input",
|
| 104 |
+
"stage_metrics": {
|
| 105 |
+
"melspectrogram": {
|
| 106 |
+
"shape_match": true,
|
| 107 |
+
"comparisons": 12,
|
| 108 |
+
"minimum_cosine": 0.9999999999999982,
|
| 109 |
+
"maximum_mse": 2.4101609596982598e-11,
|
| 110 |
+
"maximum_abs": 1.52587890625e-05
|
| 111 |
+
},
|
| 112 |
+
"embedding": {
|
| 113 |
+
"shape_match": true,
|
| 114 |
+
"comparisons": 12,
|
| 115 |
+
"minimum_cosine": 0.9999999999998549,
|
| 116 |
+
"maximum_mse": 1.3607677947409988e-10,
|
| 117 |
+
"maximum_abs": 4.1961669921875e-05
|
| 118 |
+
},
|
| 119 |
+
"classifiers": {
|
| 120 |
+
"shape_match": true,
|
| 121 |
+
"comparisons": 72,
|
| 122 |
+
"minimum_cosine": 0.9999999999999998,
|
| 123 |
+
"maximum_mse": 1.9454660105111543e-11,
|
| 124 |
+
"maximum_abs": 4.410743713378906e-06
|
| 125 |
+
}
|
| 126 |
+
},
|
| 127 |
+
"source_max_scores": {
|
| 128 |
+
"alexa_v0.1.onnx": [
|
| 129 |
+
0.0016120076179504395
|
| 130 |
+
],
|
| 131 |
+
"hey_jarvis_v0.1.onnx": [
|
| 132 |
+
2.256035804748535e-05
|
| 133 |
+
],
|
| 134 |
+
"hey_mycroft_v0.1.onnx": [
|
| 135 |
+
1.0
|
| 136 |
+
],
|
| 137 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 138 |
+
0.0026790201663970947
|
| 139 |
+
],
|
| 140 |
+
"timer_v0.1.onnx": [
|
| 141 |
+
0.9988803267478943,
|
| 142 |
+
0.011138674803078175,
|
| 143 |
+
0.011138674803078175,
|
| 144 |
+
0.012048495002090931,
|
| 145 |
+
0.011720946989953518,
|
| 146 |
+
0.011138674803078175,
|
| 147 |
+
0.011138674803078175
|
| 148 |
+
],
|
| 149 |
+
"weather_v0.1.onnx": [
|
| 150 |
+
0.18771854043006897
|
| 151 |
+
]
|
| 152 |
+
},
|
| 153 |
+
"static_max_scores": {
|
| 154 |
+
"alexa_v0.1.onnx": [
|
| 155 |
+
0.0016120672225952148
|
| 156 |
+
],
|
| 157 |
+
"hey_jarvis_v0.1.onnx": [
|
| 158 |
+
2.2590160369873047e-05
|
| 159 |
+
],
|
| 160 |
+
"hey_mycroft_v0.1.onnx": [
|
| 161 |
+
1.0
|
| 162 |
+
],
|
| 163 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 164 |
+
0.0026790201663970947
|
| 165 |
+
],
|
| 166 |
+
"timer_v0.1.onnx": [
|
| 167 |
+
0.9988803267478943,
|
| 168 |
+
0.011138674803078175,
|
| 169 |
+
0.011138674803078175,
|
| 170 |
+
0.012048495002090931,
|
| 171 |
+
0.011720946989953518,
|
| 172 |
+
0.011138674803078175,
|
| 173 |
+
0.011138674803078175
|
| 174 |
+
],
|
| 175 |
+
"weather_v0.1.onnx": [
|
| 176 |
+
0.18771809339523315
|
| 177 |
+
]
|
| 178 |
+
},
|
| 179 |
+
"expected_model": "hey_mycroft_v0.1.onnx",
|
| 180 |
+
"expected_score": 1.0,
|
| 181 |
+
"expected_detected": true,
|
| 182 |
+
"numerical_match": true,
|
| 183 |
+
"passed": true
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"audio": "openWakeWord/tests/data/hey_jane.wav",
|
| 187 |
+
"sample_rate": 16000,
|
| 188 |
+
"sample_count": 38400,
|
| 189 |
+
"frame_count": 30,
|
| 190 |
+
"initial_context": "480 zero PCM samples for fixed [1,1760] mel input",
|
| 191 |
+
"stage_metrics": {
|
| 192 |
+
"melspectrogram": {
|
| 193 |
+
"shape_match": true,
|
| 194 |
+
"comparisons": 30,
|
| 195 |
+
"minimum_cosine": 0.9999999999999951,
|
| 196 |
+
"maximum_mse": 1.836042429204099e-11,
|
| 197 |
+
"maximum_abs": 1.52587890625e-05
|
| 198 |
+
},
|
| 199 |
+
"embedding": {
|
| 200 |
+
"shape_match": true,
|
| 201 |
+
"comparisons": 30,
|
| 202 |
+
"minimum_cosine": 0.9999999999996753,
|
| 203 |
+
"maximum_mse": 1.5618928372873597e-10,
|
| 204 |
+
"maximum_abs": 3.910064697265625e-05
|
| 205 |
+
},
|
| 206 |
+
"classifiers": {
|
| 207 |
+
"shape_match": true,
|
| 208 |
+
"comparisons": 180,
|
| 209 |
+
"minimum_cosine": 0.0,
|
| 210 |
+
"maximum_mse": 4.3520742565306136e-14,
|
| 211 |
+
"maximum_abs": 2.086162567138672e-07
|
| 212 |
+
}
|
| 213 |
+
},
|
| 214 |
+
"source_max_scores": {
|
| 215 |
+
"alexa_v0.1.onnx": [
|
| 216 |
+
0.001211315393447876
|
| 217 |
+
],
|
| 218 |
+
"hey_jarvis_v0.1.onnx": [
|
| 219 |
+
0.0183732807636261
|
| 220 |
+
],
|
| 221 |
+
"hey_mycroft_v0.1.onnx": [
|
| 222 |
+
3.1888484954833984e-06
|
| 223 |
+
],
|
| 224 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 225 |
+
0.0046852827072143555
|
| 226 |
+
],
|
| 227 |
+
"timer_v0.1.onnx": [
|
| 228 |
+
0.9999986886978149,
|
| 229 |
+
0.01402811985462904,
|
| 230 |
+
0.009387511759996414,
|
| 231 |
+
0.010385164059698582,
|
| 232 |
+
0.012926612980663776,
|
| 233 |
+
0.009387511759996414,
|
| 234 |
+
0.03614084795117378
|
| 235 |
+
],
|
| 236 |
+
"weather_v0.1.onnx": [
|
| 237 |
+
0.31700584292411804
|
| 238 |
+
]
|
| 239 |
+
},
|
| 240 |
+
"static_max_scores": {
|
| 241 |
+
"alexa_v0.1.onnx": [
|
| 242 |
+
0.001211315393447876
|
| 243 |
+
],
|
| 244 |
+
"hey_jarvis_v0.1.onnx": [
|
| 245 |
+
0.018373221158981323
|
| 246 |
+
],
|
| 247 |
+
"hey_mycroft_v0.1.onnx": [
|
| 248 |
+
3.159046173095703e-06
|
| 249 |
+
],
|
| 250 |
+
"hey_rhasspy_v0.1.onnx": [
|
| 251 |
+
0.0046852827072143555
|
| 252 |
+
],
|
| 253 |
+
"timer_v0.1.onnx": [
|
| 254 |
+
0.9999986886978149,
|
| 255 |
+
0.01402811985462904,
|
| 256 |
+
0.009387511759996414,
|
| 257 |
+
0.010385164059698582,
|
| 258 |
+
0.012926612980663776,
|
| 259 |
+
0.009387511759996414,
|
| 260 |
+
0.036140866577625275
|
| 261 |
+
],
|
| 262 |
+
"weather_v0.1.onnx": [
|
| 263 |
+
0.31700563430786133
|
| 264 |
+
]
|
| 265 |
+
},
|
| 266 |
+
"expected_model": null,
|
| 267 |
+
"expected_score": null,
|
| 268 |
+
"expected_detected": null,
|
| 269 |
+
"numerical_match": true,
|
| 270 |
+
"passed": true
|
| 271 |
+
}
|
| 272 |
+
],
|
| 273 |
+
"passed": true
|
| 274 |
+
},
|
| 275 |
+
"sherpa": {
|
| 276 |
+
"sherpa_onnx_version": "1.13.4",
|
| 277 |
+
"variants": [
|
| 278 |
+
{
|
| 279 |
+
"chunk_size": 8,
|
| 280 |
+
"max_active_paths": 1,
|
| 281 |
+
"audio_count": 9,
|
| 282 |
+
"comparisons": [
|
| 283 |
+
{
|
| 284 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/en_0.wav",
|
| 285 |
+
"source_detections": [
|
| 286 |
+
"LIGHT_UP"
|
| 287 |
+
],
|
| 288 |
+
"static_detections": [
|
| 289 |
+
"LIGHT_UP"
|
| 290 |
+
],
|
| 291 |
+
"source_decode_calls": 45,
|
| 292 |
+
"static_decode_calls": 45,
|
| 293 |
+
"match": true
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/en_1.wav",
|
| 297 |
+
"source_detections": [
|
| 298 |
+
"LOVELY_CHILD"
|
| 299 |
+
],
|
| 300 |
+
"static_detections": [
|
| 301 |
+
"LOVELY_CHILD"
|
| 302 |
+
],
|
| 303 |
+
"source_decode_calls": 108,
|
| 304 |
+
"static_decode_calls": 108,
|
| 305 |
+
"match": true
|
| 306 |
+
},
|
| 307 |
+
{
|
| 308 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_0.wav",
|
| 309 |
+
"source_detections": [],
|
| 310 |
+
"static_detections": [],
|
| 311 |
+
"source_decode_calls": 39,
|
| 312 |
+
"static_decode_calls": 39,
|
| 313 |
+
"match": true
|
| 314 |
+
},
|
| 315 |
+
{
|
| 316 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_1.wav",
|
| 317 |
+
"source_detections": [],
|
| 318 |
+
"static_detections": [],
|
| 319 |
+
"source_decode_calls": 36,
|
| 320 |
+
"static_decode_calls": 36,
|
| 321 |
+
"match": true
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_2.wav",
|
| 325 |
+
"source_detections": [],
|
| 326 |
+
"static_detections": [],
|
| 327 |
+
"source_decode_calls": 32,
|
| 328 |
+
"static_decode_calls": 32,
|
| 329 |
+
"match": true
|
| 330 |
+
},
|
| 331 |
+
{
|
| 332 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_3.wav",
|
| 333 |
+
"source_detections": [
|
| 334 |
+
"法国"
|
| 335 |
+
],
|
| 336 |
+
"static_detections": [
|
| 337 |
+
"法国"
|
| 338 |
+
],
|
| 339 |
+
"source_decode_calls": 54,
|
| 340 |
+
"static_decode_calls": 54,
|
| 341 |
+
"match": true
|
| 342 |
+
},
|
| 343 |
+
{
|
| 344 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_4.wav",
|
| 345 |
+
"source_detections": [
|
| 346 |
+
"蒋友伯",
|
| 347 |
+
"女儿"
|
| 348 |
+
],
|
| 349 |
+
"static_detections": [
|
| 350 |
+
"蒋友伯",
|
| 351 |
+
"女儿"
|
| 352 |
+
],
|
| 353 |
+
"source_decode_calls": 32,
|
| 354 |
+
"static_decode_calls": 32,
|
| 355 |
+
"match": true
|
| 356 |
+
},
|
| 357 |
+
{
|
| 358 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_5.wav",
|
| 359 |
+
"source_detections": [
|
| 360 |
+
"周望军",
|
| 361 |
+
"落实"
|
| 362 |
+
],
|
| 363 |
+
"static_detections": [
|
| 364 |
+
"周望军",
|
| 365 |
+
"落实"
|
| 366 |
+
],
|
| 367 |
+
"source_decode_calls": 30,
|
| 368 |
+
"static_decode_calls": 30,
|
| 369 |
+
"match": true
|
| 370 |
+
},
|
| 371 |
+
{
|
| 372 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_6.wav",
|
| 373 |
+
"source_detections": [
|
| 374 |
+
"朱丽楠"
|
| 375 |
+
],
|
| 376 |
+
"static_detections": [
|
| 377 |
+
"朱丽楠"
|
| 378 |
+
],
|
| 379 |
+
"source_decode_calls": 26,
|
| 380 |
+
"static_decode_calls": 26,
|
| 381 |
+
"match": true
|
| 382 |
+
}
|
| 383 |
+
],
|
| 384 |
+
"detected_audio_count": 6,
|
| 385 |
+
"passed": true
|
| 386 |
+
},
|
| 387 |
+
{
|
| 388 |
+
"chunk_size": 16,
|
| 389 |
+
"max_active_paths": 1,
|
| 390 |
+
"audio_count": 9,
|
| 391 |
+
"comparisons": [
|
| 392 |
+
{
|
| 393 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/en_0.wav",
|
| 394 |
+
"source_detections": [],
|
| 395 |
+
"static_detections": [],
|
| 396 |
+
"source_decode_calls": 22,
|
| 397 |
+
"static_decode_calls": 22,
|
| 398 |
+
"match": true
|
| 399 |
+
},
|
| 400 |
+
{
|
| 401 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/en_1.wav",
|
| 402 |
+
"source_detections": [
|
| 403 |
+
"LOVELY_CHILD"
|
| 404 |
+
],
|
| 405 |
+
"static_detections": [
|
| 406 |
+
"LOVELY_CHILD"
|
| 407 |
+
],
|
| 408 |
+
"source_decode_calls": 54,
|
| 409 |
+
"static_decode_calls": 54,
|
| 410 |
+
"match": true
|
| 411 |
+
},
|
| 412 |
+
{
|
| 413 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_0.wav",
|
| 414 |
+
"source_detections": [],
|
| 415 |
+
"static_detections": [],
|
| 416 |
+
"source_decode_calls": 19,
|
| 417 |
+
"static_decode_calls": 19,
|
| 418 |
+
"match": true
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_1.wav",
|
| 422 |
+
"source_detections": [],
|
| 423 |
+
"static_detections": [],
|
| 424 |
+
"source_decode_calls": 18,
|
| 425 |
+
"static_decode_calls": 18,
|
| 426 |
+
"match": true
|
| 427 |
+
},
|
| 428 |
+
{
|
| 429 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_2.wav",
|
| 430 |
+
"source_detections": [],
|
| 431 |
+
"static_detections": [],
|
| 432 |
+
"source_decode_calls": 16,
|
| 433 |
+
"static_decode_calls": 16,
|
| 434 |
+
"match": true
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_3.wav",
|
| 438 |
+
"source_detections": [
|
| 439 |
+
"法国"
|
| 440 |
+
],
|
| 441 |
+
"static_detections": [
|
| 442 |
+
"法国"
|
| 443 |
+
],
|
| 444 |
+
"source_decode_calls": 27,
|
| 445 |
+
"static_decode_calls": 27,
|
| 446 |
+
"match": true
|
| 447 |
+
},
|
| 448 |
+
{
|
| 449 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_4.wav",
|
| 450 |
+
"source_detections": [
|
| 451 |
+
"蒋友伯",
|
| 452 |
+
"女儿"
|
| 453 |
+
],
|
| 454 |
+
"static_detections": [
|
| 455 |
+
"蒋友伯",
|
| 456 |
+
"女儿"
|
| 457 |
+
],
|
| 458 |
+
"source_decode_calls": 16,
|
| 459 |
+
"static_decode_calls": 16,
|
| 460 |
+
"match": true
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_5.wav",
|
| 464 |
+
"source_detections": [
|
| 465 |
+
"周望军",
|
| 466 |
+
"落实"
|
| 467 |
+
],
|
| 468 |
+
"static_detections": [
|
| 469 |
+
"周望军",
|
| 470 |
+
"落实"
|
| 471 |
+
],
|
| 472 |
+
"source_decode_calls": 15,
|
| 473 |
+
"static_decode_calls": 15,
|
| 474 |
+
"match": true
|
| 475 |
+
},
|
| 476 |
+
{
|
| 477 |
+
"audio": "sherpa-onnx-kws-zipformer-zh-en-3M-2025-12-20/test_wavs/zh_6.wav",
|
| 478 |
+
"source_detections": [
|
| 479 |
+
"朱丽楠"
|
| 480 |
+
],
|
| 481 |
+
"static_detections": [
|
| 482 |
+
"朱丽楠"
|
| 483 |
+
],
|
| 484 |
+
"source_decode_calls": 13,
|
| 485 |
+
"static_decode_calls": 13,
|
| 486 |
+
"match": true
|
| 487 |
+
}
|
| 488 |
+
],
|
| 489 |
+
"detected_audio_count": 5,
|
| 490 |
+
"passed": true
|
| 491 |
+
}
|
| 492 |
+
],
|
| 493 |
+
"passed": true
|
| 494 |
+
},
|
| 495 |
+
"elapsed_seconds": 9.052458902820945,
|
| 496 |
+
"all_passed": true
|
| 497 |
+
}
|