打造专属BGM,Python 深度学习教你
作者 | 李秋键
头图 | 下载于视觉中国
出品 | 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 亿美元为美军打造高科技头盔
点分享点收藏点点赞点在看
相关文章:

XML 特殊字符处理和 CDATA
在处理XML数据时,特殊字符要特殊处理,不能和节点字符混淆。 所有 XML 文档中的文本均会被解析器解析。 只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。 PCDATA PCDATA 指的是被解析的字符数据(Parsed Charac…

zookeeper集群环境搭建
2019独角兽企业重金招聘Python工程师标准>>> 至少3台zookeeper:第一台:con/zoo.cfgtickTime2000 initLimit10 syncLimit5 dataDirC:\\Users\\Administrator\\Desktop\\Zookeepers\\zookeeper-3.4.6.1\\data dataLogDirC:\\Users\\Administrator\\Desktop\\Zookeeper…

ASP.NET遍历配置文件的连接字符串
在ASP.NET 2.0中,提供了更方便的配置文件访问的类,具体可以到 System.Configuration 名称空间下进行查看。本文提供一种在开发过程中常用的得到数据库字符串的方法,为方便使用,写成一个方法进行调用: public string Ge…

#define WIN32_LEAN_AND_MEAN 的作用
[转]#define WIN32_LEAN_AND_MEAN 的作用 今天看了用mysql的库vc连接数据库,结果我用mfc application向导建立一个工程,然后添加#include "mysql.h"(已经设置好了环境),编译出现了一大堆错误,如下 Compiling...StdAfx.cppc:mysqlincludemysql_com.h(116) : error C21…

《头号玩家》中的“绿洲”,用 VR 可以找到
图源:百度百科出品 | AI科技大本营(ID:rgznai100)2045年,现实世界令人失望,人们将救赎的希望寄托于“绿洲”,一个虚拟游戏宇宙。人们只要戴上VR设备,就可以进入这个与现实形成强烈反差的虚拟世界…
Android开发之程序猿必需要懂得Android的重要设计理念2(5.20更新版)
上篇文章介绍了Android开发的设计理念的一部分,并没有得到博友们的多大认可,仅仅看到了一位博友在以下留言期待下一篇文章的发表,为了这小小的唯一支持。我决定继续把后面的8个要点介绍一下,自己也潜心反省一下,自己的…

Espresso小试
Espresso开源了,那就试着用一下, 1. 下载Espresso Espresso没有提供单独的jar包下载,建议clone整个项目或者下载zip包 git clone https://code.google.com/p/android-test-kit/ 或从这里下载:https://code.google.com/p/android-t…

XML与DataSet的相互转换类
送给大家一个XML与DataSet的相互转换的类:XmlDatasetConvert 该类提供了四种方法:1、将xml对象内容字符串转换为DataSet2、将xml文件转换为DataSet3、将DataSet转换为xml对象字符串4、将DataSet转换为xml文件 XmlDatasetConvert.csusing System;using System.Colle…

想学Python?那这套教程再适合不过了!
如果你想问最近这些年什么编程语言最值得学习,我相信很多人都会告诉你是Python!所以不仅是开发小白,甚至很多开发老手,也都开始学习Python,作为辅助第二语言来提高自己的职场竞争力。不过结合我最近这些年Python的学习…

修改360浏览器 标题栏 显示的文字
作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555qq.com E-mail: 313134555 qq.com 修改360浏览器 标题栏 显示的文字 dll修改 DLL(Dynamic Link Library)文件是一种常见的应用程序拓展,也叫动态链接库文件。若遇到一些已经…

联邦学习的隐忧:来自梯度的深度泄露
作者 | Ligeng Zhu and Song Han编译 | 对外经济贸易大学金融科技实验室头图 | 下载于视觉中国【编者按】数据交易流通是数据要素市场建立的关键环节。为了在推动数据流动的同时保护数据安全、个人信息和隐私,隐私计算技术因运而生。目前,该技术分为三个…

.net 中 using的几种用法
1. using指令。using 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到。例如:using System; 一般…

少走弯路的10条忠告
如何在涉世之初少走弯路,有一个好的开端,开始一番成功的事业?以下是一些先行者积累的10条有益的涉世忠告。好好地遵循、把握这些忠告和建议吧,比起所学的课堂课程来,它毫不逊色! 1. 买个闹钟,以…

linux实战考试题:批量创建用户和密码(不能使用循环)
批量创建10个用户,并且设置随机8位密码,要求不能用shell的循环(例如:for,while等),只能用linux命令及管道实现。方法1:[rootoldboy /]# echo stu{01..10}|tr " " "\n"|sed …

路径,文件,目录,I/O常见操作汇总
摘要: 文件操作是程序中非常基础和重要的内容,而路径、文件、目录以及I/O都是在进行文件操作时的常见主题,这里想把这些常见的问题作个总结,对于每个问题,尽量提供一些解决方案,即使没有你想要的答案,也…

Winform开发的界面处理优化
在Winform开发中,客户体验是个很好的参考性指标,如果一个功能使用的时候感觉很流畅,说明我们的程序执行效率还不错,但是随着数据的真多,原先可能流程的地方可能会变得比较卡,这时候就需要追本索源ÿ…

人工智能语音技术支持“多情感程度”调节,细腻演绎“人声”
近期,微软发布最新语音技术,支持“情感程度”轻松调节,令智能语音的情感表现力更加细腻可控。 人类的情感很大程度上体现于语音语调的微妙变化,比如一句“再见”,有时是平静而含蓄的,有时是开心而轻松的&a…

HDU 1431 素数回文
有人问我这个问题。个人感觉暴搜会TLE O(n*sqrt(n))。n100000000;(推断素数用2~sqrt(n)1 去除) 还是枚举好了。枚举 1~10000,把他每一位存下来,回文数已知 left 。求 right ,然后组合起来。比如 1 …

递归的妙用—遍历子控件
我们在ASP.NET编程中, 经常需要遍历一个Web控件的子控件 ,找到所需的控件并获取控件中相应的值。以前我都是采用循环的方式遍历子控件,但当子控件是复杂的树形结构,比如:子控件也有子控件,子控件的子控件也有子控件。这…

【原创】关于代码质量的打油诗
要想代码写得好,以下规则供参考:代码格式规范多,静态检查常做到。代码注释要工整,垃圾注释不可要。重要分支详注释,复杂逻辑拆分细。数据类型多注意,经常判空习惯好。常量类型须定义,魔幻数字要…

Java 开发技巧详细知识体系总结
本篇文章是我们整理的一份架构师的成长路线,包括了并发编程、设计模式、常用框架、中间件、微服务与分布式、常用工具、JVM、MySQL、数据结构与算法,还有架构师精选视频、架构师成长路线高清大图。又是新的一年,每一年都会有人在成为架构师的…

23-hadoop-hive的DDL和DML操作
跟mysql类似, hive也有 DDL, 和 DML操作 数据类型: https://cwiki.apache.org/confluence/display/Hive/LanguageManualDDL : primitive_type| array_type| map_type| struct_type| union_type -- (Note: Available in Hive 0.7.0 and later) primitive_type为基本类型, 包括:…

经典正则表达式
正则表达式用于字符串处理,表单验证等场合,实用高效,但用到时总是不太把握,以致往往要上网查一番。我将一些常用的表达式收藏在这里,作备忘之用。本贴随时会更新。 匹配中文字符的正则表达式: [/u4e00-/u9…

腾讯云TDSQL数据库核心技术理论取得进展 ,同时发布数据异常检测工具
近日,腾讯云和中国人民大学在数据库基础研究上有了进展,聚焦在“数据异常”领域,这是数据库可串行化理论体系中的重要概念。 数据异常是打开并发访问控制技术大门的金钥匙。在数据库行业中,以往只发现了10多种数据异常现象&#…

Android应用工程文件组成
src目录:java代码源文件。gen目录:R.java:静态内部类,系统自动生成,无需程序员维护。assets目录:资源目录,html,多媒体文件。bin目录:应用程序所生成的apk。res目录&…
matlab2014a + win764bit + vs2013混合编程(.m转成dll供C++调用)
在matlab中可以通过mbuild工具将.m文件编译成dll文件供外部的C程序调用,这样就可以实现matlab和C混合编程的目的。 1. 使用matlab生成dll文件 1.1 首先需要带有mcc编译器的matlab软件,这个可以通过在matlab命令行中输入:!mcc命令来查看 1.2…

当前日期得到本周的开始和结束日期
/// <summary> /// 本周起止时间 /// </summary> /// <param name"dt"></param> /// <returns></returns> private string weekrange(System.DateTime dt) { int weeknow Convert.ToInt32(dt.DayOfWeek); int day…

分享一个mysql 复杂查询的例子
发布:脚本学堂/MySQL 编辑:thebaby 2013-08-23 09:37:37 【大 中 小】 有关mysql复杂查询的一个例子,正在学习mysql的朋友,可以作为一个参考。在mysql中,LOCATE(dmin,email)1 表示dmi字符在email字符中出现的索引位…

百度携手同济大学,瞄准AI、智慧交通等核心科技领域攻关
4月14日,百度与同济大学在上海举行了战略合作框架协议签约仪式。百度与同济大学将围绕人工智能、智慧交通等方面,共同开展科研攻关,创造AI技术及产业交流平台、搭建AI应用人才培养机制,力争取得基础理论和关键核心技术的突破。 签…

怎样做才是最优雅方式切换 web 项目数据源 ?
随着业务变迁/需求变更,JavaEE 应用中会被迫连接多个数据源进行业务处理。 怎样在不影响原有项目结构的情况下,已最优雅/最简洁的方式动态切换数据源呢? 本文已一次添加数据源后动态切换实践为例,描述整个思考和实践过程ÿ…