Qwen2-Audio微调探索音乐转录

自动音乐转录是将 MP3 和 WAV 等音频文件转换为乐谱、吉他指法谱以及音乐家可能想要用乐器学习歌曲的任何格式的过程。

我们将介绍目前用于执行此操作的最佳工具,这些工具恰好是基于深度学习的,并采用一种新颖的方法。

1、当前最先进的技术

这项任务的当前最先进的技术来自 Magenta,这是一个开源研究项目,由现已解散(截至 2023 年 4 月)的 Google Brain 团队开发。

他们在 2021 年发表了一篇论文 使用 Transformers 进行序列到序列钢琴转录,该论文使用了受 T5 启发的 Transformer 模型(类似于“t5-small”),该模型具有 5400 万个参数和 Maestro 数据集,取得了很好的效果。使用编码器-解码器 Transformer 架构将问题作为序列到序列任务来解决。编码器将梅尔频谱图帧作为输入处理并生成嵌入,而解码器通过交叉注意使用这些嵌入来自回归生成一系列类似 MIDI 的标记。他们的词汇表由四种类型的标记组成:

  • 音符标记(MIDI 音高的 128 个值)
  • 速度标记(128 个值,包括零表示音符关闭)
  • 时间标记(10ms 箱中的 6,000 个值用于绝对计时)
  • EOS 标记(用于标记序列结束)

请参见下图,了解架构的可视化以及其自定义 MIDI 标记的示例序列:

图 1. 来自使用 Transformers 进行序列到序列钢琴转录的论文

我们的模型是一个通用的编码器-解码器 Transformer 架构,其中每个输入位置包含一个频谱图帧,每个输出位置包含来自我们类似 MIDI 的词汇表的事件。输出标记是从解码器自回归采样的,每一步都以最大概率获取标记。

2022 年,他们发表了一篇论文 MT3:多任务多轨音乐转录 。该实验使用了与上一个实验相同的方法,但添加了额外的乐器标记来表示不同的乐器。同样,他们使用了类似的 T5 模型,并在许多训练过的数据集上取得了出色的表现,尤其是 Slakh、Maestro 和 MusicNet

MR-MT3 于次年发布,作为 MT3 的轻微改进。

2、为什么要使用语言模型而不是这些 SOTA 模型?

  • 计算/GPU 资源

尽管与最小的语言模型相比,其规模要小得多,但从头开始训练它需要大量资源。2021 年的论文指出:

“我们在 32 个 TPUv3 核心上训练了所有模型,每个核心的批次大小为 8。根据验证集结果,过度拟合似乎不是问题,因此我们允许训练进行 400K 步,这对于我们的基线模型来说大约需要 2.5 天。”

MT3 论文没有提供关于训练的具体细节,只是说他们训练了 100 万步。

  • 其他限制

这些模型在输出灵活性方面有一些固有的限制。虽然语言模型通常具有大量词汇(通常超过 30,000 个标记),并且已在各种自然语言数据上进行了广泛的预训练,但 MT3 和类似的音乐转录模型使用小得多的专门标记词汇(只有几千个标记),仅专注于音乐事件。

这种专业化意味着添加新标记(例如新乐器或演奏技巧,如吉他上的手掌静音或小提琴上的拨弦)可能并不容易——需要进行大量的再训练才能将这些新标记有效地与现有词汇结合起来,并且通常需要大量的训练数据来展示这些技巧。

这与大型语言模型不同,大型语言模型通常可以在不进行修改的情况下用自然语言描述这些音乐细微差别,因为它们在广泛的预训练中遇到了这些概念。

  • 迁移学习和零样本

我们可以利用大型开源预训练音频和语言模型的迁移学习。音乐生成模型的示例包括 OpenAI 的 Jukebox 和 Meta 的 MusicGen

3、现代多模态模型架构

GPT-4o 旨在“原生”处理文本、音频和图像。尽管 OpenAI 尚未公布这方面的技术细节,但假设网络中的某些权重将处理所有模态。该模型可能使用仅解码器架构(如仅语言的 GPT 模型),而无需编码器组件先将不同模态转换为密集表示。这种设计允许模型无缝地处理和解释文本和图像等输入,从而可能在计算和模型理解方面提供性能优势。

