news 2026/9/26 2:29:14

TensorFlow Lite 语音指令识别实战:从 Speech Commands 数据集训练到 iOS 端部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TensorFlow Lite 语音指令识别实战:从 Speech Commands 数据集训练到 iOS 端部署
  • 示例工程

【免费下载链接】examples

TensorFlow examples

项目地址:https://gitcode.com/gh_mirrors/exam/examples
点击查看免费下载

语音指令识别(Speech Commands Recognition)是移动端 AI 的典型落地场景之一:设备通过麦克风持续监听,识别出用户说出的预设短词(如 "yes"、"no"、"stop"),从而支撑免提交互、语音唤醒等能力。本指南以本仓库lite/examples/speech_commands下的完整示例为主线,系统讲解基于 TensorFlow Speech Commands 数据集的端到端方案,涵盖数据集获取、音频预处理、1D 卷积模型训练、模型导出为 TFLite,以及在 iOS 设备上的推理与部署。读完本文,你将掌握一条可复现的"语音数据集 → Keras 模型 → TFLite → 移动端识别"完整链路。

示例概览与项目定位

本目录(lite/examples/speech_commands/README.md)提供了一个"端到端"的语音指令识别示例集合,目标是在移动设备上对语音指令进行识别并高亮显示说出的单词。按官方文档规划,它包含三个组成部分:

  • 使用 TensorFlow Lite 模型识别语音指令的Android 应用;
  • 使用 TensorFlow Lite 模型识别语音指令的iOS 应用(见 ios/);
  • 生成语音指令 TFLite 模型的训练与导出指南(见 ml/)。

需要说明的是,从当前仓库快照来看,lite/examples/speech_commands下实际包含的是 ml/(训练与模型导出脚本)和 ios/(iOS 示例应用)两部分;同时,仓库中的 README.md 与 ios/README.md 均带有明确的Deprecated(已弃用)警告,官方建议迁移到技术栈更新的 Sound Classification 示例。因此,本文在讲解本示例的技术实现时,也会提醒读者关注这一演进方向。

数据集:TensorFlow Speech Commands Dataset

数据集规模与内容

训练脚本依赖 TensorFlow Speech Commands 数据集。该数据集包含65,000 条 1 秒钟的语音片段,由数千名不同说话人录制,覆盖30 个英文短词,例如 "yes"、"no"、"up"、"down"、"left"、"right"、"on"、"off"、"stop"、"go" 等,同时附带_silence_(静音)与_background_noise_(背景噪声)等特殊样本类别。

类别选择

移动端指令识别通常只需要少量指令词。本示例从 30 个词中挑选10 个类别用于 TensorFlow Lite 语音指令应用:

stop down off right up go on yes left no

对应实现见 ml/classes.py:get_classes(wanted_only=True)返回这 10 个词的列表并断言长度为 10;get_classes(wanted_only=False)则返回完整的 30 词列表(用于构建未知词映射)。

值得注意的一个细节:在类别体系中,除了 10 个目标词,还有两个特殊类别参与训练与推理。从 ml/generator.py 可以看到,词表由prepare_words_list()统一构造,最终类别集合为:

_silence_ _unknown_ <10 个目标词>
  • _silence_(索引 0):静音类别,用于让模型学会"不说话时不做任何触发";
  • _unknown_(索引 1):未知词类别,把不在目标词表中的其余 20 个词归入其中,增强模型对无关语音的鲁棒性。

因此模型输出层共有12 个类别,这一点与 iOS 端模型标签文件 conv_actions_labels.txt 的内容一一对应:

_silence_ _unknown_ yes no up down left right on off stop go

数据集下载

ml/download.py 提供了数据集的一键下载脚本:它从http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz下载speech_commands_v0.01版本的数据集,解压到data/train目录后删除压缩包。运行方式:

python download.py

requirements.txt中声明的依赖包括wget==3.2(用于下载)、Keras==2.2.0、pandas==0.22.0、pandas-ml==0.5.0(用于混淆矩阵统计)以及tensorflow>=1.14.0、tensorflow-gpu>=1.14.0,详见 ml/requirements.txt。

音频数据预处理

基础采样配置

语音片段在送入模型前,会被统一整理为固定采样率、固定长度的 PCM 波形数据。文档给出的配置如下:

采样点数(Samples)采样率(Sample Rate)片段时长(Clip Duration)
1600016000 Hz1000 ms

