作者 | 李秋键

头图 | 下载于视觉中国

出品 | AI科技大本营(ID:rgznai100)

音乐+文字,组合食用,效果更佳。

引言:

“那些听不到音乐的人,以为跳舞的人疯了。” 尼采这句话好有趣,也告诉我们音乐对于日常生活的不可或缺之处。但是对于一般人来说,想要精通各种乐器难度较高。故今天我们来实践一个普通人可以制作的音乐项目,用深度学习的方法让计算机自动生成自己需要的音乐。完整代码见文末。

其中生成的效果如下可见:

模型建立

1.1 环境要求

本次环境使用的是python3.6.5+windows平台,主要用的库有:

Argparse库是python自带的命令行参数解析包,可以用来方便地读取命令行参数;

glob获取本地文件,在这里用来快速获取训练数据集;

Pickle用在机器学习中,可以把训练好的模型存储起来,这样在进行决策时直接将模型读出,而不需要重新训练模型,这样就大大节约了时间。它可以序列化对象并保存到磁盘中,并在需要的时候读取出来,任何对象都可以执行序列化操作。

Keras库是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras的核心数据结构是“模型”,模型是一种组织网络层的方式。Keras中主要的模型是Sequential模型,Sequential是一系列网络层按顺序构成的栈。在这里我们用它来建立BLSTM模型

1.2 数据集处理

本项目使用了音乐文件是midi文件,因为它们易于解析和学习使用midi文件给我们带来了很多好处,因为我们可以轻松地检测到音符的音高和持续时间。在本次项目中,时间步长和序列长度是网络的两个重要因素。时间步长决定了我们分析和产生每个音符的时间,而序列长度决定了我们如何学习歌曲中的模式。设定0.25秒的时间步长和每个时间步长8个音符。这对应于4/4的拍号,对我们来说意味着8个不同的序列,共4个音符。通过学习这些序列并重复它们,我们可以生成听起来像实际音乐的模式,并以此为基础进行构建。

音乐的重要组成部分是可变长度音符和休止符的动态和创造性使用。比如先是发出的长长的音符,然后是平静的停顿,可以在听我们听到演奏者的心灵倾泻而出的声音时,向听众发出一波情感。为了捕捉到这一点,引入长音符,短音符和休止符的方法,以便我们可以在整首歌曲中产生不同的情感。

(1)获取训练集所有的音符和和弦

notes = []
for file in self.songs:print("Parsing %s" % file)try:midi = converter.parse(file)except IndexError as e:print(f"Could not parse {file}")print(e)continuenotes_to_parse = Nonetry:  s2 = instrument.partitionByInstrument(midi)notes_to_parse = s2.parts[0].recurse()except: notes_to_parse = midi.flat.notesprev_offset = 0.0for element in notes_to_parse:if isinstance(element, note.Note) or isinstance(element, chord.Chord):duration = element.duration.quarterLengthif isinstance(element, note.Note):name = element.pitchelif isinstance(element, chord.Chord):name = ".".join(str(n) for n in element.normalOrder)notes.append(f"{name}${duration}")rest_notes = int((element.offset - prev_offset) / TIMESTEP - 1)for _ in range(0, rest_notes):notes.append("NULL")prev_offset = element.offset
with open("notes/" + self.model_name, "wb") as filepath:pickle.dump(notes, filepath)

1.3 神经网络处理成序列

为了建立BLSTM网络,需要将数据处理成序列形式。

def prepare_sequences(self, notes, n_vocab):# 获取所有pitch 名称pitchnames = sorted(set(item for item in notes))# 创建一个字典来映射音高到整数note_to_int = dict((note, number + 1) for number, note in enumerate(pitchnames))note_to_int["NULL"] = 0network_input = []network_output = []for i in range(0, len(notes) - SEQUENCE_LEN, 1):sequence_in = notes[i : i + SEQUENCE_LEN]sequence_out = notes[i + SEQUENCE_LEN]network_input.append([note_to_int[char] for char in sequence_in])network_output.append(note_to_int[sequence_out])n_patterns = len(network_input)network_input = numpy.reshape(network_input, (n_patterns, SEQUENCE_LEN, 1))network_input = network_input / float(n_vocab)print(network_output)network_output = np_utils.to_categorical(network_output)return (network_input, network_output)

