https://blog.tensorflowcn.cn/2020/06/estimating-pitch-with-spice-and-tensorflow-hub.html
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4U8Dwy_CUUKGDWro139fhvYDhU4cRRXwxy4NkcPyAgrr6D68xAILGYeEg2nNzSi1nfoZvvEWt3ppXw7GqQ0uUDN3zNA7p-JTyyT6UtDrgqYvx_1b7KzCMHMl9ZcF2TeBYpLH3qEYh38E/s1600/SPICE_Post.png
发布者 Luiz Gustavo Martins,Beat Gfeller 和 Christian Frank
音高是音乐音调的属性之一(还有持续时间、强度和音色),它可以让你描述一个音符是“高”还是“低”。音高由频率量化,以赫兹 (Hz) 为单位,1 赫兹对应每秒一个周期。频率越高,音符就越高。
音高检测是一个有趣的挑战。从历史上看,要让机器理解音高,它需要依赖复杂的、手工制作的信号处理算法来测量音符的频率,尤其是要将相关频率与背景噪声和伴奏乐器分离。如今,我们可以使用机器学习来做到这一点,更具体地说,可以使用 SPICE 模型(
SPICE:自监督音高估计)。
SPICE 是一种经过预训练的模型,可以从混合音频录制(包括噪声和伴奏乐器)中识别出基频。该模型也可以在 Web 上使用
TensorFlow.js,以及在移动设备上使用
TensorFlow Lite。
在本教程中,我们将引导你使用 SPICE 从短小的音乐片段中提取音高。首先,我们将加载音频文件并对其进行处理。然后,我们将使用机器学习来解决这个问题(你会发现,使用
TensorFlow Hub 是多么容易)。最后,我们将进行一些后处理和一些很酷的可视化操作。你可以按照此
Colab 笔记本 的步骤进行操作。
加载音频文件
该模型期望以原始音频样本作为输入。为了帮助你做到这一点,我们展示了四种方法,你可以使用这些方法将输入 wav 文件导入 Colab
- 在 Colab 中直接录制一段简短的你唱歌的片段
- 从你的计算机上传录制文件
- 从你的 Google Drive 下载文件
- 从 URL 下载文件
你可以选择其中任何一种方法。在 Colab 中直接录制自己唱歌是最容易尝试的方法,也是最有趣的方法。
音频可以用多种格式录制(例如,你可能会使用 Android 应用、台式电脑或浏览器录制音频),将你的音频转换为模型所需的精确格式可能很具有挑战性。为了帮助你做到这一点,我们提供了一个名为
convert_audio_for_model 的辅助函数,用于将你的
wav 文件转换为正确的格式,即单声道音频,采样率为 16khz。
在本博文的其余部分,我们将使用此文件
准备音频数据
现在我们已经加载了音频,我们可以使用频谱图对其进行可视化,频谱图显示了随时间变化的频率。在这里,我们使用对数频率刻度,以使唱歌更清晰地显示出来(请注意,此步骤不是运行模型所必需的,它只是用于可视化)。
|
注意:此图表是使用 Librosa 库创建的。你可以找到更多信息 此处。 |
我们还需要进行最后一次转换。输入必须归一化为 -1 到 1 之间的浮点数。在前面的步骤中,我们使用辅助函数 convert_audio_for_model 将音频转换为 16 位格式。为了对其进行归一化,我们只需要将所有值除以 2
16,或者在我们的代码中,除以 MAX_ABS_INT16
audio_samples = audio_samples / float(MAX_ABS_INT16)
执行模型
从 TensorFlow Hub 加载模型很简单。你只需使用 load 方法,并提供模型的
URL。
model = hub.load("https://tfhub.dev/google/spice/2")
注意:这里有一个有趣的细节是,Hub 中的所有模型 URL 都可以用于下载,也可以用于读取文档,因此,如果你将浏览器指向该链接,你就可以阅读有关如何使用该模型以及如何训练该模型的更多信息。
现在,我们可以通过传递归一化的音频样本,使用从 TensorFlow Hub 加载的模型
output = model.signatures["serving_default"](tf.constant(audio_samples, tf.float32))
pitch_outputs = output["pitch"]
uncertainty_outputs = output["uncertainty"]
在这一点上,我们有了音高估计和不确定性(每个检测到的音高)。将不确定性转换为置信度(
confidence_outputs = 1.0 - uncertainty_outputs
),我们可以很好地了解结果:
如图所示,对于一些预测(特别是在没有歌唱声音的地方),置信度非常低。让我们只保留高置信度的预测,删除置信度低于 0.9 的结果。
为了确认模型是否正常工作,让我们将音高从 [0.0, 1.0] 范围转换为赫兹的绝对值。要进行此转换,我们可以使用 Colab 笔记本中提供的函数
def output2hz(pitch_output):
# Constants taken from https://tfhub.dev/google/spice/2
PT_OFFSET = 25.58
PT_SLOPE = 63.07
FMIN = 10.0;
BINS_PER_OCTAVE = 12.0;
cqt_bin = pitch_output * PT_SLOPE + PT_OFFSET;
return FMIN * 2.0 ** (1.0 * cqt_bin / BINS_PER_OCTAVE)
confident_pitch_values_hz = [ output2hz(p) for p in confident_pitch_outputs_y ]
如果我们将这些值绘制在频谱图上,我们可以看到预测与主要音高的匹配程度,主要音高可以在频谱图中显示为更强的线条:
成功了!我们成功地从歌手的声音中提取了相关的音高。
请注意,对于此特定示例,基于频谱图的启发式方法也可以用于提取音高。总的来说,基于 ML 的模型比手工制作的信号处理方法表现得更好,尤其是在音频中存在背景噪声和伴奏乐器的情况下。有关 SPICE 与基于频谱图的算法 (SWIPE) 的比较,请参见
此处。
转换为音乐音符
为了使音高信息更有用,我们还可以找到每个音高所代表的音符。为此,我们将使用一些数学方法将频率转换为音符。一个重要的观察结果是,与推断的音高值相反,转换后的音符是量化的,因为这种转换涉及舍入(笔记本中的函数
hz2offset 使用了一些数学方法,你可以找到很好的解释
此处)。此外,我们还需要按时间将预测分组在一起,以便获得更长的持续音符,而不是一系列相等的音符。这种时间量化并不容易,我们的笔记本只是实现了一些启发式方法,这些方法通常不会产生完美的乐谱。但是,对于具有相同持续时间的音符序列,它确实有效,就像我们的示例一样。
我们首先根据置信度低的预测添加休止符(无歌唱间隔)。下一步更具挑战性。当一个人自由地唱歌时,旋律可能相对于音符可以代表的绝对音高值存在偏差。因此,要将预测转换为音符,需要校正这种可能的偏差。
在计算偏移量并尝试不同的速度(多少个预测构成一个八分音符)后,我们最终得到了这些渲染的音符:
我们还可以使用 music21 将转换后的音符导出到 MIDI 文件
converted_audio_file_as_midi = converted_audio_file[:-4] + '.mid'
fp = sc.write('midi', fp=converted_audio_file_as_midi)
下一步是什么?
使用 TensorFlow Hub,你可以轻松找到很棒的模型,例如 SPICE 和许多其他模型,以帮助你解决机器学习挑战。继续探索
模型,使用
Colab 玩一玩,也许尝试构建一些类似于
FreddieMeter 的东西,但使用你最喜欢的歌手!
我们渴望知道你能想出什么。在社交媒体上与我们分享你的想法,并在你的帖子中添加 #TFHub。
致谢
本博文基于 Beat Gfeller、Christian Frank、Dominik Roblek、Matt Sharifi、Marco Tagliasacchi 和 Mihajlo Velimirović 在 SPICE:自监督音高估计 上的工作。还要感谢 Polong Lin 对这篇博文的审阅并提出了很棒的想法,以及 Jaesung Chung 对创建该模型的 TF Lite 版本的支持。