【Day19】 用 4 种不同的 GAN 模型生成音乐简介

前言

  • 接下来的时间我们会试着用 4 种不同的 GAN 模型来生成音乐。
  • 更改的部分只有 Generator 与 Discriminator,训练方法与 loss 都与 Dcgan 一样。
  • 最後我们期待给这个模型一段意义不明的噪音,它就会生成可以听出旋律的钢琴音乐。

参赛者 1 号:WavenetGan

  • 就是把我们在第 7 天写的 wavenet 当成 Generator,Discriminator 维持跟 Dcgan 一样。

参赛者 2 : BidirectionalLSTMGAN

  • 受到 kaggle 上这篇文章的启发,用大量的 BidirectionalLSTM 当 Generator 跟Discriminator,缺点是训练非常久,但是效果没有话说的好。

参赛者 3 : WaveGan

  • WaveGan 是 Base On DCGAN 的模型,但他改了几个操作:
  1. 把 Transpose Convolution 2D 变成 1D
  2. Kernel size 5X5 to 25, strides from 2X2 to 4 拓展 respective filed
  3. Remove BatchNormalization from DCGAN,这是他们意外发现,也不知道原理是什麽XD
  4. 训练的时候用 WGAN-GP 的方式,也有用 WGAN 的版本,但这里我们想要方便比较所以通通固定是 Dcgan 的训练方式
  • WaveGan 的原始作者用这个网路模型成功的直接从 wave 生成出鼓声跟钢琴声( 意思是它训练时候的输入就是 raw waveform),虽然生成的都只有短短的 1 ~ 2 秒,但也许它在 MIDI 上表现可以更好?

参赛者 4 : TransformerGAN

  • 因为 BidirectionalLSTMGAN 的效果还不错但训练时间惊人,因此在想要降低训练成本的时候接触了 Transformer,但这东西感觉不先花点时间研究,写起来跟前面 3 个的模型难度上有着天壤之别(小弟资质愚鲁,到现在也是一知半解,但我会尽力解释的),结论是它确实大大加速了训练时间,结果也不错。

资料准备

里头包含了 2004 ~ 2018 他们蒐集到的资料,全都是 MIDI 档,你可以随意选你想用的音乐,我这边自己挑了 1281 首,处理的时候,我们不管 control change,只在乎 note_on (照理说应该要加 control change 下去训练,但这样处理资料变很麻烦,那时候又有时间压力所以就没又加了XD,改成最後生成的时候随机添加)。

paths = []
songs = []
#append every filepath in your_music_folder folder to paths[]
for r, d, f in os.walk("./your_music_folder"):
    for file in f:
        if '.mid' in file:
            paths.append(os.path.join(r, file))

#for each path in the array, create a Mido object and append it to songs
for path in paths:
    mid = MidiFile(path, type = 1)
    songs.append(mid)
del paths


from math import sqrt
seq_len = 256
gen_len = int(sqrt(seq_len))

notes = []
dataset = []
chunk = []

# for each in midi object in list of songs
for i in range(len(songs)):
    for msg in songs[i]:
        # filtering out meta messages
        if not msg.is_meta:
        # filtering out control changes
            if (msg.type == 'note_on'):
                notes.append(msg.note)
    for j in range(1, len(notes)):
        chunk.append(notes[j])
        #save each 16 note chunk
        if (j % seq_len == 0):
            dataset.append(chunk)
            chunk = []
    print(f"Processing {i} Song")
    chunk = []
    notes = []

del chunk
del notes
train_data = np.array(dataset)
np.save("preprocess_data.npz",train_data)

小结

到此,资料前处理的部分就完结了,明天就可以拿这个来训练了!

/images/emoticon/emoticon09.gif/images/emoticon/emoticon13.gif/images/emoticon/emoticon14.gif/images/emoticon/emoticon22.gif/images/emoticon/emoticon28.gif


<<:  【Day 04】String Methods

>>:  Day-8 Divide-and-Conquer-3 : 二分搜寻法, 费波那契数列, Strassen’s演算法

Day09:Swift 基础语法— Optional

前言 当我们处理来自外部数据源的数据时, 可能会遇到空的数据的情况。 我们需要一种方法表达一种可以为...

变更管理(Change Management)

基线的变更(任何正式批准的变更)均应进行管理。如果选定的安全控制未得到批准,未批准或未设定基线,则无...

[ Day16] Esp32s用AP mode + Relay - (程序码讲解)

1.前言 今天依旧接续之前没讲完程序码,这次主要是讲loop里面的程序码,那此次主要介绍较为主要的部...

Day 14:RecyclerView 进阶项目布局

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

Prometheus 与 Spring boot

说到 Prometheus 不得提到监控,Prometheus能帮助我们指标数据采集、指标数据储存、...