基于PyTorch和RNN的音乐生成实验笔记
实验目标
本实验旨在通过构建循环神经网络(RNN),学习音乐数据中的模式,并生成新的音乐。我们将使用PyTorch框架,以ABC符号表示的爱尔兰民间音乐数据集为基础,训练模型并生成音乐。
2.1 实验依赖与环境配置
依赖安装
实验需要安装以下Python库:
PyTorch :深度学习框架,用于构建和训练RNN模型。
Comet ML :用于跟踪模型训练过程和实验结果。
NumPy、SciPy :用于数据处理和音频文件生成。
MIT Introduction to Deep Learning package :提供实验所需的数据集和辅助函数。
安装命令如下:
1 2 !pip install comet_ml !pip install mitdeeplearning
Comet ML配置
Comet ML用于记录实验过程和结果。需要注册Comet账户并获取API Key,然后将其设置为全局变量COMET_API_KEY。
GPU检查
实验需要使用GPU加速,确保运行环境已启用GPU:
1 assert torch.cuda.is_available(), "Please enable GPU from runtime settings"
2.2 数据集准备与分析
数据集下载
实验使用了包含817首爱尔兰民间歌曲的数据集,歌曲以ABC符号格式表示。数据集通过以下代码下载:
1 songs = mdl.lab1.load_training_data()
数据集格式
每首歌曲以文本形式存储,包含音符、调式、节奏等信息。例如:
1 2 3 4 5 6 7 8 X:1 T:Alexander's Z:id:dc-hornpipe-1 M:C| L:1/8 K:D Major (3ABc|dAFA DFAd|fdcd FAdf|gfge fefd|(3efe (3dcB A2 (3ABc|! dAFA DFAd|fdcd FAdf|gfge fefd|(3efe dc d2:|!
数据集特点
数据集中共有83个唯一字符,包括音符、符号和元信息(如标题、调式等)。
字符数量的多样性增加了学习问题的复杂性。
数据集合并
将所有歌曲合并为一个长字符串,用于后续处理:
1 songs_joined = "\n\n" .join(songs)
2.3 数据预处理
文本向量化
为了将文本数据输入到神经网络中,需要将其转换为数值形式。我们创建两个映射表:
char2idx:将字符映射为唯一的整数索引。
idx2char:将整数索引映射回字符。
向量化函数如下:
1 2 3 def vectorize_string (string ): vector = [char2idx[char] for char in string] return np.array(vector)
将所有歌曲向量化:
1 vectorized_songs = vectorize_string(songs_joined)
训练样本生成
为了训练RNN模型,需要将文本数据分割为输入序列和目标序列。每个输入序列包含seq_length个字符,目标序列是输入序列向右移动一个字符的结果。
生成训练样本的函数如下:
1 2 3 4 5 6 7 8 def get_batch (vectorized_songs, seq_length, batch_size ): n = vectorized_songs.shape[0 ] - 1 idx = np.random.choice(n - seq_length, batch_size) input_batch = [vectorized_songs[i:i+seq_length] for i in idx] output_batch = [vectorized_songs[i+1 :i+seq_length+1 ] for i in idx] x_batch = torch.tensor(input_batch, dtype=torch.long) y_batch = torch.tensor(output_batch, dtype=torch.long) return x_batch, y_batch
2.4 RNN模型构建
模型架构
RNN模型基于长短期记忆网络(LSTM)架构,包含以下三个主要组件:
Embedding层 :将字符索引转换为固定维度的密集向量。
LSTM层 :处理序列数据,捕捉字符之间的时序关系。
全连接层(Linear层) :将LSTM的输出映射到词汇表大小的维度,输出每个字符的概率分布。
模型定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class LSTMModel (nn.Module): def __init__ (self, vocab_size, embedding_dim, hidden_size ): super (LSTMModel, self ).__init__() self .embedding = nn.Embedding(vocab_size, embedding_dim) self .lstm = nn.LSTM(input_size=embedding_dim, hidden_size=hidden_size, batch_first=True ) self .fc = nn.Linear(hidden_size, vocab_size) def forward (self, x, state=None , return_state=False ): x = self .embedding(x) if state is None : state = self .init_hidden(x.size(0 ), x.device) out, state = self .lstm(x, state) out = self .fc(out) return out if not return_state else (out, state)
模型参数
vocab_size:词汇表大小(83)。
embedding_dim:嵌入层维度(256)。
hidden_size:LSTM隐藏层大小(1024)。
batch_size:训练时的批量大小(8)。
2.5 模型训练
损失函数
使用PyTorch的CrossEntropyLoss计算模型输出与真实标签之间的交叉熵损失:
1 2 3 4 5 def compute_loss (labels, logits ): batched_labels = labels.view(-1 ) batched_logits = logits.view(-1 , logits.size(-1 )) loss = cross_entropy(batched_logits, batched_labels) return loss
优化器
使用Adam优化器,学习率为5e-3:
1 optimizer = torch.optim.Adam(model.parameters(), lr=params['learning_rate' ])
训练循环
训练过程如下:
随机抽取一批序列作为输入。
计算损失并进行反向传播。
更新模型参数。
训练代码如下:
1 2 3 4 5 for iter in tqdm(range (params["num_training_iterations" ])): x_batch, y_batch = get_batch(vectorized_songs, params["seq_length" ], params["batch_size" ]) x_batch = torch.tensor(x_batch, dtype=torch.long).to(device) y_batch = torch.tensor(y_batch, dtype=torch.long).to(device) loss = train_step(x_batch, y_batch)
2.6 音乐生成
生成过程
使用训练好的模型生成音乐,步骤如下:
提供一个起始字符串(如“X”)作为种子,初始化LSTM的隐藏状态。
在每一步中,模型根据当前输入和隐藏状态生成下一个字符的概率分布,通过采样得到下一个字符。
将生成的字符作为下一次输入,重复上述过程,生成指定长度的ABC格式文本。
生成代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def generate_text (model, start_string, generation_length=1000 ): input_idx = [char2idx[s] for s in start_string] input_idx = torch.tensor([input_idx], dtype=torch.long).to(device) state = model.init_hidden(input_idx.size(0 ), device) text_generated = [] for i in tqdm(range (generation_length)): predictions, state = model(input_idx, state, return_state=True ) predicted_logits = predictions[0 , -1 , :] predicted_probs = torch.nn.functional.softmax(predicted_logits, dim=-1 ) predicted_idx = torch.multinomial(predicted_probs, num_samples=1 ) predicted_char = idx2char[predicted_idx.item()] text_generated.append(predicted_char) input_idx = predicted_idx.unsqueeze(0 ) return (start_string + '' .join(text_generated))
音乐播放
将生成的ABC格式文本转换为音频文件并播放:
1 2 3 4 5 6 generated_songs = mdl.lab1.extract_song_snippet(generated_text) for i, song in enumerate (generated_songs): waveform = mdl.lab1.play_song(song) if waveform: print ("Generated song" , i) ipythondisplay.display(waveform)
2.7 实验优化与总结
实验优化方向
训练迭代次数 :增加迭代次数以提升模型性能。
学习率调整 :尝试不同的学习率以找到最优值。
数据集扩展 :增加数据集的多样性和规模。
模型架构改进 :尝试更复杂的RNN架构,如双向LSTM或GRU。
实验总结
本实验通过构建RNN模型,成功实现了基于ABC符号的音乐生成。通过调整训练参数和优化模型架构,可以进一步提升生成音乐的质量。未来可以探索多模态融合等方向,以生成更具表现力的音乐作品。