6、卷积神经网络CNN

来源:互联网 发布:linux复制文件夹指令 编辑:程序博客网 时间:2024/05/02 04:23

我们知道多层神经网络(DNN)有很强的特征学习能力,但是他有一些局限:

1、因为全连接,所以权重参数特别多,且对参数初始化很敏感

2、正是因为参数很多,所以很容易过拟合。

以上这两点在进行图像分类时,尤为严重。


卷积神经网络大大缓解了DNN参数多的问题,主要有以下几点:

1、全连接,改为局部连接,借鉴猫眼的感受野思想。

2、同一个滑动窗口,从左上角滑至右下角的过程中,权重是共享的,固定的。(每个窗口学习图像的一个特征,参数数量由窗口种数和窗口大小决定)

3、池化层,(max pooling | average pooling)也会减少参数。


使用场景:

1、图像识别、检索

2、自然语言处理:看图说话与问答、双语翻译。

3、一般都是通过CNN提取特征,送给DNN,或传统机器学习方法。


卷积神经网络层次结构:

1、输入层:包含数据预处理等

2、卷积层:局部关联、窗口滑动、权值共享。 一组固定的权重和不同窗口做内积。

3、激励层:ReLU、Sigmoid、MaxOut

4、池化层:

5、全连接层:通常在CNN尾部,倒数第二层

6、输出层。


卷积层:

每个神经元只与局部的输入特征相联;窗口从左上角滑至右下角,权值不变;

单个隐含层的参数个数 = 神经元个数 * 每个窗口的权重数


滑动的时候有三个数据:

1、深度depth:指的是下一层有多少个神经元,如下图,就有2个神经元。

2、步长stride:滑动的步长,下图的demo,步长为2哦,注意哦,步长不仅仅是从左到右的步长,也是从上到下的步长哦,即demo中第二次从左到右时,下降了2格哈哈~

3、填充值zero-padding:  如下图紫色部分是原始数据集,窗口大小3*3,步长为2,你会发现第一次从左滑到右是没问题的,但是往下滑时,发现格数不够3*3了!!!,只有2*3!!!,这时候我们一般都在外围补上一圈或者两圈零,保证可以滑。demo种的 zero-padding = 1,即一圈。


demo: cs231n.github.io/assets/conv-demo/index.html


参数共享:同一个神经元的数据窗口在滑动时,其权重是不变的。


激励层: 


Sigmoid函数面对数值很大的输入值,其梯度约等于0. 用BP算法时, 所以参数迭代就不会更新了,这个问题就是梯度弥散。直观的感受就是训练集、测试集上的loss不动了,但又不是很小。



为了让信息有一定程度的非线性变换,所以负的都为0。但是很脆弱:

如果输入的数据超出一定的范围,就会发现东西传不出去,也传不回来。

要做一个监控,看看输入和输出是否还在激活,因为一旦挂掉了,就再也不会激活了。 


Leaky ReLU:  f(x) = max(ax,x) = max(0.01x,x)

不会“饱和”/挂掉,计算也很快。

“饱和”是挂掉的一种原因。比如梯度为0 



比较少有用ELU,因为计算量大。

Maxout: 




池化层:

做一个下采样,一般夹在连续的卷积层中间,在数据量的层面上减小参数,之前卷积层是从权重的层面上减少参数的。

好处:

1、数据量小

2、减缓过拟合,因为数据量小了,你背不下来。


全连接层:

前面做了很多局部连接、下采样,有一定的信息损失。为了能够比较好的拟合出结果,所以引出了全连接层,增加灵活性。

个人理解,就是CNN找到的特征喂给DNN呗。。。。


训练算法:

1、定义Loss Function,衡量和实际结果之间的差距。

2、找到最小化损失函数的W和b,CNN用的是SGD

3、SGD需要计算W和b的偏导

4、BP算法就是计算偏导用的。


CNN的优缺点:

优点:

  • 共享卷积核,对高维数据处理无压力
  • 无需手动选取特征,训练好权重,即得特征
  • 分类效果好
缺点:
  • 需要调参,需要大样本量,训练最好要GPU
  • 黑盒,物理含义不明确


