【问题标题】:Keras LSTM Model for text-generation purpose用于文本生成目的的 Keras LSTM 模型
【发布时间】:2019-06-14 18:49:10
【问题描述】:

我是 Keras 和编写神经网络模型的初学者,实际上我正在尝试编写用于文本生成目的的 LSTM,但没有成功。我做错了什么?

我读到了这个问题:here 和其他文章,但有一些我无法得到的东西,对不起,如果我看起来很愚蠢。

目标

我的目的是生成固定长度的英文文章(1500 现在)。

假设我有一个 20k 记录数据集,包含不同长度的序列(基本上是文章),我为所有文章 (MAX_SEQUENCE_LENGTH=1500) 设置了一个固定长度并将它们标记化,得到一个矩阵 (X,我的训练数据) 看起来像:

[[   0    0    0 ...   88  664  206]
 [   0    0    0 ...    1   93  140]
 [   0    0    0 ...    3  173 2283]
 ...
 [  50 2761    4 ...  167  148  156]
 [   0    0    0 ...   10   77  206]
 [   0    0    0 ...  167  148  156]]

形状为20000x1500
我的 LSTM 的输出应该是一个 1 x MAX_SEQUENCE_LENGTH 标记数组。

我的模型是这样的:

def generator_model(sequence_input, embedded_sequences, output_shape):
    layer = LSTM(16,return_sequences = True)(embedded_sequences)
    layer = LSTM(32,return_sequences = True)(layer)
    layer = Flatten()(layer)
    output = Dense(output_shape, activation='softmax')(layer)
    generator = Model(sequence_input, output)
    return generator

与:
sequence_input = Input(batch_shape=(1, 1,1500), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)
output_shape = MAX_SEQUENCE_LENGTH

LSTM 应该在 20k x MAX_SEQUENCE_LENGTH 形状 (X) 的训练集上使用 model.fit() 进行训练。

当我调用model.predict(seed) 时,得到一个具有1 x MAX_SEQUENCE_LENGTH 形状的令牌数组作为输出,而seed 是一个随机噪声数组。

编译、拟合和预测

以下部分的cmets:
. generator.compile 有效,模型在帖子的edit 部分给出。
. generator.fit 编译,epochs=1 参数用于测试目的,将是 BATCH_NUM
.现在我对我给generator.fity 有一些疑问,现在我给出一个0 的矩阵作为目标输出,如果我用与X.shape[0] 不同的形状生成它,它会抛出错误,这意味着它需要为X 中的每条记录添加一个标签。但是如果我给他一个0 的矩阵作为targetmodel.fit,它不会只预测0 的数组吗?
.尽管我使用noise_generator()noise_integer_generator(),但给出的错误总是相同的,我相信这是因为它不喜欢我给出的y_shape 参数

embedding_layer = load_embeddings(word_index)
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,))
embedded_sequences = embedding_layer(sequence_input)
generator = generator_model(sequence_input, embedded_sequences, X.shape[1])
print(generator.summary())
generator.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
Xnoise = generate_integer_noise(MAX_SEQUENCE_LENGTH)
y_shape = np.zeros((X.shape[0],), dtype=int)
generator.fit(X, y_shape, epochs=1)
acc = generator.predict(Xnoise, verbose=1)

但实际上我收到以下错误

ValueError: Error when checking input: expected input_1 to have shape (1500,) but got array with shape (1,)

当我打电话时:

Xnoise = generate_noise(samples_number=MAX_SEQUENCE_LENGTH)
generator.predict(Xnoise, verbose=1)

我给出的噪音是一个1 x 1500 数组,但它似乎期待一个(1500,) 矩阵,所以我的输出的形状设置一定有某种错误。

我的模型是否适合我的目的?还是我写了一些我看不到的非常愚蠢的东西?

感谢您给我的帮助,我很感激!

编辑

更新日志:

v1.
###
- Changed model structure, now return_sequences = True and using shape instead of batch_shape
###
- Changed 
sequence_input = Input(batch_shape=(1,1,1500), dtype='int32')
to
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,))
###
- Changed the error the model is giving

v2.
###
- Changed generate_noise() code
###
- Added generate_integer_noise() code
###
- Added full sequence with the model compile, fit and predict
###
- Added model.fit summary under the model summary, in the tail of the post

generate_noise()代码:

def generate_noise(samples_number, mean=0.5, stdev=0.1):
    noise = np.random.normal(mean, stdev, (samples_number, MAX_SEQUENCE_LENGTH))
    print(noise.shape)
    return noise

哪个打印:(1500,)

generate_integer_noise()代码:

def generate_integer_noise(samples_number):
    noise = []
    for _ in range(0, samples_number):
        noise.append(np.random.randint(1, MAX_NB_WORDS))
    Xnoise = np.asarray(noise)
    return Xnoise

我的函数load_embeddings()如下:

def load_embeddings(word_index, embeddingsfile='Embeddings/glove.6B.%id.txt' %EMBEDDING_DIM):
    embeddings_index = {}
    f = open(embeddingsfile, 'r', encoding='utf8')
    for line in f:
        values = line.split(' ') #split the line by spaces
        word = values[0] #each line starts with the word
        coefs = np.asarray(values[1:], dtype='float32') #the rest of the line is the vector
        embeddings_index[word] = coefs #put into embedding dictionary
    f.close()

    print('Found %s word vectors.' % len(embeddings_index))

    embedding_matrix = np.zeros((len(word_index) + 1, EMBEDDING_DIM))
    for word, i in word_index.items():
        embedding_vector = embeddings_index.get(word)
        if embedding_vector is not None:
            # words not found in embedding index will be all-zeros.
            embedding_matrix[i] = embedding_vector

    embedding_layer = Embedding(len(word_index) + 1,
                                EMBEDDING_DIM,
                                weights=[embedding_matrix],
                                input_length=MAX_SEQUENCE_LENGTH,
                                trainable=False)
    return embedding_layer

