利用 Android 手机和 YAMNet ML 模型进行声音分类(一)

文 / ML GDE George Soloupis

这是教程的第 1 部分,介绍了如何利用出色的 YAMNet 机器学习 模型将手机麦克风录制的 声音分类500 多种类别

本教程分为两部分,您可以按顺序学习,也可以跳到最感兴趣或与您相关度最高的部分:

  • 第 1 部分:ML 模型的架构、将模型转换为 TensorFlow Lite (TFLite) 以及模型的基准测试
  • 第 2 部分:Android 实现

ML 模型的架构

YAMNet 是一个经过预训练的深度网络,可基于 AudioSet-YouTube 语料库 预测 521 种音频事件类别,并采用 Mobilenet_v1 深度可分离卷积架构。下载 此图像 即可查看模型的构造方式。

模型训练所使用的音频特征计算方式如下:

计算梅尔声谱图

  • 计算 log(mel-spectrum + 0.001) 得出稳定的对数梅尔声谱图,其中的偏移量用于避免对零取对数。

计算稳定的对数梅尔声谱图

  • 然后将这些特征分帧成具有 50% 重叠且长度为 0.96 秒的示例,每个示例覆盖 64 个梅尔频段,总共 96 帧,每帧 10 毫秒。

生成批量输入特征

之后,将这些 96x64 的片段馈送到 Mobilenet_v1 模型,以在卷积之上针对 1024 个内核生成一个 3x2 的激活函数数组。平均之后将得到 1024 维的嵌入向量,然后通过单个逻辑层得到对应于 960 毫秒输入波形段的 521 个按类别的输出得分(由于采用窗口分帧,您至少需要 975 毫秒的输入波形才能获得第一帧输出得分)。

模型采用了大量的卷积和深度可分离卷积层。

您可以在这一篇 文章 中找到大量有关深度可分离卷积的信息。简单来说,卷积、深度卷积和深度可分离卷积的区别如下:

常规卷积

来自 medium @zurister

深度卷积 (Depthwise Convolution):

来自 medium @zurister

深度可分离卷积 (Depthwise Separable Convolution):

来自 medium @zurister

上一示例中,我们使用对深度卷积使用 1*1 滤波器来覆盖深度维度,并将其与水平维度分开。

模型的转换

将模型转换为 TensorFlow Lite (TFLite) 文件的过程并不容易。您可以点击 此处 查看此过程的一个示例,该示例详细说明了如何解决声谱图期间使用的特定运算符(RFFTComplexAbs)的转换问题。

TensorFlow Lite 模型托管于 TensorFlow Hub。另外,此处 提供了大量此模型的相关信息。通过 Python 代码对 tflite 模型运行推理的过程如下:

interpreter = tf.lite.Interpreter('/path/to/yamnet.tflite')

input_details = interpreter.get_input_details()
waveform_input_index = input_details[0]['index']
output_details = interpreter.get_output_details()
scores_output_index = output_details[0]['index']
embeddings_output_index = output_details[1]['index']
spectrogram_output_index = output_details[2]['index']

# Input: 3 seconds of silence as mono 16 kHz waveform samples.
waveform = np.zeros(3 * 16000, dtype=np.float32)

interpreter.resize_tensor_input(waveform_input_index, [len(waveform)], strict=True)
interpreter.allocate_tensors()
interpreter.set_tensor(waveform_input_index, waveform)
interpreter.invoke()
scores, embeddings, spectrogram = (
    interpreter.get_tensor(scores_output_index),
    interpreter.get_tensor(embeddings_output_index),
    interpreter.get_tensor(spectrogram_output_index))
print(scores.shape, embeddings.shape, spectrogram.shape)  # (N, 521) (N, 1024) (M, 64)

模型的输出为:

  • 得分,一个 float32 张量,形状为 (N, 521),其中包含对 YAMNet 支持的 AudioSet 本体中每 521 个类的逐帧预测得分。
  • 嵌入向量,一个 float32 张量,形状为 (N, 1024),其中包含逐帧嵌入向量,而嵌入向量是馈送到最终分类器层的平均池化输出。
  • log_mel_spectrogram,一个 float32 张量,表示整个波形的对数梅尔声谱图。这些是传递到模型的音频特征。

性能度量

有一款出色的工具可帮助我们对 TFLite 模型进行 基准测试 (Benchmark)。TensorFlow Lite 基准测试工具目前可度量并计算以下主要性能指标的统计信息:

  • 初始化时间
  • 预热状态的推理时间
  • 稳定状态的推理时间
  • 初始化期间的内存用量
  • 总体内存用量

您可以在 Android 和 iOS 上安装相应的基准测试应用,或以本机命令行二进制文件的形式使用这些基准测试工具,无论哪种形式,皆共用相同的核心性能度量逻辑。

对 tflite 模型进行基准测试后,我们得到了出色的成绩:

在这张图中,我们可以看到,不论是使用 Pixel 3 还是 Pixel 4,我们都可以使用 CPU 的 2 个或 4 个线程,获得最少的推理时间。此外,该工具在处理模型时会指出一个 GPU 错误。查看 logcat 时我们会看到:

Error: Attempting to use a delegate that only supports static-sized tensors with a graph that has dynamic-sized tensors.

这些结果对 android 应用开发的有很大的帮助。我们无需再使用 GPU 代码,且实现的参数可提升应用的运行速度!

这样,我们对模型架构、将模型转换为 tflite 以及基准测试的讨论就告一段落了。后续步骤包括通过 android 手机的麦克风录制声音、在应用中插入 tflite 模型以及在屏幕上显示结果(教程第 2 部分未完待续)。

感谢 Sayak Paul 和 Le Viet Gia Khanh 的评审和支持。

关于作者

George Soloupis,我从一名药剂师转行成为了 Android 开发工程师。目前积极活跃于 Google 的移动操作系统 TensorFlow Lite 机器学习工作组。

原文:Classification of sounds using android mobile phone and the YAMNet ML model
中文:TensorFlow 公众号