
基于 models 仓库的 YAMNet 音频事件分类从安装、推理到多格式导出的完整实战指南【免费下载链接】modelsModels and examples built with TensorFlow项目地址: https://gitcode.com/GitHub_Trending/mode/models本文围绕 models 仓库中research/audioset/yamnet目录下的 YAMNet 音频事件分类模型展开完整覆盖 官方 README 的安装步骤、推理用法与模型说明并结合yamnet.py、params.py、features.py、inference.py等配套源码深入剖析 960ms 音频片段的特征构建方式、MobileNet_v1 风格网络结构与 TF2/TF-Lite/TF-JS 导出流程。读完本文你可以独立搭建 YAMNet 运行环境、对任意 WAV 文件做多标签音频事件分类、调参尤其是 patch hop并产出可部署的多格式模型。一、YAMNet 是什么AudioSet 上的轻量音频事件分类器YAMNet 是一个预训练深度网络在AudioSet-YouTube 语料上训练能够预测521 个音频事件类别网络结构采用MobileNet_v1 的深度可分离卷积depthwise-separable convolution架构。仓库中research/audioset/yamnet目录包含两部分内容用 Keras 构建模型的代码模型定义、超参数、特征提取将模型应用于输入音频文件的示例代码。其所属的 AudioSet 项目 由 Google 声音理解团队于 2017 年 3 月发布是一个包含超过 200 万段人工标注的 10 秒 YouTube 视频音轨、标签本体超过 600 类的大规模音频事件数据集。该目录下还包含更早的 VGGish 模型YAMNet 沿用了与 VGGish 相同的音频特征计算方式详见下文特征管线一节。相比大型音频模型YAMNet 的核心价值在于轻量据 README 统计整个分类器只有3.7M 权重处理每个 960ms 输入帧仅需69.2M 次乘加运算因此可以在 CPU 甚至嵌入式设备上实时运行。二、安装依赖、权重文件与安装验证2.1 Python 依赖YAMNet 依赖以下 Python 包见 README 的 Installation 一节依赖包作用numpy数值计算基础resampy将任意采样率音频重采样到 16 kHztensorflow模型运行环境tf-kerasKeras 2 实现关键见下方兼容性说明pysoundfileWAV 音频文件读写这些包均可通过pip install numpy resampy tensorflow soundfile tf-keras等方式安装。重要兼容性提示原文档明确说明YAMNet 目前依赖Keras 2与Keras 3TF 2.16 起的默认版本不兼容。这一点在源码中得到印证——yamnet.py 中模型定义直接从tf_keras导入from tf_keras import Model, layers因此如果你的环境是 TF 2.16 及以上需要额外安装独立的tf-keras包否则会出现 Keras 版本不匹配的问题。2.2 下载模型权重除依赖包外还需要下载模型权重文件yamnet.h5Keras HDF5 保存的权重格式。官方下载地址在 README 中以curl -O ...yamnet.h5的形式给出指向 Google 官方音频存储。下载后需将该文件放到与 README 相同的目录即research/audioset/yamnet/下。代码中加载权重的位置在 inference.py 与 yamnet_test.py 中均为yamnet.load_weights(yamnet.h5)是相对当前工作目录的路径。2.3 完整的安装与测试会话README 给出了一段示例安装会话此处按当前仓库说明整理仓库克隆步骤以本仓库实际位置为准# 先升级 pip并确认已安装 wheel python -m pip install --upgrade pip wheel # 安装依赖 pip install numpy resampy tensorflow soundfile tf-keras # 将本仓库克隆到 models 目录后进入 YAMNet 代码目录 cd models/research/audioset/yamnet # 下载权重文件到与代码相同的目录curl 命令见 README # 安装就绪运行安装测试 python yamnet_test.py # 若看到 Ran 4 tests ... OK ...即安装成功2.4 安装测试到底在验证什么python yamnet_test.py并非空跑从 yamnet_test.py 源码看测试类YAMNetTest会先加载yamnet.h5权重和类别表然后对若干合成信号做“期望类别必须出现在 top-n 预测中”的校验测试用例输入信号期望命中类别testZeros3 秒全零波形Silence静音testRandom3 秒随机白噪声固定种子 51773 保证可复现White noise白噪声testSine3 秒 440 Hz 正弦波Sine wave正弦波如果这些测试通过说明权重文件、特征管线与模型定义三者是配套的环境即可投入使用。三、代码布局与模型架构3.1 目录内各文件职责README 给出的代码布局如下本文后续章节均以此为基础文件职责yamnet.pyKeras 模型定义params.py超参数可修改patch_hop_secondsfeatures.py音频特征提取辅助函数inference.py对输入 WAV 文件做分类的示例代码yamnet_test.pyYAMNet 安装的简单测试export.py导出 TF2 SavedModel / TF-Lite / TF-JS 模型yamnet_class_map.csv521 个输出与类别名称的映射表yamnet_visualization.ipynb展示逐帧模型输出分数的示例 notebook3.2 网络结构14 层深度可分离卷积 全局池化从 yamnet.py 源码看核心层定义在_YAMNET_LAYER_DEFS第 76–92 行中共 14 层_YAMNET_LAYER_DEFS [ # (layer_function, kernel, stride, num_filters) (_conv, [3, 3], 2, 32), (_separable_conv, [3, 3], 1, 64), (_separable_conv, [3, 3], 2, 128), (_separable_conv, [3, 3], 1, 128), (_separable_conv, [3, 3], 2, 256), (_separable_conv, [3, 3], 1, 256), (_separable_conv, [3, 3], 2, 512), (_separable_conv, [3, 3], 1, 512), (_separable_conv, [3, 3], 1, 512), (_separable_conv, [3, 3], 1, 512), (_separable_conv, [3, 3], 1, 512), (_separable_conv, [3, 3], 1, 512), (_separable_conv, [3, 3], 2, 1024), (_separable_conv, [3, 3], 1, 1024) ]结构规律与 MobileNet_v1 一致第一层是普通Conv2D32 通道、stride 2其余 13 层全部是DepthwiseConv2D 1x1 Conv2D的深度可分离卷积通道数按 32 → 64 → 128 → 256 → 512 → 1024 阶梯上升每次通道翻倍时伴随一次 stride 2 的下采样。每个卷积块内部都遵循“卷积 → BatchNormalization → ReLU”的固定序列且 BatchNorm 采用centerTrue, scaleFalse, epsilon1e-4的配置由params控制。yamnet()函数第 95–105 行将特征张量 reshape 为(96, 64, 1)的图像形式依次流过上述 14 层后做GlobalAveragePooling2D得到 1024 维嵌入embedding再经一个带偏置的Dense(521)层和sigmoid激活输出 521 个类别分数def yamnet(features, params): Define the core YAMNet mode in Keras. net layers.Reshape( (params.patch_frames, params.patch_bands, 1), input_shape(params.patch_frames, params.patch_bands))(features) for (i, (layer_fun, kernel, stride, filters)) in enumerate(_YAMNET_LAYER_DEFS): net layer_fun(layer{}.format(i 1), kernel, stride, filters, params)(net) embeddings layers.GlobalAveragePooling2D()(net) logits layers.Dense(unitsparams.num_classes, use_biasTrue)(embeddings) predictions layers.Activation(activationparams.classifier_activation)(logits) return predictions, embeddings这与 README “About the Model” 一节的文字描述相互印证96×64 的特征 patch 送入 MobileNet_v1 后在卷积顶端产生3×2 个位置、1024 个核的激活图对其取平均即得到 1024 维嵌入再经单层 logisticsigmoid层输出 521 个类别分数——对应的是 960ms 输入波形段的分类结果。输出采用 sigmoid 而非 softmax是因为音频事件属于多标签问题一段声音可以同时包含多个事件。3.3 端到端帧级模型真正对外的入口是yamnet_frames_model()第 108–128 行它定义了一个从原始波形直接到分类分数的 Keras 模型内部串接了补零、特征提取与上述网络def yamnet_frames_model(params): waveform layers.Input(batch_shape(None,), dtypetf.float32) waveform_padded features_lib.pad_waveform(waveform, params) log_mel_spectrogram, features features_lib.waveform_to_log_mel_spectrogram_patches( waveform_padded, params) predictions, embeddings yamnet(features, params) frames_model Model( nameyamnet_frames, inputswaveform, outputs[predictions, embeddings, log_mel_spectrogram]) return frames_model该模型的输入是形状(num_samples,)的一维 float32 波形16 kHz 单声道、取值 [-1, 1]有三个输出输出形状含义predictions(num_patches, 521)每个时间帧的 521 类分数embeddings(num_patches, 1024)每个时间帧的 1024 维嵌入log_mel_spectrogram(num_spectrogram_frames, 64)整段波形的对数梅尔谱四、音频特征管线从波形到 96×64 patchREADME 对训练所用特征的描述如下与早期 VGGish 发布一致所有音频重采样为16 kHz 单声道用短时傅里叶变换STFT幅度谱计算频谱窗长 25 ms、窗移 10 ms、周期汉宁窗将频谱映射为64 个梅尔 bin覆盖125–7500 Hz频率范围计算稳定化对数梅尔谱log(mel-spectrum 0.001)偏置项避免对零取对数将特征按50% 重叠切分为0.96 秒的样本每个样本覆盖 64 个梅尔频段 × 96 个 10 ms 帧。4.1 超参数定义params.py上述每一步的数值都集中定义在 params.py 的冻结 dataclassParams中默认值与 README 描述一一对应dataclass(frozenTrue) # 实例不可变 class Params: sample_rate: float 16000.0 stft_window_seconds: float 0.025 stft_hop_seconds: float 0.010 mel_bands: int 64 mel_min_hz: float 125.0 mel_max_hz: float 7500.0 log_offset: float 0.001 patch_window_seconds: float 0.96 patch_hop_seconds: float 0.48 property def patch_frames(self): return int(round(self.patch_window_seconds / self.stft_hop_seconds)) num_classes: int 521 conv_padding: str same batchnorm_center: bool True batchnorm_scale: bool False batchnorm_epsilon: float 1e-4 classifier_activation: str sigmoid tflite_compatible: bool False关于修改超参数的边界params.py 的注释给出了明确指引除patch_hop_seconds外的这些超参数都用于 YAMNet 的训练修改它们会带来性能上的波动。patch hop 可以任意修改更小的 hop 会从同一段音频中产生更多 patch可能获得更好的性能但计算开销更大。也就是说patch_hop_seconds是唯一推荐安全调整的旋钮默认 0.48s即 50% 重叠其余特征参数与网络结构参数改动后属于“重新训练”范畴不应期待与原权重配套的性能。patch_frames属性自动推导出每个 patch 的帧数0.96 / 0.010 96 帧patch_bands即mel_bands64。tflite_compatible默认为False在导出 TF-Lite 时会被置为True见导出章节。4.2 特征实现细节features.pyfeatures.py 中waveform_to_log_mel_spectrogram_patches()第 22–79 行实现了上述管线几个值得注意的实现细节FFT 长度自动取 2 的幂25 ms 窗对应 400 个采样点向上取 2 的幂得fft_length 512源码为2 ** ceil(log2(400)) 512因此 STFT 输出512 // 2 1 257个频点再经tf.signal.linear_to_mel_weight_matrix投影到 64 个梅尔 bin第 33–57 行tf.signal.stft默认即周期汉宁窗与训练特征要求一致源码注释 第 28 行 有说明patch 切分使用tf.signal.frame在梅尔谱时间轴上以帧长 96、步长 48 的窗口切分第 65–76 行。源码注释提醒若波形短于一个 patch 窗0.96s则不会输出任何 patch因此正式处理前先补零TF-Lite 兼容的 STFT 替代实现当params.tflite_compatible为真时改用_tflite_stft_magnitude()第 111–165 行它不用tf.signal.stft而是通过显式构建 DFT 矩阵做矩阵乘法来实现实数 STFT 幅度谱这是为了绕开 TF-Lite 转换器的算子限制。4.3 最小输入长度为什么是 975 msREADME 提到“由于窗框机制至少需要 975 ms 的输入波形才能得到第一帧输出分数。”这个数值由 features.py 的pad_waveform()精确给出min_waveform_seconds patch_window_seconds stft_window_seconds - stft_hop_seconds 0.96 0.025 - 0.010 0.975 s即“一个完整的 patch 窗0.96s 最后一个 STFT 分析窗所需额外采样25ms 窗减去 10ms 步长”。pad_waveform()会把不足部分补零并把总长度向上取整到 patch 跳步的整数倍从而保证任意长度的输入都能输出整数个 patch——这也解释了为何模型输入可以是不定长波形。五、推理使用对 WAV 文件做分类5.1 基本用法在research/audioset/yamnet目录下yamnet.h5与代码同目录运行python inference.py input_sound.wavinference.py 会报告在整个输入的所有帧上取平均后的 top-5 最高分类别。5.2 推理代码做了什么inference.py的main()第 30–60 行完整流程如下每一行都可直接复用为工程集成参考params yamnet_params.Params() yamnet yamnet_model.yamnet_frames_model(params) yamnet.load_weights(yamnet.h5) yamnet_classes yamnet_model.class_names(yamnet_class_map.csv) # 1. 解码 WAV要求 int16 采样类型 wav_data, sr sf.read(file_name, dtypenp.int16) waveform wav_data / 32768.0 # 2. 归一化到 [-1.0, 1.0] waveform waveform.astype(float32) if len(waveform.shape) 1: waveform np.mean(waveform, axis1) # 3. 多声道取平均转单声道 if sr ! params.sample_rate: waveform resampy.resample(waveform, sr, params.sample_rate) # 4. 重采样到 16 kHz scores, embeddings, spectrogram yamnet(waveform) # 5. 前向推理 prediction np.mean(scores, axis0) # 6. 沿时间轴平均 top5_i np.argsort(prediction)[::-1][:5] # 7. 取 top-5几个关键点WAV 必须以 int16 采样类型读取源码中有断言assert wav_data.dtype np.int16float 型 WAV 需先转换模型输出的scores是(time_frames, num_classes)矩阵np.mean(scores, axis0)沿时间轴平均才是整段音频的分类结果——这是 YAMNet 官方推荐的“整段音频”打分方式README 建议如需更细粒度的输出如逐帧时间序列、指定类别的分数、或基于嵌入做下游任务可以修改inference.py的示例代码直接访问三个模型输出。5.3 逐帧输出的可视化README 指引读者参考 yamnet_visualization.ipynb 查看逐帧模型输出分数的展示示例。由于每个 patch 对应 960ms 音频、hop 480msscores矩阵天然带有时间轴信息对scores[i, j]按 patch 序号还原时间点即可绘制“类别分数随时间变化”的曲线用于判断某类声音在音频中出现的起止区间。六、类别词汇表yamnet_class_map.csv模型 521 个输出与类别名称的映射由 yamnet_class_map.csv 描述格式为三列index,mid,display_nameindex模型输出索引0..520mid该类别的机器标识符machine identifier如/m/09x0rdisplay_name人类可读的类别描述如Speech。实际文件共 522 行1 行表头 521 行类别开头几行为index,mid,display_name 0,/m/09x0r,Speech 1,/m/0ytgt,Child speech, kid speaking 2,/m/01h8n0,Conversation ... 520,/m/07hvw1,Field recording加载逻辑在 yamnet.py 的class_names()中读取 CSV、跳过表头、返回display_name字符串数组推理代码即用这个数组把分数索引翻译回类别名。为什么是 521 而不是 527原始 AudioSet 数据发布包含 527 个类别本模型应公平性Fairness评审意见删除了其中 6 个以避免潜在的冒犯性错误标注去掉了 Speech 与 Singing 的性别化版本Male/Female以及 Battle cry 和 Funny music。这一背景在 README 的 “Class vocabulary” 一节中有明确说明。七、模型性能据 README 的 “Performance” 一节在20,366 段音频的 AudioSet 评测集上、覆盖 521 个保留类别的指标为指标数值balanced average d-prime2.318balanced mAP0.306balanced average lwlrap0.393模型规模方面原文档给出的计算结果3.7M 权重每个 960ms 输入帧约 69.2M 次乘法。这些指标属于原始发布的官方评测数据引用时应注明其评测集口径20,366 段的 AudioSet eval set。八、多格式导出TF2 SavedModel、TF-Lite 与 TF-JS除了 Keras HDF5 权重export.py 提供了将 YAMNet 导出为TF2 SavedModel、TF-Lite 模型、TF-JS 模型的完整脚本该文件不在 README 的布局列表中是目录内的补充能力。8.1 使用方式脚本头部 docstring第 1–24 行说明用法python export.py path/to/YAMNet/weights-hdf-file path/to/output/directory在 yamnet 源码目录下运行各类导出会创建在输出目录的tf2/、tflite/、tfjs/子目录中若对应目录已存在则跳过该导出。导出前需pip installtensorflow_hub与tensorflowjs两个包。8.2 导出模型的统一 I/O 契约三种格式导出模型的输入输出契约一致docstring 原文归纳输入一维 float32 张量形状任意内容为单声道 16 kHz、取值 [-1, 1] 的音频波形输出[num_frames, num_classes]的预测类别分数矩阵[num_frames, embedding_size]的逐帧嵌入矩阵[num_spectrogram_frames, num_mel_bins]的整段波形对数梅尔谱。SavedModel 版本还会把类别映射 CSV 作为资产asset打包恢复后可通过模型的class_map_path()方法取得见 export.py 的YAMNet模块封装。8.3 导出流程的三个要点从 export.py 源码看导出流程有三点值得注意每次导出前后都执行健全性检查check_model()复用与 yamnet_test.py 相同的三项合成信号校验静音→Silence、白噪声→White noise、440Hz 正弦→Sine wave确保导出产物与原始模型行为一致TF2 导出还会分别在 TF2 与 TF1 图模式下用 TF-Hub 加载验证一次TF-Lite 导出使用Params(tflite_compatibleTrue)第 146 行触发 features.py 中的 DFT 矩阵版 STFT 实现再经tf.lite.TFLiteConverter.from_saved_model转换并用tf.lite.Interpreter的 signature runner 复测TF-JS 导出基于 TF-Lite SavedModel完成tfjs_saved_model_converter即三种格式形成“HDF5 权重 → TF2 SavedModel → TF-Lite → TF-JS”的转换链。8.4 维护者与资源README 注明本模型仓库由 Manoj Plakal 与 Dan Ellis 维护。更广泛的 AudioSet 项目背景、论文引用要求与联系方式见上级目录的 AudioSet README。九、小结与要点速查能力定位521 类多标签音频事件分类3.7M 权重的轻量 MobileNet_v1 风格网络适合 CPU/边缘侧音频理解场景输入契约单声道 16 kHz、[-1, 1] 波形每个 patch 覆盖 960mshop 480ms至少 975ms 才有第一帧输出短音频会被自动补零输出契约逐帧 521 类分数 1024 维嵌入 对数梅尔谱整段音频结论按时间轴平均得到可调参数仅patch_hop_seconds推荐修改更小 hop 更多 patch、更高开销其余特征/结构参数由训练决定环境要点TF 2.16 环境需显式安装tf-kerasKeras 2权重文件yamnet.h5须与代码同目录验证手段python yamnet_test.py跑通合成信号测试即环境就绪export.py可产出 TF2/TF-Lite/TF-JS 三种部署格式。【免费下载链接】modelsModels and examples built with TensorFlow项目地址: https://gitcode.com/GitHub_Trending/mode/models创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考