模型总结:

Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 1500)              0         
_________________________________________________________________
embedding_1 (Embedding)      (None, 1500, 300)         9751200   
_________________________________________________________________
lstm_1 (LSTM)                (None, 1500, 16)          20288     
_________________________________________________________________
lstm_2 (LSTM)                (None, 1500, 32)          6272      
_________________________________________________________________
flatten_1 (Flatten)          (None, 48000)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 1500)              72001500  
=================================================================
Total params: 81,779,260
Trainable params: 72,028,060
Non-trainable params: 9,751,200
_________________________________________________________________


model.fit() 总结(使用 999 大小的数据集进行测试,而不是 20k 大小):

999/999 [==============================] - 62s 62ms/step - loss: 0.5491 - categorical_accuracy: 0.9680

【问题讨论】:

  • 现在 generate_noisesequence_input = Input(batch_shape=(1, 1,1500), dtype='int32') batch_shape 中的某处似乎有错误,应将其更改为 (1, 1500)。你能提供generate_noise函数和Xnoise.shape的代码吗?我猜Xnoise 除了第一个维度之外的所有维度都应该等于batch_shape[1:]
  • ofc,使用请求的代码编辑了原始帖子!
  • 好的,有一些不清楚的地方:1)你如何适合你的模型? 2)有return_sequencesstateful=True吗?我猜是前者。那么您不需要指定batch_shape,但可以使用shape。另外,目标的所需形状是什么? (?, 1500),我说的对吗?
  • 另外,你打算如何强制embedding_layer 处理浮点值(高斯噪声),​​而不是整数?也许你应该对整数进行采样。
  • 我重写了一个答案,我还建议您再编辑一次答案,并在使用之前将所有定义准确一次。 - 更新日志是个好主意!

标签: python keras neural-network lstm


【解决方案1】:

我重写了完整的答案,现在它可以工作了(至少可以编译和运行,不能说任何关于收敛的事情)。

首先,我不知道你为什么使用sparse_categorical_crossentropy 而不是categorical_crossentropy?这可能很重要。我稍微改变了模型,所以它编译并使用了 categorical_crossentropy。如果您需要sparse,请更改目标的形状。

另外,我将batch_shape 更改为shape 参数,因为它允许使用不同形状的批次。使用起来更容易。

最后的编辑:您应该更改 generate_noise,因为嵌入层等待来自 (0, max_features) 的数字,而不是正态分布的浮点数(请参阅函数中的注释)。

编辑
针对最后的 cmets,我删除了 generate_noise 并发布了修改后的 generate_integer_noise 函数:

from keras.layers import Input, Embedding, LSTM
from keras.models import Model
import numpy as np


def generate_integer_noise(samples_number):
    """
    samples_number is a number of samples, i.e. first dimension in (some, 1500)
    """
    return np.random.randint(1, MAX_NB_WORDS, size=(samples_number, MAX_SEQUENCE_LENGTH))

MAX_SEQUENCE_LENGTH = 1500
"""
Tou can use your definition of embedding layer, 
I post to make a reproducible example
"""
max_features, embed_dim = 10, 300
embedding_matrix = np.zeros((max_features, embed_dim))
output_shape = MAX_SEQUENCE_LENGTH

embedded_layer = Embedding(
    max_features,
    embed_dim,
    weights=[embedding_matrix],
    trainable=False
)


def generator_model(embedded_layer, output_shape):
    """
    embedded_layer: Embedding keras layer
    output_shape: shape of the target
    """
    sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH, ))
    embedded_sequences = embedded_layer(sequence_input)   # Set trainable to the True if you wish to train

    layer = LSTM(32, return_sequences=True)(embedded_sequences)
    layer = LSTM(64, return_sequences=True)(layer)
    output = LSTM(output_shape)(layer)

    generator = Model(sequence_input, output)
    return generator


generator = generator_model(embedded_layer, output_shape)

noise = generate_integer_noise(32)

# generator.predict(noise)
generator.compile(loss='categorical_crossentropy', optimizer='adam')
generator.fit(noise, noise)

【讨论】:

  • 非常感谢您的建议!我用我所做的更改编辑了答案!我已经有一个嵌入层,但我忘了粘贴代码!我改变了一点模型,因为它给我一些 input_shape 麻烦,状态参数设置为 true,所以我试图让它比以前更简单,但我认为我犯了另一个错误:(
  • 它的工作!仍然需要验证预测输出是否有意义,但我想这是另一个问题!你是我的英雄,非常感谢你的帮助,现在我想我更好地理解了所有这些事情是如何运作的! :D
  • 很高兴听到它,小心形状,它们是一个很棒的消磨时间
  • 是的,现在我知道了 XD
猜你喜欢
  • 1970-01-01
  • 2018-11-22
  • 2020-05-25
  • 2019-05-09
  • 2019-10-03
  • 1970-01-01
  • 2018-04-02
  • 2018-04-17
  • 1970-01-01
相关资源
最近更新 更多