TensorFlow LSTM 预测相同的值
TensorFlow LSTM predicting same value
我想做的是向我的 LSTM 模型输入一个数字列表,然后让我的 LSTM 模型输出它自己的数字列表。我的项目是一个程序,它获取在线 MIDI 文件,将其转换为数字列表,从 LSTM 获取新的数字列表,将这些新数字更改为 MIDI,然后收听该文件。我 运行 遇到问题的地方是我从 LSTM 模型中得到一个新的数字列表。
这是我目前的主要代码:
from midi_to_text import data_parse
from split_sequence import split_sequence
import py_midicsv as pm
import math
from numpy import asarray
from tensorflow.keras import Sequential
from tensorflow.keras.layers import *
import tensorflow as tf
raw_midi = pm.midi_to_csv('OnlineMidi.mid')
data = data_parse(raw_midi)
n_steps = 1
X, y = split_sequence(data, n_steps)
X = X.reshape((X.shape[0], X.shape[1], 1))
X = tf.cast(X, dtype='float32')
model = Sequential()
model.add(LSTM(256, activation='sigmoid', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128, activation='sigmoid', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128))
model.add(Dropout(0.2))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
model.fit(X, y, epochs=100, batch_size=32, verbose=2)
notes = [64]
song_length = 10
for i in range(song_length):
prediction = model.predict(asarray(notes).reshape((-1, 1, 1)))
prediction[0][0] = (prediction[0][0] * 384) - (prediction[0][0] * 13) + 13
# Turns float from 0 to 1 back into integer
notes.append(prediction[0][0])
print(notes)
这是我创建训练集和标签的函数:
from numpy import asarray
def split_sequence(data, n_steps):
new_data, expected_values = list(), list()
for i in range(len(data)):
if n_steps + i <= len(data) - 1:
new_data.append(data[i:n_steps + i])
expected_values.append(data[n_steps + i])
else:
break
for i in new_data:
i[0] = (i[0] - 13) / (384 - 13)
for i in range(len(expected_values)):
expected_values[i] = (expected_values[i] - 13) / (384 - 13)
# Turns values into float between 0 and 1
return asarray(new_data), asarray(expected_values)
这是n_steps = 1时的x训练数据:
[[64], [76], [64], [75], [64], [76], [64], [75], [64], [76], [64], [71], [64], [74], [64], [72], [69], [64], [45], [64], [52], [64], [57], [64], [60], [64]]
这是n_steps = 1时的标签:
[76, 64, 75, 64, 76, 64, 75, 64, 76, 64, 71, 64, 74, 64, 72, 69, 64, 45, 64, 52, 64, 57, 64, 60, 64, 64, 64, 69, 71, 64, 40, 64, 52, 64, 56, 64, 64, 64,]
这是我的数据:
[64, 76, 64, 75, 64, 76, 64, 75, 64, 76, 64, 71, 64, 74, 64, 72, 69, 64, 45, 64, 52, 64, 57, 64, 60, 64, 64, 64]
这是我的模型当前输出的内容,以种子 64 开头的 9 个预测的列表:
[64, 62.63686, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864]
我不明白的是为什么这些预测都基本一致。当我在主代码的最后一个 for 循环中打印预测时,我得到一个列表的输出,其中包含 x 个列表,其中 x 是输入数据的数量。以下是这些预测之一的示例:
[[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]]
这就是为什么在那个 for 循环中我只将列表中第一个列表的值作为预测。
回顾一下,我有一个接受数字列表的程序,我想让 LSTM 模型输出一个以种子 64 开头的预测数字列表。我 运行 遇到的问题是我的模型是,由于某种原因,每次输出基本相同的预测,所以我需要有关此预测过程的帮助。
**更新:
**
我尝试将 model.fit() 和 model.predict() 放入 for 循环中,然后循环 10 次以查看发生了什么。好消息:每个预测都与上一个不同,这很好。坏消息:速度非常慢,我不确定这是否是解决此问题的最佳方法。有什么建议可以让这些值更接近预期值,或者这种方法是否更好?这似乎非常低效,因为我正在为 10 个输出音符重新训练模型 10 次(实际上是 5 个,其他 5 个值是每个音符的持续时间)。
这是我使用这个 for 循环的新输出:
[64, 56.53626, 58.395187, 61.333992, 59.08212, 58.66997, 55.86058, 59.819744, 54.183216, 55.231224, 53.8824]
这是我的新代码,它是相同的东西,只是有一个大的 for 循环:
from midi_to_text import data_parse
from split_sequence import split_sequence
import py_midicsv as pm
import math
from numpy import asarray
from tensorflow.keras import Sequential
from tensorflow.keras.layers import *
import tensorflow as tf
raw_midi = pm.midi_to_csv('OnlineMidi.mid')
data = data_parse(raw_midi)
n_steps = 1
X, y = split_sequence(data, n_steps)
print(X)
print(y)
X = X.reshape((X.shape[0], X.shape[1], 1))
X = tf.cast(X, dtype='float32')
notes = [64]
model = Sequential()
model.add(LSTM(256, activation='linear', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128, activation='linear', return_sequences=True))
model.add(LSTM(128))
model.add(Dropout(0.2))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
for i in range(10):
model.fit(X, y, epochs=5, batch_size=2, verbose=2)
prediction = model.predict(asarray(notes).reshape((-1, 1, 1)))
prediction[0][0] = (prediction[0][0] * 384) - (prediction[0][0] * 13) + 13
notes.append(prediction[0][0])
print(notes)
自定义midi_to_text数据解析器:
def data_parse(raw_midi):
temp = []
final = []
to_remove = []
shift_unit = 20
for i in range(len(raw_midi)):
temp.append(raw_midi[i].split(', '))
for i in range(len(temp)):
if temp[i][2] != 'Note_on_c':
to_remove.append(temp[i])
for i in to_remove:
temp.remove(i)
for i in temp:
i.remove(i[0])
i.remove(i[1])
i.remove(i[1])
i.remove(i[2])
for i in range(len(temp)):
if i == len(temp) - 1:
temp[i][0] = '64'
else:
temp[i][0] = str(int(temp[i + 1][0]) - int(temp[i][0]))
to_remove.clear()
for i in range(len(temp)):
if i == len(temp) - 1:
break
if temp[i + 1][0] == '0':
temp[i].append(temp[i + 1][1])
to_remove.append(temp[i + 1])
for i in to_remove:
temp.remove(i)
for i in temp:
for _ in i:
final.append(int(_))
return final
谢谢!!
我的结论是,尽管效率很低,但只需将 model.fit 和预测放入 for 循环中即可预测未来 1 步或一次生成 1 条信息。这意味着,是的,您确实必须多次拟合模型,将其生成的先前数据提供给它,但这是我可以牺牲的东西。这种方法确实有效,只是需要一些时间,并且是我找到的唯一主要解决方案。感谢所有回复的人,让我清楚地了解了所有步骤,希望这个问题能帮助其他人!
我想做的是向我的 LSTM 模型输入一个数字列表,然后让我的 LSTM 模型输出它自己的数字列表。我的项目是一个程序,它获取在线 MIDI 文件,将其转换为数字列表,从 LSTM 获取新的数字列表,将这些新数字更改为 MIDI,然后收听该文件。我 运行 遇到问题的地方是我从 LSTM 模型中得到一个新的数字列表。
这是我目前的主要代码:
from midi_to_text import data_parse
from split_sequence import split_sequence
import py_midicsv as pm
import math
from numpy import asarray
from tensorflow.keras import Sequential
from tensorflow.keras.layers import *
import tensorflow as tf
raw_midi = pm.midi_to_csv('OnlineMidi.mid')
data = data_parse(raw_midi)
n_steps = 1
X, y = split_sequence(data, n_steps)
X = X.reshape((X.shape[0], X.shape[1], 1))
X = tf.cast(X, dtype='float32')
model = Sequential()
model.add(LSTM(256, activation='sigmoid', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128, activation='sigmoid', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128))
model.add(Dropout(0.2))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
model.fit(X, y, epochs=100, batch_size=32, verbose=2)
notes = [64]
song_length = 10
for i in range(song_length):
prediction = model.predict(asarray(notes).reshape((-1, 1, 1)))
prediction[0][0] = (prediction[0][0] * 384) - (prediction[0][0] * 13) + 13
# Turns float from 0 to 1 back into integer
notes.append(prediction[0][0])
print(notes)
这是我创建训练集和标签的函数:
from numpy import asarray
def split_sequence(data, n_steps):
new_data, expected_values = list(), list()
for i in range(len(data)):
if n_steps + i <= len(data) - 1:
new_data.append(data[i:n_steps + i])
expected_values.append(data[n_steps + i])
else:
break
for i in new_data:
i[0] = (i[0] - 13) / (384 - 13)
for i in range(len(expected_values)):
expected_values[i] = (expected_values[i] - 13) / (384 - 13)
# Turns values into float between 0 and 1
return asarray(new_data), asarray(expected_values)
这是n_steps = 1时的x训练数据:
[[64], [76], [64], [75], [64], [76], [64], [75], [64], [76], [64], [71], [64], [74], [64], [72], [69], [64], [45], [64], [52], [64], [57], [64], [60], [64]]
这是n_steps = 1时的标签:
[76, 64, 75, 64, 76, 64, 75, 64, 76, 64, 71, 64, 74, 64, 72, 69, 64, 45, 64, 52, 64, 57, 64, 60, 64, 64, 64, 69, 71, 64, 40, 64, 52, 64, 56, 64, 64, 64,]
这是我的数据:
[64, 76, 64, 75, 64, 76, 64, 75, 64, 76, 64, 71, 64, 74, 64, 72, 69, 64, 45, 64, 52, 64, 57, 64, 60, 64, 64, 64]
这是我的模型当前输出的内容,以种子 64 开头的 9 个预测的列表:
[64, 62.63686, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864, 62.636864]
我不明白的是为什么这些预测都基本一致。当我在主代码的最后一个 for 循环中打印预测时,我得到一个列表的输出,其中包含 x 个列表,其中 x 是输入数据的数量。以下是这些预测之一的示例:
[[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]
[62.500393]]
这就是为什么在那个 for 循环中我只将列表中第一个列表的值作为预测。 回顾一下,我有一个接受数字列表的程序,我想让 LSTM 模型输出一个以种子 64 开头的预测数字列表。我 运行 遇到的问题是我的模型是,由于某种原因,每次输出基本相同的预测,所以我需要有关此预测过程的帮助。
**更新: ** 我尝试将 model.fit() 和 model.predict() 放入 for 循环中,然后循环 10 次以查看发生了什么。好消息:每个预测都与上一个不同,这很好。坏消息:速度非常慢,我不确定这是否是解决此问题的最佳方法。有什么建议可以让这些值更接近预期值,或者这种方法是否更好?这似乎非常低效,因为我正在为 10 个输出音符重新训练模型 10 次(实际上是 5 个,其他 5 个值是每个音符的持续时间)。
这是我使用这个 for 循环的新输出:
[64, 56.53626, 58.395187, 61.333992, 59.08212, 58.66997, 55.86058, 59.819744, 54.183216, 55.231224, 53.8824]
这是我的新代码,它是相同的东西,只是有一个大的 for 循环:
from midi_to_text import data_parse
from split_sequence import split_sequence
import py_midicsv as pm
import math
from numpy import asarray
from tensorflow.keras import Sequential
from tensorflow.keras.layers import *
import tensorflow as tf
raw_midi = pm.midi_to_csv('OnlineMidi.mid')
data = data_parse(raw_midi)
n_steps = 1
X, y = split_sequence(data, n_steps)
print(X)
print(y)
X = X.reshape((X.shape[0], X.shape[1], 1))
X = tf.cast(X, dtype='float32')
notes = [64]
model = Sequential()
model.add(LSTM(256, activation='linear', return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(128, activation='linear', return_sequences=True))
model.add(LSTM(128))
model.add(Dropout(0.2))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
for i in range(10):
model.fit(X, y, epochs=5, batch_size=2, verbose=2)
prediction = model.predict(asarray(notes).reshape((-1, 1, 1)))
prediction[0][0] = (prediction[0][0] * 384) - (prediction[0][0] * 13) + 13
notes.append(prediction[0][0])
print(notes)
自定义midi_to_text数据解析器:
def data_parse(raw_midi):
temp = []
final = []
to_remove = []
shift_unit = 20
for i in range(len(raw_midi)):
temp.append(raw_midi[i].split(', '))
for i in range(len(temp)):
if temp[i][2] != 'Note_on_c':
to_remove.append(temp[i])
for i in to_remove:
temp.remove(i)
for i in temp:
i.remove(i[0])
i.remove(i[1])
i.remove(i[1])
i.remove(i[2])
for i in range(len(temp)):
if i == len(temp) - 1:
temp[i][0] = '64'
else:
temp[i][0] = str(int(temp[i + 1][0]) - int(temp[i][0]))
to_remove.clear()
for i in range(len(temp)):
if i == len(temp) - 1:
break
if temp[i + 1][0] == '0':
temp[i].append(temp[i + 1][1])
to_remove.append(temp[i + 1])
for i in to_remove:
temp.remove(i)
for i in temp:
for _ in i:
final.append(int(_))
return final
谢谢!!
我的结论是,尽管效率很低,但只需将 model.fit 和预测放入 for 循环中即可预测未来 1 步或一次生成 1 条信息。这意味着,是的,您确实必须多次拟合模型,将其生成的先前数据提供给它,但这是我可以牺牲的东西。这种方法确实有效,只是需要一些时间,并且是我找到的唯一主要解决方案。感谢所有回复的人,让我清楚地了解了所有步骤,希望这个问题能帮助其他人!