Keras深度学习实战(40)——音频生成

news2024/10/5 19:10:35

Keras深度学习实战(40)——音频生成

    • 0. 前言
    • 1. 模型与数据集分析
      • 1.1 数据集分析
      • 1.2 模型分析
    • 2. 音频生成模型
      • 2.1 数据集加载与预处理
      • 2.2 模型构建与训练
    • 小结
    • 系列链接

0. 前言

我们已经在《文本生成模型》一节中学习了如何利用深度神经网络生成文本,除了文本数据外,音频是另一类重要的时序序列,音频生成对于音频数据增广、艺术创作等领域都有着重要作用。在本节中,我们将学习如何使用深度神经网络生成音频。

1. 模型与数据集分析

1.1 数据集分析

本节中所用数据集为 MIDI 文件,MIDI 文件通常包含有关音频文件的音符与和弦信息,其中音符对象包含有关音符的音高、八度和偏移信息,和弦对象包含一组同时演奏的音符。为了简单起见,我们仅使用一个 MIDI 文件进行训练以快速得到音频生成模型,相关数据集可以在 gitcode 链接中下载。

1.2 模型分析

在实际构建模型之前,我们首先熟悉用于构建音乐生成器的策略策略:

  • 提取音频文件中存在的音符
  • 为每个音符分配一个唯一的 ID
  • 使用滑动窗口,每次记录 100 个音符序列,然后将第 101 个音符作为输出
  • 构建用于生成音符的长短时记忆网络 (Long Short Term Memory, LSTM) 模型,并进行拟合

2. 音频生成模型

接下来,我们使用 Keras 实现上述音频生成策略。

2.1 数据集加载与预处理

(1) 导入所需的库和数据集,并读取音频文件内容:

import numpy as np
from music21 import converter, instrument, note, chord, stream
from keras.utils import np_utils
from keras.layers import  LSTM, Dropout, Dense, Activation
from keras.models import Sequential
from matplotlib import pyplot as plt

fname = 'Pokemon_Fire_Red_Route.mid'
midi = converter.parse(fname)

(2) 定义函数,用于读取乐谱流并从中提取音符,如果音频文件中存在休止符,则还需要提取休止符:

def parse_with_silence(midi=midi):
    notes = []
    notes_to_parse = None
    parts = instrument.partitionByInstrument(midi)
    if parts: # 文件包含乐器部分
        notes_to_parse = parts.parts[1].recurse()
    else: # 文件中包含平滑结构的音符
        notes_to_parse = midi.flat.notes
    for ix, element in enumerate(notes_to_parse):
        if isinstance(element, note.Note):
            _note = str(element.pitch)
            notes.append(_note)
        elif isinstance(element, chord.Chord):
            _note = '.'.join(str(n) for n in element.normalOrder)
            notes.append(_note)
        elif isinstance(element, note.Rest):
            _note = '#' + str(element.seconds)
            notes.append(_note)
    return notes

在以上代码中,通过循环遍历元素来获取音符,并根据元素是音符,和弦还是休止符来提取相应的音符,将其追加至 notes 列表中。
使用 parse_with_silence 函数从输入音频文件流中提取音符:

notes = parse_with_silence(midi)
print(notes)

数据样本的音符示例输出如下,需要注意的是,以 # 开头的值表示休止符,# 旁边的数字表示休止符的持续时间:

['#2.0', '#2.0', '#1.75', 'E-5', 'F5', 'E-3', '#2.0', 'G5', ...]

(3) 通过创建音符 ID 及其对应名称的字典来创建输入和输出数据集:

# 获取音符中的所有唯一值
pitchnames = sorted(set(item for item in notes))
# 创建字典以将音高映射到整数
note_to_int = dict((note, number) for number, note in enumerate(pitchnames))
network_input = []
network_output = []

(4) 创建输入和输出数组序列,使用滑动窗口,每次将 100 个音符序列作为输入,并将第 101 个时间戳中的音符作为输出,此外,还需要将音符转换为相应的 ID

sequence_length = 100
for i in range(0, len(notes) - sequence_length, 1):
    sequence_in = notes[i:i + sequence_length]
    sequence_out = notes[i + sequence_length]
    network_input.append([note_to_int[char] for char in sequence_in])
    network_output.append(note_to_int[sequence_out])

(5) 接下来,整形输入数据的形状,以便可以将其输入到 LSTM 网络层中,LSTM 层接受的输入形状为 (批大小, 时间戳数, 每个时间戳的特征数),同时,对输入进行归一化,并将输出转换为独热编码矢量。

