卷积神经网络学习心得以及代码实现

卷积神经网络学习心得

综述

我所理解的卷积神经网络,是一个多层网络,每层由若干个二维平面组成,每个平面由多个神经元组成。这些二维平面是原图像像素被多个卷积核卷积后的结果,将原来是一层(一个平面)的原图卷积成好多层的图合并在一起(好几个平面叠放,可以理解为立体图形),每层之间神经元是不完全连接的,下一层的一个神经元只连接上一层的几个神经元。

一些概念

卷积神经网络涉及一些概念

1.卷积核(filter)
一个卷积核代表原图中的一个特征,通过与原图卷积的结果来判定原图是否有该特征,卷积核可以是一个数字组成的二维矩阵,可以理解为一个平面,类似九宫格;也可以是一个数字组成的多维矩阵,可以理解为一个数字排列成一个长方体。

2.卷积(convolution)
即卷积核上的数字与上一层相应位置上的数字相乘,最终将所有结果相加得到一个新的数字,也就是下一层神经元的数值。在这里插入图片描述

3.池化(pooling)
池化就是以一定方式减少神经元数量,可以在每四个神经元中取一个最大值或者最小值作为下一层的一个神经元数值,这样神经元个数就减少到原来的1/2.卷积改变每层的深度,池化不改变深度,而是改变大小。

4.卷积步长(strides)
卷积是有步长的,即卷积核在一个区域卷积完成后向下个区域平移时移动的格数,下一层神经元的个数与卷积核自身大小、上一层神经元个数、卷积核的滑动步长有关。一般来说下一层神经元的个数=上一层神经元的列数/步长,得到的结果向上取整数。

5.平坦化(flat)
平坦化即将上一层多维的神经元拆开再排列成一条直线,变成一维。

卷积过程(以下方代码实现的卷积为例)

在这里插入图片描述

1.原图像素矩阵[-1,28,28,1]
如果是彩色的就是 [-1,28,28,3],3代表RGB三原色有三个值,每个值各占有一个平面(一共有三个平面),-1表示图片的张数是不确定的,中间的两个28表示每一个平面像素是28*28的。在这里插入图片描述

2.第一次卷积:用32个5*5的卷积核卷积,步长为1,得到新的一层为[-1,28,28,32].

3.第一次池化:选择2*2的范围最大值池化,步长为2,即在每四个神经元中取一个最大值作为下一层的一个神经元数值,得到[-1,14,14,32]。

4.第二次卷积:用64个5*5的卷积核卷积,步长为1,得到新的一层为[-1,14,14,64].

5.第二次池化:选择2*2的范围最大值池化,步长为2,即在每四个神经元中取一个最大值作为下一层的一个神经元数值,得到[-1,7,7,64]。

6.平坦化:将四维的层变成二维的[-1,7764=3164],其中有一维是图片张数。

7.全连接:平坦化后的层与下一层全连接,类似bp神经网络。
下一层设置1024个神经元,要指定激活函数。

8.dropout:将上一层1024个神经元随机丢弃,需要指定丢弃率,丢弃后成为一个新层。

9.输出层:丢弃后的若干神经元与输出层10个神经元全连接,不需要指定激活函数,最后输出为[-1,10].

卷积和池化可以重复多次。

代码实现

完整代码

# 需要用到tensorflow环境,以及numpy库(一个与多维数组操作有关的库)
import tensorflow as tf
import numpy as np

# Mnist数据集:里面有55000张28*28的手写数字(黑白)以及对应的标签。被tensorflow收录在自己的源码中。
# 获取这个数据集只需要一条命令from tensorflow.examples.tutorials.mnist import input_data即可。
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
sess = tf.InteractiveSession()


# 输入
# tf.placeholder()是用来占位并定义变量的属性的函数
# 参数 dtype 表示数据类型,如tf.float32,tf.int32
# 参数 shape表示形状,默认是None,[None,28*28]表示行不定,列为784.
# /255.是做均一化。因为图像像素值是(0~255)如果用原始数据计算出来的东西会很大。
input_x = tf.placeholder(tf.float32,[None,28*28])/255.
# 输出是一个one_hot的向量
output_y=tf.placeholder(tf.int32,[None,10])
# 以上定义了输入和输出的格式