即每个样本是 1 秒钟、16000 Hz、单声道、16000 个采样点的原始波形。该配置在 ml/model.py 的prepare_model_settings()中通过desired_samples = int(sample_rate * clip_duration_ms / 1000)计算得到,并且训练脚本 ml/train.py 固定使用clip_duration_ms=1000、window_size_ms=30.0、window_stride_ms=10.0、dct_coefficient_count=80、num_log_mel_features=60等超参数。

多种输入表示:raw / spec / mfcc

train.py的-output_representation参数控制模型输入特征的类型,支持四种取值,其维度计算见 ml/model.py:

表示方式含义特征维度计算
raw原始 PCM 波形(默认)desired_samples(即 16000)
spec频谱图(spectrogram)spectrogram_frequencies × spectrogram_length(257 × 频谱帧数)
mfcc梅尔频率倒谱系数num_log_mel_features × spectrogram_length
mfcc_and_rawMFCC 与原始波形拼接以 MFCC 为主,同时输出原始波形

其中频谱与 MFCC 的生成逻辑在 ml/generator.py 的prepare_processing_graph()中实现:先对波形做短时傅里叶变换(tf.signal.stft,帧长window_size_samples、帧移window_stride_samples),取幅度谱得到频谱图;再通过 80~7600 Hz 的梅尔滤波器组(linear_to_mel_weight_matrix)得到 log-Mel 频谱,进而计算 MFCC。训练时默认使用raw表示,配合下文介绍的 1D 时序卷积模型直接消费原始波形。

训练期数据增强

训练阶段还会对音频施加一系列"失真"增强(见 ml/generator.py 与 ml/utils.py 的data_gen()默认参数):

  • 背景噪声混入:从_background_noise_目录随机截取一段噪声叠加到前景语音上,训练时背景出现频率background_frequency=0.3、音量范围background_volume_range=0.15;
  • 音量调节:前景音量以foreground_frequency=0.3的概率在 ±0.15 范围内随机缩放;
  • 时间平移:以time_shift_frequency=0.3的概率在[-500, 0]个采样点范围内滚动波形(tf_roll实现),模拟指令起始时间的变化;
  • 静音样本处理:_silence_样本将前景音量置零、仅保留背景噪声,避免模型学会"以全零向量识别静音"的捷径。

验证集与测试集则关闭所有随机增强(data_gen()中对非 training 模式将增强频率全部置 0),保证评估的公平性。

模型架构:时间堆叠的 1D 卷积网络

本示例的模型(conv_1d_time_stacked)是一个面向音频波形这类时序数据的时间堆叠 VGG 风格网络,全部使用一维卷积(Conv1D),定义在 ml/model.py。核心结构可以拆解为三层设计:

  1. 输入整形与预处理:输入为 16000 个采样点的原始波形,先Reshape成[800, 20](把 1 秒波形按时间与幅值维度重组),再经过PreprocessRaw保持原值(对应preprocess_raw,见 ml/model.py)。此外代码中还有一个preprocess()((x + 0.8) / 7.0后裁剪到 [-5, 5]),用于非 raw 输入的归一化场景。

  2. 上下文卷积context_conv:使用膨胀(dilated)1D 卷积(dilation_rate=1,即普通卷积;可通过参数调整感受野)来提取更宽时间范围的上下文特征。每个卷积块都遵循Conv1D → BatchNormalization → relu6 激活的顺序,并施加 L2 正则(kernel_regularizer=l2(0.00001))、use_bias=False。

  3. 降维卷积reduce_conv:在context_conv之后,用 1D MaxPooling(pool_size=3, strides=2)对特征做降维,减少传入后续层的参数量。

从 ml/model.py 可以完整看到网络的堆叠序列——context_conv与reduce_conv交替出现,卷积核宽度从 1 逐步增长到 3,通道数逐级扩张:

context_conv(32, k=1) → reduce_conv(48, k=3) → context_conv(48, k=3) → reduce_conv(96, k=3) → context_conv(96, k=3) → reduce_conv(128, k=3) → context_conv(128, k=3) → reduce_conv(160, k=3) → context_conv(160, k=3) → reduce_conv(192, k=3) → context_conv(192, k=3) → reduce_conv(256, k=3) → context_conv(256, k=3)

