理解用于NLP文本分类的LSTM和RNN中的单词嵌入、卷积层和最大池化层



这是我的输入数据:

data['text'].head()
0    process however afforded means ascertaining di...
1          never occurred fumbling might mere mistake 
2    left hand gold snuff box which capered hill cu...
3    lovely spring looked windsor terrace sixteen f...
4    finding nothing else even gold superintendent ...
Name: text, dtype: object

这里是一个热门编码标签(多类分类,其中类的数量=3(

[[1 0 0]
[0 1 0]
[1 0 0]
...
[1 0 0]
[1 0 0]
[0 1 0]]

以下是我认为一步一步发生的事情,如果我错了,请纠正我:

  1. 将我的输入文本data['text']转换为一袋索引(序列(

    vocabulary_size = 20000
    tokenizer = Tokenizer(num_words = vocabulary_size)
    tokenizer.fit_on_texts(data['text'])
    sequences = tokenizer.texts_to_sequences(data['text'])
    data = pad_sequences(sequences, maxlen=50)
    

正在发生的是,形状为(19579, )data['text'].shape被转换为形状为(19579, 50)的索引数组,其中每个单词都被tokenizer.word_index.items()中的索引所取代

  1. 加载glove 100d字矢量

    embeddings_index = dict()
    f = open('/Users/abhishekbabuji/Downloads/glove.6B/glove.6B.100d.txt')
    for line in f:
    values = line.split()
    word = values[0]
    coefs = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = coefs
    f.close()
    print(embedding_index)
    {'the': array([-0.038194, -0.24487 ,  0.72812 , -0.39961 ,  0.083172,  0.043953,
    -0.39141 ,  0.3344  , -0.57545 ,  0.087459,  0.28787 , -0.06731 ,
    0.30906 , -0.26384 , -0.13231 , -0.20757 ,  0.33395 , -0.33848 ,
    -0.31743 , -0.48336 ,  0.1464  , -0.37304 ,  0.34577 ,  0.052041,
    0.44946 , -0.46971 ,  0.02628 , -0.54155 , -0.15518 , -0.14107 ,
    -0.039722,  0.28277 ,  0.14393 ,  0.23464 , -0.31021 ,  0.086173,
    0.20397 ,  0.52624 ,  0.17164 , -0.082378, -0.71787 , -0.41531 ,
    0.20335 , -0.12763 ,  0.41367 ,  0.55187 ,  0.57908 , -0.33477 ,
    -0.36559 , -0.54857 , -0.062892,  0.26584 ,  0.30205 ,  0.99775 ,
    -0.80481 , -3.0243  ,  0.01254 , -0.36942 ,  2.2167  ,  0.72201 ,
    -0.24978 ,  0.92136 ,  0.034514,  0.46745 ,  1.1079  , -0.19358 ,
    -0.074575,  0.23353 , -0.052062, -0.22044 ,  0.057162, -0.15806 ,
    -0.30798 , -0.41625 ,  0.37972 ,  0.15006 , -0.53212 , -0.2055  ,
    -1.2526  ,  0.071624,  0.70565 ,  0.49744 , -0.42063 ,  0.26148 ,
    -1.538   , -0.30223 , -0.073438, -0.28312 ,  0.37104 , -0.25217 ,
    0.016215, -0.017099, -0.38984 ,  0.87424 , -0.72569 , -0.51058 ,
    -0.52028 , -0.1459  ,  0.8278  ,  0.27062 ], dtype=float32),
    

所以我们现在拥有的是100维的每个单词的单词向量。

  1. 使用手套词向量创建嵌入矩阵

    vocabulary_size = 20000
    embedding_matrix = np.zeros((vocabulary_size, 100))
    for word, index in tokenizer.word_index.items():
    if index > vocabulary_size - 1:
    break
    else:
    embedding_vector = embeddings_index.get(word)
    if embedding_vector is not None:
    embedding_matrix[index] = embedding_vector
    

所以我们现在对20000个单词中的每个单词都有100个维度的vector

这是架构:

model_glove = Sequential()
model_glove.add(Embedding(vocabulary_size, 100, input_length=50, weights=[embedding_matrix], trainable=False))
model_glove.add(Dropout(0.5))
model_glove.add(Conv1D(64, 5, activation='relu')) 
model_glove.add(MaxPooling1D(pool_size=4))
model_glove.add(LSTM(100))
model_glove.add(Dense(3, activation='softmax'))
model_glove.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
print(model_glove.summary())

我得到

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_7 (Embedding)      (None, 50, 100)           2000000   
_________________________________________________________________
dropout_7 (Dropout)          (None, 50, 100)           0         
_________________________________________________________________
conv1d_7 (Conv1D)            (None, 46, 64)            32064     
_________________________________________________________________
max_pooling1d_7 (MaxPooling1 (None, 11, 64)            0         
_________________________________________________________________
lstm_7 (LSTM)                (None, 100)               66000     
_________________________________________________________________
dense_7 (Dense)              (None, 3)                 303       
=================================================================
Total params: 2,098,367
Trainable params: 98,367
Non-trainable params: 2,000,000
_________________________________________________________________

上述架构的输入将是训练数据

array([[    0,     0,     0, ...,  4867,    22,   340],
[    0,     0,     0, ...,    12,   327,  2301],
[    0,     0,     0, ...,   255,   388,  2640],
...,
[    0,     0,     0, ...,    17, 15609, 15242],
[    0,     0,     0, ...,  9517,  9266,   442],
[    0,     0,     0, ...,  3399,   379,  5927]], dtype=int32)

形状为(19579, 50)

并标记为一个热门编码。。

我的问题是理解以下(19579, 50)在经过以下每一行时到底发生了什么:

model_glove = Sequential()
model_glove.add(Embedding(vocabulary_size, 100, input_length=50, weights=[embedding_matrix], trainable=False))
model_glove.add(Dropout(0.5))
model_glove.add(Conv1D(64, 5, activation='relu')) 
model_glove.add(MaxPooling1D(pool_size=4))

我理解我们为什么需要model_glove.add(Dropout(0.5)),这是为了关闭一些概率为0.5的隐藏单元,以避免模型过于复杂。但我不知道为什么我们需要Conv1D(64, 5, activation='relu')MaxPooling1D(pool_size=4),以及它是如何进入我的model_glove.add(LSTM(100))单元的。。

理解convolution最简单的方法是将其视为一个映射,告诉神经网络哪些特征(在图像识别的情况下,像素,在那里你将使用2D卷积;或者在文本的给定单词之前或之后的单词,在这里你将使用1D卷积(在附近。如果没有这一点,网络就无法知道某个单词之前或之后的单词比更远的单词更相关。它通常还导致信息以更密集的格式呈现,从而大大减少了参数的数量(在您的情况下,从200万减少到3万(。我发现这个答案解释了它如何很好地工作的技术性:https://stackoverflow.com/a/52353721/141789

Max pooling是一种对数据进行下采样的方法。它通常直接在卷积之后使用,并实现两件事:

  1. 它再次减少了参数的数量。在您的情况下,它将用一个值(四个值中的最大值(表示四个值。它通过取前四个值,然后取四个大小的"步长",再取下四个值等来实现这一点。换句话说,池之间不会有重叠。(默认情况下keras就是这样做的,但也可以将步幅设置为2(
  2. 其次,由于它采用了max值,因此在理论上,通过采用最大值而不是平均值来"锐化"池之间的对比度

未"学习"最大池化;这只是一个简单的算术运算。这就是为什么参数的数量为零的原因。CCD_ 18也是如此。

CCD_ 19期望形状为CCD_ 20的三维输入。在执行了前面的卷积和最大池化步骤后,您已经将初始嵌入的表示形式简化为number of timesteps = 11number of features = 64。第一个值number of samples = None是您计划使用的batch size的占位符。通过用100 units(也称为hidden states(初始化LSTM,您可以参数化LSTM的"内存"大小:本质上是其输入、输出和遗忘门随时间的累积。

最新更新