Нейронная сеть регрессора, построенная с использованием Keras, предсказывает только одно значение - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь создать NN с Keras и Tensorflow, чтобы предсказать окончательную позицию на графике песни, учитывая набор из 5 функций.

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

scatter plot

Это случайная выборка из 50 точек данных из моего тестового набора в сравнении с тем, что, по мнению сети, должно быть

Сначала я понял, что это, вероятно, потому, что моя сеть была слишком сложной. У меня был один входной слой с формой (5,) и один узел в выходном слое, но затем 3 скрытых слоя с более чем 32 узлами в каждом.

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

self.model = keras.Sequential([
keras.layers.Dense(4,
    activation='relu',
    input_dim=num_features,
    kernel_initializer='random_uniform',
    bias_initializer='random_uniform'
    ),
keras.layers.Dense(1)
])

Обучение этому с оптимизатором градиентного спуска все еще приводит к тому же прогнозу, который делается все время.

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

inp = keras.Input(shape=(num_features,))
out = keras.layers.Dense(1, activation='relu')(inp)
self.model = keras.Model(inp,out)

Это тоже ничего не изменило. Мое МАЕ, прогнозируемое значение у всех одинаковое. Я пробовал так много разных вещей, различные сочетания функций оптимизации, скорости обучения, конфигурации сети, и ничто не может помочь. Я почти уверен, что данные хорошие, но на всякий случай я привел их пример.

chartposition,tagcount,dow,artistscore,timeinchart,finalpos
121,3925,5,35128,7,227
131,4453,3,85545,25,130
69,2583,4,17594,24,523
145,1165,3,292874,151,187
96,1679,5,102593,111,540
134,3494,5,1252058,37,370
6,34895,7,6824048,22,5

Образец моего набора данных, finalpos - это значение, которое я пытаюсь предсказать. Набор данных содержит ~ 40 000 записей, разделение 80/20 - обучение / тестирование

def __init__(self, validation_split, num_features, should_log):
    self.should_log = should_log
    self.validation_split = validation_split

    inp = keras.Input(shape=(num_features,))
    out = keras.layers.Dense(1, activation='relu')(inp)
    self.model = keras.Model(inp,out)

    optimizer = tf.train.GradientDescentOptimizer(0.01)
    self.model.compile(loss='mae',
                  optimizer=optimizer,
                  metrics=['mae'])

def train(self, data, labels, plot=False):

    early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=20)

    history = self.model.fit(data,
                              labels,
                              epochs=self.epochs,
                              validation_split=self.validation_split,
                              verbose=0,
                              callbacks = [PrintDot(), early_stop])
    if plot: self.plot_history(history)

Весь код, относящийся к созданию и обучению сети

def normalise_dataset(df, mini, maxi):
    return (df - mini)/(maxi-mini)

Нормализация входных данных. Мои данные тестирования и обучения нормализованы до максимума и минимума набора тестирования

loss hidden

График моих потерь в сравнении с кривыми проверки с сетью из одного скрытого слоя с адамоптимизатором, скорость обучения 0,01

loss linear

Тот же график, но с линейной регрессией и оптимизатором градиентного спуска.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Оказывается, ошибка была действительно глупой и легко пропускаемой ошибкой.

Когда я импортировал свой набор данных, я перетасовал его, однако когда я выполнял перетасовку, я случайно применял перетасовку только к набору меток, а не ко всему набору данных в целом.

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

Спасибо @dennlinger за предложение посмотреть, где я в конечном итоге обнаружил эту ошибку.

0 голосов
/ 06 сентября 2018

Так что я почти уверен, что ваша нормализация - это проблема: вы не нормализуете с помощью функции (как является отраслевым стандартом де-факто), но по всем данным . Это означает, что если у вас есть две разные функции, которые имеют очень разные порядки величины / диапазона (в вашем случае, сравните timeinchart с artistscore.

Вместо этого вы можете захотеть нормализовать, используя что-то вроде scikit-learn's StandardScaler . Это не только нормализует каждый столбец (так что вы можете передать все объекты одновременно), но также и имеет отклонение от единицы (что является некоторым предположением о ваших данных, но потенциально может также помочь).

Чтобы преобразовать ваши данные, используйте что-то вроде этого

from sklearn.preprocessing import StandardScaler
import numpy as np

raw_data = np.array([[1,40], [2, 80]])
scaler = StandardScaler()
processed_data = scaler.fit_transform(raw_data) 
# fit() calculates mean etc, transform() puts it to the new range.
print(processed_data) # returns [[-1, -1], [1,1]]

Обратите внимание, что у вас есть две возможности для нормализации / стандартизации ваших тренировочных данных: Либо масштабируйте их вместе со своими тренировочными данными, а затем разделите , а затем , или вместо этого вы подгоняете только тренировочные данные, а затем используете тот же масштабер для преобразования ваших тестовых данных.
Никогда не подходите - трансформируйте свой тестовый набор отдельно от данных тренировок!
Поскольку у вас есть потенциально разные средние / минимальные / максимальные значения, вы можете получить совершенно неверные прогнозы! В некотором смысле StandardScaler - это ваше определение «распределения источников данных», которое по сути остается тем же для вашего тестового набора, даже если они могут быть подмножеством, не точно следующим за теми же свойствами (из-за небольшого размера выборки и т. Д.)

Кроме того, вы можете использовать более продвинутый оптимизатор , такой как Адам, или указать какое-либо свойство импульса (0.9 - хороший практический выбор, как правило) для вашего SGD.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...