FEATURED · 精选文章

TinyML唤醒词检测实战:在MCU上部署轻量级语音AI系统

发布时间 / 2026/8/19 4:30:28
来源 / 创域科博编辑部
栏目 / 资讯中心
TinyML唤醒词检测实战:在MCU上部署轻量级语音AI系统 1. 项目概述当“唤醒词”遇见“微小的智能”最近在折腾一个挺有意思的小项目核心就一句话在资源极其有限的微控制器MCU上实现一个能准确识别特定“唤醒词”的本地化智能语音系统。这个项目标题里的几个关键词基本就勾勒出了它的全貌Wake word detection唤醒词检测、Tinyml微型机器学习以及一个看起来像版本号的fw18。这可不是一个简单的“Hello World”式实验而是将前沿的AI能力硬生生塞进一个可能只有几十KB内存、几百KB存储空间的微型设备里让它能脱离云端、实时响应你的语音指令。想象一下你对着一个纽扣大小的智能家居开关说“开灯”它立刻响应或者在一个完全离线的儿童玩具里内置一个只有它能听懂的秘密口令。这就是TinyML的魅力所在——让AI无处不在却又悄无声息。而“fw18”这个后缀在我的理解里很可能指向一个特定的硬件平台或固件版本比如某款MCU的评估板型号或者是项目迭代到第18个固件版本。这暗示着项目已经过了初步验证进入了深度优化和稳定化的阶段。这个项目适合谁呢首先肯定是嵌入式开发者和AI算法工程师尤其是那些对边缘AI、低功耗设备感兴趣的朋友。其次对于物联网产品经理、创客甚至是有一定编程基础的硬件爱好者这也是一个绝佳的、能亲手触摸到AI落地脉搏的实践案例。通过它你不仅能理解语音识别的基本流程更能深刻体会到在“螺丝壳里做道场”——在极端资源限制下进行工程优化的挑战与乐趣。接下来我就把自己在实现这个“唤醒词检测TinyML系统”过程中的完整思路、踩过的坑以及最终打磨出的方案毫无保留地分享出来。2. 核心思路与架构设计在资源枷锁下跳舞在资源充沛的服务器或手机上做语音识别我们有大把的模型和复杂的算法可以挥霍。但到了TinyML的世界第一条铁律就是资源是绝对的硬约束。设计整个系统的思路必须围绕着MCU的三大紧箍咒展开内存RAM、存储Flash和算力CPU频率。2.1 技术路线选择为什么是“关键词检测”而非“语音识别”首先需要明确我们做的是唤醒词检测Keyword Spotting而不是完整的连续语音识别ASR。这是两个不同量级的任务。完整ASR需要将任意长度的语音实时转写成文字模型庞大动辄百MB以上需要强大的算力支持。唤醒词检测只需判断短短1-2秒的音频片段中是否出现了某个或某几个特定的词语如“Hey Siri”、“小爱同学”。这是一个典型的音频分类问题只不过分类的类别是“有唤醒词”和“无唤醒词”或背景噪音。对于TinyML场景选择关键词检测路线是唯一可行的。我们的目标是将模型压缩到100KB以下甚至50KB以内确保它能被装载到MCU的Flash中并且前向推理的一次峰值内存消耗不超过几十KB推理时间在几百毫秒以内以满足实时性要求。2.2 端到端系统架构拆解一个完整的、部署在MCU上的唤醒词检测系统其数据流和组件如下所示这是一个经典的“传感器-前端处理-模型推理-后处理-触发动作”的管道[麦克风] - [音频采集ADC/I2S] - [音频预处理降噪、分帧] - [特征提取MFCCs] - [微型神经网络模型] - [后处理平滑、阈值判断] - [触发事件]音频采集层硬件上通过MCU的I2S或ADC接口连接数字麦克风PDM或I2S输出。这里优先选择I2S麦克风因为它传输的是已经过内部Sigma-Delta调制和降噪处理的数字信号比用ADC采集模拟麦克风信号更稳定软件处理更简单。音频预处理层采集到的是连续的音频流通常是16kHz采样率16位精度。我们需要一个滑动窗口来截取固定长度的音频片段例如1秒即16000个样本点。同时为了减少频谱泄漏并让后续特征提取更有效需要对每一帧音频应用预加重滤波器提升高频和汉明窗。特征提取层这是将原始音频波形转化为机器学习模型能“理解”的格式的关键步骤。在资源受限环境下梅尔频率倒谱系数MFCCs是事实上的标准。它模拟人耳听觉特性能有效表征语音的音色特征且数据量远小于原始波形。通常我们会计算一个音频片段如1秒的MFCC特征得到一个维度为(num_frames, num_mfcc)的矩阵例如(49, 10)再将其展平或直接作为2D输入送入模型。微型神经网络模型这是系统的核心大脑。由于资源限制像ResNet、Transformer这类大模型想都别想。我们的选择范围集中在深度可分离卷积神经网络DSCNN参数量少计算效率高特别适合移动端和嵌入式设备是TinyML语音项目的首选架构。小型的全连接网络DNN如果特征经过充分压缩一个只有两三层的全连接网络也可能够用但特征表达能力通常不如CNN。循环神经网络RNN如GRU虽然能捕捉时序信息但推理是串行的在MCU上可能较慢且状态管理稍复杂。 在我的fw18版本实现中我选择了基于DSCNN的架构并在模型设计中深度融入了剪枝Pruning和量化Quantization技术。后处理与决策层模型输出通常是一个0到1之间的分数表示当前音频片段包含唤醒词的置信度。直接用一个阈值如0.8判断会导致在唤醒词边界处频繁抖动触发。因此需要引入平滑机制例如滑动平均对最近N次的预测得分进行平均。触发延迟连续M次预测得分超过阈值才判定为有效唤醒。 这能有效防止误触发提升用户体验。2.3 为什么模型量化是TinyML的“生命线”量化尤其是8位整型INT8量化是TinyML模型部署不可或缺的步骤。在训练时模型权重和激活值通常是32位浮点数float32。一个float32占4字节而一个int8只占1字节。这意味着仅通过量化模型存储空间就能压缩至约1/4。更重要的是大多数低功耗MCU如Arm Cortex-M系列的硬件指令集对整数运算尤其是8位有高度优化甚至有些带有神经网络加速核如Ethos-U55的芯片只支持整数运算。将模型量化为INT8后推理速度可以有数倍甚至数十倍的提升功耗也会显著下降。实操心得不要试图在MCU上跑浮点模型那将是性能和功耗的灾难。量化必须作为模型训练后、部署前的标准流程。TensorFlow Lite for MicrocontrollersTFLite Micro对INT8量化提供了非常好的支持。3. 从零构建数据、训练与模型优化实战有了架构蓝图接下来就是动手实现。这部分我会详细拆解从数据准备到模型产出的每一个环节这些都是我在fw18版本中反复调试后的经验总结。3.1 数据准备质量大于一切“垃圾进垃圾出”在AI领域是真理。对于唤醒词检测我们需要两类数据正样本包含目标唤醒词的录音。例如录制数百上千次“你好小智”你的自定义唤醒词由不同性别、年龄、口音的人在不同环境安静房间、有背景音乐、轻微噪音下录制。负样本不包含唤醒词的音频。这包括背景噪音室内白噪音、街道嘈杂声、键盘敲击声等。相似词/混淆词与唤醒词发音相似的词语如“你好小子”、“你好像纸”这是提升模型辨别力的关键。其他语音一般的对话片段、新闻播报等。工具与流程录制工具可以用手机或电脑录音保存为16kHz采样率、16位深、单声道的WAV文件。更专业一点可以使用Audacity进行批量录制和初步剪辑。数据增强为了用有限的数据训练出更鲁棒的模型必须做数据增强。针对音频的增强方法包括添加背景噪音将干净的语音与不同信噪比SNR的背景噪音混合。时间拉伸与音高变换微调音频的速度和音高模拟不同语速和声调。随机偏移在音频片段中随机裁剪确保模型不依赖于唤醒词在片段中的绝对位置。生成负样本一个技巧是使用公开的语音数据集如Google的Speech Commands dataset将其中的非唤醒词命令和背景音作为负样本来源。注意事项数据集的类别一定要平衡。如果正样本太少模型会倾向于永远预测“负例”如果负样本中缺少难例混淆词模型在实际场景中会误触发率飙升。我建议正负样本比例至少在1:2到1:3之间。3.2 特征提取MFCCs参数调优详解MFCC的计算是一系列数字信号处理DSP步骤的串联。在Python中我们可以用librosa库轻松完成但理解每个参数的意义对后续在C语言中手动实现或优化至关重要。import librosa def extract_mfcc(audio_data, sample_rate16000): # 预加重y[t] x[t] - 0.97 * x[t-1] pre_emphasis 0.97 emphasized_signal np.append(audio_data[0], audio_data[1:] - pre_emphasis * audio_data[:-1]) # 分帧帧长25ms帧移10ms400个样本点160个样本点 frame_length int(0.025 * sample_rate) # 400 frame_step int(0.01 * sample_rate) # 160 frames librosa.util.frame(emphasized_signal, frame_lengthframe_length, hop_lengthframe_step) # 加窗汉明窗 frames * np.hamming(frame_length) # 计算功率谱 NFFT 512 # FFT点数通常取大于帧长的2的幂次 mag_frames np.absolute(np.fft.rfft(frames, NFFT)) pow_frames ((1.0 / NFFT) * (mag_frames ** 2)) # 梅尔滤波器组 nfilt 40 # 滤波器数量典型值20-40越多特征越精细但也越冗余 low_freq_mel 0 high_freq_mel (2595 * np.log10(1 (sample_rate / 2) / 700)) # 将最大频率转换为梅尔刻度 mel_points np.linspace(low_freq_mel, high_freq_mel, nfilt 2) hz_points (700 * (10**(mel_points / 2595) - 1)) # 转回赫兹 # ... 构建滤波器组并应用到功率谱 # 取对数计算DCT得到MFCC log_pow_frames np.log(pow_frames 1e-10) # 加一个小数防止log(0) mfcc scipy.fftpack.dct(log_pow_frames, axis0, type2, normortho)[1:13] # 取前12个系数忽略第0个能量值 return mfcc.T # 转置使得形状为 (时间帧数, MFCC系数)关键参数解析frame_length和frame_step决定了时间分辨率。25ms的帧长是语音处理的经典值能保证在一帧内语音信号相对平稳。10ms的帧移提供了足够的时间重叠避免信息丢失。nfilt梅尔滤波器数量在资源受限场景下不宜过多。我经过测试发现从40降到26甚至20对唤醒词检测的精度影响很小但特征维度大幅减少直接降低了模型输入大小和第一层网络的参数量。num_mfccMFCC系数个数通常取12-13加上一阶和二阶差分Delta Delta-Delta会变成36-39维。在TinyML中可以尝试只用静态MFCC12维甚至只取前6-8个最重要的系数能进一步压缩特征。实操心得在PC端训练时可以用librosa方便地提取特征。但一定要记录下最终确定的所有参数采样率、帧长、帧移、FFT点数、滤波器个数、MFCC系数个数。因为最终在MCU的C代码中你需要用定点数运算精确复现这个流程任何参数不一致都会导致模型性能严重下降。3.3 模型设计、训练与压缩三部曲我以DSCNN为例展示一个典型的TinyML友好型唤醒词检测模型。import tensorflow as tf from tensorflow.keras import layers, models def create_ds_cnn(input_shape, num_classes2): model models.Sequential([ # 输入层: (时间帧数, MFCC系数, 1) 例如 (49, 10, 1) layers.Input(shapeinput_shape), # 第一层常规卷积提取初级特征 layers.Conv2D(64, (3, 3), paddingsame), layers.BatchNormalization(), layers.ReLU(), layers.Dropout(0.2), # 核心深度可分离卷积块 # 深度卷积逐通道卷积 layers.DepthwiseConv2D((3, 3), paddingsame), layers.BatchNormalization(), layers.ReLU(), # 逐点卷积1x1卷积组合通道特征 layers.Conv2D(64, (1, 1), paddingsame), layers.BatchNormalization(), layers.ReLU(), layers.Dropout(0.2), # 可以重复多个上述DS卷积块 layers.DepthwiseConv2D((3, 3), paddingsame), layers.BatchNormalization(), layers.ReLU(), layers.Conv2D(64, (1, 1), paddingsame), layers.BatchNormalization(), layers.ReLU(), # 全局平均池化替代全连接层大幅减少参数 layers.GlobalAveragePooling2D(), layers.Dropout(0.2), # 输出层 layers.Dense(num_classes, activationsoftmax) ]) return model # 假设输入特征为 (49, 10, 1) model create_ds_cnn((49, 10, 1)) model.summary() # 查看参数量目标控制在5万-10万以内训练技巧损失函数使用categorical_crossentropy。优化器Adam效果不错但最终部署前可以考虑用SGD再微调有时对量化更友好。回调函数务必使用ModelCheckpoint保存最佳模型并使用ReduceLROnPlateau在精度停滞时降低学习率。模型压缩与量化 训练好浮点模型后才是TinyML工作的开始。剪枝使用TensorFlow的tfmot.sparsityAPI进行稀疏化训练。原理是逐渐将不重要的权重置零最终生成一个稀疏模型。稀疏模型在存储时可以被压缩存储非零值和索引在支持稀疏计算库的硬件上推理更快。import tensorflow_model_optimization as tfmot prune_low_magnitude tfmot.sparsity.keras.prune_low_magnitude # ... 对模型进行包装和重新训练量化使用TensorFlow Lite转换器进行训练后动态范围量化或全整数量化。converter tf.lite.TFLiteConverter.from_keras_model(pruned_model) converter.optimizations [tf.lite.Optimize.DEFAULT] # 动态范围量化 # 如果要全INT8量化需要提供代表性数据集 # def representative_dataset(): # for data in representative_data_samples: # yield [data.astype(np.float32)] # converter.representative_dataset representative_dataset # converter.target_spec.supported_ops [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] # converter.inference_input_type tf.int8 # converter.inference_output_type tf.int8 quantized_tflite_model converter.convert() with open(wakeword_model_quantized.tflite, wb) as f: f.write(quantized_tflite_model)动态范围量化将权重直接量化为INT8激活值在推理时动态量化为INT8。这是最常用、兼容性最好的方式能获得大部分量化收益。全INT8量化输入输出也要求是INT8。精度可能略有损失但能获得极致的性能和兼容性某些NPU只支持INT8。踩坑记录量化后一定要在PC上用TFLite解释器测试量化模型的精度与原始浮点模型对比。如果精度下降超过3-5个百分点可能需要检查代表性数据集是否充分或者尝试量化感知训练QAT。QAT在训练过程中模拟量化误差让模型提前适应通常能获得更好的量化后精度。4. 嵌入式端部署让模型在MCU上跑起来模型准备好了一个.tflite文件接下来就是最关键的环节——将它部署到fw18所代表的嵌入式硬件上。这里我以流行的Arm Cortex-M4内核MCU如STM32F4系列为例使用TensorFlow Lite for Microcontrollers框架。4.1 开发环境与工程搭建选择开发板确保你的开发板有足够的RAM≥128KB和Flash≥512KB并且带有一个I2S接口的数字麦克风。常见的选项有STM32F4 Discovery kit、Arduino Nano 33 BLE Sense、Espressif ESP-EYE等。搭建TFLite Micro环境TFLite Micro通常以库的形式集成到你的嵌入式IDE如STM32CubeIDE, PlatformIO项目中。最直接的方法是克隆TensorFlow仓库使用其提供的Makefile为特定目标平台编译静态库。你需要关注tensorflow/lite/micro目录。将生成的库文件、头文件以及模型转换后的C数组.tflite文件通过xxd或类似工具转换添加到你的工程中。4.2 关键代码实现解析嵌入式端的C代码主要包含以下几个模块1. 音频采集与环形缓冲区// 伪代码示例 #define AUDIO_BUFFER_SIZE 16000 // 1秒的音频样本 int16_t audio_buffer[AUDIO_BUFFER_SIZE]; uint32_t audio_buffer_index 0; // I2S或ADC中断服务程序 void I2S_IRQHandler(void) { int16_t sample read_sample_from_i2s(); // 读取一个16位样本 audio_buffer[audio_buffer_index] sample; audio_buffer_index (audio_buffer_index 1) % AUDIO_BUFFER_SIZE; // 当缓冲区有足够新数据时如一帧设置一个标志位 }这里使用一个环形缓冲区来持续接收音频流。主循环会检查是否有足够长度的新数据例如一个1秒的片段可供处理。2. 特征提取的C语言实现这是在MCU上最具挑战的部分之一。你需要用C代码重新实现MFCC计算流程并且要非常注意定点数运算和内存管理。避免动态内存分配所有数组如帧缓冲区、FFT数组、梅尔谱数组都应为静态或全局数组在编译时确定大小。使用定点数库对于三角函数log, cos、FFT等运算可以使用优化过的定点数库如CMSIS-DSP针对Arm Cortex-M。它能提供远快于软件浮点运算的速度。流程复现确保每一步的参数窗函数系数、梅尔滤波器组系数都与Python训练时完全一致。这些系数可以在PC上预先计算好作为常量数组存储在MCU的Flash中。3. TFLite Micro推理引擎集成#include tensorflow/lite/micro/micro_interpreter.h #include tensorflow/lite/micro/micro_mutable_op_resolver.h #include tensorflow/lite/schema/schema_generated.h // 1. 声明模型由tflite文件转换来的C数组 extern const unsigned char g_wakeword_model_data[]; extern const int g_wakeword_model_len; // 2. 定义操作解析器只链接模型用到的算子节省内存 tflite::MicroMutableOpResolver5 resolver; // 数字5表示最多注册5种算子 resolver.AddDepthwiseConv2D(); resolver.AddConv2D(); resolver.AddAveragePool2D(); resolver.AddReshape(); resolver.AddSoftmax(); // 3. 分配Tensor Arena这是模型输入、输出和中间结果的存储区 const int tensor_arena_size 50 * 1024; // 根据模型调整通常需要30-80KB uint8_t tensor_arena[tensor_arena_size]; // 4. 创建解释器 tflite::MicroInterpreter interpreter( tflite::GetModel(g_wakeword_model_data), resolver, tensor_arena, tensor_arena_size); // 5. 分配内存 interpreter.AllocateTensors(); // 6. 获取输入输出Tensor指针 TfLiteTensor* input interpreter.input(0); TfLiteTensor* output interpreter.output(0); // 7. 填充输入数据将提取的MFCC特征拷贝到input-data.int8 // ... // 8. 执行推理 TfLiteStatus invoke_status interpreter.Invoke(); if (invoke_status ! kTfLiteOk) { // 错误处理 } // 9. 解析输出 int8_t* output_data output-data.int8; // 量化模型输出是int8 // 将int8输出反量化为浮点分数或直接与一个int8阈值比较Tensor Arena大小这是最关键的调试参数之一。如果太小AllocateTensors()会失败如果太大则浪费宝贵RAM。可以通过TFLite Micro提供的工具估算或者从一个小值开始逐步增加直到成功。4. 后处理与触发逻辑#define SCORE_THRESHOLD 0.7f // 置信度阈值 #define TRIGGER_COUNT_THRESHOLD 3 // 连续触发次数阈值 float smoothed_score 0.0f; int trigger_counter 0; // 每次推理后 float current_score dequantize_output(output_data[1]); // 假设输出[非唤醒词得分 唤醒词得分] smoothed_score 0.8f * smoothed_score 0.2f * current_score; // 一阶低通滤波平滑 if (smoothed_score SCORE_THRESHOLD) { trigger_counter; if (trigger_counter TRIGGER_COUNT_THRESHOLD) { // 确认唤醒执行相应动作如点亮LED唤醒主处理器等 trigger_counter 0; // 重置计数器可加入一段“沉默期”防止重复触发 } } else { trigger_counter 0; // 分数低于阈值重置计数器 }4.3 功耗优化策略对于电池供电的设备功耗是生命线。降低采样率如果唤醒词特性允许尝试将音频采样率从16kHz降至8kHz。这能直接减半音频处理的数据量和后续FFT等计算量。间歇性工作让系统大部分时间处于深度睡眠模式只有麦克风电路和少量逻辑供电以极低功耗监听环境。当麦克风的硬件语音活动检测VAD模块或一个极其简单的能量检测算法发现可能有人声时再唤醒主MCU进行完整的特征提取和模型推理。这是最有效的省电方法。降低时钟频率在满足实时性要求的前提下降低MCU的主频可以线性降低动态功耗。优化外设使用推理间隙关闭不必要的硬件模块如某些传感器、无线模块。5. 调试、优化与常见问题排查即使代码跑通了距离一个稳定可靠的产品还有很长的路要走。以下是fw18版本迭代中遇到的一些典型问题及解决方法。5.1 模型精度在设备上严重下降这是最令人头疼的问题。PC上测试精度95%上板子后可能连50%都不到。排查步骤1检查特征提取一致性。这是罪魁祸首之首。在MCU上将计算出的第一帧MFCC特征通过串口打印出来与PC上用同一段原始音频、同一套参数计算出的MFCC进行逐元素对比。任何微小的差异尤其是定点化带来的误差累积都可能导致输入分布偏移模型自然失效。排查步骤2检查输入数据范围。量化模型要求输入数据也在一个特定的范围内通常是[-128, 127]。确保你的MFCC特征在填充到输入Tensor之前已经按照模型元数据input-params.scale和input-params.zero_point正确地进行了量化。// 将浮点特征值 quantized_value 转换为 int8 输入 float scale input-params.scale; int zero_point input-params.zero_point; int8_t quantized_value roundf(float_feature_value / scale) zero_point; // 确保 quantized_value 在 -128 到 127 之间排查步骤3检查模型版本与算子兼容性。确保TFLite Micro解释器注册的算子与模型文件使用的算子版本兼容。有时PC端转换用的TFLite版本与嵌入式端的TFLite Micro版本不一致会导致问题。5.2 推理速度不满足实时性要求目标是在音频缓冲区被新数据覆盖前完成推理。例如1秒的音频我们希望推理时间远小于1秒。优化点1简化特征提取。减少MFCC系数数量、减少梅尔滤波器个数、使用更快的定点FFT库如CMSIS-DSP。优化点2优化模型。使用更浅、更窄的网络。尝试用MobileNet风格的深度可分离卷积块。利用TFLite的XNNPACK委托如果MCU支持NEON指令集可以加速浮点模型但对INT8模型加速有限。优化点3降低输入维度。如果允许将输入音频长度从1秒减到0.75秒或将帧移从10ms增加到15ms都能减少特征帧数从而降低输入大小。测量方法在推理前后使用高精度定时器如ARM的DWT周期计数器测量耗时精确到微秒级找到瓶颈。5.3 误触发率False Accept过高设备总是在不该响的时候乱响。解决方案1丰富负样本。回头检查你的训练数据集是否包含了足够多的、贴近真实场景的负样本特别是那些与唤醒词相似的发音混淆词、常见的环境音水龙头声、电视声、以及其他人的谈话声。解决方案2调整后处理参数。提高置信度阈值SCORE_THRESHOLD增加连续触发次数要求TRIGGER_COUNT_THRESHOLD或者引入更复杂的平滑算法如双门限判决。解决方案3增加一个简单的预过滤VAD。在送进神经网络之前先计算音频片段的短时能量和过零率如果能量太低静音或过高爆音或者过零率特征不像人声则直接判定为负样本跳过耗时的模型推理。5.4 内存不足AllocateTensors失败根本原因tensor_arena大小不足。模型在推理过程中需要的临时内存用于存储中间激活值比想象中要大。解决方法使用TFLite Micro提供的RecordingMicroInterpreter工具在模拟环境中来精确测量模型所需的内存峰值。如果无法使用工具就采用二分法手动调试逐渐增加tensor_arena_size直到成功。考虑优化模型减少网络宽度或使用更小的算子这些都能降低中间激活的内存占用。5.5 部署清单与测试要点在将固件烧录到设备进行最终测试前建议完成以下清单检查项说明验证方法特征一致性PC与MCU计算的MFCC误差在可接受范围如1e-5数据对比打印输入量化输入数据正确按模型要求进行了量化检查输入Tensor数据范围内存分配Tensor Arena大小足够无内存溢出AllocateTensors()成功实时性单次推理耗时 音频缓冲区更新周期使用定时器测量功耗基线静态电流、识别时电流符合预期电流表测量唤醒响应在安静环境、噪音环境、混淆词下测试唤醒率人工/自动化测试误触发长时间播放负样本音频如音乐、新闻记录误触发次数长时间压力测试最后我想分享的一点个人体会是TinyML项目是软件、硬件和算法知识的深度结合。它要求开发者不仅有“雕琢模型”的算法思维更要有“榨干每一字节内存、每一毫瓦功耗”的嵌入式工程师的极致精神。fw18这个版本号背后可能意味着前17个版本都在与内存不足、精度丢失、响应延迟这些问题作斗争。每一个参数的调整每一行代码的优化都可能带来意想不到的改善或新的问题。这个过程充满挑战但当你在一个巴掌大的设备上第一次清晰地用语音唤醒它并看到它准确地响应时那种成就感是无与伦比的。这不仅仅是完成了一个项目更是亲手将一缕AI的“智能”注入了物理世界的微小角落。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