[python] 왜 신경망이 자체 훈련 데이터에 대해 잘못 예측합니까?

데이터 스톡 예측을위한지도 학습을 통해 LSTM (RNN) 신경망을 만들었습니다. 문제는 자체 교육 데이터에서 잘못 예측하는 이유는 무엇입니까? (참고 : 아래의 재현 가능한 예 )

다음 5 일 주가를 예측하기 위해 간단한 모델을 만들었습니다.

model = Sequential()
model.add(LSTM(32, activation='sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(Dense(y_train.shape[1]))
model.compile(optimizer='adam', loss='mse')

es = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
model.fit(x_train, y_train, batch_size=64, epochs=25, validation_data=(x_test, y_test), callbacks=[es])

올바른 결과는 y_test(5 개의 값)에 있으므로 모델 열차는 90 일 전을 되돌아 본 후 다음을 사용하여 최상의 val_loss=0.0030결과 ( ) 에서 가중치를 복원합니다 patience=3.

Train on 396 samples, validate on 1 samples
Epoch 1/25
396/396 [==============================] - 1s 2ms/step - loss: 0.1322 - val_loss: 0.0299
Epoch 2/25
396/396 [==============================] - 0s 402us/step - loss: 0.0478 - val_loss: 0.0129
Epoch 3/25
396/396 [==============================] - 0s 397us/step - loss: 0.0385 - val_loss: 0.0178
Epoch 4/25
396/396 [==============================] - 0s 399us/step - loss: 0.0398 - val_loss: 0.0078
Epoch 5/25
396/396 [==============================] - 0s 391us/step - loss: 0.0343 - val_loss: 0.0030
Epoch 6/25
396/396 [==============================] - 0s 391us/step - loss: 0.0318 - val_loss: 0.0047
Epoch 7/25
396/396 [==============================] - 0s 389us/step - loss: 0.0308 - val_loss: 0.0043
Epoch 8/25
396/396 [==============================] - 0s 393us/step - loss: 0.0292 - val_loss: 0.0056

예측 결과는 정말 대단하지 않습니까?

여기에 이미지 설명을 입력하십시오

알고리즘이 # 5 시대에서 최고의 가중치를 복원했기 때문입니다. 자, 이제이 모델을 .h5파일로 저장 하고 -10 일 뒤로 이동하고 지난 5 일을 예측합시다 (첫 번째 예에서는 주말을 포함하여 4 월 17-23 일에 모델을 만들고 유효성을 검사 한 후 4 월 2-8 일에 테스트하겠습니다). 결과:

여기에 이미지 설명을 입력하십시오

절대적으로 잘못된 방향을 보여줍니다. 보시다시피, 모델이 훈련되었고 4 월 17-23 일에 설정된 유효성 검사에 5 위를 차지했지만 2-8에서는 그렇지 않았습니다. 더 많은 훈련을 시도하고, 내가 선택하는 신기원을 가지고 무엇을하든, 과거에는 항상 잘못된 예측을하는 많은 시간 간격이 있습니다.

훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다. 내가 시도한 것 :

  • 50k + 행, 20 년 주가로 대규모 데이터 세트를 사용하여 더 많거나 적은 기능 추가
  • 더 많은 숨겨진 레이어 추가, 다른 batch_sizes, 다른 레이어 활성화, 드롭 아웃, 배치 정규화와 같은 다른 유형의 모델 생성
  • 사용자 정의 EarlyStopping 콜백을 만들고 많은 유효성 검사 데이터 세트에서 평균 val_loss를 얻고 가장 적합한 것을 선택하십시오.

어쩌면 내가 뭔가를 그리워? 무엇을 개선 할 수 있습니까?

다음은 매우 간단하고 재현 가능한 예입니다. yfinanceS & P 500 주식 데이터를 다운로드합니다.

"""python 3.7.7
tensorflow 2.1.0
keras 2.3.1"""


import numpy as np
import pandas as pd
from keras.callbacks import EarlyStopping, Callback
from keras.models import Model, Sequential, load_model
from keras.layers import Dense, Dropout, LSTM, BatchNormalization
from sklearn.preprocessing import MinMaxScaler
import plotly.graph_objects as go
import yfinance as yf
np.random.seed(4)


num_prediction = 5
look_back = 90
new_s_h5 = True # change it to False when you created model and want test on other past dates


df = yf.download(tickers="^GSPC", start='2018-05-06', end='2020-04-24', interval="1d")
data = df.filter(['Close', 'High', 'Low', 'Volume'])

# drop last N days to validate saved model on past
df.drop(df.tail(0).index, inplace=True)
print(df)


class EarlyStoppingCust(Callback):
    def __init__(self, patience=0, verbose=0, validation_sets=None, restore_best_weights=False):
        super(EarlyStoppingCust, self).__init__()
        self.patience = patience
        self.verbose = verbose
        self.wait = 0
        self.stopped_epoch = 0
        self.restore_best_weights = restore_best_weights
        self.best_weights = None
        self.validation_sets = validation_sets

    def on_train_begin(self, logs=None):
        self.wait = 0
        self.stopped_epoch = 0
        self.best_avg_loss = (np.Inf, 0)

    def on_epoch_end(self, epoch, logs=None):
        loss_ = 0
        for i, validation_set in enumerate(self.validation_sets):
            predicted = self.model.predict(validation_set[0])
            loss = self.model.evaluate(validation_set[0], validation_set[1], verbose = 0)
            loss_ += loss
            if self.verbose > 0:
                print('val' + str(i + 1) + '_loss: %.5f' % loss)

        avg_loss = loss_ / len(self.validation_sets)
        print('avg_loss: %.5f' % avg_loss)

        if self.best_avg_loss[0] > avg_loss:
            self.best_avg_loss = (avg_loss, epoch + 1)
            self.wait = 0
            if self.restore_best_weights:
                print('new best epoch = %d' % (epoch + 1))
                self.best_weights = self.model.get_weights()
        else:
            self.wait += 1
            if self.wait >= self.patience or self.params['epochs'] == epoch + 1:
                self.stopped_epoch = epoch
                self.model.stop_training = True
                if self.restore_best_weights:
                    if self.verbose > 0:
                        print('Restoring model weights from the end of the best epoch')
                    self.model.set_weights(self.best_weights)

    def on_train_end(self, logs=None):
        print('best_avg_loss: %.5f (#%d)' % (self.best_avg_loss[0], self.best_avg_loss[1]))


def multivariate_data(dataset, target, start_index, end_index, history_size, target_size, step, single_step=False):
    data = []
    labels = []
    start_index = start_index + history_size
    if end_index is None:
        end_index = len(dataset) - target_size
    for i in range(start_index, end_index):
        indices = range(i-history_size, i, step)
        data.append(dataset[indices])
        if single_step:
            labels.append(target[i+target_size])
        else:
            labels.append(target[i:i+target_size])
    return np.array(data), np.array(labels)


def transform_predicted(pr):
    pr = pr.reshape(pr.shape[1], -1)
    z = np.zeros((pr.shape[0], x_train.shape[2] - 1), dtype=pr.dtype)
    pr = np.append(pr, z, axis=1)
    pr = scaler.inverse_transform(pr)
    pr = pr[:, 0]
    return pr


step = 1

# creating datasets with look back
scaler = MinMaxScaler()
df_normalized = scaler.fit_transform(df.values)
dataset = df_normalized[:-num_prediction]
x_train, y_train = multivariate_data(dataset, dataset[:, 0], 0,len(dataset) - num_prediction + 1, look_back, num_prediction, step)
indices = range(len(dataset)-look_back, len(dataset), step)
x_test = np.array(dataset[indices])
x_test = np.expand_dims(x_test, axis=0)
y_test = np.expand_dims(df_normalized[-num_prediction:, 0], axis=0)

# creating past datasets to validate with EarlyStoppingCust
number_validates = 50
step_past = 5
validation_sets = [(x_test, y_test)]
for i in range(1, number_validates * step_past + 1, step_past):
    indices = range(len(dataset)-look_back-i, len(dataset)-i, step)
    x_t = np.array(dataset[indices])
    x_t = np.expand_dims(x_t, axis=0)
    y_t = np.expand_dims(df_normalized[-num_prediction-i:len(df_normalized)-i, 0], axis=0)
    validation_sets.append((x_t, y_t))


if new_s_h5:
    model = Sequential()
    model.add(LSTM(32, return_sequences=False, activation = 'sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
    # model.add(Dropout(0.2))
    # model.add(BatchNormalization())
    # model.add(LSTM(units = 16))
    model.add(Dense(y_train.shape[1]))
    model.compile(optimizer = 'adam', loss = 'mse')

    # EarlyStoppingCust is custom callback to validate each validation_sets and get average
    # it takes epoch with best "best_avg" value
    # es = EarlyStoppingCust(patience = 3, restore_best_weights = True, validation_sets = validation_sets, verbose = 1)

    # or there is keras extension with built-in EarlyStopping, but it validates only 1 set that you pass through fit()
    es = EarlyStopping(monitor = 'val_loss', patience = 3, restore_best_weights = True)

    model.fit(x_train, y_train, batch_size = 64, epochs = 25, shuffle = True, validation_data = (x_test, y_test), callbacks = [es])
    model.save('s.h5')
else:
    model = load_model('s.h5')



predicted = model.predict(x_test)
predicted = transform_predicted(predicted)
print('predicted', predicted)
print('real', df.iloc[-num_prediction:, 0].values)
print('val_loss: %.5f' % (model.evaluate(x_test, y_test, verbose=0)))


fig = go.Figure()
fig.add_trace(go.Scatter(
    x = df.index[-60:],
    y = df.iloc[-60:,0],
    mode='lines+markers',
    name='real',
    line=dict(color='#ff9800', width=1)
))
fig.add_trace(go.Scatter(
    x = df.index[-num_prediction:],
    y = predicted,
    mode='lines+markers',
    name='predict',
    line=dict(color='#2196f3', width=1)
))
fig.update_layout(template='plotly_dark', hovermode='x', spikedistance=-1, hoverlabel=dict(font_size=16))
fig.update_xaxes(showspikes=True)
fig.update_yaxes(showspikes=True)
fig.show()



답변

OP는 흥미로운 발견을 가정합니다. 다음과 같이 원래 질문을 단순화하겠습니다.

모델이 특정 시계열에 대해 훈련 된 경우 모델이 이미 훈련 된 이전 시계열 데이터를 재구성 할 수없는 이유는 무엇입니까?

답은 훈련 과정 자체에 포함되어 있습니다. 이후 EarlyStoppingoverfitting 방지하기 위해 여기에 사용되는, 최고의 모델이 저장됩니다 epoch=5val_loss=0.0030으로 OP에 의해 언급했다. 이 경우 훈련 손실은 0.0343, 즉 훈련의 RMSE와 같습니다 0.185. 데이터 세트는 다음을 사용하여 조정되므로MinMaxScalar RMSE의 크기 조정을 취소하여 진행 상황을 이해해야합니다.

시간 순서의 최소값과 최대 값은 22903380입니다. 따라서 0.185훈련의 RMSE를 갖는 것은 훈련 세트에 대해서도 예측 된 값이 대략 실제 단위와 평균 0.185*(3380-2290), 즉 ~200단위로 다를 수 있음을 의미합니다 .

이것은 이전 시간 단계에서 훈련 데이터 자체를 예측할 때 큰 차이가있는 이유를 설명합니다.

교육 데이터를 완벽하게 에뮬레이트하려면 어떻게해야합니까?

나는이 질문을 나 자신에게 물었다. 간단한 대답은 훈련 손실이 가까워 0지도록하는 것입니다.

일부 훈련 후, 32셀이있는 1 LSTM 레이어 만있는 모델 이 훈련 데이터를 재구성하기에 충분히 복잡하지 않다는 것을 깨달았습니다 . 따라서 다음과 같이 다른 LSTM 레이어를 추가했습니다.

model = Sequential()
    model.add(LSTM(32, return_sequences=True, activation = 'sigmoid', input_shape=(x_train.shape[1], x_train.shape[2])))
    # model.add(Dropout(0.2))
    # model.add(BatchNormalization())
    model.add(LSTM(units = 64, return_sequences=False,))
    model.add(Dense(y_train.shape[1]))
    model.compile(optimizer = 'adam', loss = 'mse')

그리고이 모델은 1000고려하지 않고 신기원을 위해 훈련되었습니다 EarlyStopping.

model.fit(x_train, y_train, batch_size = 64, epochs = 1000, shuffle = True, validation_data = (x_test, y_test))

1000에포크가 끝나면 0.00047훈련 손실이 귀하의 경우 훈련 손실보다 훨씬 낮습니다. 따라서 모델이 훈련 데이터를 더 잘 재구성 할 것으로 기대합니다. 다음은 4 월 2 일 -8 일에 대한 예측 도표입니다.

예측

마지막 메모 :

특정 데이터베이스에 대한 교육이 모델이 교육 데이터를 완벽하게 재구성 할 수 있어야한다는 의미는 아닙니다. 특히, 조기 정지, 정규화 및 드롭 아웃과 같은 방법이 과적 합을 피하기 위해 도입 될 때 모델은 훈련 데이터를 암기하는 것보다 더 일반화되는 경향이 있습니다.


답변

훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다.

모델이 암기 대신 입력과 출력의 관계를 배우기를 원합니다. 모델이 각 입력에 대한 올바른 출력을 기억하는 경우 훈련 데이터가 적합하지 않다고 말할 수 있습니다. 데이터의 작은 하위 집합을 사용하여 모델이 과적 합되도록 할 수있는 경우가 종종 있으므로 원하는 동작을 시도하면됩니다.


답변

기본적으로 훈련 데이터에 대한 더 나은 결과를 얻으려면 훈련 정확도가 가능한 높아야합니다. 보유한 데이터와 관련하여 더 나은 모델을 사용해야합니다. 기본적으로 테스트 정확도에 관계없이이 목적에 대한 훈련 정확도를 확인해야합니다. 이것을 과적 합이라고도하며, 이는 시험 데이터보다는 훈련 데이터의 정확도를 향상시킵니다.

훈련 정확도보다는 최상의 테스트 / 검증 정확도를 취하는이 시나리오에서는 조기 중지가 영향을받을 수 있습니다.


답변

짧은 대답 :

세트:

batch_size = 1
epochs = 200
shuffle = False

직감 : 훈련 데이터에서 높은 정확도의 우선 순위를 설명하고 있습니다. 이것은 과적 합을 설명합니다. 이렇게하려면 배치 크기를 1, 에포크가 높고 셔플 오프로 설정하십시오.


답변

훈련 된 데이터에서 모델이 왜 잘못된 결과를 보여줍니까? 나는 데이터를 훈련시켰다. 그것은이 세트의 데이터를 예측하는 방법을 기억해야하지만, 잘못 예측한다.

당신이하고있는 것을보십시오 :

  1. 일부 레이어로 모델 만들기
  2. training_data를 사용한 훈련 모델
  3. 모델을 훈련하면 모든 훈련 가능한 매개 변수가 훈련됩니다 (예 : 모델의 무게가 저장 됨)
  4. 이 가중치는 이제 입력과 출력 사이의 관계를 나타냅니다.
  5. 동일한 training_data를 다시 예측하면이 시간 훈련 된 모델은 가중치를 사용하여 출력을 얻습니다.
  6. 이제 모델의 품질에 따라 예측이 결정되므로 데이터가 동일하더라도 원래 결과와 다릅니다.

답변

몸에 잘 맞지 않아서 숨겨진 레이어에 뉴런을 추가해야한다는 점을 개선했습니다. !! 또 다른 요점은 ‘relu’활성화 기능입니다. S 자형은 좋은 결과를 제공하지 않습니다. 또한 출력 레이어에서 ‘softmax’를 정의해야합니다.!


답변

모델 아키텍처와 옵티 마이저를 Adagrad로 변경 한 후 결과를 어느 정도 개선 할 수있었습니다.

Adagrad 옵티 마이저를 사용하는 이유는 다음과 같습니다.

학습 속도를 매개 변수에 적용하여 자주 발생하는 기능과 관련된 매개 변수에 대해 더 작은 업데이트 (즉, 낮은 학습 속도)를 수행하고 드문 기능과 관련된 매개 변수에 대해 더 큰 업데이트 (즉, 높은 학습 속도)를 수행합니다. 이러한 이유로 희소 데이터를 처리하는 데 적합합니다.

아래 코드를 참조하십시오 :

model = Sequential()
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform', input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(Dropout(0.2))
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform'))
model.add(LSTM(units=100,return_sequences=True, kernel_initializer='random_uniform'))
model.add(Dropout(0.20))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(y_train.shape[1]))

# compile model
model.compile(loss="mse", optimizer='adagrad', metrics=['accuracy'])
model.summary()

주식 예측은 단일 모델의 예측을 고수하기보다는 매우 까다로운 작업이므로, 여러 모델을 함께 사용하여 예측을 수행 한 다음 앙상블 학습 방식과 유사하게 최대 투표 결과를 기반으로 전화를 걸 수 있습니다. 또한 다음과 같이 몇 가지 모델을 함께 쌓을 수 있습니다.

  1. 차원을 줄이기위한 딥 피드 포워드 자동 인코더 신경망 + 딥 재발 신경망 + ARIMA + 극한 증감 그라디언트 회귀

  2. Adaboost + Bagging + Extra Trees + Gradient Boosting + Random Forest + XGB

강화 학습 에이전트는 다음과 같이 주식 예측에서 꽤 잘하고 있습니다.

  1. 거북이 무역 에이전트
  2. 이동 평균 에이전트
  3. 신호 롤링 에이전트
  4. 정책 그라디언트 에이전트
  5. Q- 러닝 에이전트
  6. 진화 전략 요원

여기 에서 매우 유용한 링크를 찾으 십시오 .