n_patterns = len(network_input)
# 将输入整形能够输入到 LSTM 层的形状
network_input = np.reshape(network_input, (n_patterns, sequence_length, 1))
# 将输入标准化
network_input = network_input / np.max(network_input)
network_output = np_utils.to_categorical(network_output)

2.2 模型构建与训练

(1) 构建并编译音频生成模型:

model = Sequential()
model.add(LSTM(
    256,
    input_shape=(network_input.shape[1], network_input.shape[2]),
    return_sequences=True
))
model.add(Dropout(0.3))
model.add(LSTM(512, return_sequences=True))
model.add(Dropout(0.3))
model.add(LSTM(256))
model.add(Dense(256))
model.add(Dropout(0.3))
model.add(Dense(network_output.shape[1]))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()

print(network_input.shape, network_output.shape)
# (41303, 100, 1) (41303, 56)

模型的简要架构信息输入如下:

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm (LSTM)                  (None, 100, 256)          264192    
_________________________________________________________________
dropout (Dropout)            (None, 100, 256)          0         
_________________________________________________________________
lstm_1 (LSTM)                (None, 100, 512)          1574912   
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 512)          0         
_________________________________________________________________
lstm_2 (LSTM)                (None, 256)               787456    
_________________________________________________________________
dense (Dense)                (None, 256)               65792     
_________________________________________________________________
dropout_2 (Dropout)          (None, 256)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 56)                14392     
_________________________________________________________________
activation (Activation)      (None, 56)                0         
=================================================================
Total params: 2,706,744
Trainable params: 2,706,744
Non-trainable params: 0
_________________________________________________________________

(2) 拟合模型,并绘制模型训练过程中损失值的变化情况:

history = model.fit(network_input, network_output, epochs=100, batch_size=32, verbose = 1)

