[PaperRead]Symbolic Music Genre Transfer with CycleGAN

485 阅读8分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

本文使用Cycle Gan实现了不同音乐类型的转换,在原有模型的基础上,引入了新的loss提升生成的音乐质量.

论文名称:Symbolic Music Genre Transfer with CycleGAN

作者:Gino Brunner, Yuyi Wang, Roger Wattenhofer and Sumu Zhao

Code:github.com/sumuzhao/Cy…

网络结构

image-20210615195420518

标识(嫌太麻烦可以先看2.1):

  1. 蓝线:表示从源域A目标域B再到源域A的转换
  2. 红线:表示从目标域B源域A再到目标域B的转换
  3. 黑线:指向损失函数
  4. GABG_{A\rightarrow B},GBAG_{B\rightarrow A}:表示在两个域之间转换的生成器
  5. DAD_A,DBD_B:表示两个域的判别器
  6. DA,mD_{A,m},DB,mD_{B,m}表示两个额外的判别器,其迫使生成器学习更多的高级特征
  7. xAx_A,xBx_B:表示来自源域A目标域B中的真实样本数据,同时也是网络的输入
  8. x^B\hat{x}_B:表示转换到目标域B的样本数据,记为x^B=GAB(xA)\hat x_B=G_{A\rightarrow B}(x_A)
  9. x~B\tilde{x}_B:表示转换回目标域B的样本数据,记为x~B=GAB(x^A)=GAB(GBA(xB))\tilde{x}_B=G_{A\rightarrow B}(\hat{x}_A)=G_{A\rightarrow B}(G_{B\rightarrow A}(x_B))
  10. x~A\tilde{x}_A:表示转换回源域A的样本数据,记为x~A=GBA(x^B)=GBA(GAB(xA))\tilde{x}_A=G_{B\rightarrow A}(\hat{x}_B)=G_{B\rightarrow A}(G_{A\rightarrow B}(x_A))
  11. x^A\hat{x}_A:表示转换到源域A的样本数据,记为x^A=GBA(xB)\hat{x}_A=G_{B\rightarrow A}(x_B)
  12. M:是一个包含多个域的音乐集,例如M=ABM=A\cup B,但也可能MABM\supset A\cup B
  13. xMx_M:表示来自M的样本数据

对于各种样本数据,带有^\hat{}上标表示中间输出,带有~\tilde{}上标表示最终输出

简化结构

让我们分以下几步来简化这个结构

  1. 忽略判别器,把它当作一个损失函数
  2. 只提取出其中的GABG_{A\rightarrow B},GBAG_{B\rightarrow A}

接下来,让我们仅仅针对x_A来看一下它的对抗网络之旅

  1. 首先xAx_A会输入GABG_{A\rightarrow B}得到中间输出x^B\hat{x}_B
  2. x^B\hat{x}_B会输入GBAG_{B\rightarrow A}得到最终输出x~A\tilde{x}_A

至此,我们称这是一个循环,我们会对中间输出x^B\hat{x}_BxBx_B求损失

同理,对于xBx_B,会进行一个反向的循环,即先输给GBAG_{B\rightarrow A}再输入给GABG_{A\rightarrow B},得到x^A\hat{x}_Ax~B\tilde{x}_B,同样会对x^A\hat{x}_AxAx_A求损失

此时我们得到了两个最终输出x~A\tilde{x}_A,x~B\tilde{x}_B,分别和xAx_A,xBx_B求损失( 见下循环一致损失)

生成器结构

生成器结构如下,不是很复杂

image-20210616162851000

image-20210616163005547

判别器结构

判别器的结构十分简单,激活函数替换为Leaky ReLU

image-20210616162940240

image-20210616162916705

分类器结构

分类器是作者单独提出用来分类分格迁移的音乐有没有达到效果

image-20210616163035862

image-20210616163056246

损失函数

生成器损失

总损失如下

LG=lGAB+lGBA+λLcL_G=l_{G_{A\rightarrow B}}+l_{G_{B\rightarrow A}}+\lambda L_c

其分为两个部分:对抗损失和循环一致损失

这里的λ\lambda表示循环一致损失的权重,论文中是10

对抗损失

使用L2lossL2\quad loss来作为生成器的损失

LGAB=DB(x^B)12LGBA=DA(x^A)12L_{G_{A\rightarrow B}}=||D_B(\hat{x}_B)-1||_2\\ L_{G_{B\rightarrow A}}=||D_A(\hat{x}_A)-1||_2

对于生成器,我们希望其生成的数据都被判定为真,从而欺骗判别器,因此这里减去1,1即代表着标签

循环一致损失

在此前的工作中,为了加强前后一致性,进入了一个L1normL1\quad norm作为损失项,被称为循环一致损失( cycle consistency loss)

Lc=x~AxA1+x~BxB1L_c=||\tilde{x}_A-x_A||_1+||\tilde{x}_B-x_B||_1

循环一致损失保证了输入经过两个生成器之后,即完成了一次循环,最终能被映射回自身

如果取消循环一致损失,输入与输出之间的关系将大大减弱

同时,循环一致损失也可以看做一个正则化项,它保证了生成器不忽略输入的数据,而是保留更多必要信息,以完成反向转换

判别器损失

LD,all=LD+γ(LDA,m+LDB,m)L_{D,all}=L_D+\gamma(L_{D_{A,m}}+L_{D_{B,m}})

