Регрессор со слоем LSTM продолжает возвращать одно и то же значение

#tensorflow #machine-learning #keras #neural-network #lstm

Вопрос:

Если я выполню следующий код, я получу массив тех же значений (прогнозируемых), как вы можете видеть здесь: введите описание изображения здесь

В основном мой ввод в регрессор-это массив чисел 0, 1, 2, … 99, и я ожидаю, что вывод будет 100. Я делаю это последовательно (несколько раз), как вы можете видеть в коде. Этот код должен быть доступен для выполнения. Что я делаю не так, и почему ожидаемый результат и результат отличаются?

введите описание изображения здесь

Код:

 import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt

from keras.layers import Dense
from keras.layers import LSTM
from keras.models import Sequential
from keras.layers import Dropout
from sklearn.preprocessing import MinMaxScaler
from datetime import datetime
from datetime import timedelta
from time import mktime


my_data = []
for i in range(0, 1000):
    my_data.append(i)

X_train = []
y_train = []

np_data = np.array(my_data)

for i in range(0, np_data.size - 100 ):
    X_train.append(np_data[i : i 100])
    y_train.append(np_data[i 100])

X_train, y_train = np.array(X_train), np.array(y_train)

X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1], 1])

regressor = Sequential()

regressor.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], 1)))

regressor.add(Dropout(0.2))


regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50, return_sequences=True))
regressor.add(Dropout(0.2))

regressor.add(LSTM(units=50))
regressor.add(Dropout(0.2))

regressor.add(Dense(units=1))

regressor.compile(optimizer='adam', loss='mean_squared_error')

regressor.fit(X_train, y_train, epochs=5, batch_size=32)


X_test = []
y_test = []

my_data = []
for i in range(1000, 1500):
    my_data.append(i)

np_data = np.array(my_data)

for i in range(0, np_data.size - 100 ):
    X_test.append(np_data[i : i 100])
    y_test.append(np_data[i 100])

X_test = np.array(X_test)

X_test = np.reshape(X_test, [X_test.shape[0], X_test.shape[1], 1])

predicted = regressor.predict(X_test)


plt.plot(y_test, color = '#ffd700', label = "Real Data")
plt.plot(predicted, color = '#1fb864', label = "Predicted Data")

plt.title(" Price Prediction")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.legend()
plt.show()
 

Комментарии:

1. Я думаю, это просто потому, что модель слишком сложна для изучения, это всего лишь простая задача линейного прогнозирования, одного плотного слоя было бы достаточно.

2. Привет @seermer, не могли бы вы, пожалуйста, предложить рабочий код?

3. смотрите ответ ниже, я изменил код, который работает так, как ожидалось

Ответ №1:

Как я объяснил в комментарии, это простая линейная задача, поэтому вы можете использовать линейную регрессию. Если вы хотите использовать keras/tf, вы можете построить модель с одним плотным слоем, вот код, который будет работать:

 import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
from keras import optimizers
from keras.layers import Dense
from keras.layers import LSTM
from keras.models import Sequential
from keras.layers import Dropout
from sklearn.preprocessing import MinMaxScaler
from datetime import datetime
from datetime import timedelta
from time import mktime

my_data = []
for i in range(0, 1000):
    my_data.append(i)

X_train = []
y_train = []

np_data = np.array(my_data)

for i in range(0, np_data.size - 100):
    X_train.append(np_data[i: i   100])
    y_train.append(np_data[i   100])

X_train, y_train = np.array(X_train), np.array(y_train)

X_train = np.reshape(X_train, [X_train.shape[0], X_train.shape[1]])

regressor = Sequential()

regressor.add(Dense(units=1, input_shape=(len(X_train[1]),)))

regressor.compile(optimizer=optimizers.adam_v2.Adam(learning_rate=0.1), loss='mean_squared_error')

regressor.fit(X_train, y_train, epochs=1000, batch_size=len(X_train))

X_test = []
y_test = []

my_data = []
for i in range(1000, 1500):
    my_data.append(i)

