[toc]

机器学习之卷积神经网络

标签(空格分隔): 机器学习 卷积神经网络


1. 神经网络是啥?

神经网络

神经网络其实就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(full connected, FC)神经网络,通过观察上面的图,我们可以发现它的规则包括:

  • 神经元按照层来布局。最左边的层叫做输入层,负责接收输入数据;最右边的层叫输出层,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层叫做隐藏层,因为它们对于外部来说是不可见的。
  • 同一层的神经元之间没有连接。
  • 第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入。
  • 每个连接都有一个权值。

上面这些规则定义了全连接神经网络的结构。事实上还存在很多其它结构的神经网络,比如卷积神经网络(CNN)、循环神经网络(RNN),他们都具有不同的连接规则。

但是一个神经网络的搭建,都需要满足三个条件。

  • 输入和输出
  • 权重(w)和阈值(b)
  • 多层感知器的结构

2. 神经网络的训练

搭建一个神经网络,首先要画出它的网络结构,也就是上面那张图。

不考虑超参数(hyperparameter),其中,最困难的部分就是确定权重(w)和阈值(b)。目前为止,这两个值都是主观给出的,但现实中很难估计它们的值,必需有一种方法,可以找出答案。

这种方法就是试错法。其他参数都不变,w(或b)的微小变动,记作Δw(或Δb),然后观察输出有什么变化。不断重复这个过程,直至得到对应最精确输出的那组w和b,就是我们要的值。这个过程称为模型的训练。

因此,神经网络的运作过程如下。

  1. 确定输入和输出
  2. 找到一种或多种算法,可以从输入得到输出
  3. 找到一组已知答案的数据集,用来训练模型,估算w和b
  4. 一旦新的数据产生,输入模型,就可以得到结果,同时对w和b进行校正

上述是阮一峰老师对神经网络运作过程的定义。 下面我以三层BP神经网络为例,简单介绍它的构造以及传播过程: 1. 确定隐藏层数目,输入输出层 2. 选择每一层对应的激活函数:为什么要引入激活函数呢?因为有些问题,线性模型不能很好的解决,所以我们需要对线性模型做一个变换,或者引入激活函数(activation function),常用的激活函数有tanh,sigmoid,ReLU,Softmax等。我们一般使用ReLU作为中间隐层神经元的激活函数,AlexNet中提出用ReLU来替代传统的激活函数是深度学习的一大进步。 3. 确定损失函数(loss function) 4. 选择合适的方法更新参数(这里以梯度下降法为例),确定学习率$$ \alpha $$,学习率决定学习快慢。但是设置过大可能会导致函数不收敛。 5. 随机初始化参数(w) (b)将数据喂入神经网络。 6. 根据下图公式进行前向传播 BP1 7. 如下图所示C在这里是代价函数,这是一个求最小化损失函数问题。首先来看看梯度下降的一个直观的解释。比如我们在一座大山上的某处位置,由于我们不知道怎么下山,于是决定走一步算一步,也就是在每走到一个位置的时候,求解当前位置的梯度,沿着梯度的负方向,也就是当前最陡峭的位置向下走一步,然后继续求解当前位置梯度,向这一步所在位置沿着最陡峭最易下山的位置走一步。这样一步步的走下去,一直走到觉得我们已经到了山脚。当然这样走下去,有可能我们不能走到山脚,而是到了某一个局部的山峰低处。 梯度下降 反向传播第一步,求C对最后一层中的两个分量求偏导。 BP3 反向传播第二部,求C对第二层中的三个分量求偏导。 BP5 都用到了积分的链式求导法则。总之,选定损失函数与激活函数,这些问题都可以迎刃而解。 8. 参数更新,重复前向传播,反向传播过程,直到损失函数小于某个设定好的数。 现在大家对神经网络应该有了基本的了解,现在我们来看看卷积神经网络(CNN)

3. 卷积神经网络处理(CNN)来处理中文文本。

3.1 什么是卷积神经网络(CNN)?

