Ответ 1
Я создал суть с простым генератором, который строится поверх вашей первоначальной идеи: это сеть LSTM, подключенная к предварительно подготовленным вложениям word2vec, обученная предсказать следующее слово в предложении. Данные - это список тезисов с сайта arXiv.
Здесь я расскажу о наиболее важных частях.
Gensim Word2Vec
Ваш код в порядке, за исключением количества итераций для его обучения. Значение по умолчанию iter=5
выглядит довольно низким. Кроме того, это определенно не узкое место - обучение LSTM занимает гораздо больше времени. iter=100
выглядит лучше.
word_model = gensim.models.Word2Vec(sentences, size=100, min_count=1,
window=5, iter=100)
pretrained_weights = word_model.wv.syn0
vocab_size, emdedding_size = pretrained_weights.shape
print('Result embedding shape:', pretrained_weights.shape)
print('Checking similar words:')
for word in ['model', 'network', 'train', 'learn']:
most_similar = ', '.join('%s (%.2f)' % (similar, dist)
for similar, dist in word_model.most_similar(word)[:8])
print(' %s -> %s' % (word, most_similar))
def word2idx(word):
return word_model.wv.vocab[word].index
def idx2word(idx):
return word_model.wv.index2word[idx]
Матрица внедрения результата сохраняется в массив pretrained_weights
который имеет форму (vocab_size, emdedding_size)
.
Модель Keras
Ваш код почти прав, за исключением функции потери. Поскольку модель предсказывает следующее слово, это задача классификации, следовательно, потеря должна быть categorical_crossentropy
или sparse_categorical_crossentropy
. Я выбрал последнее по соображениям эффективности: таким образом, он избегает одноразовой кодировки, что довольно дорого для большого словарного запаса.
model = Sequential()
model.add(Embedding(input_dim=vocab_size, output_dim=emdedding_size,
weights=[pretrained_weights]))
model.add(LSTM(units=emdedding_size))
model.add(Dense(units=vocab_size))
model.add(Activation('softmax'))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
Обратите внимание на перенос предварительно подготовленных весов на weights
.
Подготовка данных
Чтобы работать с sparse_categorical_crossentropy
, оба предложения и метки должны быть индексами слов. Короткие предложения должны быть дополнены нулями до общей длины.
train_x = np.zeros([len(sentences), max_sentence_len], dtype=np.int32)
train_y = np.zeros([len(sentences)], dtype=np.int32)
for i, sentence in enumerate(sentences):
for t, word in enumerate(sentence[:-1]):
train_x[i, t] = word2idx(word)
train_y[i] = word2idx(sentence[-1])
Создание образца
Это довольно прямолинейно: модель выводит вектор вероятностей, из которых следующее слово отбирается и добавляется к входу. Обратите внимание, что сгенерированный текст будет лучше и разнообразнее, если будет выбрано следующее слово, а не выбрано как argmax
. Здесь описывается случайная выборка, основанная на температуре.
def sample(preds, temperature=1.0):
if temperature <= 0:
return np.argmax(preds)
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)
def generate_next(text, num_generated=10):
word_idxs = [word2idx(word) for word in text.lower().split()]
for i in range(num_generated):
prediction = model.predict(x=np.array(word_idxs))
idx = sample(prediction[-1], temperature=0.7)
word_idxs.append(idx)
return ' '.join(idx2word(idx) for idx in word_idxs)
Примеры сгенерированного текста
deep convolutional... -> deep convolutional arithmetic initialization step unbiased effectiveness
simple and effective... -> simple and effective family of variables preventing compute automatically
a nonconvex... -> a nonconvex technique compared layer converges so independent onehidden markov
a... -> a function parameterization necessary both both intuitions with technique valpola utilizes
Не имеет особого смысла, но способен вырабатывать предложения, которые выглядят как минимум грамматически звуковыми (иногда).
Ссылка на полный исполняемый скрипт.