Google Speech Commands 在 MAX78000 上的训练、量化与部署
本文记录如何在 Windows + WSL 环境中,使用 Google Speech Commands v0.02 训练一个 12 类关键词识别模型,并将模型量化为 8 bit,生成 MAX78000 CNN 加速器代码,最后部署到 MAX78000FTHR 开发板。
本文使用原生命令逐步操作,不依赖项目私有的自动化脚本。读者可以根据自己的 目录结构替换示例中的路径。
1. 实验目标与最终结果
模型识别 10 个英语口令,并增加静音与未知语音两个拒识类别:
ID标签中文含义固件处理
| 0 | down | 下 | 接受 |
| 1 | go | 前进 | 接受 |
| 2 | left | 左转 | 接受 |
| 3 | no | 否 | 接受 |
| 4 | off | 关闭 | 接受 |
| 5 | on | 开启 | 接受 |
| 6 | right | 右转 | 接受 |
| 7 | stop | 停止 | 接受 |
| 8 | up | 上 | 接受 |
| 9 | yes | 是 | 接受 |
| 10 | _silence_ | 静音 | 拒绝 |
| 11 | _unknown_ | 未知语音 | 拒绝 |
本次实验结果如下:
项目结果
| 数据集 | Google Speech Commands v0.02 |
| 训练集 | 87,829 条 |
| 验证集 | 10,355 条 |
| 测试集 | 4,891 条 |
| 网络 | ai85kws20netv3 |
| 参数量 | 167,168 |
| 训练轮数 | 200 |
| QAT 开始轮次 | 第 150 轮 |
| 最佳验证 Top-1 | 84.57% |
| 测试 Top-1 | 90.98% |
| 测试 Top-5 | 99.39% |
| 权重位宽 | 8 bit |
| CNN 推理时间 | 约 1.849 ms |
| 实时固件 FLASH | 230,144 字节,43.90% |
| 实时固件 SRAM | 38,416 字节,29.31% |
整体流程为:
环境安装 → 数据下载与处理 → 浮点训练与 QAT → 8-bit 量化 → ai8xize 代码生成 → 麦克风固件集成 → 编译、烧录与串口验证
2. 硬件和软件准备
2.1 硬件
MAX78000FTHR 开发板;
USB 数据线;
开发板板载数字麦克风;
板载 DAPLink 下载器和调试串口。
开发板运行状态如下:

图 1:MAX78000FTHR 通过 USB 连接并运行关键词识别固件。
2.2 本次使用的软件版本
软件版本
| WSL | Ubuntu 22.04.5 LTS |
| Python | 3.11.8 |
| PyTorch | 2.3.1+cpu |
| torchaudio | 2.3.1+cpu |
| NumPy | 1.26.4 |
| ONNX | 1.16.1 |
| AI8X Training | develop 分支 |
| AI8X Synthesis | develop 分支 |
| MSDK | 2024.02 系列 |
训练使用 CPU 完成。如果计算机具有可用的 NVIDIA GPU,可以根据 AI8X Training 的依赖要求安装对应 CUDA 版本的 PyTorch。
3. 搭建 WSL 和 AI8X 环境
3.1 安装 WSL
以管理员身份打开 PowerShell:
wsl --install -d Ubuntu-22.04
安装完成并重启后,打开 Ubuntu 终端,更新系统并安装编译、音频和 Python 构建依赖:
sudo apt update sudo apt install -y \ make build-essential git ca-certificates curl wget \ libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \ llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev \ libffi-dev liblzma-dev libsndfile1-dev portaudio19-dev \ libsox-dev sox libgdbm-dev libnss3-dev libdb-dev \ libexpat1-dev uuid-dev
3.2 安装 Python 3.11.8
使用 pyenv 可以让训练环境与系统 Python 隔离:
git clone --depth 1 https://github.com/pyenv/pyenv.git ~/.pyenv export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" pyenv install 3.11.8
为了让设置在下次启动终端时仍然有效,可将 PYENV_ROOT 和 PATH 两行加入~/.bashrc。
3.3 获取 AI8X Training 和 AI8X Synthesis
mkdir -p ~/max78000-ai cd ~/max78000-ai git clone --depth 1 --branch develop --recurse-submodules \ https://github.com/analogdevicesinc/ai8x-training.git git clone --depth 1 --branch develop \ https://github.com/analogdevicesinc/ai8x-synthesis.git
分别建立虚拟环境:
~/.pyenv/versions/3.11.8/bin/python -m venv \ ~/max78000-ai/ai8x-training/.venv ~/.pyenv/versions/3.11.8/bin/python -m venv \ ~/max78000-ai/ai8x-synthesis/.venv
安装训练环境。以下示例使用 CPU 版 PyTorch:
cd ~/max78000-ai/ai8x-training .venv/bin/python -m pip install --upgrade \ pip wheel setuptools==80.9.0 .venv/bin/python -m pip install \ torch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 \ --index-url https://download.pytorch.org/whl/cpu .venv/bin/python -m pip install --no-build-isolation visdom==0.2.4 .venv/bin/python -m pip install \ -r requirements-base.txt -r requirements-distiller.txt
如果 requirements-datasets.txt 中已经下架的旧版 pyffmpeg 导致安装失败, 将 pyffmpeg==2.4.2.18.1 改为 pyffmpeg==2.5.2.3.2,再执行:
.venv/bin/python -m pip install \ --constraint requirements-base.txt \ -r requirements-datasets.txt
安装代码生成环境:
cd ~/max78000-ai/ai8x-synthesis .venv/bin/python -m pip install --upgrade \ pip wheel setuptools==80.9.0 .venv/bin/python -m pip install torch==2.3.1 \ --index-url https://download.pytorch.org/whl/cpu .venv/bin/python -m pip install -r requirements.txt
最后检查环境:
~/max78000-ai/ai8x-training/.venv/bin/python -c \ "import torch, torchaudio; print(torch.__version__, torchaudio.__version__)" ~/max78000-ai/ai8x-synthesis/.venv/bin/python \ ~/max78000-ai/ai8x-synthesis/ai8xize.py --help
4. 下载和处理 Google Speech Commands
4.1 数据来源和许可
本实验使用 Google Speech Commands v0.02:
数据集采用 CC BY 4.0。发布原始数据或衍生数据时,应保留来源、许可和署名。
4.2 手动下载
建立原始数据目录:
mkdir -p ~/max78000-ai/data/KWS/raw mkdir -p ~/max78000-ai/data/KWS/raw_test
下载并解压训练与验证数据:
cd ~/max78000-ai/data/KWS/raw wget -c \ http://download.tensorflow.org/data/speech_commands_v0.02.tar.gz tar -xzf speech_commands_v0.02.tar.gz
下载并解压官方测试数据:
cd ~/max78000-ai/data/KWS/raw_test wget -c \ http://download.tensorflow.org/data/speech_commands_test_set_v0.02.tar.gz tar -xzf speech_commands_test_set_v0.02.tar.gz
主数据压缩包约 2.3 GiB,生成缓存后整个数据目录约占 7.6 GiB,建议至少预留 10 GiB 空间。
4.3 适配 AI8X 的 12 类数据加载
AI8X Training 已包含 KWS_12_benchmark 类别定义,可以以它为基础建立 12 类 加载入口。为了避免数据准备失败,本次做了三个调整:
只使用 Google Speech Commands,不下载后续会被过滤的 LibriSpeech;
关闭三倍静态速度复制,避免 WSL 在生成缓存时因内存不足退出;
保留动态随机平移与高斯噪声增强。
动态增强参数为:
augmentation = {
"aug_num": 0,
"shift": {"min": -0.1, "max": 0.1},
"snr": {"min": -5.0, "max": 20.0},
}Google 数据中的其他单词用于构造 _unknown_,背景噪声切片用于构造_silence_。由于原始 KWS 类别字典为 LibriSpeech 保留了内部 ID,还需要建立 一个空目录以保持标签顺序:
mkdir -p ~/max78000-ai/data/KWS/raw/librispeech
加载器首次读取数据时会生成:
~/max78000-ai/data/KWS/processed/dataset.pt
最终得到:
Training: 87,829 Validation: 10,355 Test: 4,891
_unknown_ 样本远多于单个目标词,因此训练时为它设置 0.056 的损失权重, 以避免该类别支配整体损失。
5. 模型与训练
5.1 网络配置
使用 ai85kws20netv3:
输入尺寸:128 × 128;
原始音频:16,384 个采样点,约 1.024 秒;
8 个一维卷积层;
9 个参数层;
输出:12 类;
参数量:167,168;
无 bias;
面向 MAX78000 CNN 加速器。
网络部署配置需要将最后一层输出数改为 12,并为各层设置处理器映射、输出偏移 和内存位置。该 YAML 配置在量化完成后由 ai8xize.py 读取。
5.2 训练参数
参数配置
| Epoch | 200 |
| Batch size | 64 |
| 优化器 | Adam |
| 初始学习率 | 0.001 |
| Weight decay | 0 |
| DataLoader workers | 0 |
| 确定性训练 | 开启 |
| QAT | 第 150 轮开始 |
| 量化位宽 | 8 bit |
学习率在第 100、140、180、190、195 轮乘以 0.5。前 149 轮完成常规训练, 第 150 轮开始量化感知训练,使网络提前适应部署时的整数运算误差。
5.3 启动训练
进入 AI8X Training 目录后执行:
cd ~/max78000-ai/ai8x-training .venv/bin/python train.py \ --epochs 200 \ --batch-size 64 \ --optimizer Adam \ --lr 0.001 \ --wd 0 \ --deterministic \ --compress policies/schedule_kws20.yaml \ --qat-policy policies/qat_policy_late_kws20.yaml \ --model ai85kws20netv3 \ --dataset KWS_GOOGLE_12 \ --data "$HOME/max78000-ai/data" \ --confusion \ --device MAX78000 \ --compiler-mode none \ --workers 0 \ --cpu \ --print-freq 100 \ --name kws_google_12 \ --out-dir "$HOME/max78000-ai/logs"
如果使用上游原始数据入口,应将数据集名称换成相应注册名称;如果使用前文的 Google-only 适配入口,则保持 KWS_GOOGLE_12。
训练期间重点观察:
训练损失是否持续下降;
验证 Top-1 是否稳定上升;
第 150 轮进入 QAT 后是否出现明显精度骤降;
混淆矩阵中 _silence_ 与 _unknown_ 是否大量误判为目标词。
5.4 训练结果
CPU 训练耗时约 3 小时 10 分钟:
检查项结果
| 最佳验证轮次 | 195 |
| 最佳验证 Top-1 | 84.5678% |
| 最佳验证 Top-5 | 99.5750% |
| 最佳 QAT 模型测试 Top-1 | 90.9834% |
| 最佳 QAT 模型测试 Top-5 | 99.3866% |
| 最佳 QAT 模型测试损失 | 0.2876 |
最佳模型应根据验证集选择,测试集只用于最终评估。后续量化应使用 QAT 阶段产生 的最佳检查点。
6. 8-bit 量化
6.1 为什么 QAT 后还要量化
QAT 检查点记录了训练阶段的量化状态,但部署仍需生成确定的整数权重。AI8X 量化工具会把参数转换为 MAX78000 可使用的 8-bit 表示,并保留各层量化信息。
进入 AI8X Synthesis 目录,将最佳检查点复制到模型工作目录:
mkdir -p ~/max78000-ai/models/kws_google_12 cp /path/to/kws_google_12_qat_best.pth.tar \ ~/max78000-ai/models/kws_google_12/model-best.pth.tar cd ~/max78000-ai/ai8x-synthesis
执行量化:
.venv/bin/python quantize.py \ ~/max78000-ai/models/kws_google_12/model-best.pth.tar \ ~/max78000-ai/models/kws_google_12/model-q8.pth.tar \ --device MAX78000 \ -v
检查输出中是否包含全部 9 个参数层,并确认权重位宽为 8 bit。本次量化后的权重 共 167,168 字节,无 bias 数据。
7. 使用 ai8xize 生成 MAX78000 代码
准备三项输入:
上一步得到的 8-bit 检查点;
12 类网络 YAML 配置;
一个形状正确的 128 × 128 样本输入。
执行:
cd ~/max78000-ai/ai8x-synthesis .venv/bin/python ai8xize.py \ --test-dir "$HOME/max78000-ai/generated" \ --prefix kws_google_12 \ --checkpoint-file \ "$HOME/max78000-ai/models/kws_google_12/model-q8.pth.tar" \ --config-file networks/kws_google_12.yaml \ --sample-input tests/sample_kws_20.npy \ --device MAX78000 \ --timer 0 \ --display-checkpoint \ --verbose \ --softmax
生成目录中主要包含:
cnn.c cnn.h weights.h softmax.c main.c sampledata.h sampleoutput.h project.mk Makefile
本次网络计算量如下:
项目数量
| Hardware ops | 8,400,224 |
| MACC | 8,343,040 |
| Comparisons | 54,496 |
| Additions | 2,688 |
先编译固定样本工程,确认网络配置、权重和 MSDK 工具链可以正常工作:
cd ~/max78000-ai/generated/kws_google_12 make -j2 BOARD=FTHR_RevA MAXIM_PATH=/path/to/msdk arm-none-eabi-objcopy \ -O ihex build/max78000.elf build/max78000.hex
固定样本工程的资源占用为:
FLASH:239,360 字节,45.65%;
SRAM:5,212 字节,3.98%。
该工程只用于验证固定输入,不是最终实时麦克风应用。
8. 集成实时麦克风固件
将生成的 cnn.c、cnn.h 和 weights.h 接入 MAX78000FTHR 麦克风示例工程, 并完成以下处理:
以 16 kHz 采集板载数字麦克风;
使用高通滤波移除直流分量;
根据平均能量判断语音起点和终点;
组成 16,384 点窗口,不足部分补零;
转置为 CNN 所需的 128 × 128 HWC 布局;
执行 CNN 推理和定点 Softmax;
对 silence 与 unknown 强制拒识;
对目标词应用置信度、类别差值和冷却时间;
仅在通过全部条件时产生口令事件。
本次使用的主要门限为:
#define THRESHOLD_HIGH 350 #define THRESHOLD_LOW 100 #define INFERENCE_THRESHOLD 95 #define INFERENCE_MARGIN_THRESHOLD 15
不同硬件修订版、麦克风距离和环境噪声可能需要不同能量门限。置信度门限也不应 只根据单次成功样本设置,应同时测试目标词、非目标语音、静音和背景噪声。
编译实时工程:
cd /path/to/msdk/Examples/MAX78000/CNN/kws_google_12_demo make clean MAXIM_PATH=/path/to/msdk make -j2 BOARD=FTHR_RevA MAXIM_PATH=/path/to/msdk make build/max78000.hex MAXIM_PATH=/path/to/msdk
本次实时固件资源占用:
FLASH: 230,144 / 524,288 bytes = 43.90% SRAM: 38,416 / 131,072 bytes = 29.31%
9. 手动烧录
MAX78000FTHR 的板载 DAPLink 可以像 U 盘一样烧录:
使用 USB 数据线连接开发板;
等待系统出现名为 DAPLINK 的磁盘;
找到实时工程生成的 build/max78000.hex;
将 HEX 文件复制到 DAPLINK 磁盘根目录;
等待复制结束和开发板自动复位;
检查 DAPLink 根目录是否出现 FAIL.TXT;
如果存在 FAIL.TXT,打开文件查看烧录失败原因。
不要烧录固定样本测试工程生成的 HEX;实时识别必须使用已经集成麦克风采集逻辑 的固件。
10. 串口运行与识别验证
在 Windows 设备管理器中查找 DAPLink 对应的 COM 端口,然后使用 PuTTY、 Tera Term、MobaXterm 或其他串口工具连接:
波特率:115200 数据位:8 校验位:None 停止位:1 编码:UTF-8
如果打开串口后没有启动信息,保持串口窗口开启并按开发板 SW4 RESET。
测试词 up 被识别为类别 8,置信度 99.9%,CNN 推理时间约 1,849 微秒:

图 2:低置信度窗口被拒绝,随后 UP 以 99.9% 置信度被接受。
机器可读事件为:
KWS_EVENT,8,UP,99.9
从日志可以看到:
91.0% 置信度低于 95% 门限,因此被拒绝;
10.0% 的非语音窗口被拒绝;
UP 的类别差值为 99.8%,通过歧义检查;
麦克风样本范围达到 -127~127;
每次 CNN 推理约 1.849 ms。
11. 常见问题
11.1 数据处理出现退出码 137
通常表示 WSL 内存不足。关闭三倍静态速度复制,只保留训练时动态平移和噪声 增强;必要时提高 WSL 内存上限,然后删除旧的 dataset.pt 重新生成。
11.2 标签数量或顺序异常
确认 raw/librispeech 空目录存在。原始类别字典为该类别保留了内部 ID,直接 删除会导致之后的 Google 标签整体错位。
11.3 中文串口乱码
确认固件源文件、终端和串口接收工具都使用 UTF-8。串口参数应为 115200 8-N-1。若终端不支持 UTF-8,可以只输出 ASCII 机器事件,例如KWS_EVENT,8,UP,99.9。
11.4 识别准确率低或误触发多
实际说出英语口令,而不是中文翻译;
控制说话距离,避免声音过小;
检查采样是否长期达到 -128/127,防止严重削波;
在目标环境中采集板载麦克风数据用于微调;
添加目标噪声环境下的 silence 和 unknown 样本;
分别统计误接受率和误拒绝率,再调整置信度与类别差值门限;
不要只依据单个成功样本降低门限。
11.5 烧录后没有运行
检查 DAPLink 中的 FAIL.TXT;
确认构建目标是 FTHR_RevA;
确认烧录的是实时麦克风工程 HEX;
重新插拔 USB,然后按 SW4 RESET;
确认串口号没有因重新枚举而改变。
12. 总结
本流程完成了从公开语音数据到 MAX78000 实时端侧关键词识别的完整闭环:
使用 Google Speech Commands 提高说话人和录音设备的多样性;
加入 silence 与 unknown,降低非目标声音触发;
进行 200 轮训练,并从第 150 轮开始 8-bit QAT;
使用 quantize.py 生成 8-bit 权重;
使用 ai8xize.py 生成 MAX78000 CNN 代码;
集成麦克风采集、能量检测、Softmax 和拒识门限;
通过 DAPLink 手动烧录并使用串口验证;
实测 UP 达到 99.9% 置信度,单次 CNN 推理约 1.849 ms。
如果要用于真实产品,应继续采集实际安装环境中的板载麦克风数据,分别统计不同 说话人、距离、噪声和语速下的误接受率与误拒绝率,再决定是否微调模型或调整 门限。
我要赚赏金