1.4 模型网络建立

通过在歌曲中某个特定位置建立之前和之后的音符,可以生成听起来与人类相似的旋律。通常,在听音乐时,之前发生的事情可以帮助听众预测接下来的音节。很多时候我一直在听一首歌,我可以随着特定的节奏跳动,因为我可以预测接下来会发生什么。这恰恰是在增加一首歌曲时发生的情况。比如这首歌变得越来越强烈,这使听众在预期落下时会产生紧张感,并在最终击打时产生那种放松和兴奋的时刻。通过利用这一点,我们能够产生听起来自然的节奏,并产生出我们已经习惯于现代音乐中期望的相同情感。

对于BLSTM层中的节点数,我们选择512。对于激活函数,我们选择softmax。对于损失函数,我们选择交叉熵,因为它们可以很好地解决诸如音符预测之类的多类分类问题。最后,我们选择RMSprop作为优化程序,这是Keras为RNN推荐的。

def train(self, network_input, network_output):""" train the neural network """filepath = (self.model_name + "-weights-improvement-{epoch:02d}-{loss:.4f}-bigger.hdf5")checkpoint = ModelCheckpoint(filepath, monitor="loss", verbose=0, save_best_only=True, mode="min")callbacks_list = [checkpoint]self.model.fit(network_input,network_output,epochs=self.epochs,batch_size=64,callbacks=callbacks_list,)
def create_network(network_input, n_vocab):print("Input shape ", network_input.shape)print("Output shape ", n_vocab)""" create the structure of the neural network """model = Sequential()model.add(Bidirectional(LSTM(512, return_sequences=True),input_shape=(network_input.shape[1], network_input.shape[2]),))model.add(Dropout(0.3))model.add(Bidirectional(LSTM(512)))model.add(Dense(n_vocab))model.add(Activation("softmax"))model.compile(loss="categorical_crossentropy", optimizer="rmsprop")return model

音乐生成

创作音乐最重要的部分之一就是结构。我们设定结构形式如下,我们从随机音符中生成了第一节音律,然后根据第一条音律生成了第二节音律。实际上,这将生成一个两倍的长度并将其分成两半的部分。这里的思考过程是,如果我们创作一首音乐,那么第二首音乐仍应符合相同的氛围,并且通过将第一首音乐作为参考,我们可以实现这一目标。

(1)根据音符序列从神经网络中生成音符

