音乐生成文本

前言

今天给大家介绍一篇音乐生成文本的paper,具体的是生成描述当前这个音乐的文本,同时还可以学一下其中作者设计的一个对比学习,笔者也贴了一下自己对其基本的代码实现,感兴趣的小伙伴可以收藏一下~

论文链接:https://arxiv.org/pdf/2210.00434.pdf

硬广

哈哈,在开始之前,如果有小伙伴对多模态感兴趣,笔者之前也写过几篇,大家感兴趣也可以看看,不过都是关于图文的:

https://zhuanlan.zhihu.com/p/435697429

https://zhuanlan.zhihu.com/p/453581899

https://zhuanlan.zhihu.com/p/454314421

https://zhuanlan.zhihu.com/p/570332906

数据集

为啥要做这个任务呢?作者也是给了一些case如下:

alt

可以看到这里列出了两首乐章,以往的工作基本上都是对音乐进行分类,比如上图中的Tags,两首乐章的Tags是相同的,但是实际上两首乐章的风格其实有比较大的区别的,一首是比较优美的(peaceful, and extraordinarily beautiful treatment),而另外一首是比较悲伤的(sadness and loss),为此作者认为有必要做这项研究。

由于这个任务比较新,之前没有相关的工作做过,也就没有相关的公开标注数据集拿来训练,于是作者第一步就是需要构建数据集。

其实最主要的就是构建music-text pairs,作者选择爬取数据的网站是:https://www.earsense.org/,数据集中的95%的音乐时长是2.5min到14min不等,对应的描述性文本长度是14到192不等,最后共收集到了2380个文本,其中1955个有对应的音乐。

模型

可以看到这个任务其实是一个跨模态生成任务:

alt

具体做的都也很常规,不过值得看一下的是paper中说的一个对比学习: Group Topology-Preservation Loss (GTP Loss)。

首先需要encoder和对应的decoder来分别对music和text提取特征和重建,具体的作者分别选用的是CNN和transformer。

所以各个模态编码解码对应两个loss如下,公式(1)是音频模态,公式(2)是文本模态:

alt
alt

接下来就是一个跨模态对齐loss:

alt

可以看到也很简单,就是直接加一层MLP映射,然后求L2距离即可。

说完了上面常见的,作者重点讲述了一下自己提出的创新点即paper中所说的的GTP Loss:

alt

作者讲了很多理论和故事来阐述这个设计,这里笔者不想按部就班的讲作者的故事,而是通过一个例子来阐述一下:

假设当前batch=4,那么对应的输入数据中文本假设是[a,b,c,d],音乐是[e,f,g,h],也就是说文本a是音乐e的描述性语言,同理b和f、c和g、d和h分别是对应的pair。

假设a和b、c、d相似度(sfotmax后的)分别是0.2、0.6、0.2;假设e和f、g、h相似度(sfotmax后的)分别是0.1、0.7、0.3

好,到这里最重要的一个对比学习思想来了:

a和b、c、d相似度分布应该尽可能与e和f、g、h相似度相似,换句话说:[0.2、0.6、0.2]和[0.1、0.7、0.3]尽可能的相似。

同理b和a、c、d相似度分布应该尽可能与f和e、g、h相似度相似,以此类推。

看到这里相信大家也比较明白了,其实就是个对比学习,不过相比于作者设计的这个对比学习,还有一个设计方式其实更容易想到,那就是:

a和e的相似度要大于a和f、g、h相似度,同理b和f的相似度要大于b和e、g、h相似度。

同时作者这里也借鉴目前对比学习的代码,分别实现一下上述两个对比学习loss(pytorch版本的),大家有兴趣也可以在自己的工作中加个对比学习loss试一下

wai_user_embedding和nei_user_embedding可以看成是两个模态的emb(对应到本篇就是音乐和文本的表征),维度都是[batch, hidden_size],这里笔者在量化分布相似的时候用的是KL散度,没用作者所说的L2,大家都可以改着试试。