许多多模态模型采用了一种更简单的方法,让人联想到编码器-解码器架构:它们结合了两个预先训练的模型——一个用于特定输入模态的编码器(如用于视觉的 ViT 或用于声音的音频编码器)和一个大型语言模型(如 LLaMA、Gemma 或 Qwen)。这些模型通过投影层连接起来。

这些投影层通常只使用一个线性层,在共享潜在空间中对齐它们的表示。这些投影层学习将编码器的输出转换为与 LLM 的预期输入维度和特征相匹配的格式。投影从输入模态创建新的嵌入/标记,然后可以将其注入到 LLM 的输入序列中。LLaVA 是这种架构在视觉语言任务中的典型示例,而 Spotify 的 Llark 和 Qwen-Audio 则使用音频编码器而不是视觉编码器应用了相同的原理。

以下是一些关于如何将模型拼接在一起的伪代码:

# Extract features from final layer of audio encoder
# Shape: [batch_size, audio_seq_len, encoder_dim=1024]
audio_features = audio_model(audio_input)
    
# Project audio features to match LLM's embedding dimension
# Shape: [batch_size, audio_seq_len, llm_embed_dim=4096]
audio_embeddings = projection_layer(audio_features)
    
# Get text embeddings from LLM's embedding layer
# Shape: [batch_size, text_seq_len, llm_embed_dim=4096]
text_embeddings = llm.embed_text(text_input)
    
# Concatenate along sequence length dimension
# Shape: [batch_size, audio_seq_len + text_seq_len, llm_embed_dim=4096]
combined_input = concatenate([audio_embeddings, text_embeddings], dim=1)
    
# Feed them into the LLM as normal for generation
output = llm(combined_input)

4、Spotify Llark 和 Qwen2-Audio

Llark 使用 OpenAI 的 Jukebox,而 Qwen2-Audio 使用 OpenAI 的 Whisper 作为音频塔。Jukebox 是一种音乐生成模型,但它也可以将音频片段作为输入并输出音频片段的延续。Whisper 用于将语音转录为文本。

考虑到它们的用途,音频模块的选择很明确:Llark 专注于音乐分析,而 Qwen2Audio 主要专注于通过一些基本的音频和音乐分析功能响应语音指令。

确定从大型预训练模型中提取嵌入的最佳来源涉及研究和实验。此外,决定是否微调整个模块或冻结部分模块是一个至关重要的设计选择。例如,LlaVa 的训练策略涉及冻结视觉塔并专注于微调投影层和语言模型。我们将在下面介绍每个模型的这个方面。

4.1 Llark:为什么是 Jukebox?

确定从大型模型中提取嵌入的最佳位置通常需要进行大量探索。这涉及通过反复试验的过程在不同的分类任务上测试模型的各种激活或提取层。对于音乐生成模型,这可能包括流派识别、乐器检测、情绪检测以及谐波结构和时间模式分析等任务。许多商业嵌入模型(如 OpenAI 的嵌入模型)都是专门为嵌入生成而训练的,具有专门的架构和训练目标,而不是现有语言模型的微调版本。

两个最大的公开可用的音乐生成和音乐延续(即:能够将音频作为输入)模型是 Jukebox 和 MusicGen。MusicGen 更新更快,因此对我来说似乎是显而易见的选择。然而,根据这篇关于探索 MusicGen 的论文,从 Jukebox 中提取的嵌入在分类任务中似乎平均优于 MusicGen。这篇论文的研究结果促使 Llark 的作者使用以下方法来提取嵌入:

  • 嵌入是根据 Castellon 等人描述的方法从 Jukebox 编码器第 36 层的输出得出的。
  • 原始 Jukebox 编码:345Hz 的 4800 维向量,对于 25 秒的剪辑:超过 4.14 * 10⁷ 个浮点值
  • 作者使用下采样方法:100ms 帧内的平均池化,结果:下采样频率:10Hz,嵌入大小:25 秒音频剪辑的 1.2 × 10⁶。这意味着形状为 [240, 4800] 的二维数组。
  • 保留时间信息(与 Ca​​stellon 等人在时间维度上取平均值不同)

