一个简单的CNN model,训练集MNIST

一个简单的CNN model,训练集MNIST

最近学了点机器学习相关的东西,迫不及待跑了一下MNIST,现拿出来分享一下,也算是个记录笔记

一、谈谈我的理解

1.卷积

卷积就像全连接层的权重W,主要更新的参数也就是这些卷积核,卷积核有不同的大小尺寸1x1,2x2,3x3,5x5……,尺寸的不同代表能提取的特征也不相同,尺寸大表示能从‘更广的视野’去看问题。
但是尺寸越大也意味着计算量越大,但是在inception V3中,5x5的卷积被两个3x3级联代替了,训练结果表示模型并不会因此而变差,这表示这些不同的特征之间也是有某种联系的,并非相互独立。某篇论文也展示了层与层(即特征与特征)之间的联系有时是高度相关的。

2.池化

池化就是用来提取特征的。一幅图经过卷积之后会得到不同的特征图,这些特征分散的分布在一整幅图片中,maxpooling能提取主要的特征,同时减小尺寸(类似压缩图片)

3.pad

由于这里的卷积是点乘操作,所以ZeroPadding引入的0,对卷积和pooling影响都不大,只是为了输出尺寸而设计的

4.过拟合

随着迭代次数增加,网络的权重参数会使训练集的准确度不断上升,出现“坐井观天”的情况,测试集的准确度反而下降了

5.Dropout

应对过拟合的常用方法,通常放在激活层之后,通过“掐断”一部分神经元,使得对网络引入一个随机变量,有效阻止过拟合

6.BatchNormalization

归一化处理input数据,这并不会使网络结构发生变化,归一化只是数据集的平移伸缩变换,将数据的分布位置改变了,一个良好的分布位置能很好的训练和调整参数,而不会出现梯度消失或梯度爆炸。
同时引入BN层也相当于引入了一个随机变量,同样可以达到防止过拟合的效果,只不过这种随机不可控,而Dropout可以调整参数,因而可控。一般我们在发现即使引入了BN层仍然出现了过拟合,此时就可以考虑加Dropout等

7.优化算法

SGD对学习率很讲究,学习率大了,步子就迈大了,容易扯着*,学习率小了,又像穿着小鞋,跑不快,而且可能陷入局部解。因此变成了SGD+Momentum的方式,引入了动量,使齐能够冲出局部解,同时加入摩擦系数,使其能更好的到达最优解
AdaGrad算法是引入梯度的平方,而且是累计项,即所有之前梯度平方的和,那么这个累计项是单调增的,让累计项做分母会使刚开始步子迈的大些,后面会越来越小,很容易在后面陷入局部解,永远出不来。RMSProp算法改进了AdaGrad算法,引入了衰减因子(衰减因子不能太小,否则不更新,一般取0.9or0.99),这使得之前累加的梯度会因衰减因子而逐渐消失,(一个不太恰当的比喻,想象一下数据结构中的队列,这个队列差不多,只不过是平滑的)
Adam算法结合了上面两大类的优点,即引入了动量,又引入了带衰减因子的梯度平方项,是个很好的算法,我首选Adam优化算法

二、代码部分

下面放代码

0.import

import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
import os
import struct

1.读取MNIST训练集

这是读取了手动下载的MNIST训练集,要读取测试集的话方法类似,改下变量名即可,不再赘述

def read_trainsets():
    # 读取二进制数据
    train_img_sets = open('MNIST/train-images.idx3-ubyte', 'rb').read()
    train_label_sets = open('MNIST/train-labels.idx1-ubyte', 'rb').read()

    # 解析文件头信息,依次为魔数、图片数量、每张图片高、每张图片宽
    offset_img, offset_label = 0, 0
    img_header = '>iiii'  # '>IIII'是说使用大端法读取4个unsinged int32
    label_header = '>ii'

    (magic_number,
     num_images,
     num_rows,
     num_cols) = struct.unpack_from(img_header,
                                    train_img_sets,
                                    offset_img)

    (magic_number,
     num_labels) = struct.unpack_from(label_header,
                                      train_label_sets,
                                      offset_label)
    print('trainsets--魔数:%d, 图片数量: %d张, 图片大小: %d*%d'
          % (magic_number, num_images, num_rows, num_cols))

    # 解析数据集
    offset_img += struct.calcsize(img_header)
    train_img = []
    for i in range(num_images):
        temp = struct.unpack_from('>784B', train_img_sets, offset_img)
        train_img.append(np.reshape(temp, (28, 28, 1)))
        offset_img += struct.calcsize('>784B')

    offset_label += struct.calcsize(label_header)
    train_label = []
    for i in range(num_labels):
        temp = struct.unpack_from('>1B', train_label_sets, offset_label)
        train_label.append(temp[0])
        offset_label += struct.calcsize('>1B')
    return np.array(train_img), np.array(train_label)