网络尾部依次是Dropout(0.3)(防止过拟合)、输出 12 类的Conv1D(num_classes, 5, activation='softmax')以及Reshape([-1])。模型使用 Adam 优化器(学习率3e-4)、categorical_crossentropy损失函数和categorical_accuracy指标完成编译(ml/model.py)。该架构思想源于论文Convolutional Neural Networks for Small-footprint Keyword Spotting,是经典的轻量级关键词唤醒(Keyword Spotting)模型范式。

训练流程

命令行参数

训练入口为 ml/train.py,它通过 argparse 定义如下参数:

python train.py [-h] [-sample_rate SAMPLE_RATE] \ [-batch_size BATCH_SIZE] \ [-output_representation OUTPUT_REPRESENTATION] \ -data_dirs DATA_DIRS [DATA_DIRS ...]

各参数含义(默认值来自 ml/train.py):

参数默认值说明
-sample_rate16000音频采样率
-batch_size32训练批次大小
-output_representationraw输入特征表示,可选raw、spec、mfcc、mfcc_and_raw
-data_dirs必填数据集目录列表,例如data/train

训练示例

文档给出的完整训练命令:

python train.py -sample_rate 16000 -batch_size 64 -output_representation raw -data_dirs data/train

执行后脚本会按以下流程运行(ml/train.py):

  1. 初始化 TensorFlow Session 与 Keras 后端;
  2. 用prepare_model_settings()计算模型设置(10 个目标词 +_silence_+_unknown_,共 12 类);
  3. 构建AudioProcessor加载并划分数据:silence_percentage=13.0(每个划分集中静音样本占 13%)、unknown_percentage=60.0(未知词样本占 60%)、validation_percentage=10.0、testing_percentage=0.0;其中训练/验证/测试集的划分基于文件名哈希(which_set(),见 ml/generator.py),保证同一音频始终划入同一子集;
  4. 构建conv_1d_time_stacked模型,输入维度按output_representation取fingerprint_size或desired_samples;
  5. 训练 100 个 epoch,并在每个 epoch 结束时通过回调记录混淆矩阵、学习率衰减与模型检查点。

回调与监控

训练期间挂载了四个 Keras 回调(ml/train.py):

  • ConfusionMatrixCallback(ml/callbacks.py):每个 epoch 结束后在验证集上计算混淆矩阵,并写入confusion_matrix.txt与wanted_confusion_matrix.txt(后者把非目标词折叠为_unknown_);同时把val_loss、val_categorical_accuracy等指标回填到日志;
  • ReduceLROnPlateau:监控val_categorical_accuracy,连续 4 个 epoch 无提升时将学习率减半(factor=0.5),下限1e-5;
  • TensorBoard:日志写入logs/目录,便于可视化训练曲线;
  • ModelCheckpoint:以val_categorical_accuracy为监控指标、save_best_only=True,把最优权重保存到checkpoints/conv_1d_time_stacked_model/下,文件名为ep-{epoch:03d}-vl-{val_loss:.4f}.hdf5。

训练结果

文档记录的训练结果为:训练 100 个 epoch 后,val_categorical_accuracy达到 0.94,并给出了用于评估分类性能的混淆矩阵:

[099]: val_categorical_accuracy: 0.94

预测值\实际值silencedowngoleftnooffonrightstoptwoupyes
silence32200000000000
down02406070100400
go532230211001520
left00022120010807
no004024602001400
off001002292005150
on300007227001410
right000400022202131
stop20110100224830
two645762630146840
up1000010100112300
yes21024010060240

其中two行/列来源于验证集中包含的完整 30 词样本(非目标词在评估时归入_unknown_,但完整混淆矩阵会按原始标签统计),其余 10 个目标词与_silence_均表现出很高的对角线准确率,说明该 1D 时序卷积模型在轻量前提下对指令词识别是有效的。

导出 TFLite 模型

训练完成后,需要把 Keras 模型转换为 TensorFlow Lite 格式,才能在移动端运行。ml/export/目录提供了三种导出方式:

1. 直接转换 Keras 模型

ml/export/convert_keras_lite.py 演示了用TFLiteConverter.from_keras_model_file()直接转换:脚本中指定了keras_model(示例指向../conv_1d_time_stacked_model/ep-084-vl-0.2595.hdf5)以及输入/输出张量名the_input/the_output,转换产物写为converted_speed_keras_model.tflite。

