用于语言任务的卷积神经网络
虽然卷积神经网络通常适用于视觉问题,但它们对于某些语言任务可能非常有效。
编者注:更多人工智能内容请关注2018年4月10-13日人工智能北京大会

在处理序列数据(如自然语言处理任务)这类问题时,递归神经网络(RNN)通常是首选方法。 尽管RNN的时间序列性质与文本数据相关的问题是天然匹配的,但是在处理视觉任务中曾获得巨大成功的卷积神经网络(CNN)在这些问题上也同样有效

我们的LSTM教程中,我们深入了解了长短期记忆模型(LSTM)的工作机制,并使用TensorFlow构建了一个多层LSTM网络,通过社交媒体信息对股市情绪进行建模。 在这篇文章中,我们将简要地讨论如何将CNN应用于文本数据,同时提供一些示例TensorFlow代码来构建CNN,以执行与我们的股票市场情绪模型类似的二分类任务。

image1-b4d9a40d7d18c24d8208f0dd35b3cf63

图1.用于文本分类的示例CNN模型结构。Garrett Hoffman提供图片,来自于论文《用于句子分类的卷积神经网络

我们在图1中,看到了一个用于文本分类的样本CNN网络结构。首先,我们从输入句子(长度为seq_len)开始,它表示为一个矩阵,其中行是我们的词向量,列是分布式词嵌入。 在计算机视觉问题中,我们通常会看到RGB的三个输入通道;不过,对于文本我们只有一个输入通道。 当我们在TensorFlow中实现我们的模型时,我们首先为输入定义占位符,然后建立词嵌入矩阵和嵌入查找表。

# Define Inputs

inputs_ = tf.placeholder(tf.int32, [None, seq_len], name=’inputs’)

labels_ = tf.placeholder(tf.float32, [None, 1], name=’labels—)

training_ = tf.placeholder(tf.bool, name=’training’)

# Define Embeddings

embedding = tf.Variable(tf.random_uniform((vocab_size, embed_size), -1, 1))

embed = tf.nn.embedding_lookup(embedding, inputs_)

注意CNN如何将输入作为一个完整的句子来处理,而不是像LSTM一样逐字地处理。对于CNN,我们将句子中所有单词索引的张量传递给我们的词嵌入查找表,并针对句子将返回的矩阵用作我们网络的输入。

现在,我们已经拥有了输入句子的嵌入表达,我们构建了卷积层。在我们的CNN中,我们将使用一维卷积,而不是通常用于视觉任务的二维卷积。我们将只定义一个高度,而不是为我们的卷积核定义一个高度和一个宽度,宽度总是嵌入维度。与图像在CNN中的表现方式相比,这是非常直观的。当我们处理图像时,每个像素都是一个分析单位,这些像素存在于我们输入图像的两个维度上。对于我们的句子,每个单词都是一个分析单位,用我们的词嵌入维度(我们的输入矩阵的宽度)表示,所以单词只存在于我们的”行”这一单一维度中。

我们可以使用尽量多的一维卷积核,而且我们喜欢不同的大小。图1显示了大小为2的卷积核(红框输入)和大小为3的卷积核(黄框输入)。我们还为每个图层定义了统一数量的卷积核数量(与我们对于二维卷积图像采用相同的方式),这将是卷积的输出维数。我们使用relu激活函数,并为我们的输出添加一个时间轴上的max-pooling (极大值池化),使每次卷积时,从每个卷积核中获得最大输出,每个卷积核中提取单独的模型特征。

# Define Convolutional Layers with Max Pooling

convs = []

for filter_size in filter_sizes:

conv = tf.layers.conv1d(inputs=embed, filters=128, kernel_size=filter_size, activation=tf.nn.relu)

pool = tf.layers.max_pooling1d(inputs=conv, pool_size=seq_len-filter_size+1, strides=1)

convs.append(pool)

我们可以将这些卷积层看作是“并行的” ,即一个卷积层不会再把输入送进下一层,它们都接受相同的输入,得到独立的输出,我们对其拼接,得到结果。

# Concat Pooling Outputs and Flatten

pool_concat = tf.concat(convs, axis=-1)

pool_flat = tf.layers.Flatten(pool_concat)

然后,我们现在用一个Sigmoid函数激活来构建一个全连接层,以便用我们拼接的卷积输出预测。 请注意,如果问题是多于两类的分类问题,我们也可以在这里使用tf.nn.softmax激活函数。 我们在这里还包括一个Dropout层来对模型进行正则化,让模型获得更好的泛化性能。

drop = tf.layers.Dropout(inputs=pool_flat, rate=keep_prob, training=training_)

dense = tf.layers.Dense(inputs=drop, num_outputs=1, activation_fn=tf.nn.sigmoid)

我们可以使用model_fn将这些代码封装到一个自定义的tf.Estimator中,制作一个简单的用于模型训练,模型评估和做预测的API

现在我们就有了“用于文本分类的卷积神经网络结构”。

与任何模型间比较相似的是,CNN和RNN之间在文本分类方面互有胜负。尽管RNN似乎是语言的一种更为自然的选择,但是CNN被证明训练速度比RNN快5倍,并且在特征检测非常重要的文本上表现良好。然而,当对输入序列的长期依赖性是重要因素时,RNN变体通常优于CNN。

最终,不同研究领域的语言问题会有所不同,因此在您的库中使用多种技术是非常重要的。这只是我们在不同研究领域成功应用趋势性技术的一个例子。虽然卷积神经网络传统上一直是计算机视觉世界的明星,但是我们开始看到将它们应用于序列数据时,会有更多突破。

这篇文章是O’Reilly和TensorFlow的合作。在此查看我们的编辑独立性声明

Garrett Hoffman

Garrett Hoffman是StockTwits公司的高级数据科学家,他主要致力于使用数据科学和机器学习来了解社会动态,并开发了一种研发工具,超过100万投资者都在使用。Garrett拥有数学和计算机科学方面的技术背景,但是从以人为本的角度来解决数据问题最让人兴奋 - 使用我们已知或可以从复杂系统中学到的知识来驱动最优化的决策、经验以及成果。

冰箱贴诗歌(来源: Steve Johnson)