3x3的滤波器做卷积运算 上图是3x3的滤波器做卷积运算的直观显示。 把左侧的矩阵想象成一幅黑白图像。每一个元素对应一个像素点,0表示黑点,1表示白点(灰度图的像素值一般是0~255)。移动窗口又称作核、滤波器或是特征检测器。这里我们使用3x3的滤波器,将滤波器与矩阵对应的部分逐元素相乘,然后求和。我们平移窗口,使其扫过矩阵的所有像素,对整幅图像做卷积运算。

说到CNN,大家自然想到图像处理。 说到NLP,大家自然想到LSTM,RNN。 但是,16年的斯坦福论文表明,CNN照样可以应用于NLP,并且效果可能更好。 我用清华大学数据集做了训练,结果标明RNN和CNN在测试集都可以达到90%左右的效果,但是,CNN比RNN快了很多倍。

卷积神经网络与普通神经网络的区别在于,卷积神经网络包含了一个由卷积层和子采样层构成的特征抽取器。在卷积神经网络的卷积层中,一个神经元只与部分邻层神经元连接。在CNN的一个卷积层中,通常包含若干个特征平面(featureMap),每个特征平面由一些矩形排列的的神经元组成,同一特征平面的神经元共享权值,这里共享的权值就是卷积核。卷积核一般以随机小数矩阵的形式初始化,在网络的训练过程中卷积核将学习得到合理的权值。共享权值(卷积核)带来的直接好处是减少网络各层之间的连接,同时又降低了过拟合的风险。子采样也叫做池化(pooling),通常有均值子采样(mean pooling)和最大值子采样(max pooling)两种形式。子采样可以看作一种特殊的卷积过程。卷积和子采样大大简化了模型复杂度,减少了模型的参数。

3.2 如何将CNN用于NLP呢?

3.2.1 NLP的输入问题

NLP任务的输入不再是像素点了,大多数情况下是以矩阵表示的句子或者文档。矩阵的每一行对应于一个分词元素,一般是一个单词,也可以是一个字符。也就是说每一行是表示一个单词的向量。通常,这些向量都是word embeddings(一种底维度表示)的形式,如word2vec和GloVe,但是也可以用one-hot向量的形式,也即根据词在词表中的索引。若是用100维的词向量表示一句10个单词的句子,我们将得到一个10x100维的矩阵作为输入。这个矩阵相当于是一幅“图像”。

3.2.2 如何解决不同的文本长度不统一的问题?

这是一个非常显然的问题,在LeNet-5中,每个输入都是32*32的图像文件,这样我们才能设置固定大小和数量的filters,如果图像分辨率发生了变化,那么就会造成多余的conv操作的结果丢失,从而对模型的结果产生影响,或者会使得网络内部状态发生混乱。在图像处理中,可以通过固定输入的图像的分辨率来解决,但是在自然语言处理中,由于输入的是文档或者sentence,而输入的长度是不固定的,那么如何解决这个问题呢?其实,在NLP中,研究人员一般都采用的是“单层CNN结构”,这里的单层并不是只有一层,而是只有一对卷积层和池化层。可以看到,每次在卷积的时候,都是整行整行的进行的。

以下内容引用自Kim, Y. (2014). Convolutional Neural Networks for Sentence Classification. Proceedings, Kim, Y. (2014). 卷积神经网络用来语句分类 在不同的分类数据集上评估CNN模型,主要是基于语义分析和话题分类任务。CNN模型在各个数据集上的表现非常出色,甚至有个别刷新了目前最好的结果。令人惊讶的是,这篇文章采用的网络结构非常简单,但效果相当棒。输入层是一个表示句子的矩阵,每一行是word2vec词向量。接着是由若干个滤波器组成的卷积层,然后是最大池化层,最后是softmax分类器。该论文也尝试了两种不同形式的通道,分别是静态和动态词向量,其中一个通道在训练时动态调整而另一个不变。 用于句子分类器的卷积神经网络(CNN)结构示意图 这里我们对滤波器设置了三种尺寸:2、3和4行,每种尺寸各有两种滤波器。每个滤波器对句子矩阵做卷积运算,得到(不同程度的)特征字典。然后对每个特征字典做最大值池化,也就是只记录每个特征字典的最大值。这样,就由六个字典生成了一串单变量特征向量(univariate feature vector),然后这六个特征拼接形成一个特征向量,传给网络的倒数第二层。最后的softmax层以这个特征向量作为输入,用其来对句子做分类;我们假设这里是二分类问题,因此得到两个可能的输出状态。

