基于深度学习⽣成⾳乐(mid格式的⾳乐)附代码,⾃⼰调试
过,python3的
代码链接:
之前在看Andrew Ng 的deep learning 视频教程,在RNN 这⼀节的课后作业⾥,实现了⼀个基于的music generator,实验之后发现产⽣的结果还有模有样的,这激发了我的兴趣,于是我就查阅了⼀些资料,看看⾳乐的⾃动⽣成⽅⾯最近有哪些进展,特别是深度学习在这⼀块的应⽤.在这⾥稍微总结⼀下,并且写⼀写⼀些有趣的应⽤.
---------------------------------------------------- Part I : deep jazz 的简单介绍-------------------------------------------------------------
1.What is deepjazz?
以下内容搬运⾃deepjazz的:
deepjazz 是⼀个使⽤theano 和keras的基于深度学习的jazz music ⽣成器.我在编程马拉松(hackathon)使⽤36个⼩时创建了deepjazz.它使⽤了theano和keras这两个库来⽣成jazz music.具体地说,它构建了两
层的LSTM,从midi files 中学习.它使⽤了深度学习技术,以及AI技术,这个技术创造了著名的google AlphaGo和IBM的Watson,来产⽣⾳乐.⽽⾳乐被认为是⾮常human的.
2.怎样使⽤deepjazz?
2.1 训练模型并产⽣midi⽂件
继续运⾏,还是由于兼容性的问题,仍然会报错:
"melody_voice.insert(0, key.KeySignature(sharps=1,mode='major'))TypeError: init() got an unexpected keyword argument
'mode'
这⾥我们只需要将mode = 'major'移除就可以了,后⾯还需要将generator.py中的 _sample 函数修改为:
def __sample(a, temperature=1.0):
a = np.log(a) / temperature
# a = np.exp(a) / np.p(a))
# return np.argmax(np.random.multinomial(1, a, 1))
dist = np.exp(a)/np.p(a))
choices = range(len(a))
return np.random.choice(choices, p=dist)
做了如上的修改之后,再运⾏python generator.py 应该就可以正常run起来了,运⾏结束之后,在midi ⽂件夹下,会多出⼀个
deepjazz_128_epochs.midi ⽂件,这个就是我们通过 original_metheny.mid 训练学习得到的⽣成⽂件了.需要注意的是,⽆论我们训练还是⽣成的都不是常见的.mp3,.wav格式的⾳频⽂件,⽽是.mid(或者.midi)格式的⽂件.那么这两者有什么区别呢?这⾥引⽤百度百科的定义简单说明⼀下:
与波形⽂件不同,MIDI⽂件不对⾳乐进⾏抽样,⽽是对⾳乐的每个⾳符记录为⼀个数字,所以与波形⽂件相⽐⽂件要⼩得多,可以满⾜长时间⾳乐的需要。MIDI标准规定了各种⾳调的混合及发⾳,通过输出装置可以将这些数字重新合成为⾳乐。
MIDI⾳乐的主要限制是它缺乏重现真实⾃然声⾳的能⼒,因此不能⽤在需要语⾳的场合。此外,MIDI只能记录标准所规定的有限种乐器的组合,⽽且回放质量受到声⾳卡的合成芯⽚的限制。近年来,国外流⾏的声⾳卡普遍采⽤波表法进⾏⾳乐合成,使MIDI的⾳乐质量⼤⼤提⾼。
MIDI⽂件有⼏个变通格式,如RMI和CIF等。其中CMF⽂件(creative music format)是随声霸卡⼀起使⽤的⾳乐⽂件。RMI⽂件是Windows使⽤的RIFF(resource interchange file format)⽂件的⼀种⼦格式,称为RMID,即包含MIDI⽂件的格式。
简单来说就是:常见的.mp3,.wav格式的⽂件记录的都是真实的⾳频内容,因此⼀般体积会⽐较⼤(⼏兆到⼏⼗兆不等),⽽midi格式的⽂件没有记录真实的⾳频信息,它只是记录了⼀种代表格式的数字,计算机可以按照⼀定的标准识别出这种数字,然后把它转化为对应的⾳频播放出来.因此⼀般.midi格式的⽂件体积⾮常⼩,这是它的⼀个很⼤的优点,其缺点就是对于真实的声⾳还原较差(因为它只能通过有限种指定的乐器来模拟声⾳).
2.2 如何播放midi⽂件?
⾔归正传,在得到⽣成的midi⽂件之后,我们当然需要播放它好好欣赏⼀番啦.在windows下有不少软件可以播放midi格式的⽂件,但是我使⽤的系统是ubuntu16.04,默认的播放器不⽀持midi格式,在查阅了资料以后发现需要安装timidity,在ubuntu 下
直接sudo apt-get install timidity 即可.我找了⼀个python脚本play_midi.py(基于pygame),可以播放midi ⽂件,代码如下:
import pygame
import pygame as pg
def play_music(music_file):
'''
stream music with mixer.music module in blocking manner
this will stream the sound from disk while playing
'''
clock = pg.time.Clock()
try:
pg.mixer.music.load(music_file)
print("Music file {} loaded!".format(music_file))
:
print("File {} not found! {}".format(music_file, pg.get_error()))
return
pg.mixer.music.play()
# check if playback has finished
while pg._busy():
clock.tick(30)
# pick a midi or MP3 music file you have in the working folder
# or give full pathname
music_file = input("Please input the midi file path:")
#music_file = "Drumtrack.mp3"
freq = 44100  # audio CD quality
bitsize = -16  # unsigned 16 bit
channels = 2  # 1 is mono, 2 is stereo
buffer = 2048  # number of samples (experiment to get right sound)
pg.mixer.init(freq, bitsize, channels, buffer)
# optional volume 0 to 1.0
pg.mixer.music.set_volume(0.8)
try:
play_music(music_file)
except KeyboardInterrupt:
# if user hits Ctrl/C then exit
# (works only in console mode)
pg.mixer.music.fadeout(1000)
pg.mixer.music.stop()
raise SystemExit
运⾏python play_midi.py ,然后输⼊midi⽂件的路径,就可以播放啦.试着播放我们⽣成的midi⽂件,你会发现听起来是相当不错的!
当然其实安装了timidity之后,我们就可以直接播放midi⽂件了,直接运⾏ timidity xxx.midi 就可以了.但是有可能会出问题,因为我们还需要⼀些额外的配置⽂件,运⾏命令'sudo apt-get install fluid-soundfont-gm fluid-soundfont-gs' 安装好soundfont(声⾳字体,⽤于解析midi,并且播放),然后打开/etc/timidity/timidity.cfg ⽂件,将最后⼀⾏'source freepats.cfg' 注释掉,如果是ubuntu系统的话改为: dir /usr/share/sounds/sf2/
soundfont FluidR3_GM.sf2
如果是centos系统的话改为:
dir /usr/share/soundfonts/
soundfont FluidR3_GM.sf2
然后重启timidity,执⾏命令:sudo /etc/init.d/timidity restart
这样我们再执⾏timidity xxx.midi应该就可以正常播放啦!
2.3 如何将midi⽂件转化为⼀般的⾳频⽂件(mp3,wav等格式)
现在我们可以正常播放midi⽂件了.但是还有⼀个问题,⼀般我们使⽤的⾳频格式是wav,mp3这种格式的,因为它们更易于被⼀般的播放器识别并且播放.那么有没有上⾯办法可以将midi⽂件转化为这样的格式呢?当然是有办法的,最简单的办法就是使⽤timidity(之前我们已经安装过啦),运⾏下⾯的命令:
timidity --output-24bit --output-mono -A120 source.mid -Ow -o source.wav
就可以把source.mid 转化为source.wav 了.其中 --output指定输出的格式,-A指定⾳量(volume),-Ow
表⽰转化为RIFF WAVE file输出格式,-o指定输出⾳频⽂件的名字,具体可以timidity --help 查看各个参数的含义.
如果没有问题的话,我们就得到⼀个.wav⽂件啦,这样你使⽤任何⼀个⾳乐播放器都可以播放它啦!
顺便提⼀个⼩问题.wav⽂件⼀般体积⽐较⼤(质量较好),⽽在⽹络上更常见的是mp3⽂件,那么这两者该如何转化呢?这⾥我提供两种解决办法:
1.使⽤ffmpeg 这个⾳视频库来进⾏转化.运⾏命令
ffmpeg -i source.wav -acodec libmp3lame source.mp3
就可以将source.wav 转化为source.mp3了.这⾥ -i 表⽰输⼊⾳频,-acodec 表⽰设置 audio codec(⾳频编码)格式,是"-codec:a"的别名,更多的信息可以输⼊ ffmpeg --help 或者 man ffmpeg查看
2.也可以安装python的⾳频库pydub进⾏转化,这个我在之前的博客介绍过,有兴趣可以⾃⾏查看.
如何将wav,mp3⽂件转化为midi⽂件?
这个问题我⼀开始以为是挺容易实现的⼀个任务,哪知道查了资料以后才发现是⼀个很hard的问题,
⽬前仍然有很多⼈研究music transcription(⾳乐转换)的问题.我没有找到⼀个很好地解决这个问题的api,具体可以参看stackoverflow的这个,⽬前也有很多的plugin可以做这个事情,⽐如Sonic Annotator等,但是就涉及到很专业的知识了,我想了⼀个还是放弃了...总之如果要做批量的从wav,mp3到midi的转化还是很困难的,特别是要求⽐较⾼的质量的话,如果有兴趣,⼤家可以⾃⾏研究了.但是如果不要求⼤规模的⾃动转换,还是有不少软件可以完成wav(mp3)到midi的转化的,⽐如这个可以在线将mp3转换为midi格式.
如何训练⾃⼰的midi⽂件?
之前我们是拿作者给的⼀个original_metheny.mid⽂件进⾏训练然后⽣成mid⽂件的.那么我们可以拿⾃⼰的mid⽂件进⾏训练吗?这⾥有⼀个可以打包下载很多的midi⽂件,或者访问这个可以下载⾃⼰喜欢的流⾏⾳乐的midi格式.我们发现我们下载的midi⽂件的
format,tracks,divisions都和deepjazz作者提供的original_metheny.mid格式不同,所以如果只是把mid⽂件换成我们⾃⼰的是没有办法顺利train的,总是会报错.我⼤概看了⼀下代码,主要是使⽤music21处理midi格式转换的代码部分有问题.我尝试了半天,因为⾃⼰对于music21以及midi格式不是很熟悉,所以这个问题暂时没有解决.如果我后⾯有时间了会好好再分析⼀下deepjazz的源码,解决这个问题.
-
--------------------------------------------------------------------------Part II magenta ---------------------------------------------------------------
1.What is magenta?
下⾯是的介绍.
magenta是⼀个旨在探索使⽤机器学习来创造艺术和⾳乐的研究项⽬.⽬前它主要使⽤新兴的深度学习技术以及强化学习技术来产⽣歌曲,绘画,图⽚等等.同时它也旨在探索构建智能化的⼯具和接⼝,这样艺术家可以使⽤这些模型来扩展(⽽不是取代)他们的部分⼯作.
magenta最初是由Google Brain 的⼀些研究员发起的,但是其他的很多研究⼈员也为这个项⽬做出了巨⼤的贡献.我们使⽤
tensorflow在github上发布我们的模型和代码.如果你想要了解更多关于magenta的事情,你可以查看我们的,我们在那⾥介绍了很多技术上的细节.你也可以加⼊.
2.How to install magenta and use it?
安装magenta⾮常简单,可以直接使⽤pip install magenta 安装,但是要注意在此之前你需要安装好了tensorflow.
magenta⽀持gpu加速(你只需要安装gpu版本的tensorflow),使⽤pip install magenta-gpu 安装即可.magenta其实提供了⾮常多的,包含了语⾳,图⽚等.这⾥我们主要关注⾳乐⽣成⽅⾯的模型.
2.1 drums_rnn model
这是⼀个训练得到drums 风格⾳乐的.这个模型使⽤了LSTM将语⾔模型应⽤在drum track ⽣成上.和melodies不⼀样,drum tracks是多⾳的,多个drums可能会同时存在.尽管这样,我们还是通过以下⼿段将drum track 作为⼀个single sequence 来处理:
a)将所有不同的midi drums 映射到⼀个更⼩的drum classes上去
b)将每⼀个event表达为⼀个单⼀值,该值代表了该次struck(敲击)所属的drums classes 类别
这⾥model 提供了两个configurations:one drum 和drum kit.具体可以参考原⽹址的说明
下⾯来说明如何训练drums_rnn model.magenta其实已经提供了pre trained model,我们可以⾸先快速来inference⼀下.⾸先下载⽂件,然后将下载的drum_kit_rnn.mag⽂件放⼊某⼀个⽂件夹下(⽐如model/下).然后我们写⼀个脚本generate_drums_rnn.sh:
#!/bin/bash
drums_rnn_generate \
--config='drum_kit' \
--bundle_file=../data/drum_kit_rnn.mag \
--output_dir=../output \
--num_outputs=5 \
--num_steps=256 \
--primer_drums="[(36,)]"
这⾥ --config 是配置 configuration,有'drum_kit'和'one_drum'两个选项
--bundle_file 指定我们bundle file的地址(就是刚才下载的drum_kit_rnn.mag⽂件)
--output_dir 指定输出midi⽂件的地址
--num_outputs 指定输出midi⽂件的个数(默认是10个)
-
-num_steps 指定训练的epochs(训练轮数)
--primer_drums 指定开始的⼀些⾳节(必填)
上⾯的脚本会以⼀个bass drum hit(低⾳)开始,如果你愿意的话,你也可以使⽤其他的字符串形式的python list,但是list中的元素必须是⼀个tuple,⽽且必须要是代表drum 的midi ⾳节的整数.⽐如说:--primer_drums="[(36, 42), (), (42,)]"表⽰的意思就是⼀个bass 和⼀个hit-hat,然后是⼀个silence,最后是⼀个hit-hat.如果你不使⽤--primer_drums参数,你也可以使⽤--primer_midi参数,来使⽤⼀个drum midi ⽂件来作为primer(开头).
如果按照上⾯的⽅式来进⾏尝试的话,你会得到⼀些midi⽂件.然后播放它吧,有些还是相当不错的!
上⾯我们使⽤了pre trained model,然后可以直接得到⽣成的midi⽂件,那么该如何来训练⾃⼰的model呢?训练⾃⼰的model有些复杂,我们可以按照如下的steps 进⾏操作:
step1:build your dataset
⾸先我们需要准备⾃⼰的midi datasets,可以在这个打包下载,或者在这个⾃⼰⼿动下载,然后我们需要将这些midi files 转化为NoteSequences.使⽤如下的脚本convert_midi.sh进⾏转换:
#!/bin/bash
convert_dir_to_note_sequences \
--input_dir=$INPUT_DIRECTORY \
--output_file=$SEQUENCES_TFRECORD \
--recursive
上⾯的参数:
--input_dir表⽰输⼊midi files 的⽂件夹地址(可以包含⼦⽂件夹)
--output_file 表⽰输出.tfrecord⽂件的地址
--recursive 表⽰递归遍历midi files
注意如果你使⽤的是前⼀个midi datasets的话,由于这个数据集⾮常⼤(有1.6G左右),包含了⾮常多的midi⽂件,所以训练起来可能会⾮常耗时,我⼤概训练了两个⼩时还没训练完最后提前终⽌了,当然如果你的计算机性能⾮常好,你也可以尝试训练完.
训练完之后,我们会得到⼀个lmd_matched_notesequences.tfrecord⽂件.接下来进⼊step2
step2:
注意我们输⼊模型进⾏训练和评估的是SequenceExamples.每⼀个SequenceExample都会包含⼀个序列输⼊和⼀个序列标签,代表了⼀个drum track.可以运⾏下⾯的命令将之前得到的NoteSequences 转化为SequenceExamples.这样将会产⽣两个部分的SequenceExamples,⼀个⽤于training,⼀个⽤于evaluation.具体可以使⽤--eval_ratio来指定两者的⽐例.⽐如指定eval_ratio = 0.1(或者10%),会将提取出的drums tracks 的10%⽤于evaluation,剩下的90%⽤于training.
drums_rnn_create_dataset \
--config=<one of 'one_drum' or 'drum_kit'> \
--input=/tmp/notesequences.tfrecord \
--output_dir=/tmp/drums_rnn/sequence_examples \
--eval_ratio=0.10
上⾯的参数中:
--config 只能取值为'one_drum'或者'drum_kit'
--input 为step1得到的tfrecord⽂件地址
--output_dir 为输出SequenceExamples的⽂件夹地址
--eval_ratio 指定evaluation 和training的⽐例
step3:train and evaluate the model
运⾏下⾯的代码(train.sh)就可以进⾏train了.
#!/bin/bash
drums_rnn_train \
--config=drum_kit \
--run_dir=/tmp/drums_rnn/logdir/run1 \
--sequence_example_file=/tmp/drums_rnn/sequence_examples/training_drum_tracks.tfrecord \
--hparams="batch_size=64,rnn_layer_sizes=[64,64]}" \
-
-num_training_steps=20000
各个参数的含义如下:
--config:'one_drum' or 'drum_kit'
--run_dir 是运⾏tensorflow训练模型checkpoints存放的⽂件夹地址
--sequence_example_file是⽤于训练模型的SequenceExamples tfrecord⽂件地址
--num_training_steps 指定训练的steps(轮数),如果不指定的话,会⼀直运⾏直到⼿动终⽌(CTRL-C或者CTRL-Z)
--hparams ⽤于指定其他的超参数,⽐如这⾥我们指定了batch_size = 64,⽽不是默认的128.使⽤更⼩的batch size 有助于降低OOM(内存溢出)的风险,当然,如果你的内存够⼤,也可以设置较⼤的batch_size.这⾥还设定使⽤2 layers的RNN,每⼀个layer 的hidden units都是64,⽽不是默认的3 layers,每个layer有256个hidden units.这样可以加速训练(当然损失了⼀定的精度),如果你的计算机性能很⾼,你可以尝试更⼤的hidden units以获得更好的结果.我们还可以设定--attn_length 参数来指定多少个steps进⾏⼀次attention machanism.这⾥我们使⽤的是默认值32.
运⾏下⾯的代码(eval.sh)就可以进⾏evaluation.
!/bin/bash
drums_rnn_train \
--config=drum_kit \
--run_dir=/tmp/drums_rnn/logdir/run1 \
--sequence_example_file=/tmp/drums_rnn/sequence_examples/eval_drum_tracks.tfrecord \
--hparams="batch_size=64,rnn_layer_sizes=[64,64]" \
--num_training_steps=20000 \
--eval
step4:generate drum tracks
完成了step1~step3之后我们就可以来产⽣⾃⼰的midi ⽂件了.运⾏的脚本为:

更多推荐

格式,训练,播放