Однократное векторное предсказание всегда возвращает одно и то же значение


Моя глубинная нейронная сеть возвращает один и тот же результат для каждого входа. Я попробовал (безуспешно) различные варианты:

  • потеря
  • оптимизатор
  • топология сети / типы слоев
  • число эпох (1-100)

У меня есть 3 выхода (один-горячий), и для каждого входного выхода они похожи (он меняется после каждой тренировки):

4.701869785785675049 e-01 4.793547391891479492 e-01 2.381391078233718872 e-01

Эта проблема возникает вероятно, из-за крайне случайного характера моих тренировочных данных (прогнозирование запасов).

Набор данных также сильно смещен в сторону одного из ответов (именно поэтому я использовал sample_weight - вычисленный пропорционально).

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

Один из примеров моей сети:

xs_conv = xs.reshape(xs.shape[0], xs.shape[1], 1)
model_conv = Sequential()
model_conv.add(Conv1D(128, 15, input_shape=(input_columns,1), activation='relu'))
model_conv.add(MaxPooling1D(pool_size=3))
model_conv.add(Dropout(0.4))
model_conv.add(Conv1D(64, 15, input_shape=(input_columns,1), activation='relu'))
model_conv.add(MaxPooling1D(pool_size=3))
model_conv.add(Dropout(0.4))
model_conv.add(Flatten())
model_conv.add(Dense(128, activation='relu'))
model_conv.add(Dropout(0.4))
model_conv.add(Dense(3, activation='sigmoid'))

model_conv.compile(loss='mean_squared_error', optimizer='nadam', metrics=['accuracy'])
model_conv.fit(xs_conv, ys, epochs=10, batch_size=16, sample_weight=sample_weight, validation_split=0.3, shuffle=True)
Я бы понял, если бы выходы были случайными, но то, что происходит, кажется очень странным. Есть идеи?

Данные: вычислено.csv

Весь код:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from keras.layers import Input, Dense, Conv1D, Dropout, MaxPooling1D, Flatten
from keras.models import Model, Sequential
from keras import backend as K
import random

DATA_DIR = '../../Data/'
INPUT_DATA_FILE = DATA_DIR + 'computed.csv'

def get_y(row):
    profit = 0.010
    hot_one = [0,0,0]
    hot_one[0] = int(row.close_future_5 >= profit)
    hot_one[1] = int(row.close_future_5 <= -profit)
    hot_one[2] = int(row.close_future_5 < profit and row.close_future_10 > -profit)
    return hot_one

def rolling_window(window, arr):
    return [np.array(arr[i:i+window]).transpose().flatten().tolist() for i in range(0, len(arr))][0:-window+1]

def prepare_data(data, widnow, test_split):
    xs1 = data.iloc[:,1:26].as_matrix()
    ys1 = [get_y(row) for row in data.to_records()]
    xs = np.array(rolling_window(window, xs1)).tolist()
    ys = ys1[0:-window+1]
    zipped = list(zip(xs, ys))
    random.shuffle(zipped)

    train_size = int((1.0 - test_split) * len(data))

    xs, ys = zip(*zipped[0:train_size])
    xs_test, ys_test = zip(*zipped[train_size:])
    return np.array(xs), np.array(ys), np.array(xs_test), np.array(ys_test)

def get_sample_weight(y):
    if(y[0]): return ups_w
    elif(y[1]): return downs_w
    else: return flats_w

data = pd.read_csv(INPUT_DATA_FILE)
window = 30
test_split = .9

xs, ys, xs_test, ys_test = prepare_data(data, window, test_split)

ups_cnt = sum(y[0] for y in ys)
downs_cnt = sum(y[1] for y in ys)
flats_cnt = sum(y[0] == False and y[1] == False for y in ys)
total_cnt = ups_cnt + downs_cnt + flats_cnt
ups_w = total_cnt/ups_cnt
downs_w = total_cnt/downs_cnt
flats_w = total_cnt/flats_cnt

sample_weight = np.array([get_sample_weight(y) for y in ys])

_, input_columns = xs.shape


xs_conv = xs.reshape(xs.shape[0], xs.shape[1], 1)
model_conv = Sequential()
model_conv.add(Conv1D(128, 15, input_shape=(input_columns,1), activation='relu'))
model_conv.add(MaxPooling1D(pool_size=3))
model_conv.add(Dropout(0.4))
model_conv.add(Conv1D(64, 15, input_shape=(input_columns,1), activation='relu'))
model_conv.add(MaxPooling1D(pool_size=3))
model_conv.add(Dropout(0.4))
model_conv.add(Flatten())
model_conv.add(Dense(128, activation='relu'))
model_conv.add(Dropout(0.4))
model_conv.add(Dense(3, activation='sigmoid'))

model_conv.compile(loss='mean_squared_error', optimizer='nadam', metrics=['accuracy'])
model_conv.fit(xs_conv, ys, epochs=1, batch_size=16, sample_weight=sample_weight, validation_split=0.3, shuffle=True)

xs_test_conv = xs_test.reshape(xs_test.shape[0], xs_test.shape[1], 1)
res = model_conv.predict(xs_test_conv)

plotdata = pd.concat([pd.DataFrame(res, columns=['res_up','res_down','res_flat']), pd.DataFrame(ys_test, columns=['ys_up','ys_down','y_flat'])], axis = 1)

plotdata[['res_up', 'ys_up']][3000:3500].plot(figsize=(20,4))
plotdata[['res_down', 'ys_down']][3000:3500].plot(figsize=(20,4))
1 2

1 ответ:

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

Например, в строке 623 есть значение inf в .csv. После того, как я отфильтровал их все с помощью
xs1 = xs1[np.isfinite(xs1).all(axis=1)]

... Я собрал некоторую статистику по xs, а именно min, max и mean. Они получились довольно примечательными:

-43.0049723138
32832.3333333    # !!!
0.213126234391

В среднем значения близки к 0, но некоторые из них на 6 порядков выше. Эти строки определенно повредит нейронной сети, поэтому вы должны либо фильтровать их, либо придумать умный способ нормализации функций.

Но даже с их помощью модель оказалась с точностью проверки 71-79%. Распределение результатов немного смещено в сторону 3-го класса, но в целом довольно разнообразно, чтобы назвать его своеобразным: 19% для класса 1, 7% для класса 2, 73% для класса 3. Пример вывода теста:
[[  1.93120316e-02   4.47684433e-04   9.97518778e-01]
 [  1.40607255e-02   2.45630667e-02   9.74113524e-01]
 [  3.07740629e-01   4.80920941e-01   2.28664145e-01]
 ..., 
 [  5.72797097e-02   9.45571139e-02   8.07634115e-01]
 [  1.05512664e-01   8.99530351e-02   6.70437515e-01]
 [  5.24505274e-03   1.46622911e-01   9.42657173e-01]]