3.2.3 CNN的超参数问题

窄卷积 vs 宽卷积

在上文中解释卷积运算的时候,我忽略了如何使用滤波器的一个小细节。在矩阵的中部使用3x3的滤波器没有问题,在矩阵的边缘该怎么办呢?左上角的元素没有顶部和左侧相邻的元素,该如何滤波呢?解决的办法是采用补零法(zero-padding)。所有落在矩阵范围之外的元素值都默认为0。这样就可以对输入矩阵的每一个元素做滤波了,输出一个同样大小或是更大的矩阵。补零法又被称为是宽卷积,不使用补零的方法则被称为窄卷积。

步长

卷积运算的另一个超参数是步长,即每一次滤波器平移的距离。上面所有例子中的步长都是1,相邻两个滤波器有重叠。步长越大,则用到的滤波器越少,输出的值也越少。下图来自斯坦福的cs231课程网页,分别是步长为1和2的情况: 卷积步长 卷积步长。左侧:步长为1,右侧:步长为2。

池化层

卷积神经网络的一个重要概念就是池化层,一般是在卷积层之后。池化层对输入做降采样。常用的池化做法是对每个滤波器的输出求最大值。我们并不需要对整个矩阵都做池化,可以只对某个窗口区间做池化。例如,下图所示的是2x2窗口的最大值池化(在NLP里,我们通常对整个输出做池化,每个滤波器只有一个输出值): CNN的最大池化 池化的特点之一就是它输出一个固定大小的矩阵,这对分类问题很有必要。例如,如果你用了1000个滤波器,并对每个输出使用最大池化,那么无论滤波器的尺寸是多大,也无论输入数据的维度如何变化,你都将得到一个1000维的输出。这让你可以应用不同长度的句子和不同大小的滤波器,但总是得到一个相同维度的输出结果,传入下一层的分类器。

池化还能降低输出结果的维度,(理想情况下)却能保留显著的特征。你可以认为每个滤波器都是检测一种特定的特征,例如,检测句子是否包含诸如“not amazing”等否定意思。如果这个短语在句子中的某个位置出现,那么对应位置的滤波器的输出值将会非常大,而在其它位置的输出值非常小。通过采用取最大值的方式,能将某个特征是否出现在句子中的信息保留下来,但是无法确定它究竟在句子的哪个位置出现。这个信息出现的位置真的很重要吗?确实是的,它有点类似于一组n-grams模型的行为。尽管丢失了关于位置的全局信息(在句子中的大致位置),但是滤波器捕捉到的局部信息却被保留下来了,比如“not amazing”和“amazing not”的意思就大相径庭。

在图像识别领域,池化还能提供平移和旋转不变性。若对某个区域做了池化,即使图像平移/旋转几个像素,得到的输出值也基本一样,因为每次最大值运算得到的结果总是一样的。

通道

通道即是输入数据的不同“视角”。比如说,做图像识别时一般会用到RGB通道(红绿蓝)。你可以对每个通道做卷积运算,赋予相同或不同的权值。你也同样可以把NLP想象成有许多个通道:把不同类的词向量表征(例如word2vec和GloVe)看做是独立的通道,或是把不同语言版本的同一句话看作是一个通道。


卷积神经网络(CNN)在自然语言处理的应用

1. 模型的构建

