LSTM 词预测模型仅预测最频繁的词,或用于不平衡数据的损失

Posted

技术标签:

【中文标题】LSTM 词预测模型仅预测最频繁的词,或用于不平衡数据的损失【英文标题】:LSTM word prediction model predicts only the most frequent words, or which loss to use for imbalanced data 【发布时间】:2019-11-30 22:26:21 【问题描述】:

我决定尝试使用循环神经网络构建单词预测模型。网上有很多不同的例子,包括在线课程,听起来构建这样一个模型相当容易。他们中的大多数使用 LSTM。此外,大多数(如果不是全部)使用非常小的数据集。我决定尝试使用更大的数据集,即 20 News Groups 数据集from sklearn.datasets import fetch_20newsgroups。我做了一些最小的预处理:删除标点符号、停用词和数字。

我根据前面 10 个单词的历史来预测一个单词。我只使用至少有 11 个单词的帖子。对于每个帖子,我通过一个大小为 11 的滑动窗口并沿帖子滑动来构建一个训练集。对于每个位置,前 10 个单词是预测变量,第 11 个单词是目标。我整理了一个简单的模型:嵌入层、LSTM 层和输出密集层。代码如下:

def make_prediction_sequences(input_texts, max_nb_words, sequence_length = 10):
# input_texts is a list of strings/texts

# select top vocab_size words based on the word counts
# word_index is the dictionary used to transform the words into the tokens. 
    tokenizer = Tokenizer(oov_token='UNK',num_words=max_nb_words)
    tokenizer.fit_on_texts(input_texts)
    sequences = tokenizer.texts_to_sequences(input_texts)

    prediction_sequences = []
    for sequence in sequences:
        if len(sequence) > sequence_length: # at least 1 for prediction
            for j in range(0,len(sequence) - sequence_length):
                prediction_sequences.append(sequence[j:sequence_length+j+1])

    word_index = e:i-1 for e,i in tokenizer.word_index.items()  if i <= max_nb_words # i-1 because tokenizer is 1 indexed


    return (np.array(prediction_sequences) , word_index)

def batch_sequence_data(prediction_sequences, batch_size, sequence_length, vocab_size):
    number_batches = int(len(prediction_sequences)/batch_size)
    while True:
        for i in range(number_batches):
            X = prediction_sequences[i*batch_size:(i+1)*batch_size, 0:sequence_length]
            Y = to_categorical(prediction_sequences[i*batch_size:(i+1)*batch_size, sequence_length], num_classes=vocab_size)
            yield np.array(X),Y

VOCAB_SIZE = 15000
SEQUENCE_LENGTH = 10
BATCH_SIZE = 128
prediction_sequences, word_index = make_prediction_sequences(data, VOCAB_SIZE, sequence_length=SEQUENCE_LENGTH)

## define the model
EMBEDDING_DIM = 64
rnn_size = 32

sequence_input = Input(shape=(SEQUENCE_LENGTH,), dtype='int32', name='rnn_input')
embedding_layer = Embedding(len(word_index), EMBEDDING_DIM, input_length=SEQUENCE_LENGTH)
embedded_sequences = embedding_layer(sequence_input)
x = LSTM(rnn_size, use_bias=True)(embedded_sequences)
preds = Dense(VOCAB_SIZE, activation='softmax')(x)
model = Model(sequence_input, preds)
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['categorical_accuracy'])

#train the model
steps_per_epoch = len(prediction_sequences)/(BATCH_SIZE * SEQUENCE_LENGTH)
earlystop = EarlyStopping(patience=3, restore_best_weights=True,monitor='loss')
history = model.fit_generator(batch_sequence_data(prediction_sequences, BATCH_SIZE, SEQUENCE_LENGTH, VOCAB_SIZE), 
                    steps_per_epoch = steps_per_epoch, epochs=30, callbacks=[earlystop])

训练达到了 ~0.1 的准确度。当我应用该模型从训练数据中预测 10 个单词 sn-ps 的单词时,输出绝大多数是最常见的单词“one”。

我尝试了一个更复杂的模型,它有 2 个 LSTM 层、2 个 Dense 层。我尝试使用 gensim word2vec 模型使用预训练的词嵌入。准确率总是~0.1,大多数时候预测是“一”。

当我考虑时,这有点道理。预测不平衡数据的最常见类别可以“免费”提供高精度。这显然是一个局部最小值,但很难逃脱。 问题是,该算法不会最小化准确性,它会最小化损失,即 categorical_crossentropy,它应该适用于不平衡的数据。但是,也许这并不总是正确的,并且有不同的损失可以用来更好地处理不平衡的数据?

【问题讨论】:

您可以尝试使用像 glove 这样的预训练嵌入,它需要大量数据(数十亿个令牌)来训练。你的方法似乎对这项任务来说太简单了 @meowongac,谢谢你的建议。我尝试使用 GoogleNews-vectors-negative300.bin,结果相同。我同意你的观点,这种方法似乎太简单了,但由于它在很多地方都有宣传,我决定自己尝试一下,以获得真实世界的尺寸数据。 【参考方案1】:

在四处寻找之后,我发现了一个 research paper 引入了焦点损失,并且方便地,一个用于 keras 的 github 实现。

再加上@meowongac 的建议(我使用了 Google word2vec 嵌入),可以更好地采样频率较低的单词。

我还单独使用了class_weight

model.fit_generator(batch_sequence_data(prediction_sequences, 
                    BATCH_SIZE, SEQUENCE_LENGTH, VOCAB_SIZE), 
                    steps_per_epoch = steps_per_epoch, epochs=30, callbacks=[earlystop],
                    class_weight = class_weight)

我设置的与词频成反比。 同样,结合使用 Google 词嵌入,它在某种意义上更有效,可以找到频率较低的词。

例如,对于 10 个单词的序列:

['two', 'three', 'marines', 'sort', 'charges', 'pending', 'another', 'fight', 'week', 'interesting']

gamma = 5 的focal loss 方法预测下一个单词people,class_weight 方法预测attorney

【讨论】:

以上是关于LSTM 词预测模型仅预测最频繁的词,或用于不平衡数据的损失的主要内容,如果未能解决你的问题,请参考以下文章

是否有一些用于时间序列预测的预训练 LSTM、RNN 或 ANN 模型?

用于罕见事件时间序列预测的LSTM模型体系结构

Python中利用LSTM模型进行时间序列预测分析 - 预测爱尔兰的电力消耗

keras 序贯(Sequential)模型 常见设置

加载glove或者word2vec训练好的词向量进行训练LSTM等模型的训练

使用LSTM-RNN建立股票预测模型