history_dict = history.history
loss_values = history_dict['loss']
epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, loss_values, marker='x', label='Traing loss')
plt.title('Training loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

训练过程中损失变化
(3) 接下来,我们使用训练完成的模型生成音频:

start = np.random.randint(0, len(network_input)-1)
int_to_note = dict((number, note) for number, note in enumerate(pitchnames))
pattern = network_input[start].tolist()
prediction_output = []

在以上代码中,选择了一个随机的音频位置,并从该位置开始采样一个序列,该序列将用作生成将来时间戳音符的种子。
生成预测的过程,与模型训练过程相同,一次输入 100 个音符序列,生成下一个预测,将其附加到输入序列中,然后通过获取最近 100 个音符的最新序列生成下一个预测:

# 生成 500 个音符
for note_index in range(500):
    prediction_input = np.reshape(pattern, (1, len(pattern), 1))
    prediction_input = prediction_input 
    prediction = model.predict(prediction_input, verbose=0)
    index = np.argmax(prediction)
    result = int_to_note[index]
    prediction_output.append(result)
    pattern.append([index/48])
    pattern = pattern[1:len(pattern)]

需要注意的是,在以上代码中,我们将索引(即模型的预测输出)除以最大索引,就像我们在构建模型输入时所进行的归一化处理(除以 np.max(network_input) )一样。
音乐生成与文本生成任务略有不同,在文本生成模型中,我们根据输入单词 ID 之上生成嵌入,但在音乐生成中我们并没有使用嵌入,这是由于输入中的唯一值较少,因此该模型在没有嵌入这种情况下仍然可以生成较为令人满意的音乐。

(4) 然后,根据模型生成的值创建音符,同时,我们将每个音符偏移 0.5 秒,以便在生成输出时音符之间不会彼此重叠:

offset = 0
output_notes = []
# 根据模型生成的值创建音符和和弦对象
for pattern in prediction_output:
    # pattern 为和弦
    if (('.' in pattern) or pattern.isdigit()) and pattern[0] != '#':
        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 = offset
        output_notes.append(new_chord)
    # pattern 为音符
    elif pattern[0] != '#':
        new_note = note.Note(pattern)
        new_note.offset = offset
        new_note.storedInstrument = instrument.Piano()
        output_notes.append(new_note)
    else:
        new_note = note.Rest()
        new_note.offset = offset
        new_note.storedInstrument = instrument.Piano()
        new_note.quarterLength = float(pattern[1:])
        output_notes.append(new_note)
    # 增加每次迭代的偏移量,以便音符并不会重叠
    offset += 0.5

最后,将生成的预测写入音乐流文件:

midi_stream = stream.Stream(output_notes)
midi_stream.write('midi', fp='test_output.mid')

小结

随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。

系列链接

Keras深度学习实战(1)——神经网络基础与模型训练过程详解
Keras深度学习实战(2)——使用Keras构建神经网络
Keras深度学习实战(3)——神经网络性能优化技术
Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解
Keras深度学习实战(5)——批归一化详解
Keras深度学习实战(6)——深度学习过拟合问题及解决方法
Keras深度学习实战(7)——卷积神经网络详解与实现
Keras深度学习实战(8)——使用数据增强提高神经网络性能
Keras深度学习实战(9)——卷积神经网络的局限性
Keras深度学习实战(10)——迁移学习详解
Keras深度学习实战(11)——可视化神经网络中间层输出
Keras深度学习实战(12)——面部特征点检测
Keras深度学习实战(13)——目标检测基础详解
Keras深度学习实战(14)——从零开始实现R-CNN目标检测
Keras深度学习实战(15)——从零开始实现YOLO目标检测
Keras深度学习实战(16)——自编码器详解
Keras深度学习实战(17)——使用U-Net架构进行图像分割
Keras深度学习实战(18)——语义分割详解
Keras深度学习实战(19)——使用对抗攻击生成可欺骗神经网络的图像
Keras深度学习实战(20)——DeepDream模型详解
Keras深度学习实战(21)——神经风格迁移详解
Keras深度学习实战(22)——生成对抗网络详解与实现
Keras深度学习实战(23)——DCGAN详解与实现
Keras深度学习实战(24)——从零开始构建单词向量
Keras深度学习实战(25)——使用skip-gram和CBOW模型构建单词向量
Keras深度学习实战(26)——文档向量详解
Keras深度学习实战(27)——循环神经详解与实现
Keras深度学习实战(28)——利用单词向量构建情感分析模型
Keras深度学习实战(29)——长短时记忆网络详解与实现
Keras深度学习实战(30)——使用文本生成模型进行文学创作
Keras深度学习实战(31)——构建电影推荐系统
Keras深度学习实战(32)——基于LSTM预测股价
Keras深度学习实战(33)——基于LSTM的序列预测模型
Keras深度学习实战(34)——构建聊天机器人
Keras深度学习实战(35)——构建机器翻译模型
Keras深度学习实战(36)——基于编码器-解码器的机器翻译模型
Keras深度学习实战(37)——手写文字识别
Keras深度学习实战(38)——图像字幕生成
Keras深度学习实战(39)——音乐音频分类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81694.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能、人机融合智能和深度态势感知

内容摘要:人工智能的符号主义、联结主义和行为主义三大学派,分别从不同角度切入智能的本质,其研究观点相互补充但各有局限。在人机融合过程中,怎样进行人机功能分配,人机怎样融合学习、理解、决策、推理乃至感知。数据…

获取微信公众号token

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token 接口调用请求说明 https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appidAPPID&secretAPPSECRET参数说明 参数是否必填说…

牛!单表千万行数据库: LIKE 搜索优化手记

我们可以在 txt 列上建立索引,用于优化该查询: CREATE INDEX tbl_like_txt_idx ON [tbl_like] ( [txt] ) 应用索引后,查询速度大大加快,仅需 5 毫秒: 由此可知:对于左前缀匹配,我们可以通过增…

市政工控典型安全解决方案

汽车制造业 MES系统 DNC系统 生产 安全域1 管理层 工控安全隔离装置 交换机 安全配置核查系统 HMI 历史数据库 运行监控系统 实时数据库 打印机过程 安全域2 监控层 工控漏洞扫描系统 安全交换机 工控安全审计系统 工控入侵检测系统工程师站 A 操作员站 A 实时数据库A 操作员站…

Linux中的文件传输命令(scp、rsync)、Linux之间通过sshkey公钥免密登录

scp测试环境:centos7.7 最小化安装,默认是有scp命令 -r 递归复制整个目录 -p 保留源文件的修改时间、访问时间和权限 -v 详细方式显示输出 -P(大写)指定port(端口)输出scp命令使用格式 scp /filename 目…

Linux 程序开发 之 库打桩机制

目录前言一、库打桩定义二、编译时打桩三、链接时打桩四、运行时打桩五、处理目标文件的工具前言 Linux 链接器支持一个很强大的技术,称为库打桩(library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩…

m基于ACO蚁群优化的货车运输路线规划matlab仿真,考虑车辆载重,单位运输成本等因素

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 蚁群算法是通过对自然界中真实蚂蚁的集体行为的观察,模拟而得到一种仿生优化算法,它具有很好的并行性,分布性.根据蚂蚁群体不同的集体行为特征,蚁群算法可分为受蚂蚁觅食行为启发的模型和受孵化分…

渗透学习-靶场篇-WebGoat靶场(JWT攻击)

文章目录前言一、介绍JWTJWT令牌结构获取的令牌的基本过程二、攻击方式以及靶场的搭建1.安装cWebGoat2.空加密验证攻击3.字典爆破三、认证-键值逻辑前言 本次主要学习了javaweb项目方面任意出现的一些安全问题,最主要的是有关于JWT身份认证上的攻击,并利…

es的搜索服务

1、在项目中&#xff0c;创建一个搜索服务的模块&#xff1a;search-service 2、在新创建的搜索模块中添加依赖&#xff1a; <dependencies><!--nacos--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-start…

MyBatis-Plus中的逻辑删除使用

系列文章目录 Mybatis-PlusSpringBoot结合运用_心态还需努力呀的博客-CSDN博客MyBaits-Plus中TableField和TableId用法_心态还需努力呀的博客-CSDN博客 MyBatis-Plus分页查询&#xff08;快速上手运用&#xff09;_心态还需努力呀的博客-CSDN博客_mybatis plus分页查询 MyBa…

【ESXi 7.x 升 8.x】ESXi 升级 —— 使用 ESXCLI 升级 ESXi(Offline Bundle ZIP)

目录3.1 示例 — 使用 ESXCLI 升级 ESXi&#xff08;Offline Bundle ZIP&#xff09;【目标&#xff1a;将 ESXi 6.5 U2 GA 升级为 7.0 U3f】&#xff08;1&#xff09;下载离线升级ZIP包&#xff08;2&#xff09;升级 ESXi① 查看离线包② 升级前确认ESXi版本③ 获取升级用的…

[附源码]Python计算机毕业设计大学生社团管理系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

ChatGPT教程之 01 什么是ChatGPT革命性的对话生成新工具

今天,我想揭开 ChatGPT 的神秘面纱——GANs*(生成对抗网络)的一个迷人的新应用程序,它在 AI 社区中引起了很大的轰动。 对于那些不熟悉 GAN 的人来说,它们是一种神经网络,它使用两个相互竞争的网络——一个生成器和一个鉴别器——来创建逼真的输出。生成器创建假输出,而…

Paper Note——经典Polyline类型Map论文损失函数

文章目录1. Hierarchical Recurrent Attention Networks for Structured Online Maps2. DAGMapper: Learning to Map by Discovering Lane Topology1. Hierarchical Recurrent Attention Networks for Structured Online Maps https://patrick-llgc.github.io/Learning-Deep-Le…

QT(4)-QAbstractItemView

QAbstractItemView1 说明2 常用函数2.1 交替行颜色2.1.1 alternatingRowColors2.1.2 setAlternatingRowColors2.2 autoScroll2.2.1 hasAutoScroll2.2.2 setAutoScroll2.3 autoScrollMargin2.3.1 autoScrollMargin2.3.2 setAutoScrollMargin2.4 defaultDropAction2.4.1 setDefau…

python--飞机大战

实现功能&#xff1a; 1&#xff1a;飞机的移动&#xff0c;发射子弹&#xff0c;手雷&#xff0c;生命值&#xff0c;生命条 2&#xff1a;敌飞机有3种形态&#xff08;小&#xff0c;中&#xff0c;大&#xff09;不同的飞机大小不一样&#xff0c;生命值不一样&#xff0c…

基于springboot+mybatis+mysql+vue在线订餐系统

基于springbootmybatismysqlvue在线订餐系统一、系统介绍二、功能展示1.主页(用户)2.菜单(用户)3.用户注册(用户)4.用户登陆(用户)5.我的订单(用户)6.我的购物车(用户)7.首页(管理员)8.用户管理(管理员)9.商品管理(管理员)9.订单管理(管理员)10.评论管理(管理员)三、获取源码一…

c++ 类型的转换

文章目录1. C语言中的类型转换1.1 隐式转换1.2 显示转换2. C的类型转换2.1 static_cast2.2 reinterpret_cast2.3 const_cast2.4 dynamic_cast3. 常见面试题前言&#xff1a; C给出了四种类型转换&#xff0c;这是做出的一些规范&#xff0c;为了减少隐式转换。隐式转换的问题&a…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK14特性讲解】

JDK各个版本特性讲解-JDK14特性 一、Java14概述 Oracle在2020年3月17日宣布JAVA14 全面上市,JAVA14通过每六个月发布一次新功能,为企业和开发人员社区提供增强功能,继续了Oracle加快创新的承诺. 最新的JAVA开发工具包提供了新功能,其中包括两项备受期待的新预览功能,实例匹配的…