下图是本次项目中使用的卷积神经网络结构图: CNN模型连接图

  1. 首先确定网络结构,如上图。
  2. 本项目第一个Fully Connected层之后接dropout以及relu激活函数。 Relu激活函数 由于是多分类问题,所以输出层使用Softmax函数。 Softmax函数
  3. 损失函数(loss function)用交叉熵(Cross Entropy)函数交叉熵函数
  4. 优化器用了AdamOptimizer 前面我们已经介绍了Embedding层,卷积层,池化层,现在我们来介绍全连接层(Fully Connected)全连接层(fully connected layers,FC)在整个卷积神经网络中起到“分类器”的作用,传统的网络我们的输出都是分类,也就是几个类别的概率甚至就是一个数–类别号,那么全连接层就是高度提纯的特征了,方便交给最后的分类器或者回归。因为全连接的参数太多了,所以我们需要dropout一部分参数。

上述模型用以下代码来构建:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# coding: utf-8

import tensorflow as tf


class TCNNConfig(object):
    """CNN配置参数"""

    embedding_dim = 64  # 词向量维度
    seq_length = 600  # 序列长度
    num_classes = 14  # 类别数
    num_filters = 512  # 卷积核数目
    kernel_size = 9  # 卷积核尺寸
    vocab_size = 6000  # 词汇表达小

    hidden_dim = 128  # 全连接层神经元

    dropout_keep_prob = 0.6  # dropout保留比例
    learning_rate = 1e-3  # 学习率

    batch_size = 128  # 每批训练大小
    num_epochs = 10  # 总迭代轮次

    print_per_batch = 1000  # 每多少轮输出一次结果
    save_per_batch = 10  # 每多少轮存入tensorboard


class TextCNN(object):
    """文本分类,CNN模型"""

    def __init__(self, config):
        self.config = config

        # 三个待输入的数据
        self.input_x = tf.placeholder(tf.int32, [None, self.config.seq_length], name='input_x')
        self.input_y = tf.placeholder(tf.float32, [None, self.config.num_classes], name='input_y')
        self.keep_prob = tf.placeholder(tf.float32, name='keep_prob')

        self.cnn()

    def cnn(self):
        """CNN模型"""
        # 词向量映射
        with tf.device('/cpu:0'):
            embedding = tf.get_variable('embedding', [self.config.vocab_size, self.config.embedding_dim])
            embedding_inputs = tf.nn.embedding_lookup(embedding, self.input_x)

        with tf.name_scope("cnn"):
            # CNN layer
            conv = tf.layers.conv1d(embedding_inputs, self.config.num_filters, self.config.kernel_size, name='conv')
            # global max pooling layer
            gmp = tf.reduce_max(conv, reduction_indices=[1], name='gmp')

        with tf.name_scope("score"):
            # 全连接层,后面接dropout以及relu激活
            fc = tf.layers.dense(gmp, self.config.hidden_dim, name='fc1')
            fc = tf.contrib.layers.dropout(fc, self.keep_prob)
            fc = tf.nn.relu(fc)

            # 分类器
            self.logits = tf.layers.dense(fc, self.config.num_classes, name='fc2')
            self.y_pred_cls = tf.argmax(tf.nn.softmax(self.logits), 1)  # 预测类别

        with tf.name_scope("optimize"):
            # 损失函数,交叉熵
            cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y)
            self.loss = tf.reduce_mean(cross_entropy)
            # 优化器
            self.optim = tf.train.AdamOptimizer(learning_rate=self.config.learning_rate).minimize(self.loss)

        with tf.name_scope("accuracy"):
            # 准确率
            correct_pred = tf.equal(tf.argmax(self.input_y, 1), self.y_pred_cls)
            self.acc = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

2. 数据预处理