np_data = np.array(my_data)

for i in range(0, np_data.size - 100):
    X_test.append(np_data[i: i   100])
    y_test.append(np_data[i   100])

X_test = np.array(X_test)

X_test = np.reshape(X_test, [X_test.shape[0], X_test.shape[1]])

predicted = regressor.predict(X_test)

plt.plot(y_test, color='#ffd700', label="Real Data")
plt.plot(predicted, color='#1fb864', label="Predicted Data")

plt.title(" Price Prediction")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.legend()
plt.show()
 

Приведенный выше код приведет к желаемому прогнозу, вот изменения, которые я внес:

  1. изменил модель на один плотный слой, как я объяснил, это линейная зависимость
  2. увеличьте размер пакета. это просто для более быстрого обучения, вы можете уменьшить, если хотите, но тогда вам нужно одновременно снизить скорость обучения и увеличить эпохи
  3. увеличьте эпохи до 1000. Эти данные содержат тонны бесполезной информации, полезно только последнее значение каждого X, поэтому для изучения этого требуется относительно больше эпох. На самом деле, при использовании линейной регрессии, подобной этой, обычно возникают тысячи или даже десятки тысяч эпох, поскольку каждая эпоха в любом случае очень быстрая
  4. преобразуйте данные в (num_samples, num_features), что ожидается плотным слоем
  5. увеличьте скорость обучения, просто чтобы быстрее учиться

Я просто изменил это, чтобы доказать свою точку зрения, я больше не настраивал никакие другие параметры, я уверен, что вы можете добавить регуляторы, изменить скорость обучения и так далее, чтобы сделать это быстрее и проще. Но, честно говоря, я не думаю, что стоит тратить время на их настройку, так как предсказание линейных взаимосвязей на самом деле не то, для чего нужно глубокое обучение.
надеюсь, это поможет, не стесняйтесь комментировать, если у вас возникнет дальнейшая путаница 🙂

Ответ №2:

Ваша модель абсолютно избыточна для этой проблемы, но это не проблема ! Мы хотим предсказать линейную функцию, которая может присутствовать только с 2 параметрами (предсказано = модель(x) = param1 param2 * x). Модели только с одним нейроном (высота смещение) должно быть достаточно. Здесь ваша модель имеет 91 251 параметр ! Модель, использующая LSTM, и модель, использующая плотный слой, топологически голоморфны, поэтому каждая модель LSTM может достичь того же результата, что и плотная модель, и наоборот. (LSTM обычно легко обучаются для достижения того же результата, что и плотная модель.)

Существует множество проблем, и в вашем коде не соблюдаются лучшие практики.

Такого рода проблемы называются «Прогнозирование временных рядов», в них много замечательных статей в Интернете, если вы хотите подробнее изучить эту тему.

Прежде всего, всегда масштабируйте свои данные !
Не масштабированные данные усложняют обучение.
Как правило, для задач регрессии набор данных масштабируется от 0 до 1. Поэтому просто разделите данные с максимальным значением в ваших np_data.
Чрезвычайно высокие значения функции потерь, такие как «mean_square_error», должны указывать на то, что данные, которые получает модель, не масштабируются.

Для модели с использованием слоя LSTM измените форму X_train и y_train :

  • X_train должен быть в форме : (размер набора данных, n_past, n_feature)
  • y_train должен быть в форме : (размер набора данных, n_future, n_feature)

Где :

  • n_feature : количество различных данных, присутствующих в наборе данных, которые модель должна иметь для прогнозирования. Например, если вы хотите предсказать среднюю температуру на следующий день, учитывая среднее давление, среднюю температуру и количество осадков за последние N дней, n_feature должно быть равно 3 («Прогнозирование временных рядов с несколькими переменными»).
  • n_past : количество прошлых записей, переданных модели.
  • n_future : количество будущих прогнозов, которые вы должны предсказать («Многоступенчатое прогнозирование временных рядов»)