def GroupTopologyPreservationLoss(self, wai_user_embedding, nei_user_embedding):
  wai_user_embedding_similarity = F.cosine_similarity(wai_user_embedding.unsqueeze(1), wai_user_embedding.unsqueeze(0), dim=-1)
  nei_user_embedding_similarity = F.cosine_similarity(nei_user_embedding.unsqueeze(1), nei_user_embedding.unsqueeze(0), dim=-1)
  n = wai_user_embedding_similarity.size()[0]
  wai_user_embedding_similarity = wai_user_embedding_similarity.flatten()[:-1].view(n-1,n+1)[:,1:].flatten().view(n, n-1)
  nei_user_embedding_similarity = nei_user_embedding_similarity.flatten()[:-1].view(n-1,n+1)[:,1:].flatten().view(n, n-1)
  kl_wai_nei = F.kl_div(F.log_softmax(wai_user_embedding_similarity, dim=-1), F.softmax(nei_user_embedding_similarity, dim=-1), reduction='sum')
  kl_nei_wai = F.kl_div(F.log_softmax(nei_user_embedding_similarity, dim=-1), F.softmax(wai_user_embedding_similarity, dim=-1), reduction='sum')
  loss = (kl_wai_nei+kl_nei_wai)/2
  return loss

另外一种就是笔者所说的第二种常见的,大家可以看一下这里https://blog.csdn.net/weixin_44966641/article/details/120382198

不过需要说明的是,上述链接中预先定义了一个negatives_mask buff,其大小是固定的,但是有的时候我们的代码在跑的时候,最后一个batch有可能不够预设的大小即我们的样本总数是102,每个batch假设是25,那么最后一个batch其实是2,这个时候在用这个negatives_mask buff计算loss的时候就会出错,那怎么办呢?很简单我们多加两行代码:

def contrastiveLoss(self, emb_i, emb_j):
  temp_batch_size = emb_i.size()[0]
  negatives_mask = self.negatives_mask[:temp_batch_size*2, :temp_batch_size*2]
  ...

可以看到是为了适配当前传进来embedding的大小。

看到这里,笔者就再多说一句吧,有的时候我们处理的不是多模态,假设是文本和文本之间的对比学习,最后我们还是想得到类似emb_i, emb_j两个矩阵来进行对比学习,那这两个emb怎么得到呢?要过两次模型(比如bert模型)吗?其实很简单,只需要在bert模型输入的时候将两部分样本进行cat成一批,然后输进去,在输出的时候再按顺序拿到对应的emb即可,只不过为了加对比学习,总体可跑的batch可能就要减半了。

总结

(1)今天给大家介绍了一个很好玩的研究方向,其实还可以反过来,根据文本生成bgm,这个感觉更有意思。

(2)介绍了点对比学习和代码,希望对大家有用。

关注

欢迎关注,下期再见啦~

知乎csdngithub微信公众号

本文由 mdnice 多平台发布

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,你可以将旋律编写为MIDI文件格式,以便可以导入到各种音乐软件中进行编辑和制作。 以下是将上面生成的旋律转换为MIDI文件的示例代码,使用Python的`mido`库来生成MIDI文件: ```python import mido # 定义旋律和其他MIDI相关的参数 tempo = 120 note_duration = 0.5 velocity = 64 # 将旋律转换为MIDI消息列表 notes = [("note_on", 60, velocity), ("note_on", 62, velocity), ("note_on", 64, velocity), ("note_on", 65, velocity), ("note_on", 67, velocity), ("note_on", 69, velocity), ("note_on", 71, velocity), ("note_on", 72, velocity), ("note_on", 71, velocity), ("note_on", 69, velocity), ("note_on", 67, velocity), ("note_on", 65, velocity), ("note_on", 64, velocity), ("note_on", 62, velocity)] # 创建一个MIDI文件 mid = mido.MidiFile() track = mido.MidiTrack() # 添加MIDI元信息,包括文件格式、时间分辨率和曲速 mid.type = 1 mid.ticks_per_beat = 480 track.append(mido.MetaMessage('set_tempo', tempo=mido.bpm2tempo(tempo), time=0)) # 将MIDI消息添加到轨道中 time = 0 for msg in notes: note_type, note_number, velocity = msg track.append(mido.Message(note_type, note=note_number, velocity=velocity, time=int(time))) time += int(mid.ticks_per_beat * note_duration) # 将轨道添加到MIDI文件中并保存 mid.tracks.append(track) mid.save('my_melody.mid') ``` 这将创建一个名为"my_melody.mid"的MIDI文件,其中包含上述旋律。然后,您可以将该MIDI文件导入到音乐制作软件中,例如Ableton Live或Logic Pro,并使用该软件进一步编辑和处理旋律。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值