网络构建好了,然后我们通过以下代码对THUCNews数据集进行处理,将数据集都保存到txt文件中。数据集划分为70%训练集 15%验证集 15%测试集,运用以下代码对数据进行预处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
将文本整合到 train、test、val 三个文件中
"""

import os
from pathlib import Path #python3自带

def _read_file(filename):
    """读取一个文件并转换为一行"""
    with open(filename, 'r', encoding='utf-8') as f:
        return f.read().replace('\n', '').replace('\t', '').replace('\u3000', '')

def save_file(dirname):
    """
    将多个文件整合并存到3个文件中
    dirname: 原数据目录
    文件内容格式:  类别\t内容
    """
    f_train = open('data/cnews/cnews.train.txt', 'w', encoding='utf-8')
    f_test = open('data/cnews/cnews.test.txt', 'w', encoding='utf-8')
    f_val = open('data/cnews/cnews.val.txt', 'w', encoding='utf-8')
    for category in os.listdir(dirname):   # 分类目录
        cat_dir = os.path.join(dirname, category)
        if not os.path.isdir(cat_dir):
            continue
        files = os.listdir(cat_dir)
        count = 0
        data_num = len(list(Path(cat_dir).iterdir())) #读取当前目录下的文件总数
        for cur_file in files:
            filename = os.path.join(cat_dir, cur_file)
            content = _read_file(filename)
            if count < int(data_num*0.7):
                f_train.write(category + '\t' + content + '\n')
            elif count < int(data_num*0.85):
                f_test.write(category + '\t' + content + '\n')
            else:
                f_val.write(category + '\t' + content + '\n')
            count += 1

        print('Finished:', category)

    f_train.close()
    f_test.close()
    f_val.close()


if __name__ == '__main__':
    save_file('data/thucnews')
    print(len(open('data/cnews/cnews.train.txt', 'r', encoding='utf-8').readlines()))
    print(len(open('data/cnews/cnews.test.txt', 'r', encoding='utf-8').readlines()))
    print(len(open('data/cnews/cnews.val.txt', 'r', encoding='utf-8').readlines()))

我们的数据集划分如下 数据集结构 经过预处理,得到以下格式的数据。

Data Shape Data Shape
x_train [585247, 600] y_train [585247, 14]
x_val [125403, 600] y_val [125403, 14]
x_test [125425, 600] y_test [125425, 14]

3. 模型的训练

现在开始将数据喂进输入层,进行传播。也是两步前向传播和反向传播。

前向传播:输入数据->通过embedding层将输入的一维序列转为2维矩阵,比如输入层有m个句子,经过embedding层处理之后得到的是一个[m,600,64]的矩阵。然后就可以进行卷积,池化等操作了。 反向传播:确定了每个层的激活函数,以及损失函数,选择了AdamOptimizer优化方法。利用TensorFlow即可自动完成一系列运算。

由于数据量巨大,我们使用了阿里云的竞价服务器来跑这个神经网络,阿里云服务器

CNN训练过程如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Configuring TensorBoard and Saver...
Loading training and validation data...
Time usage: 0:09:09
2018-04-06 22:03:56.913969: I T:\src\github\tensorflow\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2018-04-06 22:03:57.574615: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1344] Found device 0 with properties:
name: Tesla P100-PCIE-16GB major: 6 minor: 0 memoryClockRate(GHz): 1.3285
pciBusID: 0000:00:08.0
totalMemory: 15.91GiB freeMemory: 15.50GiB
2018-04-06 22:03:57.574811: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1423] Adding visible gpu devices: 0
2018-04-06 22:06:25.657284: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:911] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-04-06 22:06:25.657401: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:917]      0
2018-04-06 22:06:25.658838: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:930] 0:   N
2018-04-06 22:06:25.691139: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1041] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 15039 MB memory) -> physical GPU (device: 0, name: Tesla P100-PCIE-16GB, pci bus id: 0000:00:08.0, compute capability: 6.0)
Training and evaluating...
Epoch: 1
Iter:      0, Train Loss:    2.6, Train Acc:  14.06%, Val Loss:    2.6, Val Acc:  18.46%, Time: 0:00:20 *
Iter:   1000, Train Loss:   0.25, Train Acc:  91.41%, Val Loss:   0.57, Val Acc:  83.44%, Time: 0:01:13 *
Iter:   2000, Train Loss:   0.33, Train Acc:  92.97%, Val Loss:   0.58, Val Acc:  83.11%, Time: 0:02:06
Iter:   3000, Train Loss:   0.18, Train Acc:  96.09%, Val Loss:   0.54, Val Acc:  84.72%, Time: 0:02:59 *
Iter:   4000, Train Loss:   0.19, Train Acc:  92.97%, Val Loss:   0.51, Val Acc:  84.84%, Time: 0:03:52 *
Epoch: 2
Iter:   5000, Train Loss:  0.087, Train Acc:  96.88%, Val Loss:   0.52, Val Acc:  84.83%, Time: 0:04:46
Iter:   6000, Train Loss:   0.14, Train Acc:  96.88%, Val Loss:   0.52, Val Acc:  85.21%, Time: 0:05:39 *
Iter:   7000, Train Loss:   0.29, Train Acc:  92.97%, Val Loss:   0.53, Val Acc:  85.06%, Time: 0:06:32
Iter:   8000, Train Loss:   0.13, Train Acc:  96.88%, Val Loss:   0.54, Val Acc:  84.69%, Time: 0:07:24
Iter:   9000, Train Loss:   0.16, Train Acc:  95.31%, Val Loss:   0.52, Val Acc:  84.90%, Time: 0:08:17
Epoch: 3
Iter:  10000, Train Loss:   0.12, Train Acc:  96.09%, Val Loss:   0.57, Val Acc:  83.93%, Time: 0:09:11
Iter:  11000, Train Loss:  0.082, Train Acc:  97.66%, Val Loss:   0.56, Val Acc:  84.58%, Time: 0:10:04
Iter:  12000, Train Loss:   0.12, Train Acc:  95.31%, Val Loss:   0.56, Val Acc:  84.67%, Time: 0:23:15
Iter:  13000, Train Loss:   0.14, Train Acc:  95.31%, Val Loss:   0.55, Val Acc:  84.99%, Time: 0:24:08
Epoch: 4
Iter:  14000, Train Loss:   0.11, Train Acc:  95.31%, Val Loss:   0.59, Val Acc:  85.23%, Time: 0:25:03 *
Iter:  15000, Train Loss:   0.17, Train Acc:  94.53%, Val Loss:   0.64, Val Acc:  84.65%, Time: 0:25:56
Iter:  16000, Train Loss:   0.11, Train Acc:  96.09%, Val Loss:   0.64, Val Acc:  83.83%, Time: 0:26:48
Iter:  17000, Train Loss:   0.13, Train Acc:  94.53%, Val Loss:   0.62, Val Acc:  84.13%, Time: 0:27:41
Iter:  18000, Train Loss:  0.054, Train Acc:  99.22%, Val Loss:   0.62, Val Acc:  84.48%, Time: 0:28:34
Epoch: 5
Iter:  19000, Train Loss:  0.076, Train Acc:  98.44%, Val Loss:   0.69, Val Acc:  84.41%, Time: 0:32:38
Iter:  20000, Train Loss:  0.062, Train Acc:  96.88%, Val Loss:   0.74, Val Acc:  84.36%, Time: 0:35:25
Iter:  21000, Train Loss:   0.11, Train Acc:  97.66%, Val Loss:   0.72, Val Acc:  83.92%, Time: 0:36:18
Iter:  22000, Train Loss:   0.15, Train Acc:  93.75%, Val Loss:   0.65, Val Acc:  83.98%, Time: 0:37:11
Epoch: 6
Iter:  23000, Train Loss:  0.056, Train Acc:  96.88%, Val Loss:   0.79, Val Acc:  84.31%, Time: 0:38:05
Iter:  24000, Train Loss:  0.071, Train Acc:  97.66%, Val Loss:   0.75, Val Acc:  83.90%, Time: 0:38:57
No optimization for a long time, auto-stopping...

可以看出在验证集上的最佳效果为85.23%。

4. 模型的检验

开始跑测试集,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Configuring CNN model...
WARNING:tensorflow:From C:\Anaconda3\lib\site-packages\tensorflow\python\util\deprecation.py:497: calling conv1d (from tensorflow.python.ops.nn_ops) with data_format=NHWC is deprecated and will be removed in a future version.
Instructions for updating:
`NHWC` for data_format is deprecated, use `NWC` instead
WARNING:tensorflow:From C:\Users\Administrator\Desktop\text_classification\cnn_model.py:66: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.
Instructions for updating:

Future major versions of TensorFlow will allow gradients to flow
into the labels input on backprop by default.

See tf.nn.softmax_cross_entropy_with_logits_v2.

Loading test data...
2018-04-06 22:56:42.164669: I T:\src\github\tensorflow\tensorflow\core\platform\cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
2018-04-06 22:56:42.612697: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1344] Found device 0 with properties:
name: Tesla P100-PCIE-16GB major: 6 minor: 0 memoryClockRate(GHz): 1.3285
pciBusID: 0000:00:08.0
totalMemory: 15.91GiB freeMemory: 15.50GiB
2018-04-06 22:56:42.612903: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1423] Adding visible gpu devices: 0
2018-04-06 22:56:43.294863: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:911] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-04-06 22:56:43.295002: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:917]      0
2018-04-06 22:56:43.298126: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:930] 0:   N
2018-04-06 22:56:43.299510: I T:\src\github\tensorflow\tensorflow\core\common_runtime\gpu\gpu_device.cc:1041] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 15039 MB memory) -> physical GPU (device: 0, name: Tesla P100-PCIE-16GB, pci bus id: 0000:00:08.0, compute capability: 6.0)
Testing...
Test Loss:   0.28, Test Acc:  92.24%
Precision, Recall and F1-Score...
             precision    recall  f1-score   support

         体育       0.98      0.99      0.99     19741
         财经       0.83      0.77      0.80      5565
         房产       1.00      1.00      1.00      3007
         家居       0.94      0.93      0.94      4888
         教育       0.93      0.93      0.93      6290
         科技       0.91      0.97      0.94     24439
         时尚       0.88      0.91      0.89      2005
         时政       0.84      0.93      0.88      9463
         游戏       0.90      0.87      0.88      3656
         娱乐       0.95      0.94      0.94     13895
         股票       0.93      0.87      0.90     23160
         彩票       0.97      0.85      0.91      1138
         社会       0.91      0.84      0.87      7627
         星座       0.98      0.87      0.92       537

avg / total       0.92      0.92      0.92    125411

Confusion Matrix...
[[19548     0     0     4     6    45     2    10     6    89     5     8
     18     0]
 [    0  4273     0    11     0    11     0    85     0     3  1169     0
     13     0]
 [    0     0  3005     1     0     0     0     0     0     0     1     0
      0     0]
 [   11     5    10  4558    26    23    92     8     1   129    12     0
     10     3]
 [   21     2     0    12  5874    59    17   116     5    23    40     0
    121     0]
 [    8    14     0   106    28 23621    37    49   308    53   174     1
     39     1]
 [    3     0     0    29    22    17  1817    37     1    50     1     0
     25     3]
 [   47    12     1     8    91   201     0  8787     1    42   106     5
    162     0]
 [   33     1     0     6    14   312     9     9  3187    68     6     0
     11     0]
 [  118     1     0    26    39   228    52   125    31 13090    55     0
    128     2]
 [   14   787     1    39    34  1150     3   852    10    74 20112     0
     82     2]
 [  100     1     0     1     3     5     0     5     0    11     2   963
     47     0]
 [   26    81     1    19   165   369    11   350     2   175    33    13
   6382     0]
 [    3     0     0     7     6     0    24     1     4    24     2     0
      0   466]]
Time usage: 0:01:37

在测试集上的准确率达到了92.24%,根据查准率与查全率(Precision & Recall)的调和平均值F1-Score来看,最低为财经类的0.80,其它的几乎都在0.90左右,是一个很不错的成绩。