欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NLP中的卷积神经网络

程序员文章站 2022-07-07 15:11:56
...

原文:http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/

一、何为卷积

1、卷积最开始是指信号处理领域的卷积操作:https://www.cnblogs.com/alexanderkun/p/8149059.html

2、图像的卷积,理解卷积最简单的方法是把它想成一个应用到矩阵上的滑动窗口函数

NLP中的卷积神经网络

想象左边的矩阵表示一张黑白的图片。每一个输入表示一个像素,0表示黑色,1表示白色(对于灰度图来说,取值通常介于0~255)。滑动窗口叫做kernelfilter, 或者 feature detector。这里我们用一个 3x3 的filter,和原始矩阵做点乘,然后相加。为了得到所有的卷积,我们通过在整个矩阵上滑动filter对每个元素都这样做。

图像经过卷积核后输出图像的大小:

输入图像(height,width) ,卷积核大小(h, w) 步长 (s , s)

padding = same时不考虑卷积核大小,输出图像: ceil(height/s,width/s)向上取整

padding = valid 时 输出图像 :(height-h+1)/s (width-w+1)/s

上图中,输入图像(5,5),卷积核(3,3)步长(1,1)则经过卷积之后得到的特征图大小为

NLP中的卷积神经网络

 二、NLP中的卷积

和图像像素不同,大多数NLP任务的输入是表示成矩阵的句子或者文档。矩阵的每一行对应一个token,也就是一个word,但是它可以是一个字符。也就是说每一行是一个向量,它代表一个word。通常来说,这些向量是word embeddings(低维表示),像 word2vec 或者 GloVe,但是也可以是索引词到词汇表的one-hot编码的向量。对于一个使用100维embedding的包含10个word的句子,我们的输入是一个10*100的矩阵,这就是我们的“图像”。

2.1 一维卷积

此时的卷积核在矩阵的每一行上滑动。也就是卷积核的宽和输入矩阵的宽度相同。高或者说区域的大小可能会变化,但是常用的滑动窗口一次包含2-5个words,即卷积核大小为:word个数 x(2-5)。如下图,一共6个卷积核,每个的卷积核的宽都是5,高分别是4,4,3,3,2,2。

NLP中的卷积神经网络

 

 2.2 池化:NLP中为某个维度的最大池化

Pooling也会减少输出的维度,但是(希望)保持最重要的信息。你可以认为每个filter都是用来探测特定的特征的,比如探测句子是否包含像“not amazing”的否定词。如果这个短语出现在句子中的某个地方,应用filter到那个区域的结果是获得一个很大的值,但是在其他区域得到的是较小的值。通过进行max操作,你可以保持特征是否出现在句子中的信息,但是你丢失了它到底出现在哪的信息。但是关于位置的信息不是真的有用吗?是的,它没有用,这和n-grams的词袋模型做的事情有一点类似。你丢失了位置的全局信息(where in a sentence something happens),但是你保持了filters捕获的局部信息,比如“not amazing”和“amazing not”就很不同。

2.3 全连接

CNN的最后一层,全连接层。在分类任务中,输出神经元个数=类别数。

三、TensorFlow中的一维卷积

tf.layers.conv1d(
inputs,
filters,
kernel_size,
strides=1,
padding='valid',
data_format='channels_last',
dilation_rate=1,
activation=None,
use_bias=True,
kernel_initializer=None,
bias_initializer=tf.zeros_initializer(),
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
trainable=True,
name=None,
reuse=None
)

前三个参数为最重要的参数

  • inputs: 输入tensor, 维度(batch_size, seq_length, embedding_dim) 是一个三维的tensor;其中,batch_size指每次输入的文本数量;seq_length指每个文本的词语数或者单字数;embedding_dim指每个词语或者每个字的向量长度;例如每次训练输入2篇文本,每篇文本有100个词,每个词的向量长度为20,那input维度即为(2, 100, 20)。

  • filters:过滤器(卷积核)的数目

  • kernel_size:卷积核的大小,卷积核本身应该是二维的,这里只需要指定一维,因为第二个维度即长度与词向量的长度一致,卷积核只能从上往下走,不能从左往右走,即只能按照文本中词的顺序,也是列的顺序。

vocabulary_size = 10000  # 词汇表达小
sequence_length = 600  # 序列长度
embedding_size = 64  # 词向量维度
num_filters = 256  # 卷积核数目
filter_size = 5  # 卷积核尺寸
num_fc_units = 128  # 全连接层神经元
dropout_keep_probability = 0.5  # dropout保留比例
learning_rate = 1e-3  # 学习率
batch_size = 64  # 每批训练大小
X_holder = tf.placeholder(tf.int32, [None, sequence_length])
embedding = tf.get_variable('embedding', [vocabulary_size, embedding_size])
#将输入数据做词嵌入,得到新变量embedding_inputs的形状为batch_size*sequence_length*embedding_size,即64*600*64
embedding_inputs = tf.nn.embedding_lookup(embedding,X_holder)
equence_length = 600  # 序列长度
filter_size = 5  # 卷积核尺寸
方法结果赋值给变量conv,形状为batch_size*596*num_filters,596是600-5+1的结果
conv = tf.layers.conv1d(embedding_inputs, num_filters, filter_size) # 64*596*256
max_pooling = tf.reduce_max(conv,[1]) # 64*256
full_connect = tf.layers.dense(max_pooling,num_fc_units) #64*128
full_connect_dropout = tf.contrib.layers.dropout(full_connect, keep_prob=dropout_keep_probability)
full_connect_activate = tf.nn.relu(full_connect_dropout) #**函数
softmax_before = tf.layers.dense(full_connect_activate, num_classes)  #64*14

 代码理解:

要在TensorFlow中创建文字嵌入,我们首先将文本分割成文字,然后为词汇表中的每个单词分配一个整数。假设这已经完成,那word_ids是这些整数的一个向量。例如,“I have a cat.”这个句子可以被分解[“I”, “have”, “a”, “cat”, “.”],然后相应的word_ids张量就会形成[5]并由5个整数组成。为了将这些单词id映射到向量,我们需要创建嵌入变量并使用tf.nn.embedding_lookup如下函数:

word_embeddings = tf.get_variable(“word_embeddings”,
    [vocabulary_size, embedding_size])
embedded_word_ids = tf.nn.embedding_lookup(word_embeddings, word_ids)

在此之后,在我们的例子中张量embedded_word_ids将具有形状[5, embedding_size],并且包含5个单词中的每一个的嵌入(密集向量)。在训练结束时,word_embeddings将包含词汇表中所有单词的嵌入,为词汇表。