Почему нейронная сеть дает такой хороший результат?
Использую lstm, для предсказания временных рядов. И, к примеру, использую только 15% процентов всей выборки для обучения и её предсказания практически безупречны.
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(yest_nadarayG.reshape(-1, 1))
train_size = int(len(dataset) * 0.15)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size, :], dataset[train_size:len(dataset), :]
#Создание матриц для внедрения их в модель МЛ
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset) - look_back - 1):
a = dataset[i:(i + look_back), 0]
dataX.append(a)
dataY.append(dataset[i + look_back, 0])
return np.array(dataX), np.array(dataY)
look_back = 1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
# LSTM
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=2)
#trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
#trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:, 0]))
print('Test Score: %.2f RMSE' % (testScore))
trainPredictPlot = np.empty_like(dataset)
trainPredictPlot[:, :] = np.nan
trainPredictPlot[look_back:len(trainPredict) + look_back, :] = trainPredict
testPredictPlot = np.empty_like(dataset)
testPredictPlot[:, :] = np.nan
testPredictPlot[len(trainPredict) + (look_back * 2) + 1:len(dataset) - 1, :] = testPredict
plt.plot(scaler.inverse_transform(dataset))
plt.plot(testPredictPlot)
plt.show()
Что я делаю не так? Ведь нейросеть не может по такому маленькому кол-ву данных выдывать практически 100% результат?
Ответы (1 шт):
На самом деле, судя по графику, не так уж и хорошо ваше предсказание. Сколько у вас получилось RMSE? Попробуйте сравнить хотя бы с таким бейзлайном (следующее значение = предыдущему), как правильно предложил Stanislav Volodarskiy:
testScore = math.sqrt(mean_squared_error(testY[0][1:], testY[0][:-1]))
print('Baseline Score: %.2f RMSE' % (testScore))
Я погонял ваш код на случайных данных, у меня в некоторых случаях бейзлайн был просто чуть лучше чем предсказание нейросети, а в некоторых случаях он был лучше вообще на порядок (и график сильно отличался).
И практика показывает, что в случае графиков биржевых цен и подобных им данных, лучшее предсказание - это действительно цена в предыдущий момент времени. Вот если вы хотите предсказать на некоторый промежуток времени вперёд - там уже хитрые модели вроде ARIMA могут получить некоторое преимущество. А предсказание на шаг вперёд всегда будет лучшее то, которое равно предыдущему шагу.
Да, и ещё на задачах на временные ряды очень важна кросс-валидация, если хотите добиться реально хороших результатов. Обучение на едином куске тренировочных данных без использования кросс-валидации (причём, специального варианта кросс-валидации, заточенного под временные ряды) у вас всегда будет потом плохо работать на тестовых данных на самом деле.
Пример полученного мной результата:
Test Score: 5181.37 RMSE
Baseline Score: 2935.01 RMSE
Код на котором я экспериментировал (lookback я разный пробовал, это не сильно влияет на самом деле):
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from keras import Sequential
from keras.layers import LSTM,Dense
import math
from sklearn.metrics import mean_squared_error
import matplotlib.pylab as plt
dataset = ((np.random.rand(1000, 1) - 0.5)*10000).cumsum().reshape(-1, 1)
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
train_size = int(len(dataset) * 0.15)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size, :], dataset[train_size:len(dataset), :]
#Создание матриц для внедрения их в модель МЛ
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset) - look_back - 1):
a = dataset[i:(i + look_back), 0]
dataX.append(a)
dataY.append(dataset[i + look_back, 0])
return np.array(dataX), np.array(dataY)
look_back = 5
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
# LSTM
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=20, batch_size=1, verbose=0)
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
#trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:, 0]))
print('Test Score: %.2f RMSE' % (testScore))
testScore = math.sqrt(mean_squared_error(testY[0][1:], testY[0][:-1]))
print('Baseline Score: %.2f RMSE' % (testScore))
trainPredictPlot = np.empty_like(dataset)
trainPredictPlot[:, :] = np.nan
trainPredictPlot[look_back:len(trainPredict) + look_back, :] = trainPredict
testPredictPlot = np.empty_like(dataset)
testPredictPlot[:, :] = np.nan
testPredictPlot[len(trainPredict) + (look_back * 2) + 1:len(dataset) - 1, :] = testPredict
plt.plot(scaler.inverse_transform(dataset))
plt.plot(testPredictPlot)
plt.show()