FINE-TUNING:

何谓fine-tuning:使用已用于其他目标,预训练好模型的权重或者部分权重,作为初始值开始训练

原因:自己从头训练卷积神经网络容易出现问题;fine-tuning能很快收敛到一个较理想的状态。

做法:复用相同层的权重,新定义层取随机权重初始值;调大新定义层的学习率,调小复用层学习率。




代码:

MNIST数据集:

几万张28像素*28像素的手写数字组成,这些图片只包含灰度值。我们要讲这些图片分类,转成0~9
训练集55000个样本,测试集10000,验证集5000

#-*-coding:utf-8-*-"""Created on 17/3/26 下午4:01base Info"""__author__ = 'sun'__version__ = '1.0''''我们依旧用MNIST数据集,简单介绍:几万张28像素*28像素的手写数字组成,这些图片只包含灰度值。我们要讲这些图片分类,转成0~9训练集55000个样本,测试集10000,验证集5000本次讲使用两个卷积层加一个全连接层'''from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets("MNIST_data/",one_hot=True)# print(mnist.train.images.shape,mnist.train.labels.shape)# print(mnist.test.images.shape,mnist.test.labels.shape)# print(mnist.validation.images.shape,mnist.validation.labels.shape)import tensorflow as tfsess = tf.InteractiveSession()# 有很多权重和偏置需要创建,我们先定义好初始化函数以便重复使用。def weight_variable(shape):    initial = tf.truncated_normal(shape,stddev=0.1) #给权重制造噪声,打破完全对称    return tf.Variable(initial)def bias_variable(shape):    initial = tf.constant(0.1,shape=shape) #避免死亡节点(dead neurons)    return tf.Variable(initial)# 卷积层、池化层也要重复使用def conv2d(x,W):    return tf.nn.conv2d(x,W,                #conv2d 是2维卷积函数                        strides=[1,1,1,1],  #stride代表滑动步长,都为1,代表不会遗漏地划过图片的每一个点。                        padding='SAME')     #边界的处理方式,SAME代表让卷积的输出和输入保持同样的尺寸。def max_pool_2x2(x):    return tf.nn.max_pool(x,                          ksize=[1,2,2,1],                          strides=[1,2,2,1],#横竖两个方向以2为步长                          padding='SAME')# 定义输入的placeholderx = tf.placeholder(tf.float32,[None,784])y_ = tf.placeholder(tf.float32,[None,10])x_image = tf.reshape(x,[-1,28,28,1]) # CNN需要用到空间结构,所以讲1*784形式转化为28*28形式。前面的-1代表样本不固定,后面的1代表一个颜色通道# 定义第一个卷积层,先将W和b初始化,在放到激活函数中,再将输出结果进行池化操作。W_conv1 = weight_variable([5,5,1,32]) #5*5的窗口,1个颜色通道,32个卷积核(神经元)b_conv1 = bias_variable([32])h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)h_pool1 = max_pool_2x2(h_conv1)# 定义第二个卷积层,代码一样,唯一不同的是卷积核变成了64个。W_conv2 = weight_variable([5,5,32,64]) #5*5的窗口,32个输入卷积核结果,32个卷积核(神经元)b_conv2 = bias_variable([64])h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2)h_pool2 = max_pool_2x2(h_conv2)# 因为前面经历了两次步长为2*2的最大池化层,所以变成已经只有1/4了。图片由28*28变成了7*7# 我们使用tf.reshape函数对第二个卷积层的输出tensor进行变形,将其转化成1D的向量,然后全连接。w_fc1 = weight_variable([7*7*64, 1024])  # 隐含层节点1024b_fc1 = bias_variable([1024])h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,w_fc1) + b_fc1)# 为了减轻过拟合,使用一个Dropout层,在训练时,我们随机丢弃一部分节点的数据,预测时则保留全部数据来追求最好的预测性能keep_prob = tf.placeholder(tf.float32)h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob) # 这里在全连接层后面才用 是不是太晚了,可以在第一个卷积层后面就用哦# softmax层,概率输出w_fc2 = weight_variable([1024,10])b_fc2 = bias_variable([10])y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,w_fc2) + b_fc2)# 定义损失函数为cross entropy 交叉信息熵,优化器选Adamcross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv),                                              reduction_indices=[1]))train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)# 定义评测准确率correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))# 计算图都被我们设计好了,现在开始训练tf.global_variables_initializer().run()for i in range(20000):    batch = mnist.train.next_batch(50)    if i%10 == 0:        train_accuracy = accuracy.eval(feed_dict={x:batch[0],y_:batch[1],keep_prob: 1.0})        print("step %d, training accuracy %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}))