下采样的嵌入大小大约比许多多模态视觉模型中使用的 CLIP ViT-L14 模型大 6 倍

4.2 Qwen2Audio:Whisper

本文未详细提及 Qwen2Audio 的嵌入提取。 Whisper 是一种编码器-解码器架构,其中编码器生成音频的深度学习表示,解码器将表示解码为文本(转录)。在 Qwen2Audio 中,他们似乎从 Whisper 编码器的最后一层提取嵌入,尽管他们没有提到他们是否在训练期间冻结它。

​​4.3 预训练权重、训练数据和数据集

不幸的是,Spotify 尚未向公众提供任何数据集或其训练过的模型权重,并指出:

“关于输入:我们模型的输入是公开的、开源的、知识共享的

许可的音频和相关注释。但是,每个单独的音频文件都可以有自己的、可能更严格的许可证。许多音频文件都包含“无衍生品”许可证。我们鼓励数据集的用户熟悉这些许可证的限制;为了遵守此类许可证,我们不会发布本文中训练数据的任何衍生品(包括查询-响应对或训练模型权重)。”

他们使用了以下数据集:

  • MusicCaps(Agostinelli 等人,2023 年)
  • YouTube8M-MusicTextClips(McKee 等人,2023 年)
  • MusicNet(Thickstun 等人,2017 年)
  • FMA(Defferrard 等人,2017 年)
  • MTG-Jamendo(Bogdanov 等人,2019 年)
  • MagnaTagATune(Law 等人,2009 年)

Llark 在以下摘录中详细介绍了其训练数据生成过程:

“我们使用 ChatGPT 的变体来提取所有实验的指令调整数据。但是,所使用的确切语言模型因数据集而异。我们选择 OpenAI 模型如下:我们对所有推理任务都使用 GPT-4。我们发现 GPT-4 更擅长遵循推理任务系列中的复杂指令。对于包含超过 25k 个样本的数据集,我们将推理数据限制为 25k 个音轨的随机子样本。”

这会产生如下问答数据:

LLark 的示例文本输入和输出,用于提供的音频

用于训练 Qwen2Audio 的数据集也没有共享,但经过训练的模型是广泛可用的,并且也在 transformers 库中实现:

对于这个项目,微调预先训练的 Llark 模型将是最佳选择,因为它据称在 Spotify 在论文中所述的评估基准方面表现良好。

但是,鉴于他们没有发布它的权重,如果没有相当多的专业知识和资金,从头开始训练这样的模型是不可行的。Spotify 对其进行了训练:

我们的模型在 4 个 80GB NVIDIA A100 GPU 上进行训练。训练大约需要 54 小时。

使用 LambdaLabs 等提供商,这将花费约 700 美元。

出于上述原因,我选择了 Qwen。但是,Qwen2-Audio 在节奏和乐器检测等基本音乐任务中表现不佳。我将在下面的评估部分详细说明这一点。这意味着该模型可能不够大或预训练不足,无法完成这项任务,但我希望至少可以为将来微调这项任务设定一个起点和框架。正如阿里巴巴在其 Qwen2-Audio 博客文章中所述:

我们还计划构建更大的 Qwen2-Audio 模型,以探索音频语言模型的规模定律。

不过,为了我自己的学习,我确实尝试使用 torch 和带有 transformers 库的预训练模型重新创建模型。

我还为问答数据和嵌入创建了数据集。我为 URMP 数据集生成了简短形式的问答数据,例如:“这首曲目的节奏是多少”、“这段音频中演奏了哪些乐器”。

这是在 Colab 环境中运行 Jukebox 的笔记本,以利用廉价的 T4 GPU。我在此处将问答和嵌入数据集上传到了 HuggingFace。

这是复制了 Llark 的笔记本

5、音乐转录的训练数据

我选择 ABC 音乐符号作为语言模型预期转录音乐的输出格式。以下是一个例子:

X:1
M:4/4
L:1/16
K:none
Q:67

