一文读懂CNN

在讲卷积神经网络之前,我们先考虑一下什么是卷积?他为什么会出现?他的出现有什么用?以及如何用当下流行的tensorflow实现其基本的流程。

我们下来说一下什么是卷积,其数学上的意义我在这不在赘述,我们着重说一下在神经网络中的卷积是什么。以图像处理为例,卷积好比是一个“筛子”,他将图像的一小块,一小块的过这个“筛子”,进而提取我们想要得到的东西(筛子想要的粒大的粮食,我们在这想要的是他的显著特征)。用矩阵来说的话就是我们把图片的每个像素点按照亮度,色彩,给定一个数值,卷积就是用一个我们准备好的矩阵(矩阵中的每个值就是我们需要求得的参数)来对这个像素矩阵进行矩阵运算(还是一小块一小块的进行)。这就是卷积。(图片引自网络)

一般我们看到卷积时总会伴随着池化,全连接,那这是什么呢?他有什么作用呢?

所谓池化就是提取显著特征的过程,因为需要,我们要对图像进行放缩,为了保证在这个过程中图像的主要美容不丢失或不失真,我们会对其进行池化,池化又两方面作用:

1:上采样:放大图片,下采样:缩小图片;

2:最大值(maxpooling):选取该区域最大值,最小值(minpooling)选取该区域最小值。

下图是其具体的形象展示(引自网络:)


我们再来看全连接,我们可以把全连接看作是我们之前学到的一系列特征的汇总,归类,实际上我们可以把全连接看作一个多项式,他可以来拟合除一条曲线,用来根据输入(各特征图)来得到一个输出,我们根据这个输出能判断他属于哪一类(这个涉及到标签与预测值的交叉熵的学习,这个后面会提到)最后我们会用softmax函数来统计各个区间(各个类)的个数来推断图片属于各个类的概率。

那么,CNN为什么会出现?在他出现之前,我们的神经网络各层之间几乎都是全连接(为了防止过拟合,可能会断掉一些链接),这样会造成巨大的算力浪费,下面,让我们来举个例子,该例子引自Tensorflow实战:

假设我们要处理的图片是1000*1000像素的,也就是由100万个像素点,即输入的维度是100万,假设我们的隐藏层也是100万(隐层神经元的个数要大于等于输入神经元个数),这样一来,一个全连接层,我们就要处理1万亿个数据.想要跑一个网络,其所需算力几乎无法想象。如果深度学习完全依赖于硬件,那要软件何用?于是深度学习大佬Yann Lecun提出了卷积神经网络这一神器,下面我们就来说说他是如何在保证精度的情况下将复杂度降下来的。

一:局部卷积,提到局部卷积,我们不得不提一下感受野的概念,想象一下,当你看一副图画时,你的目光会有一个焦点,你会记得这个焦点以及周围的一些信息,远处的信息对你而言时模糊的(这也是大脑为了防止眼部疲劳做出的保护性动作),既然如此,我们为何不把这一概念引入到深度学习中呢?基于此,大佬提出了卷积核的概念,从此,隐层上的一个神经元只与被卷积图的一块区域存在映射关系,而不是之前的神经元与整幅图的各个点存在映射关系,我们来算一下之前我们需要1万亿各参数,现在呢?100万个隐层神经元,假设我们的卷积核大小为10x10也就是100个参数,100x100=一亿个参数,较之前缩小了一万倍,这是一个巨大的进步,但是一亿个参数还只是这一层的如果层数变多,依然是无比庞大的算力,呢我们如何继续减小他的复杂度呢?

上图引自Tensorflow实战

二:权值共享,我们想想看,在之前的局部卷积上每一块卷积后对应一个神经元,但是这样的操作不仅繁琐,还容易使得到的隐层各个神经元学到的信息存在巨大差别,组合后可能会造成巨大的失真,颇有断章取义,盲人摸象的赶脚,因此,我们可不可以把这些卷积核化为一个呢?用来学习图片的一种特征?事实证明,这不仅可行,而且效果还出奇的好,但是一个卷积核仅学习一种特征,别的特征我们不要了吗?想啥呢!不要能学好吗?我们可以多放几个卷积核,一个核学习一种特征,这样就完美的解决了上面的问题,假设我们放置100个卷积核,每个卷积核大小为10x10这样我们总共有100x100=10000个参数,从此,图像处理规模彻底与图像大小say goodbey,只与卷积核大小和卷积核个数有关,从此复杂度进入人类可控阶段,这是一个巨大的进步!

