Примечание: это просто идея, и она может быть ошибочной.Попробуйте, если хотите, и я буду признателен за любые отзывы.
Есть ли способ достичь того, чего я хочу (избегать экстремальных скачков при прогнозировании вероятности), или этоданный факт?
Вы можете сделать это эксперимент : установить аргумент return_sequences
последнего слоя LSTM на True
и реплицировать метки каждого образца столько же, сколько и длинакаждого образца.Например, если образец имеет длину 100, а его метка равна 0, то создайте новую метку для этого образца, которая состоит из 100 нулей (вы, вероятно, можете легко сделать это, используя функцию numpy, например np.repeat
).Затем переобучите свою новую модель и протестируйте ее на новых образцах.Я не уверен в этом, но я ожидал бы больше монотонно увеличивающихся / уменьшающихся графов вероятности на этот раз.
Обновление: Указанная вами ошибка вызвана тем, что меткидолжен быть трехмерным массивом (посмотрите на выходную форму последнего слоя в сводке модели).Используйте np.expand_dims
, чтобы добавить еще одну ось размера один в конец.Правильный способ повторения меток будет выглядеть следующим образом, при условии, что y_train
имеет форму (num_samples,)
:
rep_y_train = np.repeat(y_train, num_reps).reshape(-1, num_reps, 1)
Эксперимент с набором данных IMDB:
На самом деле,Я попробовал эксперимент, предложенный выше для набора данных IMDB, используя простую модель с одним слоем LSTM.Один раз я использовал по одной метке на каждый образец (как в оригинальном подходе @Shlomi), а в другой раз я копировал метки, чтобы по одной метке на каждый временной шаг образца (как я предложил выше).Вот код, если вы хотите попробовать его самостоятельно:
from keras.layers import *
from keras.models import Sequential, Model
from keras.datasets import imdb
from keras.preprocessing.sequence import pad_sequences
import numpy as np
vocab_size = 10000
max_len = 200
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=vocab_size)
X_train = pad_sequences(x_train, maxlen=max_len)
def create_model(return_seq=False, stateful=False):
batch_size = 1 if stateful else None
model = Sequential()
model.add(Embedding(vocab_size, 128, batch_input_shape=(batch_size, None)))
model.add(CuDNNLSTM(64, return_sequences=return_seq, stateful=stateful))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
return model
# train model with one label per sample
train_model = create_model()
train_model.fit(X_train, y_train, epochs=10, batch_size=128, validation_split=0.3)
# replicate the labels
y_train_rep = np.repeat(y_train, max_len).reshape(-1, max_len, 1)
# train model with one label per timestep
rep_train_model = create_model(True)
rep_train_model.fit(X_train, y_train_rep, epochs=10, batch_size=128, validation_split=0.3)
Затем мы можем создать реплики с отслеживанием состояния моделей тренировок и запустить их на некоторых тестовых данных, чтобы сравнить их результаты:
# replica of `train_model` with the same weights
test_model = create_model(False, True)
test_model.set_weights(train_model.get_weights())
test_model.reset_states()
# replica of `rep_train_model` with the same weights
rep_test_model = create_model(True, True)
rep_test_model.set_weights(rep_train_model.get_weights())
rep_test_model.reset_states()
def stateful_predict(model, samples):
preds = []
for s in samples:
model.reset_states()
ps = []
for ts in s:
p = model.predict(np.array([[ts]]))
ps.append(p[0,0])
preds.append(list(ps))
return preds
X_test = pad_sequences(x_test, maxlen=max_len)
На самом деле, первая выборка X_test
имеет метку 0 (то есть принадлежит отрицательному классу), а вторая выборка X_test
имеет метку 1 (то есть принадлежит положительному классу).Итак, давайте сначала посмотрим, как будет выглядеть прогноз состояния с состоянием test_model
(то есть тот, который был обучен с использованием одной метки на выборку) для этих двух выборок:
import matplotlib.pyplot as plt
preds = stateful_predict(test_model, X_test[0:2])
plt.plot(preds[0])
plt.plot(preds[1])
plt.legend(['Class 0', 'Class 1'])
Результат:
test_model stateful predictions">
Правильная метка (т. Е. Вероятность) в конце (т. Е. Временной шаг 200), но очень колючая и колеблющаяся между ними.Теперь давайте сравним его с предсказаниями состояния rep_test_model
(то есть того, который был обучен с использованием одного ярлыка на каждый временной шаг):
preds = stateful_predict(rep_test_model, X_test[0:2])
plt.plot(preds[0])
plt.plot(preds[1])
plt.legend(['Class 0', 'Class 1'])
Результат:
rep_test_model stateful predictions">
Опять же, исправьте предсказание метки в конце, но на этот раз с гораздо более плавным и монотонным трендом, как и ожидалось.
Обратите внимание, что это был просто пример для демонстрации, и поэтому я использовал очень простую модель с одним слоем LSTM, и я вообще не пытался его настраивать.Я полагаю, что при лучшей настройке модели (например, при настройке количества слоев, количества единиц в каждом слое, используемых функций активации, типа и параметров оптимизатора и т. Д.) Вы можете получить гораздо лучшие результаты.