def get_start():# pick a random sequence from the input as a starting point for the predictionstart = numpy.random.randint(0, len(network_input) - 1)pattern = network_input[start]prediction_output = []return pattern, prediction_output
# generate verse 1
verse1_pattern, verse1_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):prediction_input = numpy.reshape(verse1_pattern, (1, len(verse1_pattern), 1))prediction_input = prediction_input / float(n_vocab)prediction = model.predict(prediction_input, verbose=0)index = numpy.argmax(prediction)print("index", index)result = int_to_note[index]verse1_prediction_output.append(result)verse1_pattern.append(index)verse1_pattern = verse1_pattern[1 : len(verse1_pattern)]
# generate verse 2
verse2_pattern = verse1_pattern
verse2_prediction_output = []
for note_index in range(4 * SEQUENCE_LEN):prediction_input = numpy.reshape(verse2_pattern, (1, len(verse2_pattern), 1))prediction_input = prediction_input / float(n_vocab)prediction = model.predict(prediction_input, verbose=0)index = numpy.argmax(prediction)print("index", index)result = int_to_note[index]verse2_prediction_output.append(result)verse2_pattern.append(index)verse2_pattern = verse2_pattern[1 : len(verse2_pattern)]
# generate chorus
chorus_pattern, chorus_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):prediction_input = numpy.reshape(chorus_pattern, (1, len(chorus_pattern), 1))prediction_input = prediction_input / float(n_vocab)prediction = model.predict(prediction_input, verbose=0)index = numpy.argmax(prediction)print("index", index)result = int_to_note[index]chorus_prediction_output.append(result)chorus_pattern.append(index)chorus_pattern = chorus_pattern[1 : len(chorus_pattern)]
# generate bridge
bridge_pattern, bridge_prediction_output = get_start()
for note_index in range(4 * SEQUENCE_LEN):prediction_input = numpy.reshape(bridge_pattern, (1, len(bridge_pattern), 1))prediction_input = prediction_input / float(n_vocab)prediction = model.predict(prediction_input, verbose=0)index = numpy.argmax(prediction)print("index", index)result = int_to_note[index]bridge_prediction_output.append(result)bridge_pattern.append(index)bridge_pattern = bridge_pattern[1 : len(bridge_pattern)]
return (verse1_prediction_output+ chorus_prediction_output+ verse2_prediction_output+ chorus_prediction_output+ bridge_prediction_output+ chorus_prediction_output
)

(2)将预测输出转换为notes,并从notes创建midi文件。根据模型生成的值创建note和chord对象。

for pattern in prediction_output:if "$" in pattern:pattern, dur = pattern.split("$")if "/" in dur:a, b = dur.split("/")dur = float(a) / float(b)else:dur = float(dur)# pattern is a chordif ("." in pattern) or pattern.isdigit():notes_in_chord = pattern.split(".")notes = []for current_note in notes_in_chord:new_note = note.Note(int(current_note))new_note.storedInstrument = instrument.Piano()notes.append(new_note)new_chord = chord.Chord(notes)new_chord.offset = offsetnew_chord.duration = duration.Duration(dur)output_notes.append(new_chord)# pattern is a restelif pattern is "NULL":offset += TIMESTEP# pattern is a noteelse:new_note = note.Note(pattern)new_note.offset = offsetnew_note.storedInstrument = instrument.Piano()new_note.duration = duration.Duration(dur)output_notes.append(new_note)# 增加每次迭代的偏移量,这样笔记就不会堆积offset += TIMESTEP
midi_stream = stream.Stream(output_notes)
output_file = os.path.basename(self.weights) + ".mid"
print("output to " + output_file)
midi_stream.write("midi", fp=output_file)

源码

完整代码下载链接:

https://pan.baidu.com/s/1uPflHi1u6Vl_J_L7Q_JFaA

提取码:8n1p

作者简介:李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等。

2020-2021中国开发者调查报告重磅来袭,直接扫码或微信搜索「CSDN」公众号,后台回复关键词「开发者」,快速获取完整的报告内容!


更多精彩推荐
☞市值达 58 亿美元,吴恩达的在线教育平台 Coursera 正式上市☞英特尔第三代 Ice Lake 发布正面与 AMD EPYC PK,结果令人大跌眼镜!☞AR 第一大单,微软 219 亿美元为美军打造高科技头盔
点分享点收藏点点赞点在看