2. 冻结图 + 量化导出

ml/export/convert_keras_to_quantized.py 提供了更完整的导出管线:先把 Keras 权重加载进模型(示例加载ep-022-vl-0.2864.hdf5),用tf.identity给输出节点命名,再用convert_variables_to_constants冻结为常量图,最后通过tf.io.write_graph写出 .pb 文件。脚本支持以下参数:

参数默认值说明
-input_fld.Keras 权重文件所在目录
-output_fld同 input冻结图输出目录
-input_model_filemodel.h5输入权重文件名
-output_model_file<input>.pb输出文件名
-num_outputs1输出分支数(多流网络时设为输出个数)
-graph_defFalse是否额外写出 ASCII 图定义
-output_node_prefixoutput_node输出节点命名前缀
-quantizeFalse是否启用权重/节点量化(quantize_weights、quantize_nodes)
-theano_backendFalseTheano 后端时使用 channels_first;与量化不兼容

3. 使用 tflite_convert 命令行

ml/export/convert_tensorflow_lite.sh 展示了命令行转换方式:

tflite_convert --output_file converted_speech_model.tflite \ --graph_def_file model.h5.pb \ --output_format TFLITE \ --inference_type FLOAT \ --inference_input_type FLOAT \ --input_arrays input_1 \ --output_arrays output_node0

该命令以冻结图model.h5.pb为输入,指定输入张量input_1、输出张量output_node0,推理类型保持 FLOAT,生成converted_speech_model.tflite。

如果不想自行训练,也可以直接使用官方预训练模型:iOS 端的 RunScripts/download_models.sh 会在首次构建时从https://storage.googleapis.com/download.tensorflow.org/models/tflite/conv_actions_tflite.zip自动下载conv_actions_frozen.tflite与conv_actions_labels.txt到SpeechCommands/Model/目录。

iOS 端部署

环境要求

根据 ios/README.md,iOS 示例应用的要求如下:

  • iOS 12.0 及以上,Xcode 10.0 及以上;
  • 需要安装 Xcode 命令行工具:xcode-select --install(新安装 Xcode 时需先运行一次以同意许可协议);
  • 应用需要麦克风权限,且必须在真实 iOS 设备上运行——模拟器可以编译运行,但会抛出"找不到麦克风(camera not found exception)"异常;
  • 无需自行构建整个 TensorFlow 库,使用CocoaPods即可拉取 TensorFlow Lite 库。

构建步骤

  1. 安装 CocoaPods(如未安装):sudo gem install cocoapods;
  2. 进入示例目录并安装 Pod 依赖、生成工作区文件:
cd examples/speech_commands/ios/ pod install

如果之前安装过该 Pod 而命令失效,可尝试pod update。完成后应生成SpeechCommands.xcworkspace。

  1. 用 Xcode 打开SpeechCommands.xcworkspace(注意不要打开 .xcodeproj);
  2. 在General -> Signing中把 Bundle Identifier 改为唯一标识,并选择自己的开发团队;
  3. 构建并运行应用,首次启动时授予麦克风权限,之后对着设备说出指令词即可看到识别结果。

模型文件无需手动下载——它们由 Xcode 构建时的 Run Script 阶段(RunScripts/download_models.sh)自动下载并放入SpeechCommands/Model/目录。

注意事项:克隆仓库后请勿删除项目中指向 .tflite 与 .txt 的"空引用"。这些引用会在首次构建运行、模型和标签文件下载后被自动修复;如果误删引用,模型文件仍会被下载到 Model 目录,但需要手动把引用加回工程才能运行。

推理逻辑:从 PCM 到指令识别

应用完全使用 Swift 编写,通过 TensorFlow Lite Swift 库执行推理(Objective-C 开发者可改用 Objective-C 库)。核心实现在 ModelDataHandler.swift:

  • 使用Interpreter加载conv_actions_frozen.tflite,线程数默认 1(上限 10);
  • 每个推理周期把[Int16]麦克风缓冲区归一化(除以maxInt16AsFloat32 = 32767.0)后拷贝到第 0 个输入张量(音频缓冲),并把采样率 16000 作为第 1 个输入张量;
  • 调用interpreter.invoke()后读取输出张量,得到 12 个类别的置信度分数;
  • 通过labelOffset = 2跳过_silence_与_unknown_,只展示 10 个指令词的识别结果。

