1.CNN基础内容
CNN的全称是Convolutional Neural Network,是一种前馈神经网络。由一个或多个卷积层、池化层以及顶部的全连接层组成,在图像处理领域表现出色。
本文主要学习TextCNN,作为是CNN在文本分类领域的一个应用。
什么是卷积
- 卷积在图像处理领域中:
图片是由RGB或其他颜色模型下多种颜色图像叠加而成。而RGB由颜色由浅到深分为256个等级,故可将图片转化为数字矩阵。
构建正方形点阵,简单设置为3*3矩阵,该点阵为卷积核
将卷积核扣到图像上,将对应格子的数字相乘再相加
该过程为二维离散卷积操作
最外面一层无法进行卷积的,通常会在之前补为0,来保证输入输出维度一致。
(卷积核也被称为过滤器) - 卷积的数学表达
卷积可以理解火车进山洞或者山洞包火车的程度,g函数内取反原因类似火车掉头,而随着火车进入时间乘以速度为其进入山洞的程度。(形象理解)
池化
池化(pooling)一般在上述卷积过程之后,其对于输入的图片,选择某种方式对卷积结果进行压缩,一般有两种:
- 平均池化
平均池化顾名思义:在对应邻域内算出平均值 - 最大池化
最大池化顾名思义:在对应邻域内找到最大值
最大池化保留了纹理特征,平均池化保留整体的数据特征
添加池化层的作用:
- 降维。这点很好理解,就是经过池化操作后,图像"变小"了。在图像处理中,把图像缩小就称为下采样或降采样,由此可窥见池化操作的降维性质。
- 不变性(invariance)。包括平移不变性(translation invariance),旋转不变性(rotation invariance),尺度不变性(scale invariance)。简单来说,池化操作能将卷积后得到的特征图中的特征进行统一化。平移不变性,是指一个特征,无论出现在图片的哪一个位置,都会识别出来(也有人说平移不变性是权值共享带来的,权值共享:给一张输入图片,用一个卷积核去扫这张图,卷积核里面的数就叫权重,这张图每个位置是被同样的卷积核扫的,所以权重是一样的,也就是共享)。
- 定长输出。比如我们的文本分类的例子中就是使用到了这个特性。无论经过卷积后得到的特征图有多大,使用池化操作后总能得到一个scalar,再将这些scalar拼接在一起,就能得到一个定长的向量。
TextCNN
过程原理
单个卷积核只能提取一种类型的特征,那么我们若想使卷积层能够提取多个特征,则可以并行使用多个卷积核,其中每个卷积核提取一种特征。feature map 特征图是卷积层的输出的别名。
第一层是图中最左边的7乘5的句子矩阵,每行是词向量,维度=5,这个可以类比为图像中的原始像素点了。以1个样本为例,整体的前向逻辑是:
- 对词进行embedding,得到[seq_length, embedding_dim]
- 用N个卷积核,得到N个seq_length-filter_size+1长度的一维feature map
- 对feature map进行max-pooling(因为是时间维度的,也称max-over-time pooling),得到N个1x1的数值,这样不同长度句子经过pooling层之后都能变成定长的表示了
- 然后拼接成一个N维向量,作为文本的句子表示。
- 最后接一层全连接的 softmax 层,将N维向量压缩到类目个数的维度,输出每个类别的概率。
每层理解:
- 输入层
输入得到是n×k的矩阵,n为句子的单词数,k为每个词对应的词向量维度。在图中输入层的每一行就表示的是一个单词的5维词向量。这里为了使得向量长度一致对原句子进行了padding操作。
每个词向量可以是预训练好的(在其他语料库),也可以作为未知的参数由网络训练得到。故在图中的输入层采用的是双通道形式,有两个n×k输入矩阵,其中一个用预训练好的词向量嵌入表达,训练过程中不会发生改变。另外一个同样方式初始化后,将作为参数随着网络模型训练下去。 - 卷积层
由于卷积核和word embedding的宽度一致,一个卷积核对于一个sentence,卷积后得到的结果是一个vector,其shape=(sentence_len - filter_window_size + 1, 1),那么,在经过max-pooling操作后得到的就是一个Scalar。
使用多个filter_window_size(原因是,这样不同的kernel可以获取不同范围内词的关系,获得的是纵向的差异信息,即类似于n-gram,也就是在一个句子中不同范围的词出现会带来什么信息。比如可以使用3,4,5个词数分别作为卷积核的大小),每个filter_window_size又有num_filters个卷积核(原因是卷积神经网络学习的是卷积核中的参数,每个filter都有自己的关注点,这样多个卷积核就能学习到多个不同的信息。一个卷积核经过卷积操作只能得到一个scalar,将相同filter_window_size卷积出来,num_filter个scalar组合在一起,组成这个filter_window_size下的feature_vector。最后再将所有filter_window_size下的feature_vector也组合成一个single vector,作为最后一层softmax的输入。 - 池化层
图中所示的网络采用了1-Max池化,即为从每个滑动窗口产生的特征向量中筛选出一个最大的特征,然后将这些特征拼接起来构成向量表示。
TextCNN超参数:
注意在文本分类中特征就是词向量,有静态(static)和非静态(non-static)方式。static方式采用比如word2vec预训练的词向量,训练过程不更新词向量,实质上属于迁移学习了,特别是数据量比较小的情况下,采用静态的词向量往往效果不错。non-static则是在训练过程中更新词向量。
w2v_train:
import warnings
import logging
import os.path
import sys
import jieba
from collections import Counter
import multiprocessing
import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
# 忽略警告
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
if __name__ == '__main__':
program = os.path.basename(sys.argv[0]) # 读取当前文件的文件名
logger = logging.getLogger(program)
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s', level=logging.INFO)
logger.info("running %s" % ' '.join(sys.argv))
# input为输入语料, outp_model为输出模型, outp_vector为vector格式的模型
input = './word2vec_tree/data_con_str_train_new_50000.txt'
out_model = './word2vec_tree/con_tree_vector_768.model'
out_vector = './word2vec_tree/con_tree_vector_768.vector'
# 训练skip-gram模型(CBOW)
model = Word2Vec(LineSentence(input), # 空格分词
vector_size=768, # 维度大小
window=5, # 词向量上下文最大距离
min_count= 3,
workers=multiprocessing.cpu_count()) # 多核训练
# 训练模型
model.train(LineSentence(input), total_examples=model.corpus_count, epochs=10)
# 保存模型
model.save(out_model)
# 保存词向量
model.wv.save_word2vec_format(out_vector, binary=False)
# 建立词表
# model.build_vocab(LineSentence(input), update=True)
# model = Word2Vec.load(out_model)
gensim_dict = model.wv.key_to_index # word:num词典
str = gensim_dict.get('[unk]')
print(str)
print(len(model.wv.key_to_index))
print("word2vec model completed")