# 输入层是[28*28*1],tf.reshape()函数将输入的数据改变形状
# 如果是一张则是三维[28,28,1],一共有几张是未知的,-1表示未知所以将形状改成[-1,28,28,1],最后一位的1代表平面数
input_x_images = tf.reshape(input_x,[-1,28,28,1])


# mnist的test数据集有图像和对应标签,从该数据集中选取3000个手写数字的图片和对应标签
test_x=mnist.test.images[:3000] #image
test_y=mnist.test.labels[:3000] #label

# 数据准备完毕,开始搭建

# 第一次卷积
# 卷积函数tf.layers.conv2d()
# inputs 输入,是一个张量
# 卷积核:每个尺寸5*5,有32个
# filters 卷积核个数,也就是卷积层的厚度
# kernel_size 卷积核的尺寸
# strides: 扫描步长
# padding: 边边补0 valid不需要补0,same需要补0,为了保证输入输出的尺寸一致,补多少不需要知道
# activation: 激活函数
conv1=tf.layers.conv2d(
    inputs=input_x_images,
    filters=32,
    kernel_size=[5,5],
    strides=1,
    padding='same',
    activation=tf.nn.relu
)
# 结束后变成[-1,28,28,32]


# 第一次池化
# 最大值池化函数tf.layers.max_pooling2d()
# inputs 输入,张量必须要有四个维度
# pool_size: 过滤器的尺寸

pool1=tf.layers.max_pooling2d(
    inputs=conv1,
    pool_size=[2,2],
    strides=2
)
# 结束后变成[?,14,14,32]


# 再一次进行卷积加池化
# 卷积核:尺寸5*5,共64个,步长为1
conv2=tf.layers.conv2d(
    inputs=pool1,
    filters=64,
    kernel_size=[5,5],
    strides=1,
    padding='same',
    activation=tf.nn.relu
)
# 输出变成了 [?,14,14,64]


# 第二次池化
# pool2
pool2=tf.layers.max_pooling2d(
    inputs=conv2,
    pool_size=[2,2],
    strides=2
)
# 输出变成了[?,7,7,64]


# flat(平坦化),用tf.reshape()函数改变形状即可。
flat = tf.reshape(pool2, [-1, 7*7*64])
# 形状变成了[?,3136]二维的,3136是一个图片的神经元个数


# 全连接层
# densely-connected layers 全连接层 设置1024个神经元,上一层3136个神经元与其全连接。
# 全连接函数tf.layers.dense()
# inputs: 张量
# units: 神经元的个数
# activation: 激活函数
dense=tf.layers.dense(
    inputs=flat,
    units=1024,
    activation=tf.nn.relu
)


# dropout丢弃
# 丢弃函数tf.layers.dropout()
# inputs 张量
# rate 丢弃率
# training 是否是在训练的时候丢弃
dropout = tf.layers.dropout(
    inputs=dense,
    rate=0.5,
)


# 输出层,不用激活函数(本质就是一个全连接层)
# 最后输出的是十个神经元
logits = tf.layers.dense(
    inputs=dropout,
    units=10
)
# 输出形状[?,10]


# 开始操作

# 计算输出值由于标签的误差
# 计算误差 cross entropy(交叉熵),再用Softmax计算百分比的概率
# 应用函数tf.losses.softmax_cross_entropy
# onehot_labels: 标签值
# logits: 神经网络的输出值
loss=tf.losses.softmax_cross_entropy(onehot_labels=output_y,
                                     logits=logits)

# 训练操作
# 用Adam 优化器来最小化误差,学习率0.001 类似梯度下降
print(loss)

train_op=tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)