由于单帧推理结果噪声较大,应用还用 RecognizeCommands.swift 对连续结果做了滑窗平均与去重,文档说明"界面显示的百分比是 1000ms 窗口内的平均指令识别置信度"。其核心参数包括:

  • averageWindowDuration = 1000.0:平均窗口时长(ms),与训练时的 1 秒片段时长对应;
  • detectionThreshold:识别阈值(初始化时传入 0.3);
  • suppressionTime = 1500.0:抑制时间——同一指令被识别后 1.5 秒内不重复触发;
  • minimumCount = 3:窗口内至少积累 3 帧结果才参与判定;
  • minTimeBetweenSamples = 30.0:相邻两次推理的最小时间间隔。

process()的逻辑是:把最新推理结果按时间戳追加到滑动窗口,丢弃超出平均窗口时长的旧结果;对窗口内各帧的 12 类分数做平均、排序;只有当最高平均分超过阈值、且距上次触发超过抑制时间时,才判定为新指令(isNew = true)并展示给用户。这套"滑窗平均 + 阈值 + 抑制"机制有效避免了单帧误判和指令重复触发,是语音指令类应用的标准后处理范式。

小结与演进方向

本示例完整覆盖了一条可复现的语音指令识别链路:Speech Commands 数据集下载 → 原始波形/频谱特征生成与增强 → 时间堆叠 1D 卷积模型训练 → 混淆矩阵评估 → Keras 冻结图导出为 TFLite → iOS 端 Interpreter 推理与滑窗后处理。其中 ml/ 与 ios/ 的源码可直接作为二次开发的起点。

同时需要再次强调:官方已在本示例的 README.md 与 ios/README.md 中明确标注Deprecated,并推荐迁移到采用最新技术栈的 Sound Classification 示例(该目录同样提供了 iOS 端的声音分类示例应用)。在阅读本指南时,建议把 1D 时序卷积建模、滑窗识别后处理等思想作为核心收获,而在新项目中优先采用官方当前推荐的 Sound Classification 方案。

  • 示例工程

【免费下载链接】examples

TensorFlow examples

项目地址:https://gitcode.com/gh_mirrors/exam/examples
点击查看免费下载

相关推荐

上一篇:Blawn语法详解:告别复杂,体验简洁编程的终极魅力
下一篇:LMMS虚拟乐器编程终极指南:使用Python自动化控制音乐创作

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 2:28:32

PostgreSQL用户与权限管理:角色、授权与默认权限实战

如果管理过任何一套正经的 PostgreSQL&#xff0c;你大概率遇到过两种经典场面&#xff1a;一是新同事在测试库上死活查不着一张表&#xff0c;你在工位上一看就知道是权限没给到位&#xff1b;二是上线前夜&#xff0c;有人来问某个账号为啥能碰生产库的数据。两个问题指向同一…

作者头像 李华
网站建设 2026/9/26 2:25:29

黑马电商后台管理系统实战:从环境搭建到前后端联调与部署

简介&#xff1a;这是一套面向前后端开发者的电商后台管理系统实战资源&#xff0c;以前端 Vue.js 与后端 Node.js 为主线&#xff0c;覆盖用户管理、商品管理、订单管理、库存管理、数据分析、权限控制等核心业务模块&#xff0c;既适合初学者理解项目结构&#xff0c;也适合有…

作者头像 李华
网站建设 2026/9/26 2:24:37

恩施碎米荠基因组--Cell Discovery

The Cardamine enshiensis genome reveals whole genome duplication and insight into selenium hyperaccumulation and tolerance 恩施碎米荠基因组揭示全基因组复制事件及硒超富集与耐硒机制 摘要 恩施碎米荠&#xff08;Cardamine enshiensis&#xff09;是知名的硒超富集…

作者头像 李华
网站建设 2026/9/26 2:24:17

森林火灾烟雾检测数据集:VOC/COCO/YOLO标签转换与YOLO训练全流程

简介&#xff1a;本资源面向目标检测初学者与需要森林火灾烟雾识别方案的开发者&#xff0c;提供一套可直接用于YOLO系列训练的真实场景数据集。数据包含1000张高质量图片&#xff0c;场景丰富&#xff0c;经labelimg精细标注&#xff0c;并同步提供voc(xml)、coco(json)与yolo…

作者头像 李华