CNN的出现给图像识别领域带来了巨大的利好,同时经过这些年的发展,他还被嵌入到别的深度学习算法中,由于他能学习临近信息的能力,他还被用在了声学处理上,随着技术的不断进度与理念的改变,他还会被用在哪个领域呢?这就要靠大家的共同努力了。

可能有人还会存在这样的疑问,卷积层之间的连接方式是什么样的呢?

对于这个问题,我们也查阅了书籍并在小组里讨论,最后我们认为,在卷积层之间是一种全连接。我们想想看,我们经过了一次卷积,学到了不同的特征,可能是圈,可能是点,可能是线,我们不能就这样放着,这样放着神仙也判断不出来这是啥,那我们就要进行组合了,不知道大家有没有看过钢铁侠1,斯塔克被武装分子控制后开发的第一代盔甲因为要保密所以他将不同的部件画在不同的纸上,最后将这些纸叠放在一块就出来盔甲的全部样貌,卷积的全连接方式与这个基本一样,大家可以画个图好好理解一下。

上面讲述了CNN的背景知识,下面,我们讲讲如何用tensorflow来实现一个基本的卷积神经网络。给例子使用mnist数据集,用来识别手写数字。关键代码如下:

1:定义卷积核,偏置:

 

w_conv1 = weight_variable([5,5,1,32])

b_conv1 = bias_variable([32])

2:调用tf自带的卷积函数进行卷积,池化:

 

h_conv1 = tf.nn.relu(conv2d(x_image,w_conv1) + b_conv1)

h_pool1 = max_poo_2x2(h_conv1)


3:重复1~2步:

4:全连接,同时使用dropout随机断掉部分连接,提高泛化能力:

 

d_conv1 = tf.nn.relu(tf.matmul(d_input,w_dence1) + b_dence1)

 

keep_prob = tf.placeholder(tf.float32)

d_drop = tf.nn.dropout(d_conv1,keep_prob)

5:使用softmax进行归类:

 

d_conv2 = tf.nn.softmax(tf.matmul(d_drop,w_dence2) + b_dence2)

6:定义损失函数(使用交叉熵):

 

cross_entropy = tf.reduce_sum(-y*tf.log(d_conv2))

7:使用tf自带优化器(Adam)进行优化:

 

train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

(优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳)

全部代码如下(环境:ubuntut16.04.1+python2.7+tensorflow1.3.0):

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data',one_hot=True)

sess = tf.InteractiveSession()

def weight_variable(shape):
    inital = tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(inital)

def bias_variable(shape):
    inital = tf.constant(0.1,shape=shape)
    return tf.Variable(inital)

def conv2d(x,w):
    return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding='SAME')

def max_poo_2x2(x):
    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])

x_image = tf.reshape(x,[-1,28,28,1])

w_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])

h_conv1 = tf.nn.relu(conv2d(x_image,w_conv1) + b_conv1)
h_pool1 = max_poo_2x2(h_conv1)

w_conv2 = weight_variable([5,5,32,64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1,w_conv2) + b_conv2)
h_pool2 = max_poo_2x2(h_conv2)

w_dence1 = weight_variable([7*7*64,1024])
b_dence1 = bias_variable([1024])

d_input = tf.reshape(h_pool2,[-1,7*7*64])

d_conv1 = tf.nn.relu(tf.matmul(d_input,w_dence1) + b_dence1)

keep_prob = tf.placeholder(tf.float32)
d_drop = tf.nn.dropout(d_conv1,keep_prob)

w_dence2 = weight_variable([1024,10])
b_dence2 = bias_variable([10])

d_conv2 = tf.nn.softmax(tf.matmul(d_drop,w_dence2) + b_dence2)

cross_entropy = tf.reduce_sum(-y*tf.log(d_conv2))

train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

correct_prediction = tf.equal(tf.argmax(d_conv2,1),tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
init = tf.initialize_all_variables()


sess.run(init)

for i in range(10000):
    batch = mnist.train.next_batch(50)
    if i % 100 == 0:
        train_accuracy = accuracy.eval(feed_dict={x:batch[0],y:batch[1],keep_prob:1.0})
	print "step %d,training accuracy is %g" %(i,train_accuracy)
    train_step.run(feed_dict={x:batch[0],y:batch[1],keep_prob:0.5})
print "test accuracy %g" %accuracy.eval(feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值