(примечание: n_feature в X_train и y_train не могут быть одинаковыми)

Здесь :

  • n_past : 100 (что является излишним, я уменьшаю до 4 в своем коде, чтобы ускорить обучение)
  • n_future : 1 потому что вам нужно предсказать только одно число, но вы можете предсказать, например, следующие 10 чисел (вам нужно изменить способ создания y_train, чтобы он соответствовал форме (dataset_len, 10, 1), очевидно)
  • n_feature : 1

Начните с более простой модели :
количество скрытого слоя, количество нейронов и для LSTM n_past-это гиперпараметры, такие как оптимизатор, скорость обучения, размер пакета, вес и инициализация смещения… Поэтому начните с простого и увеличьте сложность модели, если ваша модель не в состоянии достичь вашей цели.

Увеличьте количество тренировочных периодов.

Исследуйте поведение функции потерь во время тренировки: цель состоит в том, чтобы сойтись к 0.

Сделайте набор проверки, чтобы контролировать переобучение во время тренировки.

 my_data = []
for i in range(0, 1000):
    my_data.append(i)

X_train = []
y_train = []

np_data = np.array(my_data)

# last 4 values to predict the next one
n_past = 4
n_future = 1
n_feature = 1

for i in range(0, np_data.size - n_past):
    X_train.append(np_data[i : i   n_past])
    y_train.append(np_data[i   n_past])

X_train, y_train = np.array(X_train), np.array(y_train)

# Reshape
X_train = np.reshape(X_train, [X_train.shape[0], n_past, n_feature])
y_train = np.reshape(y_train, [y_train.shape[0], n_future, n_feature])

# Rescale dataset ]0,1]
max_value = np.max(np_data)
X_train = X_train / max_value
y_train = y_train / max_value

# More simple model (always overkill for linear function anyway)
# No Droupout because I dont know if the model is doing overfitting
regressor = Sequential()
regressor.add(LSTM(units=16, return_sequences=True, input_shape=(n_past, n_feature)))
regressor.add(LSTM(units=16, return_sequences=True))
regressor.add(LSTM(units=16))
regressor.add(Dense(units=1))

regressor.compile(optimizer='Adam', loss='mse')

# Summary the model to see if all layers are well combinated.
regressor.summary()

# validation_split = 0.2 : 20% of X_train and y_train are using to test your model
history = regressor.fit(X_train, y_train, epochs=100, batch_size=32, validation_split=0.2)

# Plot the training
plt.plot(history.history["loss"], color = 'red', label = "Traning loss")
plt.plot(history.history["val_loss"], color = 'green', label = "Validation loss")
plt.title("Training")
plt.xlabel("Epoch")
plt.ylabel("mse")
plt.legend()
plt.show()


# Make one test
test_i = 12
data = X_train[test_i].reshape(1, n_past, 1) # taking [test_i] result to the lost of the first dimension so : reshape to (batch_size=1, n_past, n_feature) for making prediction
expected = y_train[test_i]
predicted = regressor.predict(data)
print(f"data: {data.reshape(-1,) * max_value}nExpected: {expected * max_value}nPredicted: {predicted[0] * max_value}")
# multipled by max_value to rescale to the original data


X_test = []
y_test = []
my_data = []
for i in range(1000, 1500):
    my_data.append(i)

np_data = np.array(my_data)

for i in range(0, np_data.size - n_past ):
    X_test.append(np_data[i : i   n_past])
    y_test.append(np_data[i   n_past])

X_test = np.array(X_test)
X_test = np.reshape(X_test, [X_test.shape[0], n_past, n_feature])

# scale the data with the max_value of the training
X_test = X_test / max_value
predicted = regressor.predict(X_test)

# rescale the prediction
predicted = predicted * max_value

plt.plot(y_test, color = '#ffd700', label = "Real Data")
plt.plot(predicted, color = '#1fb864', label = "Predicted Data")

plt.title(" Price Prediction")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.legend()
plt.show()
 

введите описание изображения здесь
введите описание изображения здесь