无需分词/嵌入的LSTM连续音乐数值序列模型构建及样本生成咨询
连续型音乐序列的LSTM处理方案
一、数据预处理与加载
连续浮点序列无需分词/嵌入,核心是将原始序列转换为模型可接受的输入输出对,并做标准化处理:
- 数据标准化
音乐序列的浮点值范围差异较大,先归一化到[0,1]区间,帮助模型收敛:
from sklearn.preprocessing import MinMaxScaler import numpy as np # 假设所有歌曲数据存于all_songs列表,每个元素是一维numpy数组 all_data = np.concatenate(all_songs).reshape(-1, 1) scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(all_data)
- 生成训练样本
按固定序列长度seq_length切分每个歌曲的序列,生成输入(X)和目标(y):
seq_length = 64 X_train, y_train = [], [] # 遍历每首歌的标准化后数据 for song in all_songs: scaled_song = scaler.transform(song.reshape(-1, 1)).flatten() song_len = len(scaled_song) # 生成该歌曲的所有训练样本 for i in range(song_len - seq_length): # 输入:连续seq_length个点 X_train.append(scaled_song[i:i+seq_length]) # 目标:接下来的seq_length个点(序列到序列预测),单步预测可改为scaled_song[i+seq_length] y_train.append(scaled_song[i+1:i+seq_length+1]) # 转换为模型需要的形状:(样本数, 序列长度, 特征数),这里特征数为1 X_train = np.array(X_train).reshape(-1, seq_length, 1) y_train = np.array(y_train).reshape(-1, seq_length, 1)
二、模型结构调整
移除嵌入层,直接以连续序列作为输入,适配回归任务(预测连续值):
import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout, TimeDistributed batch_size = 16 seq_length = 64 num_epochs = 100 optimizer_ = tf.keras.optimizers.Adam() model = Sequential() # 直接输入连续序列,shape为(seq_length, 1);若用stateful需指定batch_input_shape=(batch_size, seq_length, 1) model.add(LSTM(256, return_sequences=True, input_shape=(seq_length, 1))) model.add(Dropout(0.2)) model.add(LSTM(256, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(256, return_sequences=True)) model.add(Dropout(0.2)) # 输出维度为1(预测连续值),TimeDistributed实现序列到序列预测 model.add(TimeDistributed(Dense(1))) # 回归任务用MSE损失,MAE作为评估指标 model.compile(loss="mse", optimizer=optimizer_, metrics=["mae"])
关于Stateful LSTM的说明
若使用stateful=True,需保证每个batch的样本来自同一首歌的连续片段,训练时手动控制数据分组,训练后调用model.reset_states()重置状态。该模式适合长序列连贯学习,但实现复杂度高,新手可先从无状态模型入手。
三、模型训练
用预处理后的训练数据直接训练:
model.fit(X_train, y_train, batch_size=batch_size, epochs=num_epochs, validation_split=0.1)
四、样本生成流程
训练完成后,通过种子序列逐步生成新音乐序列:
def generate_sequence(model, seed, length, scaler): generated = seed.flatten().tolist() current_seq = seed for _ in range(length): # 预测下一个序列段 pred = model.predict(current_seq.reshape(1, seq_length, 1), verbose=0) # 取预测的最后一个时间步作为新生成的点 next_val = pred[0, -1, 0] generated.append(next_val) # 更新当前序列:移除第一个点,加入新预测值 current_seq = np.append(current_seq[1:], next_val).reshape(seq_length, 1) # 反归一化回到原始数据范围 generated = scaler.inverse_transform(np.array(generated).reshape(-1, 1)).flatten() return generated # 从训练数据中随机选一段种子序列 seed_idx = np.random.randint(0, len(X_train)) seed_sequence = X_train[seed_idx].reshape(seq_length, 1) # 生成长度为500的新序列 new_song = generate_sequence(model, seed_sequence, 500, scaler)
内容的提问来源于stack exchange,提问作者Harambe
相关产品推荐
相关产品推荐

