卷积神经网络CNN(Convolutional Neural Network)原理与代码实现 Le-Net5
图像识别经典数据集:
图像识别是人工智能的一个重要的领域。其他常用的图像识别数据集:
CIFAR: http://www.cs.toronto.edu/~kriz/cifar.html
CIFAR数据集分为CIFAR-10和CIFAR-100两个问题。
CIFAR-10数据集共有60000张彩色图像,这些图像是32*32,分为10个类,每类6000张图。这里面有50000张用于训练,构成了5个训练批,每一批10000张图;另外10000用于测试,单独构成一批。测试批的数据里,取自10类中的每一类,每一类随机取1000张。抽剩下的就随机排列组成了训练批。注意一个训练批中的各类图像并不一定数量相同,总的来看训练批,每一类都有5000张图。
数据集下载: http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
ImageNet数据集:
为了解决CIFAR数据集存在的问题:真实环境中的图像的分辨率远大于32X32, 且一张图像中不是只包含一种类别,所以便出现了ImageNet, ImageNet是一个计算机视觉系统识别项目,是目前世界上图像识别最大的数据库。是美国斯坦福的计算机科学家李飞飞模拟人类的识别系统建立的。能够从图片识别物体。目前已经包含14197122张图像,是已知的最大的图像数据库。每年的ImageNet大赛更是魂萦梦牵着国内外各个名校和大型IT公司以及网络巨头的心。
卷积神经网络CNN:
Top-N正确率: 图像识别算法给出的前N个答案中有一个是正确答案的概率。
CNN的基本结构:
卷积神经网络构成部分:
1.输入层:
神经网络的输入,在处理图像时,一般代表图像的像素矩阵。大小通常为 w x h x 3或者w x h x 1的矩阵。
2.卷积层:
卷积层中每一个节点的输入只是上一层神经网络的的一小块。大小通常为3x3或者5x5.卷积层的作用是将图像中的每一小块进行更加深入地分析从而得到抽象程度更高的特征。经过卷积层处理的节点矩阵会变深。
卷积层中过滤器(filter)的结构:
过滤器的作用是将当前层神经网络上的子节点矩阵转化为下一层神经网络上的一个单位节点矩阵(长宽为1,深度不计)。
过滤器的参数: 长度,宽度,深度(处理得到的下一层节点矩阵的深度)。
在卷积层的前向传播过程中,下一层单矩阵中第i个节点的取值为:
卷积层的操作过程就是将上面的filter从当前层的左上角移动到右下角。在移动过程中计算每一个对应的单位矩阵。如下图所示:
(图片来源: https://www.jianshu.com/p/cbe93f5152cb)
可以采用zero-padding来填充当前层的矩阵,以保证卷积操作后矩阵的尺寸不变。同时,还可以设定filter的移动步长来调整结果矩阵的大小。
结果矩阵的大小:
a. 当使用zero-padding的时候:
b 当不使用zero-padding的时候:
卷积层filter的参数是共享的(包括偏置项),这样使得图像上的内容不受位置的影响(mnist中1出现在哪里都是属于同一类别);同时可以减少网络的参数。
tensorflow实现:
import tensorflow as tf# 定义一个过滤器
# [5,5,3,16] 尺寸为5x5, 当前层的深度3,filter的深度16
filter_1 = tf.get_variable(name='filter_1', shape=[5, 5, 3, 16], dtype=tf.float32,initializer=tf.random_normal(mean=0, stddev=1))# 定义偏置项
biases_1 = tf.get_variable(name='biases_1', shape=[16], dtype=tf.float32, initializer=tf.random_normal(mean=0, stddev=1))# 卷积层前向传播算法
# 参数 输入input 四维矩阵,第一个维度表示batch的大小,后面的维度表示输入层的维度 filter,
# strides=[1,1,1,1] 第一和最后一个数字必须是1,其他两个是步长参数
# padding: SAME(zero-padding) VALID(no-padding)
conv = tf.nn.conv2d(input=input, filter=filter_1, strides=[1, 1, 1, 1], padding='SAME')
layer_1 = tf.nn.bias_add(conv, biases_1)
activated_layer_1 = tf.nn.relu(layer_1)
3.池化层:
池化层不改变三维矩阵的升深度,但是会改变矩阵的大小。池化层操作可以看作是将一张图像处理成分辩率更低的图像,从而减少最后全连接层中的节点数,进一步减少神经网络参数的数目。
池化层的操作于卷积层的filter类似,但是池化层不是加权,而实采用最大值或者平均值, max-pool和average-pool,与卷积层的filter不同的是,池化层在长度,宽度和深度上移动。
# 最大池化层 参数
# value: 输入数据,四维矩阵
# ksize: 过滤器尺寸[1,3,3,1]第一个和最后一个参数必须为1
# strides参数与卷积层相同
# padding参数与卷积层相同
pool = tf.nn.max_pool(value=activated_layer_1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],padding='SAME')
4.全连接层:
在经过多层的卷积层和池化层操作后,一般会有1-2个全连接层,给出最后的分类结果。可以将卷积层和池化层看作自动提取图像特征的操作,经过操作会将图像信息含量更高的特侦提取出来。最后任然需要使用全连接层来完成分类任务。
5. softmax层:
将神经网络的输入转化为概率分布。
dropout:
一般只用在全连接层,将全连接层随机的部分节点的输出改为0,dropout可以避免过拟合,使得模型在测试数据上更加健壮
经典的卷积神经网络模型:
Le-Net5模型:于98年提出,第一个应用于图像识别问题的卷积神经网络
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import numpy as np
from tqdm import tqdmclass TrainData:def __init__(self, data_path, batch_size=100):""":param data_path: 训练数据路径"""self.batch_size = batch_sizeself.mnist = input_data.read_data_sets(train_dir=data_path, one_hot=True)def display_data_info(self):"""输出数据集的信息:return:"""print("-"*40)print("training data size: {}".format(self.mnist.train.num_examples))print("test data size: {}".format(self.mnist.test.num_examples))print("validation data size: {}".format(self.mnist.validation.num_examples))print("-"*40)def next_batch(self):"""获取下一个batch的数据 经过处理后的图片为(28x28=784)的一维数组:return:"""xs, ys = self.mnist.train.next_batch(self.batch_size) # 返回训练数据和标签 xs: [batch_size, 784]return xs, ysdef validation_data(self):"""返回验证集:return:"""images, labels = self.mnist.validation.images, self.mnist.validation.labelsreturn images, labelsdef test_data(self):"""返回测试集:return:"""images, labels = self.mnist.test.images, self.mnist.test.labelsreturn images, labelsdef get_batch_num(self):return self.mnist.train.num_examples // self.batch_sizeclass Model:def __init__(self, input_image_size, output_node, learning_rate, train_data, board_data, model_save, train_step, regularize=False):self.input_image_size = input_image_sizeself.input_node = self.input_image_size[0] * self.input_image_size[1] * self.input_image_size[2] # 输入节点数量self.output_node = output_nodeself.learning_rate = learning_rateself.train_data = train_dataself.board_data = board_dataself.model_save = model_saveself.train_step = train_stepself.regularize = regularizeif self.regularize:self.regularize_rate = 0.01# 卷积层1self.conv1_deep = 32self.conv1_size = 5self.conv1_stride = 1# 卷积层2self.conv2_deep = 64self.conv2_size = 3self.conv2_stride = 1# 池化层self.pool1_size = 2self.pool1_stride = 2# 池化层self.pool2_size = 2self.pool2_stride = 2# 全连接层self.fc_size = 500with tf.name_scope("placeholder"):self.x = tf.placeholder(dtype=tf.float32, shape=[None, self.input_image_size[0], self.input_image_size[1],self.input_image_size[2]],name='x-input') # 输入是一个四维矩阵self.y_ = tf.placeholder(dtype=tf.float32, shape=[None, 10], name='y-input') # 标签with tf.name_scope("layer1_conv1"): # 定义卷积层1权重# 定义一个过滤器# [5,5,3,16] 尺寸为5x5, 当前层的深度3,filter的深度32# stride=1# padding: SAME# 输出 28x28x32self.conv1_weight = tf.get_variable(name='conv1_weight', shape=[self.conv1_size, self.conv1_size,self.input_image_size[2], self.conv1_deep],dtype=tf.float32,initializer=tf.truncated_normal_initializer(mean=0, stddev=0.5))self.conv1_biases = tf.get_variable(name='conv1_biases', shape=[self.conv1_deep], dtype=tf.float32,initializer=tf.constant_initializer(0.0))self.conv1 = tf.nn.conv2d(input=self.x, filter=self.conv1_weight, strides=[1, self.conv1_stride,self.conv1_stride, 1],padding='SAME') # 这里的输出为28x28x32self.layer1 = tf.nn.relu(tf.nn.bias_add(value=self.conv1, bias=self.conv1_biases))with tf.name_scope("layer2_pool1"): # 定义池化层# 定义一个过滤器# [1, 2, 2, 1] 尺寸为2x2, 当前层的深度32# stride = 2# padding SAME# 输出 ceil(28/stride)=14 14x14x32self.layer2 = tf.nn.max_pool(value=self.layer1, ksize=[1, self.pool1_size, self.pool1_size, 1],strides=[1, self.pool1_stride, self.pool1_stride, 1],padding='SAME') # 输出为14*14*32 celi(28/2)=14with tf.name_scope("layer3_conv2"):# 定义一个过滤器# [3, 3, 32, 64] 尺寸为5x5, 当前层的深度32# stride = 1# padding SAME# 输出 ceil(14/stride)=14 14x14x64self.conv2_weight = tf.get_variable(name='conv2_weight', shape=[self.conv2_size, self.conv2_size,self.conv1_deep, self.conv2_deep],dtype=tf.float32,initializer=tf.truncated_normal_initializer(mean=0, stddev=0.4))self.conv2_biases = tf.get_variable(name='conv2_biases', shape=[self.conv2_deep], dtype=tf.float32,initializer=tf.constant_initializer(0.0))self.conv2 = tf.nn.conv2d(input=self.layer2, filter=self.conv2_weight, strides=[1, self.conv2_stride,self.conv2_stride, 1],padding='SAME')self.layer3 = tf.nn.relu(tf.nn.bias_add(value=self.conv2, bias=self.conv2_biases))with tf.name_scope("layer4_pool2"):# 定义一个过滤器# [1, 2, 2, 1] 尺寸为2x2, 当前层的深度64# stride = 2# padding SAME# 输出 ceil(14/stride)=7 7x7x32self.layer4 = tf.nn.max_pool(value=self.layer3, ksize=[1, self.pool2_size, self.pool2_size, 1],strides=[1, self.pool2_stride, self.pool2_stride, 1],padding='SAME')# 将第四层池化层的输出转化为全连接层的形式with tf.name_scope("layer5_fc1"): # 全连接层self.pool_shape = self.layer4.get_shape().as_list() # self.pool_shape [batch_size, w, h, d] 四维数组nodes = self.pool_shape[1] * self.pool_shape[2] * self.pool_shape[3]self.fc = tf.reshape(tensor=self.layer4, shape=[-1, nodes])self.fc1_weight = tf.get_variable(name="fc1_weight", shape=[nodes, self.fc_size], dtype=tf.float32,initializer=tf.random_normal_initializer(mean=0, stddev=1))self.fc1_biases = tf.get_variable(name='fc1_biases', shape=[self.fc_size], dtype=tf.float32,initializer=tf.constant_initializer(0.0))self.layer5 = tf.nn.relu(tf.matmul(self.fc, self.fc1_weight) + self.fc1_biases)self.layer5 = tf.nn.dropout(x=self.layer5, keep_prob=0.5)if self.regularize:tf.add_to_collection(name='loss',value=tf.contrib.layers.l2_regularizer(self.regularize_rate)(self.fc1_weight))with tf.name_scope("layer6_fc2"): # 全连接层self.fc2_weight = tf.get_variable(name='fc2_weight', shape=[self.fc_size, self.output_node],dtype=tf.float32,initializer=tf.truncated_normal_initializer(mean=0, stddev=1))self.fc2_biases = tf.get_variable(name='fc2_biases', shape=[self.output_node],dtype=tf.float32,initializer=tf.constant_initializer(0.0))self.layer6 = tf.matmul(self.layer5, self.fc2_weight) + self.fc2_biasesif self.regularize:tf.add_to_collection(name='loss',value=tf.contrib.layers.l2_regularizer(self.regularize_rate)(self.fc2_weight))with tf.name_scope("layer7_output"): # soft max层self.cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.layer6,labels=tf.argmax(self.y_, 1))self.cross_entropy_mean = tf.reduce_mean(self.cross_entropy)tf.add_to_collection(name='loss', value=self.cross_entropy_mean)with tf.name_scope('loss'):self.loss = tf.add_n(tf.get_collection('loss'))with tf.name_scope('optimizer'):self.optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(loss=self.loss)with tf.name_scope('evaluate'): # 计算验证数据集的准确率self.predict_correction = tf.equal(tf.argmax(self.layer6, 1), tf.argmax(self.y_, 1))self.accuracy = tf.reduce_mean(tf.cast(self.predict_correction, dtype=tf.float32), name="accuracy")# tensor board显示数据with tf.name_scope("summary"):tf.summary.scalar("loss", self.loss)tf.summary.scalar("accuracy", self.accuracy)self.summary_op = tf.summary.merge_all()def train(self, train_data):# 输入图像的大小with tf.Session() as sess:init_op = tf.group(tf.local_variables_initializer(), tf.global_variables_initializer())sess.run(init_op)writer = tf.summary.FileWriter(logdir=self.board_data, graph=sess.graph) # 保存tensorboard中的数据saver = tf.train.Saver(tf.global_variables(), max_to_keep=2) # 保存模型count = 0for step in range(self.train_step):for _ in range(train_data.get_batch_num()):xs, ys = train_data.next_batch()xs = np.reshape(xs, newshape=(-1,self.input_image_size[0],self.input_image_size[1],self.input_image_size[2]))feed_dict = {self.x: xs, self.y_: ys}_, loss, summary = sess.run([self.optimizer, self.loss, self.summary_op], feed_dict=feed_dict)# print("The loss at step {} is {}".format(count, loss))count += 1if count % 100 == 0:x_valid, y_valid = train_data.validation_data()x_valid = np.reshape(x_valid, newshape=(-1,self.input_image_size[0],self.input_image_size[1],self.input_image_size[2]))feed_dict_validation = {self.x: x_valid, self.y_: y_valid}accuracy = sess.run(self.accuracy, feed_dict=feed_dict_validation)print("The accuracy After {} steps is {}".format(count, accuracy))# 保存模型saver.save(sess=sess, save_path=self.model_save)# 保存tensor board数据writer.add_summary(summary=summary, global_step=step)def predict(train_data, load_model, image_size):sess = tf.Session()check_point_file = tf.train.latest_checkpoint(load_model)saver = tf.train.import_meta_graph("{}.meta".format(check_point_file), clear_devices=True)saver.restore(sess=sess, save_path=check_point_file)graph = sess.graphtest_data = graph.get_operation_by_name("placeholder/x-input").outputs[0]test_label = graph.get_operation_by_name("placeholder/y-input").outputs[0]test_accuracy = graph.get_operation_by_name("evaluate/accuracy").outputs[0]x_t, y_t = train_data.test_data()x_t = np.reshape(x_t, newshape=(-1, image_size[0], image_size[1], image_size[2]))feed_dict = {test_data: x_t, test_label: y_t}accuracy = sess.run(test_accuracy, feed_dict=feed_dict)print("The test accuracy is {}".format(accuracy))if __name__ == '__main__':data_path = r'E:\code\112\tensorflow_project\chapter5\data\tensorflow_data'board_data = r"E:\back_up\code\112\tensorflow_project\newbook\chapter4\model\tensorboard" # tensorboard数据保存路径model_save = r'E:\back_up\code\112\tensorflow_project\newbook\chapter4\model\garph\graph' # 保存模型的数据load_model = r"E:\back_up\code\112\tensorflow_project\newbook\chapter4\model\garph"train_data = TrainData(data_path=data_path, batch_size=100)train_data.display_data_info()model = Model(input_image_size=[28, 28, 1], output_node=10, learning_rate=0.001,train_data=train_data,board_data=board_data, model_save=model_save, train_step=40)model.train(train_data=train_data)print("---------test-----------")predict(train_data=train_data, load_model=load_model, image_size=[28, 28, 1])
训练的结果:
在卷积神经网络中,卷积层过滤器的深度一般都设置为逐层递增的方式,卷积层的步长一般为1.,2或者3。池化层过滤器的边长一般为2或者3,步长一般也为2或者3.
卷积神经网络CNN(Convolutional Neural Network)原理与代码实现 Le-Net5相关推荐
- 卷积神经网络(Convolutional Neural Network,CNN)
卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现. 它包括卷积层(con ...
- 卷积神经网络CNN(Convolutional Neural Networks)没有原理只有实现
零.说明: 本文的所有代码均可在 DML 找到,欢迎点星星. 注.CNN的这份代码非常慢,基本上没有实际使用的可能,所以我只是发出来,代表我还是实践过而已 一.引入: CNN这个模型实在是有些年份了, ...
- “卷积神经网络(Convolutional Neural Network,CNN)”之问
目录 Q1:CNN 中的全连接层为什么可以看作是使用卷积核遍历整个输入区域的卷积操作? Q2:1×1 的卷积核(filter)怎么理解? Q3:什么是感受野(Receptive field)?
- 从CNN视角看在自然语言处理上的应用 原创 2017年10月24日 00:00:00 1339 作者 | 卞书青 卷积神经网络(Convolutional Neural Network)最早是应用在
从CNN视角看在自然语言处理上的应用 原创 2017年10月24日 00:00:00 标签: 1339
- CNN(Convolutional Neural Network) 的基础
卷积神经网络(Convolutional Neural Network,简称CNN),是一种前馈神经网络,人工神经元可以响应周围单元,可以进行大型图像处理.卷积神经网络包括卷积层和池化层. 卷积神经网 ...
- 仅使用NumPy完成卷积神经网络CNN的搭建(附Python代码)
摘要: 现有的Caffe.TensorFlow等工具箱已经很好地实现CNN模型,但这些工具箱需要的硬件资源比较多,不利于初学者实践和理解.因此,本文教大家如何仅使用NumPy来构建卷积神经网络(Con ...
- 【卷积神经网络】卷积神经网络(Convolutional Neural Networks, CNN)基础
卷积神经网络(Convolutional Neural Networks, CNN),是一种 针对图像 的特殊的 神经网络. 卷积神经网络概述 Why not DNN? 图像数据的维数很高,比如 1, ...
- 第四门课 卷积神经网络(Convolutional Neural Networks)
第四门课 卷积神经网络(Convolutional Neural Networks) 第一周 卷积神经网络(Foundations of Convolutional Neural Networks) ...
- 吴恩达深度学习笔记——卷积神经网络(Convolutional Neural Networks)
深度学习笔记导航 前言 传送门 卷积神经网络(Convolutional Neural Networks) 卷积神经网络基础(Foundations of Convolutional Neural N ...
- 一步一步分析讲解深度神经网络基础-Convolutional Neural Network
Convolutional Neural Network 参考http://cs231n.github.io/convolutional-networks/ history Convolutional ...
最新文章
- 2018 年最值得期待的学术进展——致人工智能研究者们的年终总结
- jquery 源码分析九 - Sizzle
- centos6.2系统使用扩展源epel报错问题解决方法
- php udp 非阻塞,使用非阻塞udp读取时丢失消息
- vue中如何使用vi-for限制遍历的条数?只查询前三条、查询4-6条怎么实现?
- 表面配准论文1--基于高阶图匹配方法的稠密表面配准
- 【T-SQL基础】02.联接查询
- 一段JS代码实现光标定位输入框文字最后
- numpy获得ndarray的byte数 内存中的大小
- matlab微带带通滤波器,带通滤波器的ADS仿真设计
- pr.exe、Churrasco.exe、ms10048.exe用法及提权原理 上帝模式
- Codeblock一直卡在编译界面
- 安装软件时“应用程序无法启动,因为应用程序的并行配置不正确......”
- android镜像_如何在任何Windows PC上镜像和控制您的Android手机
- iOS的iPhone最全尺寸、分辨率、PPI、Reader总结(包括XS、XS Max、XR)
- 微信小程序怎么做淘宝客优惠券商城手把手教你完成从申请到上线
- python空行分隔代码_python空行分隔
- mvn install BUILD FAILURE : Downloading from central: https://repo.maven.apache.org/maven2/org/sp...
- C++统计正数数目和负数的数目,并计算平均值
- IOS条形码扫描技术实现
热门文章
- SpringCloud工作笔记087---SpringBoot启动报错:IDEA 错误: 找不到或无法加载主类 解决方法_connected to the target VM, address:
- opencv实现多个图拼接成一个图
- 去除eclipse打开后不断update的问题
- 随想录(用好红黑树)
- 【你不能错过的数组基础知识整理】(学习笔记9--数组下)
- python画猪头_使用Python画小猪佩奇 社会人标配
- pythonguitkinter编程入门_Python Tkinter GUI编程入门介绍
- 初中 计算机文化知识,计算机文化知识(Computer literacy).doc
- oracle能不能改外键属性,CSS_小议Oracle外键约束修改行为(五), Oracle的外键用来限制子表 - phpStudy...
- php date( ymd_PHP DATE()