# 计算准确率操作
# 计算预测值和实际标签的匹配程度
# tf.metrics.accuracy计算精度的函数
# labels:真实标签
# predictions: 预测值
# 函数返回值有两个 (accuracy,update_op),accuracy 是一个张量准确率,update_op 是一个op可以求出精度。
# 这两个都是局部变量
accuracy_op = tf.metrics.accuracy(
    labels=tf.argmax(output_y, axis=1),
    predictions=tf.argmax(logits, axis=1)
    # tf.argmax()函数为在一个矩阵中查找最大元素。axis=1:按行查找最大元素 axis=0:按列查找最大元素
    # 返回的是该元素的索引(正好代表了是哪个数字)
)[1]# 1是因为,我们要得到的不是要准确率这个数字,而是一个op


# 接下来进行数据传输
# 创建会话
sess = tf.Session()
# 初始化变量
# tf.group()函数,把很多个操作弄成一个组
# 初始化变量,全局tf.global_variables_initializer(),和局部tf.local_variables_initializer()
init=tf.group(tf.global_variables_initializer(),
              tf.local_variables_initializer())
sess.run(init)
# 相当于sess.run(tf.global_variables_initializer())
# sess.run(tf.local_variables_initializer())
# 运行初始化函数init=tf.group()


# 数据流动
# 迭代20000次,每次在 mnist 数据集中抽50个数据作为一个样本,下一次迭代再取下一个样本
for i in range(20000):
    batch=mnist.train.next_batch(50) # 从Train(训练)数据集中取下一个样本
    train_loss,train_op_ = sess.run([loss, train_op], {input_x: batch[0], output_y: batch[1]})
    # sess.run函数,第一个参数是要进行的两个操作,函数返回的也是这两个操作的返回值。
    # 第二个参数是指将batch[0](mnist数据集中的图像信息)作为输入input_x,
    #             将batch[1](mnist数据集中对应的标签信息)作为输出output_y.

    if i%100==0:
        test_accuracy = sess.run(accuracy_op, {input_x: test_x, output_y: test_y})
        print("Step=%d, Train loss=%.4f,[Test accuracy=%.2f]"%(i,train_loss,test_accuracy))

# 训练完成之后进行测试: 打印20个预测值和真实值
test_output = sess.run(logits, {input_x: test_x[:20]})
# 运行logits,即实际输出,输入的是test数据库里面前20个图像。
inferenced_y = np.argmax(test_output, 1)
print(inferenced_y, 'Inferenced numbers')# 推测的数字
print(np.argmax(test_y[:20], 1), 'Real numbers')
sess.close()

(代码来源于网络)

运行结果

运行时间很长,可能由于迭代的次数太多。
从前几次可以看到误差越来越小,准确率越来越大。
在这里插入图片描述
最终准确率达到90%
测试的20个数字全部正确
在这里插入图片描述

保存模型

# 模型保存
#saver = tf.train.Saver()
#saver.save(sess, './path_to_model.ckpt')

#加载读取模型
saver = tf.train.Saver()
sess= tf.Session()
saver.restore(sess,'./path_to_model.ckpt')
init = tf.group(tf.global_variables_initializer(),
                    tf.local_variables_initializer())
sess.run(init)

下一次运行时可以不必再训练一次,直接调用保存的模型即可(模型和代码保存在了同一个路径下)。模型保存代码块上面的代码依然与前面的代码相同。
然后进行测试:

test = sess.run(logits, {input_x: test_x[:2]})
pre_y = np.argmax(test, 1)
real_y = np.argmax(test_y[:2], 1)
print("预测数字",pre_y)
print("真实数字",real_y)
sess.close()

遇到的问题

“TimeoutError: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败”
可能是由于并没有下载mnist数据集,下载链接如下:
MNIST数据下载网页:http://yann.lecun.com/exdb/mnist/点击红色链接下载
下载完毕后将这四个文件放入与代码文件相同的路径中,将四个文件放入MNIST_data文件夹里(这四个文件的原来位置可以在下载中寻找)。
在这里插入图片描述
左键单击CNN运行代码文件,再点击file path查看代码储存路径
在这里插入图片描述

点开MNIST_data,出现四个文件在这里插入图片描述
点击文件,如果打不开就按照出现的指示下载解压软件。注意,解压软件下载完毕后在点击还是打不开的,会提示只有在相应应用中才能打开。这一点时没关系的,在运行python代码的时候就可以打开了,代码运行成功

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值