6、卷积神经网络CNN

我们知道多层神经网络(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:01

base Info
"""
__author__ = 'sun'
__version__ = '1.0'

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

本次讲使用两个卷积层加一个全连接层
'''

from tensorflow.examples.tutorials.mnist import input_data
mnist = 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 tf
sess = 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')
# 定义输入的placeholder
x = 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])  # 隐含层节点1024
b_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 交叉信息熵,优化器选Adam
cross_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/cifar10
base 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 tf
import numpy as np
import time

max_steps = 3000 #训练轮数
batch_size = 128
data_dir = '/tmp/cifar10_data/cifar-10-batches-bin' # 下载数据的默认路径

# 定义初始化weight的函数,不仅使用了截断的正态分布来初始化权重,也会给weight加一个L2的loss
def 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].value
weight3 = 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_test
labels_test的batch
"""

num_examples = 10000
import math
num_iter = int(math.ceil(num_examples / batch_size))
true_count=0
total_sample_count = num_iter * batch_size
step = 0
while 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 += 1
precision = true_count / total_sample_count
print('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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值