V:1 name="Electric Bass (finger)"
%%octave-default C4
GAA^2E3A2<A^2 | D^D^2E2A2A^4 A^2E2 | A2A^4A^2E2 A2A^4 | A^2E2A2A^4A^2E2A2 |
A^4 A^2E2 A2A^4A^2 E2 | A2A^4 |

V:2 name="Bright Acoustic Piano"
%%octave-default C5
[E3C3][E3C3][E3C3] [E3C3][A^,2E2A^2] | [E3A^3][E3A^3][E3A^3][E3A^3][E3A^3] |
[E3A^3][E3A^3][E3A^3] [E3A^3][E3A^3] | [E3A^3][E3A^3][E3A^3][E3A^3][E3A^3] |
[E3A^3][E3A^3][E3A^3] [E3A^3][E3A^3] | [E3A^3] |

V:3 name="Electric Guitar (jazz)"
%%octave-default C5
E'3C'3A^4E'3C'3 | A^4E'3 C'3A^4E'3C'3 | A^4 E'3C'3A^4 E'3C'3 | A^4E'3C'3A^4E'3C'3 |
A^4E'3C'3 A^4E'3C'3 | A^4 |

在此符号中,我们在顶部定义了拍号和节奏,用“M”和“Q”表示。“L”表示符号的默认音符长度,在本例中为十六分音符,这是常态。然后,我们定义每种乐器,以及它们在为每个乐器写音符时应遵循的默认八度。以下是 ABC 音乐符号中写音符的关键句法要点的总结:

  • 音符用字母 A-G 表示,小写字母表示高八度
  • 升号在音符前用 ^ 表示,降号用 _ 表示
  • 自然符号用 = 表示
  • 音符长度用音符后的数字表示(C2 是 C 的两倍长)
  • 附点音符在音符后使用 .(C. 是附点四分音符)
  • 休止符用 z 表示,用数字表示持续时间(z2 是半休止符)
  • 和弦用方括号 [CEG] 括起来
  • 连音线用连字符 - 表示
  • 小节线用 | 表示
  • 断奏节奏在音符之间使用 > 或 <(C>D 表示附点 C 八分音符后跟 D 六分音符)
为什么是 ABC记谱法?

选择这种符号的原因是:

  • 这是一种极简的音乐创作格式
  • 它被广泛使用且很受欢迎;语言模型已经对 ABC 符号有了很好的理解,因为它对其进行了广泛的预训练。
  • 它很灵活,可以轻松扩展以包括节奏变化、拍号变化、如上所述的其他演奏风格等……

我使用这个库将数据集提供的 MIDI 文件转换为 ABC 符号。创建数据集的笔记本在这里。

6、评估

为了评估原始模型以及此后执行的每个微调阶段,我从 URMP 数据集中随机选择了 30 个复杂程度不同的样本,并在每个样本上运行模型三次,手动检查所有响应。

通过手动测试,我发现最佳解码参数是温度为 0.7,top_p 为 1.2。返回的最大标记数上限为 2048。调整最大值似乎对性能影响不大。

原始模型在此评估集上表现不佳。虽然它偶尔会正确预测节奏和乐器,但大多数时候都无法做到。评估结果的文本文件可在此处获取。

鉴于此起点,如果没有强大的预训练模型,我们不太可能从此实验中看到出色的结果。但是,目标是制定策略,以便在将来有更高级的预训练模型可用时应用。

7、微调策略

我首先尝试使用基本交叉熵损失进行微调。使用交叉熵损失的监督微调是一种快速开始教授模型的方法,但像这样的基本损失函数有局限性,我们将在下面看到。此训练阶段背后的直觉是,它会将模型推向正确的方向,并会拾取数据集可能具有的任何模式或任何自定义 ABC 符号,而模型可能从未见过这些模式或符号。

7.1 带有教师强制的交叉熵损失

首先,我们以典型的语言模型监督微调方式对其进行训练。为此,我使用了 trl 库中的 SFTtrainer,它使用交叉熵损失和教师强制,具体定义如下:

  • 模型预测序列中的下一个标记。
  • 损失是根据预测概率 (logits) 与实际下一个标记之间的差异计算得出的。
  • 对于下一个预测,模型会获得实际正确的标记 (ground truth),而不是其自己的预测。这被称为教师强制,它有助于稳定训练并显著加快训练速度,尤其是在早期阶段。