打造专属BGM,​Python 深度学习教你相关推荐

  1. Python深度学习实现DIY专属个人表情包

    引言: 在现代社交媒体的时代,表情包已经成为了人们日常生活中不可或缺的一部分.表情包可以用来表达情感.传递信息,甚至成为一种文化符号.然而,随着表情包的日益普及,大量的表情包已经不能满足人们的需求,许 ...

  2. 运用深度学习教机器人理解自然语言

    运用深度学习教机器人理解自然语言 2016-08-16 16:33 转载 CSDN 1条评论 雷锋网按:本文作者Jonathan是21CT的首席科学家.他主要研究机器学习和人工智能如何使用在文本和知识 ...

  3. 如何一夜暴富?深度学习教你预测比特币价格

    如何一夜暴富?深度学习教你预测比特币价格 2018年08月06日 17:50:00 近年来,以比特币为代表的加密数字货币一直是社交媒体和搜索引擎上的热门.但是,比特币价格浮动也使各位看官们经历了过山车 ...

  4. 《Python深度学习从零开始学》简介

    #好书推荐##好书奇遇季#深度学习入门书<Python深度学习从零开始学>,京东当当天猫都有发售.从模型和实验入手,快速掌握深度学习技术. 业内大咖强力推荐!!!武汉大学信息管理学院教授 ...

  5. Python深度学习篇

    Python深度学习篇一<什么是深度学习> Excerpt 在过去的几年里,人工智能(AI)一直是媒体大肆炒作的热点话题.机器学习.深度学习 和人工智能都出现在不计其数的文章中,而这些文章 ...

  6. 5700刀打造3卡1080Ti深度学习机器

    北京 上海巡回站 | NVIDIA DLI深度学习培训 2018年1月26/1月12日 NVIDIA 深度学习学院 带你快速进入火热的DL领域 阅读全文                        ...

  7. Python深度学习:基于TensorFlow

    作者:吴茂贵,王冬,李涛,杨本法 出版社:机械工业出版社 品牌:机工出版 出版时间:2018-10-01 Python深度学习:基于TensorFlow

  8. Python深度学习:基于PyTorch [Deep Learning with Python and PyTorch]

    作者:吴茂贵,郁明敏,杨本法,李涛,张粤磊 著 出版社:机械工业出版社 品牌:机工出版 出版时间:2019-11-01 Python深度学习:基于PyTorch [Deep Learning with ...

  9. python神经结构二层_《python深度学习》笔记---8.3、神经风格迁移

    <python深度学习>笔记---8.3.神经风格迁移 一.总结 一句话总结: 神经风格迁移是指将参考图像的风格应用于目标图像,同时保留目标图像的内容. 1."神经风格迁移是指将 ...

最新文章

  1. 《搜索引擎-信息检索实践》7.2.1 分类应用与检索/BM25检索模型
  2. DIY走向高端化:用料成为比拼焦点
  3. springcloud 服务与服务之间实现灰度发布 基于Aspect
  4. JSONP的诞生、原理及应用实例
  5. 构建前端自动化工作流环境
  6. 扩展方法略好于帮助方法
  7. Flask-第二课:路由
  8. 使用 Preload/Prefetch 优化
  9. java 线程协作 wait(等待)与 notiy(通知)
  10. Silverlight中Shape,Geometry
  11. WPS安装office自定义项安装期间出错
  12. 记一次刷路由器固件的经历
  13. operate new、delete new和placement new
  14. 迷你计算机可玩游戏,e客迷你电脑能玩什么游戏
  15. 关于pc端微信登录前后端分离的java后台开发
  16. 苹果发布“合二为一”芯片,华为公布“芯片叠加”的专利
  17. 【知识科普】解读闪电/雷电网络,零基础秒懂!
  18. 三只松鼠股东大撤退幕后
  19. java学习路线 Java学习路线
  20. 文件新旧判断和字符串判断

热门文章

  1. Hystrix 超时配置重写
  2. AI时代:推荐引擎正在塑造人类
  3. 第 7 章 项目运作
  4. Centos 6.4下MySQL备份及还原详情介绍
  5. 新技术、新思维开创公共安全管理新模式
  6. python3正则表达式符号和用法
  7. 自定义classloader中的接口调用
  8. CSSA email list
  9. 关于接口使用抛异常还是返回错误码,下列哪些说法符合《阿里巴巴Java开发手册》
  10. 计算机语言学教程,《语言学教程》-中文笔记(完整).doc