2.模型建立

这里借鉴VGG的结构,每次尺寸减半,深度翻倍
首先定义一个block,一个block组成为input->Dropout->Conv->BN->ReLU
然后每两个block接一个Maxpooling(尺寸减半,深度翻倍),最后用GlobalAveragePooling代替全连接层,减少参数量,然后输出

class CNNmodel:
    def Convblock(self, num_filters, kernel_size=(3, 3),
                  strides=(1, 1), padding='same'):
        self.layer = tf.keras.layers.Dropout(0.1)(self.layer)
        self.layer = tf.keras.layers.Conv2D(num_filters, kernel_size,
                                            strides, padding)(self.layer)
        self.layer = tf.keras.layers.BatchNormalization(
            axis=1, epsilon=0.001)(self.layer)
        self.layer = tf.keras.layers.ReLU()(self.layer)

    def createCNNmodel(self, input_shape):
        self.inpt = tf.keras.layers.Input(shape=input_shape)
        self.layer = self.inpt

        # 28*28*32
        self.Convblock(32)
        self.Convblock(32)
        self.layer = tf.keras.layers.MaxPool2D(
            (2, 2), strides=(2, 2), padding='valid')(self.layer)
        # 14*14*64
        self.Convblock(64)
        self.Convblock(64)
        self.layer = tf.keras.layers.MaxPool2D(
            (2, 2), strides=(2, 2), padding='valid')(self.layer)
        # 7*7*128
        self.Convblock(128)
        self.Convblock(128)
        self.layer = tf.keras.layers.MaxPool2D(
            (2, 2), strides=(2, 2), padding='valid')(self.layer)
        # 1*128
        self.layer = tf.keras.layers.GlobalAveragePooling2D()(self.layer)
        # 1*10
        self.layer = tf.keras.layers.Dense(
            10, activation='softmax')(self.layer)
        self.model = tf.keras.Model(inputs=self.inpt, outputs=self.layer)

        return self.model

3.读取数据集

train_img, train_label = read_trainsets()
test_img, test_label = read_testsets()

4.创建模型实例

UseNewModel = 0  # 0表示加载模型,1表示重新跑一边模型
Modeltype = 'CNN'
modelfilename = Modeltype + '_model.tf'

# set model
if (os.path.exists(modelfilename) == 1 and
        UseNewModel == 0):
    print('Loading model...')
    model = tf.keras.models.load_model(modelfilename )
    print('Load complete')
else:
    print('create a ' + Modeltype + ' model')
    if(Modeltype == 'CNN'):
        model = CNNmodel().createCNNmodel((28, 28, 1))

5.编译运行并保存模型

model.compile(optimizer='Adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

history = model.fit(train_img, train_label, epochs=20,
                    batch_size=32,
                    validation_data=(test_img, test_label))

test_loss, test_acc = model.evaluate(test_img, test_label)
print("准确率: %.4f,共测试了%d张图片 " % (test_acc, len(test_label)))
tf.keras.models.save_model(model, modelfilename)

6.显示acc和loss曲线图

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

# Plot training & validation loss values
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

三、实验数据

这是迭代20次后的结果,可以看到,一次迭代完成就达到了98%以上的准确率,越往后训练集train的准确度越高,可以达到99.9%的准确度,可这并没有造成对测试集test的准确度下降,迭代5次以后,模型对测试集的准确度就保持在99.2%-99.4%之间,这已经略好于tensorflow官方在手册中给的代码(官方的准确度约在99.2%左右,http://www.tensorfly.cn/tfdoc/tutorials/mnist_pros.html)
模型acc曲线图
在这里插入图片描述
(PS:我的笔记本跑的太慢了,我曾经尝试跑ResNet,看了看进度……我放弃了)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值