这个训练阶段的结果很差。它降低了原始模型的性能。该模型以前可以很好地处理节奏和乐器识别,但现在大部分都出错了。它还开始产生无休止重复的乱码文本输出。即使在设置低学习率、应用梯度裁剪和使用低 LoRA 等级来缓解对模型的重大更改时,也会发生这种情况。总体而言,该模型似乎对所应用的训练非常敏感。

然而,虽然这个训练阶段可能会带来一些改进,但由于我们的基本损失函数的局限性,它不会带来最佳性能。该函数很难完全捕捉模型的性能细微差别。

例如,当使用教师强制时,乐器预测可能会在某些标记部分产生看似较低的损失。如果乐器名称以“V”开头,则无论准确度如何,模型都可能根据我们的数据集自信地预测“小提琴”或“中提琴”。此外,损失函数可能无法准确反映近乎失误的情况,例如预测节奏为 195 而不是 200——这是一个相当准确的小差异,但可能会受到惩罚,这严重依赖于 logit 之间的概率分布。相邻数字也可能具有较高的概率。

7.2 RLHF 与 PPO

由于这些限制,我们可以创建自己的自定义损失函数,可以更准确地对模型的响应进行评分。也就是说,给定模型的预测序列,损失函数可以给出 0 到 1 之间的分数来表示其好坏。

然而,将这个自定义损失函数集成到监督微调中是一个重大挑战。问题源于自定义损失函数引入的非线性,这阻止了梯度的直接计算。让我们来分析一下:

在具有交叉熵损失的传统 SFT 中:

  • 模型输出词汇表中每个标记的 logit(原始分数)
  • 这些 logit 直接表示模型的预测概率
  • 损失函数将这些概率与基本事实进行比较
  • 可以通过此比较直接计算梯度
  • 微积分的链式法则使我们能够将这些梯度传播回模型

使用我们的自定义损失函数:

  • 模型必须首先生成完整的文本输出
  • 此生成过程涉及从概率分布中抽样
  • 然后我们的损失函数会分析此文本输出(检查节奏、音符等)
  • 这在模型的 logits 和我们的损失计算之间创建了一个不可微分的步骤
  • 抽样和文本分析步骤打破了反向传播所需的梯度链

为了克服这个问题,可以采用强化学习技术,如近端策略优化 (PPO)。PPO 专门设计用于处理不可微分的损失函数,可以通过考虑整个策略(模型的输出分布)来优化模型,而不是依赖来自 logits 的梯度信息。

请注意,这里有很多很棒的文章解释 PPO!

PPO 的关键见解是,它不是尝试直接通过不可微分步骤进行反向传播,而是:

  • 将模型的输出视为强化学习框架中的动作
  • 使用自定义损失函数作为奖励信号
  • 更新模型的策略(其在 token 上的概率分布)以最大化预期奖励
  • 同时确保更新后的策略不会偏离当前策略太远

这种方法使我们能够使用自定义损失函数有效地训练模型,确保性能改进而不会破坏核心训练动态。PPO 算法的保守更新策略有助于在训练期间保持稳定性,这在使用大型语言模型时尤为重要。

通常,此评分函数将以“奖励模型”的形式作为单独的 LLM 实现,通常用于通过 RLHF 对模型进行微调,这是 ChatGPT 问世时首次引入的一项突破。由于此任务的性质,我们可以手动编写代码来对响应进行评分,这使用更少的资源并且更快。

对于拍号和节奏识别,这很容易计算。我们使用正则表达式提取所有预测项,例如提取节拍:

def extract_metre(self, abc_string):
  return re.search(r'M:(\S+)', abc_string).group(1)

模型应该学习我们希望它在 SFT 阶段输出的语法和结构。如果它输出的内容会导致我们的正则表达式找不到任何内容或出现错误,我们可以跳过该样本,假设它只是数据集的一小部分。

我们提取预测的节奏并编写一个函数,该函数对小错误更宽容,但对大错误惩罚更严厉:

  • 对于小差异(≤10 BPM),它使用线性缩放。
  • 对于较大的差异,它会切换到指数缩放。
  • 最终损失上限为 0 到 1。