CIFAR-10数据集:

#-*-coding:utf-8-*-"""Created on 17/3/26 下午5:18文档目录: /Users/sun/tensorflow/Action/chapter/ch05/CIFAR-10/models/tutorials/image/cifar10base Info"""__author__ = 'sun'__version__ = '1.0'"""CIFAR-10包含60000张32*32的彩色图片,其中训练集50000,测试集10000.标注了10类,每类6000张图片,分布为:airplane ,automobile, bird, cat, deer, dog, frog, horse, ship, truck在这个CNN模型中,我们使用一些新的技巧:1、对weights进行了L2正则化2、对图片进行了翻转、随机剪切等数据增强,制造了更多样本。数据量大小恰恰是深度学习最看重的。3、每个卷积-最大池化层后面使用了LRN层,增强了模型的泛化能力。"""import  cifar10,cifar10_input  #载入Tensorflow Models中自动下载、读取CIFAR10数据的类import tensorflow as tfimport numpy as npimport timemax_steps = 3000 #训练轮数batch_size = 128data_dir = '/tmp/cifar10_data/cifar-10-batches-bin' # 下载数据的默认路径# 定义初始化weight的函数,不仅使用了截断的正态分布来初始化权重,也会给weight加一个L2的lossdef variable_with_weight_loss(shape,stddev,w1):    var = tf.Variable(tf.truncated_normal(shape,stddev=stddev))    if w1 is not None:        weight_loss = tf.multiply(tf.nn.l2_loss(var),w1,name='weight_loss')        tf.add_to_collection('losses',weight_loss)    return var# 下载、解压、展开到默认位置cifar10.maybe_download_and_extract()# 生成训练数据 ,这里面封装了数据增强的过程,并且将图片剪切为24*24了。images_train,labels_train = cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size)# 生成测试数据images_test,labels_test = cifar10_input.inputs(eval_data=True,data_dir=data_dir,batch_size=batch_size)# 创建输入数据的placeholder,因为batch_size在之后定义网络结构用到了,所以数据尺寸的第一个值需要预先设定image_holder = tf.placeholder(tf.float32,[batch_size,24,24,3])label_holder = tf.placeholder(tf.int32,[batch_size])"""创建第一个卷积层,这里用到了LRN层,模仿了生物神经系统的'侧抑制'机制,对局部神经元的活动创建竞争环境,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。LRN对ReLU这种没有上限边界的激活函数会比较有用,因为它会从附近的多个卷积核的响应中挑选比较大的反馈,但不适合Sigmoid这种有固定边界并且能抑制过大值的激活函数。"""weight1 = variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,w1=0.0)kernel1 = tf.nn.conv2d(image_holder,weight1,[1,1,1,1],padding='SAME')bias1 = tf.Variable(tf.constant(0.0,shape=[64]))conv1 = tf.nn.relu(tf.nn.bias_add(kernel1,bias1))pool1 = tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')norm1 = tf.nn.lrn(pool1,4,bias=1.0,alpha=0.001/9.0,beta=0.75)"""创建第二个卷积层,基本类似于第一个,区别如下:输入的通道数改为64,bias初始化0.1,调换了最大池化层和LRN层的顺序。"""weight2 = variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,w1=0.0)kernel2 = tf.nn.conv2d(norm1,weight2,[1,1,1,1],padding='SAME')bias2 = tf.Variable(tf.constant(0.1,shape=[64]))conv2 = tf.nn.relu(tf.nn.bias_add(kernel2,bias2))norm2 = tf.nn.lrn(conv2,4,bias=1.0,alpha=0.001/9.0,beta=0.75)pool2 = tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')"""全连接层,隐含节点384个,这里我们希望这个全连接层不要过拟合,因此设了一个非零的weight loss值。"""reshape = tf.reshape(pool2,[batch_size,-1])dim = reshape.get_shape()[1].valueweight3 = variable_with_weight_loss(shape=[dim,384],stddev=0.04,w1=0.004)bias3 = tf.Variable(tf.constant(0.1,shape=[384]))local3 = tf.nn.relu(tf.matmul(reshape,weight3) + bias3)"""全连接层2,隐含节点下降了一半"""weight4 = variable_with_weight_loss(shape=[384,192],stddev=0.04,w1=0.004)bias4 = tf.Variable(tf.constant(0.1,shape=[192]))local4 = tf.nn.relu(tf.matmul(local3,weight4) + bias4)"""最后一层,这里不像之前那样使用softmax 输出结果,因为我们把softmax的操作放在了计算loss部分,计算softmax主要是为了算loss,这里我们直接比较数值大小就知道应该分哪类了。"""weight5 = variable_with_weight_loss(shape=[192,10],stddev=1/192.0,w1=0.0)bias5 = tf.Variable(tf.constant(0.0,shape=[10]))logits = tf.add(tf.matmul(local4,weight5),bias5)"""计算CNN的loss,依然使用cross entropy,最后将cross entropy的loss 加上最后两个全连接层的weight的loss"""def loss(logits,labels):    labels = tf.cast(labels,tf.int64)    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,                                                                   labels=labels,                                                                   name='cross_entropy_per_example')    cross_entropy_mean = tf.reduce_mean(cross_entropy,name='cross_entropy')    tf.add_to_collection('losses',cross_entropy_mean)    return tf.add_n(tf.get_collection('losses'),name='total_loss')loss = loss(logits,label_holder)train_op = tf.train.AdamOptimizer(1e-3).minimize(loss)top_k_op = tf.nn.in_top_k(logits,label_holder,1)  # 输出结果中top k的准确率sess = tf.InteractiveSession()tf.global_variables_initializer().run()tf.train.start_queue_runners() #启动前面提到的图片数据增强的线程队列,使用了16个线程"""正式开始训练"""for step in range(max_steps):    start_time = time.time()    image_batch,label_batch = sess.run([images_train,labels_train])    _,loss_value = sess.run([train_op,loss],                            feed_dict={image_holder: image_batch,label_holder:label_batch})    duration = time.time()-start_time    if step%10==0:        examples_per_sec = batch_size / duration        sec_per_batch = float(duration)        format_str = ('step %d,loss=%.2f (%.1f examples/sec; %.3f sec/batch)')        print(format_str % (step,loss_value,examples_per_sec,sec_per_batch))"""模型在测试集上的准确率先计算一共要多少个batch才能将全部样本评测完,同时,在每一个step中使用session的run方法获取images_testlabels_test的batch"""num_examples = 10000import mathnum_iter = int(math.ceil(num_examples / batch_size))true_count=0total_sample_count = num_iter * batch_sizestep = 0while step < num_iter:    image_batch,label_batch = sess.run([images_test,labels_test])    predictions = sess.run([top_k_op],feed_dict={image_holder:image_batch,                                                 label_holder:label_batch})    true_count += np.sum(predictions)    step += 1precision = true_count / total_sample_countprint('precision  = %.3f' % precision)



深度学习其他算法:

循环神经网络(RNN)的引入原因:

1、传统神经网络输入与输出是独立的,无法解决“我是中国人,我的母语是————”这样的问题。

2、RNN引入“记忆”的概念,输出依赖于输入与“记忆”



Long Short Term 网络(LSTM)的引入原因:

1、RNN不能依赖很久远的信息。

http://www.jianshu.com/p/9dc9f41f0b29



深度学习的典型应用:

1、NBA精彩进球集锦

2、视频中的软性广告

3、场景判断、危险监控

4、双语翻译

5、阅读理解、问答系统


学习资料:

1、斯坦福231N

2、斯坦福224d

3、Michael Nielsen: Neural NetWorks and Deep Learning

4、 Yobhua Bengio Deep Learning Book


0 0
原创粉丝点击