Символьный LSTM продолжает генерировать одну и ту же последовательность символов - PullRequest
0 голосов
/ 04 января 2019

Я тренирую двухслойный персонаж LSTM с керасом, чтобы сгенерировать последовательности символов, похожие на корпус, на котором я тренируюсь.Однако, когда я тренирую LSTM, сгенерированный вывод обученного LSTM повторяется снова и снова.

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

Мой обучающий код LSTM выглядит следующим образом:

# [load data from file]
raw_text = collected_statements.lower()
# create mapping of unique chars to integers
chars = sorted(list(set(raw_text + '\b')))
char_to_int = dict((c, i) for i, c in enumerate(chars)) 
seq_length = 100
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
    seq_in = raw_text[i:i + seq_length]
    seq_out = raw_text[i + seq_length]
    dataX.append([char_to_int[char] for char in seq_in])
    dataY.append(char_to_int[seq_out]) 

# reshape X to be [samples, time steps, features]
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))
# normalize
X = X / float(n_vocab)
# one hot encode the output variable
y = np_utils.to_categorical(dataY)

# define the LSTM model
model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), 
return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(256))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')

# define the checkpoint
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, 
save_best_only=True, mode='min')
callbacks_list = [checkpoint]

# fix random seed for reproducibility
seed = 8
numpy.random.seed(seed)
# split into 80% for train and 20% for test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
  random_state=seed)

# train the model
model.fit(X_train, y_train, validation_data=(X_test,y_test), epochs=18, 
  batch_size=256, callbacks=callbacks_list)

Мой код генерации выглядит следующим образом:

filename = "weights-improvement-18-1.5283.hdf5"
model.load_weights(filename)
model.compile(loss='categorical_crossentropy', optimizer='adam')
int_to_char = dict((i, c) for i, c in enumerate(chars))
# pick a random seed
start = numpy.random.randint(0, len(dataX)-1)
pattern = unpadded_patterns[start]
print("Seed:")
print("\"", ''.join([int_to_char[value] for value in pattern]), "\"")
# generate characters
for i in range(1000):
x = numpy.reshape(pattern, (1, len(pattern), 1))
x = (x / float(n_vocab)) + (numpy.random.rand(1, len(pattern), 1) * 0.01)
prediction = model.predict(x, verbose=0)
index = numpy.argmax(prediction)
#print(index)
result = int_to_char[index]
seq_in = [int_to_char[value] for value in pattern]
sys.stdout.write(result)
pattern.append(index)
pattern = pattern[1:len(pattern)]
print("\nDone.")

Когда я запускаю код генерации, я получаю то же самоепоследовательность снова и снова:

we have the best economy in the history of our country." "we have the best 
economy in the history of our country." "we have the best economy in the 
history of our country." "we have the best economy in the history of our 
country." "we have the best economy in the history of our country." "we 
have the best economy in the history of our country." "we have the best 
economy in the history of our country." "we have the best economy in the 
history of our country." "we have the best economy in the history of our 
country."

Могу ли я попробовать еще что-нибудь, что могло бы помочь генерировать что-то, кроме одной и той же последовательности снова и снова?

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Модель генерирует в качестве выходных данных вероятность следующего символа с учетом предыдущего символа.И в процессе генерации текста вы просто берете персонажа с вероятностью максимум .Вместо этого, это может помочь добавить некоторую стохастичность (то есть случайность) в этот процесс путем выборки следующего символа на основе распределения вероятностей, сгенерированного моделью.Один из простых способов сделать это - использовать функцию np.random.choice:

# get the probability distribution generated by the model
prediction = model.predict(x, verbose=0)

# sample the next character based on the predicted probabilites
idx = np.random.choice(y.shape[1], 1, p=prediction[0])[0]

# the rest is the same...

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

Кроме того, вы можете дополнительно добавить стохастичность, введя softmax температура впроцесс выборки, который вы можете увидеть в ответе @ Primusa, который основан на примере Keras char-rnn .По сути, его идеи состоят в том, что он перевесит распределение вероятностей, чтобы вы могли контролировать, насколько неожиданным (т.е. более высокая температура / энтропия) или предсказуемым (т.е. более низкая температура / энтропия) будет следующий выбранный символ.

0 голосов
/ 04 января 2019

При генерации вашего персонажа я бы предложил взять выборку из вероятностей, которые выводит ваша модель, вместо того, чтобы брать argmax напрямую.Вот что пример keras char-rnn делает для получения разнообразия.

Это код, который они используют для выборки в своем примере:

def sample(preds, temperature=1.0):
    # helper function to sample an index from a probability array
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

В вашем кодеу вас есть index = numpy.argmax(prediction)

Я бы предложил просто заменить это на index = sample(prediction) и поэкспериментировать с выбранными вами температурами.Имейте в виду, что более высокие температуры делают ваш вывод более случайным, а более низкие - менее случайным.

...