让我们分解一下此自定义损失的关键组成部分:

自定义损失的代码在这里

  • 节拍损失

节拍损失侧重于乐曲的拍号。它将预测的节拍与基本事实进行比较,分别考虑分子和分母以及它们的比率。这种方法允许进行细致入微的评估,可以准确处理各种拍号。

节拍损失使用线性和指数缩放的组合来惩罚差异。小的差异会导致损失线性增加,而较大的差异会导致指数增加,最大值为 1。

  • 节奏损失

节奏损失评估预测的每分钟节拍数 (BPM) 的准确性。与节拍损失类似,它使用线性和指数缩放的组合。

对于小的节奏差异(≤10 BPM),该函数应用线性缩放。较大的差异会触发指数缩放,从而确保显著的节奏不匹配受到更严厉的惩罚。

  • 音高损失

音高损失可能是最关键的部分,因为它评估转录音符的准确性。此函数使用 Levenshtein 距离来比较每个声音中的音符序列。

音高损失计算考虑了多个声音,将每个预测声音与最接近的真实声音进行匹配。这种方法允许灵活地对声音进行排序,同时仍保持整体音高内容的准确性。

  • 乐器损失

乐器损失评估每个声音的乐器选择的准确性。

此函数考虑精确匹配、来自同一家族的乐器,并使用字符串相似性进行更细致的比较。它全面评估了模型识别和为每个声音分配乐器的能力。

  • 合并损失

最终损失是这些单个组件的加权组合:

total_loss = (0.5 * pitch_loss +
 0.15 * metre_loss +
 0.15 * tempo_loss +
 0.2 * instrument_loss)

此加权方案优先考虑音高准确性,同时仍考虑音乐转录的其他重要方面。

8、训练和超参数

PPO 训练通常需要比 SFT 多得多的内存,原因如下:

  • 多个策略评估 — PPO 需要同时维护当前策略(模型权重)和“旧”策略来计算它们之间的概率比。这有效地将内存中的模型参数增加了一倍。
  • 经验缓冲区——PPO 存储经验缓冲区(状态、动作、奖励等),以小批量执行更新。此缓冲区可能非常大,占用大量内存。
  • 优势估计——计算优势需要跟踪轨迹中的价值估计和回报,这又增加了一层内存开销。
  • 额外的优化目标——PPO 跟踪多个损失成分(策略损失、价值损失、熵奖励)及其梯度,而 SFT 只有一个损失。

由于上述原因,我们在可训练模型的大小和成本方面比 SFT 更受限制。虽然我可以在 Colab 中的 A100 40GB 上进行上述训练,但对于 PPO 训练,我需要更多内存。我在一台 80GB 的 H100 上进行了训练,它可以训练一个等级为 128、批处理大小为 8 的 LoRA。

我的超参数范围很窄,我选择了最直观的方法,批处理大小范围从 1 到 16,学习率从 2e-5 到 2e-4。

该模型对任务没有改进。结果的文本文件在http://asdf/

我使用权重和偏差 (WandB) 跟踪了各种训练指标。关键指标包括策略损失、价值损失、总损失、KL 散度和奖励模型的分数。

对于所有超参数运行,记录的奖励和损失随时间推移没有改善。KL 散度保持在预定义的阈值内。

9、结束语

虽然这个初步实验在音乐转录方面没有达到预期的性能,但我们为该领域的未来发展奠定了一些基础。遇到的挑战为解决这一复杂任务的技术要求和潜在方法提供了宝贵的见解。未来的工作可以探索几个有希望的方向:

  • 在更大的预训练模型可用时对其进行实验
  • 使用更多样化的音乐示例扩展训练数据集
  • 进一步细化奖励函数以捕捉更细微的音乐关系
  • 探索将传统音乐处理技术与语言模型功能相结合的混合方法

这是我使用 Qwen2-Audio 运行这些实验的笔记本!这是我的 github 链接,其中包含所有笔记本。


原文链接:Exploring Music Transcription with Multi-Modal Language Models

汇智网翻译整理,转载请标明出处