如何使用LSTM构建语言模型以分配给定句子的发生概率

目前,我使用三元模型来实现这一目标。它为给定的句子分配发生的概率。但它仅限于两个词的上下文。然而,LSTM可以做得更多。那么,如何构建一个使用LSTM模型来分配给定句子发生概率的模型呢?


回答:

我刚刚编写了一个非常简单的示例,展示了如何使用LSTM模型计算句子的发生概率。完整的代码可以在这里找到这里

假设我们想预测以下数据集的句子发生概率(这首儿歌大约在1765年在伦敦的《鹅妈妈的旋律》中出版):

# Datadata = ["Two little dicky birds",        "Sat on a wall,",        "One called Peter,",        "One called Paul.",        "Fly away, Peter,",        "Fly away, Paul!",        "Come back, Peter,",        "Come back, Paul."]

首先,让我们使用keras.preprocessing.text.Tokenizer来创建词汇表并对句子进行标记化:

# Preprocess datatokenizer = Tokenizer()tokenizer.fit_on_texts(data)vocab = tokenizer.word_indexseqs = tokenizer.texts_to_sequences(data)

我们的模型将一系列词作为输入(上下文),并输出给定上下文下词汇表中每个词的条件概率分布。为此,我们通过填充序列并在其上滑动窗口来准备训练数据:

def prepare_sentence(seq, maxlen):    # Pads seq and slides windows    x = []    y = []    for i, w in enumerate(seq):        x_padded = pad_sequences([seq[:i]],                                 maxlen=maxlen - 1,                                 padding='pre')[0]  # Pads before each sequence        x.append(x_padded)        y.append(w)    return x, y# Pad sequences and slide windowsmaxlen = max([len(seq) for seq in seqs])x = []y = []for seq in seqs:    x_windows, y_windows = prepare_sentence(seq, maxlen)    x += x_windows    y += y_windowsx = np.array(x)y = np.array(y) - 1  # The word <PAD> does not constitute a classy = np.eye(len(vocab))[y]  # One hot encoding

我决定为每节诗歌单独滑动窗口,但这可以有不同的处理方式。

接下来,我们使用Keras定义并训练一个简单的LSTM模型。该模型包括一个嵌入层,一个LSTM层,以及一个带有softmax激活的密集层(它使用LSTM的最后一个时间步的输出,生成给定上下文下词汇表中每个词的概率):

# Define modelmodel = Sequential()model.add(Embedding(input_dim=len(vocab) + 1,  # vocabulary size. Adding an                                               # extra element for <PAD> word                    output_dim=5,  # size of embeddings                    input_length=maxlen - 1))  # length of the padded sequencesmodel.add(LSTM(10))model.add(Dense(len(vocab), activation='softmax'))model.compile('rmsprop', 'categorical_crossentropy')# Train networkmodel.fit(x, y, epochs=1000)

句子w_1 ... w_n发生的联合概率P(w_1, ..., w_n)可以使用条件概率规则计算:

P(w_1, ..., w_n)=P(w_1)*P(w_2|w_1)*...*P(w_n|w_{n-1}, ..., w_1)

其中每个条件概率由LSTM模型给出。请注意,这些概率可能非常小,因此为了避免数值不稳定问题,最好在对数空间中工作。将所有内容整合在一起:

# Compute probability of occurence of a sentencesentence = "One called Peter,"tok = tokenizer.texts_to_sequences([sentence])[0]x_test, y_test = prepare_sentence(tok, maxlen)x_test = np.array(x_test)y_test = np.array(y_test) - 1  # The word <PAD> does not constitute a classp_pred = model.predict(x_test)  # array of conditional probabilitiesvocab_inv = {v: k for k, v in vocab.items()}# Compute product# Efficient version: np.exp(np.sum(np.log(np.diag(p_pred[:, y_test]))))log_p_sentence = 0for i, prob in enumerate(p_pred):    word = vocab_inv[y_test[i]+1]  # Index 0 from vocab is reserved to <PAD>    history = ' '.join([vocab_inv[w] for w in x_test[i, :] if w != 0])    prob_word = prob[y_test[i]]    log_p_sentence += np.log(prob_word)    print('P(w={}|h={})={}'.format(word, history, prob_word))print('Prob. sentence: {}'.format(np.exp(log_p_sentence)))

注意:这是一个非常小的玩具数据集,我们可能会过拟合。


更新 2022年10月29日:对于更大的数据集,如果一次处理整个数据集,可能会耗尽内存。在这种情况下,我建议使用生成器来训练您的模型。请查看这个gist,了解使用数据生成器的修改版本。

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注