TextCNN——基于卷积神经网络的文本分类学习

1.CNN基础内容

CNN的全称是Convolutional Neural Network,是一种前馈神经网络。由一个或多个卷积层、池化层以及顶部的全连接层组成,在图像处理领域表现出色。
本文主要学习TextCNN,作为是CNN在文本分类领域的一个应用。

什么是卷积

  1. 卷积在图像处理领域中:
    图片是由RGB或其他颜色模型下多种颜色图像叠加而成。而RGB由颜色由浅到深分为256个等级,故可将图片转化为数字矩阵。
    TextCNN——基于卷积神经网络的文本分类学习_第1张图片
    构建正方形点阵,简单设置为3*3矩阵,该点阵为卷积核
    将卷积核扣到图像上,将对应格子的数字相乘再相加
    TextCNN——基于卷积神经网络的文本分类学习_第2张图片
    该过程为二维离散卷积操作
    TextCNN——基于卷积神经网络的文本分类学习_第3张图片
    最外面一层无法进行卷积的,通常会在之前补为0,来保证输入输出维度一致。
    TextCNN——基于卷积神经网络的文本分类学习_第4张图片
    (卷积核也被称为过滤器)
  2. 卷积的数学表达
    TextCNN——基于卷积神经网络的文本分类学习_第5张图片
    卷积可以理解火车进山洞或者山洞包火车的程度,g函数内取反原因类似火车掉头,而随着火车进入时间乘以速度为其进入山洞的程度。(形象理解)

池化

池化(pooling)一般在上述卷积过程之后,其对于输入的图片,选择某种方式对卷积结果进行压缩,一般有两种:

  1. 平均池化
    TextCNN——基于卷积神经网络的文本分类学习_第6张图片
    平均池化顾名思义:在对应邻域内算出平均值
  2. 最大池化
    TextCNN——基于卷积神经网络的文本分类学习_第7张图片
    最大池化顾名思义:在对应邻域内找到最大值
    最大池化保留了纹理特征,平均池化保留整体的数据特征

添加池化层的作用:

  1. 降维。这点很好理解,就是经过池化操作后,图像"变小"了。在图像处理中,把图像缩小就称为下采样或降采样,由此可窥见池化操作的降维性质。
  2. 不变性(invariance)。包括平移不变性(translation invariance),旋转不变性(rotation invariance),尺度不变性(scale invariance)。简单来说,池化操作能将卷积后得到的特征图中的特征进行统一化。平移不变性,是指一个特征,无论出现在图片的哪一个位置,都会识别出来(也有人说平移不变性是权值共享带来的,权值共享:给一张输入图片,用一个卷积核去扫这张图,卷积核里面的数就叫权重,这张图每个位置是被同样的卷积核扫的,所以权重是一样的,也就是共享)。
  3. 定长输出。比如我们的文本分类的例子中就是使用到了这个特性。无论经过卷积后得到的特征图有多大,使用池化操作后总能得到一个scalar,再将这些scalar拼接在一起,就能得到一个定长的向量。

TextCNN

过程原理

单个卷积核只能提取一种类型的特征,那么我们若想使卷积层能够提取多个特征,则可以并行使用多个卷积核,其中每个卷积核提取一种特征。feature map 特征图是卷积层的输出的别名。
第一层是图中最左边的7乘5的句子矩阵,每行是词向量,维度=5,这个可以类比为图像中的原始像素点了。以1个样本为例,整体的前向逻辑是:

  1. 对词进行embedding,得到[seq_length, embedding_dim]
  2. 用N个卷积核,得到N个seq_length-filter_size+1长度的一维feature map
  3. 对feature map进行max-pooling(因为是时间维度的,也称max-over-time pooling),得到N个1x1的数值,这样不同长度句子经过pooling层之后都能变成定长的表示了
  4. 然后拼接成一个N维向量,作为文本的句子表示。
  5. 最后接一层全连接的 softmax 层,将N维向量压缩到类目个数的维度,输出每个类别的概率。
    TextCNN——基于卷积神经网络的文本分类学习_第8张图片

每层理解:

  1. 输入层
    输入得到是n×k的矩阵,n为句子的单词数,k为每个词对应的词向量维度。在图中输入层的每一行就表示的是一个单词的5维词向量。这里为了使得向量长度一致对原句子进行了padding操作。
    每个词向量可以是预训练好的(在其他语料库),也可以作为未知的参数由网络训练得到。故在图中的输入层采用的是双通道形式,有两个n×k输入矩阵,其中一个用预训练好的词向量嵌入表达,训练过程中不会发生改变。另外一个同样方式初始化后,将作为参数随着网络模型训练下去。
  2. 卷积层
    由于卷积核和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的输入。
  3. 池化层
    图中所示的网络采用了1-Max池化,即为从每个滑动窗口产生的特征向量中筛选出一个最大的特征,然后将这些特征拼接起来构成向量表示。

TextCNN超参数:
TextCNN——基于卷积神经网络的文本分类学习_第9张图片
注意在文本分类中特征就是词向量,有静态(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")

你可能感兴趣的:(cnn,分类,学习)