GAN的训练是高度不平衡的,通常在早期判别器会过度强大,从而导致网络收敛到一个很差的局部最优

此外,对于风格迁移任务还存在着另一个困难:生成器需要学习源域和目标域的两种特征来欺骗判别器,然而生成器可以通过生成某种音乐类型独有的模式来欺骗判别器(我在复现的过程中也确实遇到了这种情况),这样即使判别器被欺骗了,生成器的生成也不一定是真实的。因此添加了两个额外的判别器通过学习混合域的音乐来迫使生成器学习到更优的高级特征,并且使用了约束损失(我自己这么叫的)

其中γ\gamma用来加权鉴别器的额外损失,论文中是1

为了保持训练的稳定性,同时添加了高斯噪声到判别器的输入(这应该是为了缓解判别器前期过于强大的情况)

标准判别器损失

LDA=12(DA(xA)12+DA(x^A))2)LDB=12(DB(xB)12+DB(x^B))2)L_{D_A}=\frac{1}{2}(||D_A(x_A)-1||_2+||D_A(\hat{x}_A))||_2)\\ L_{D_B}=\frac{1}{2}(||D_B(x_B)-1||_2+||D_B(\hat{x}_B))||_2)

约束损失

LDA,m=12(DA,m(xM)12+DA,m(x^A)2)LDB,m=12(DB,m(xM)12+DB,m(x^B)2)L_{D_{A,m}}=\frac{1}{2}(||D_{A,m}(x_M)-1||_2+||D_{A,m}(\hat{x}_A)||_2)\\ L_{D_{B,m}}=\frac{1}{2}(||D_{B,m}(x_M)-1||_2+||D_{B,m}(\hat{x}_B)||_2)

DB,mD_{B,m},DA,mD_{A,m}主要使用生成的假数据和多个域中的数据x_M进行训练

这有助于使生成器保持在“音乐流形”上,并生成逼真的音乐。更重要的是,它让生成器保留了许多输入结构,从而确保在转换后仍然能够识别出原始内容。

简单来说,我认为这两个判别器起到了一个约束的作用,其目的是将生成的音乐约束限制在音乐域M中,从而解决上述第二个问题

先将生成器生成约束在真实音乐的范围,再由其他判别器和损失函数增强其相应音乐风格转换的能力

数据集和处理

MIDI格式

与波形文件不同,MIDI文件不对音乐进行采样,而是将每一个音符记录为一个数字

虽然midi缺乏重现真实自然声音的能力,但是这是一种很好的将音乐离散化的方法

MIDI文件拥有note onnote off两种信号,note on消息指示一个音符开始被演奏,它还指定了该音符的速度(响度)。note off消息表示一个注释的结束。

采样策略

我们以每小节16个时间步对MIDI文件进行采样,因为绝大部分部分小节当中一个拍子的音符时值都不会低于十六分音符

我们最终的数据维度是(t,p)(t,p)ttpp分别表示采样时间步的大小和音高

同时将速度都设置为127,使他们的响度保持一致,这会使学习更简单,因为只有note onnote off两种状态

于是,数据维度也是表示为在每个时间步上包含一个p维的k-hot向量,k为同时弹奏的音,此外,MIDI的音域大于钢琴的音域,我们只取了p=84,使用连续的4个小节作为而训练数据,因此数据维度大小为(64,84)(64,84)

音轨

一首乐曲通常有很多音轨,若是忽略了伴奏会丢失很多原有的信息,因此,做了一个简单的处理:将所有音轨合并为一个音轨。

这样可以保留大部分原有信息,然而所有的不同音轨通常由不同乐器演奏,这样一来,所有音轨都会变为一种乐器演奏,生成时便会显得十分凌乱

此外,还去除了鼓的音轨,因为使用其他乐器演奏他通常很奇怪

数据处理

首先,过滤掉第一拍不以0开始的MIDI文件

然后删除掉拍号不为4/4拍或者会在中途改变的曲目

最终得到12,341个爵士、16,545个古典和20,780个流行音乐采样,每个文件包含4个小节

为了避免不同流派音乐数据的不均衡,训练时会减少大数据集的样本数,与小数据集进行匹配,如当训练爵士和古典时,从古典音乐中随即抽取12,341个文件

在预处理阶段,将数据归一化

代码复现

原论文是TensorFlow实现的,我这里使用pytorch进行了复现,想吐槽的一点就是作者论文的参数和代码写的不一样,原论文引入了Instance NormLeakyReLU,使用Adam优化器,α=0.0002\alpha = 0.0002β1=0.5\beta_1 = 0.5β2=0.999\beta_2 = 0.999Batchsize=16Batchsize=16epoch=30epoch=30

但是复现的效果不是很好,当训练次数过多时,就遇到了文中提到的问题——生成器通过生成某种音乐类型独有的模式来欺骗判别器,虽然loss已经降到了足够低,但是几乎所有风格迁移的音乐几乎都一摸一样,我训练的是古典-爵士,几乎所有迁移的音乐都是一阵沉默然后突然巨响一下,可能这就是判别器学习到的爵士音乐吧(笑)。

后来降低了训练epoch的数量,效果就好了很多,后续可以尝试提高循环一致损失和判别器约束损失的权重,可能会缓解上述问题。

复现地址如下:

github.com/Asthestarsf…