【数据极客】Week3_梯度下降_卷积神经网络CNN_LeNet5实现

    • Week3
  • 理论学习
    • 梯度下降 Gradient Descent 李宏毅课程
      • 1 公式
      • 2 调整学习率
      • 3 区别梯度下降与随机梯度下降Stochastic Gradient Descent
      • 4 特征缩放Feature Scaling
      • 5 梯度下降背后的数学
      • 6 梯度下降的局限
    • Hello World of Deep Learning - Mnist Works with Keras 李宏毅课程
    • 卷积神经网络 CNN
      • 1 普通神经网络和卷积神经网络的区别
      • 2 卷积网络组成结构
        • Review
        • 卷积层
        • 激励层 ReLU Layer
        • 池化层 Pooling Layer
        • 全连接层 Fully-Connected Layer FC Layer
  • 思考问题
    • 1 Batch Normalization原理 benefit优点
    • 2 如何理解卷积
    • 3 如何理解卷积神经网络CNN中的卷积Convolution Kernel和池化Pooling 有哪些Pooling
    • 4 Learning Rate 的如何选取它过大过小会产生什么影响
    • 5 机器学习中有哪些正则化的方法 的是什么 Dropout的好处是
    • 6 Covariate Shift 和 Internal Covariate Shift 如何理解
    • 7 如何理解 Momentum weight decay 它们在神经网络训练中的作用是什么
    • 8 如何理解过拟合overfitting神经网络训练如何避免overfitting
      • 神经网络的过拟合的理解
      • 如何避免过拟合
    • 9 各种优化方法SGDMomentumAdagradAdam等对比优缺点
      • SGD 随机梯度下降
      • Momentum 动量
      • Adagrad 自适应
      • Adam
    • 10 经典的卷积神经网络CNN之一LeNet5模型详细解释
  • 实践任务
    • 1 在MNIST手写数字数据集上使用LeNet5模型进行训练和测试评估准确率
  • Input层
  • 第一次卷积池化非线性
  • 第二次卷积池化非线性
  • 全连接层非线性
  • Dropout层
  • Softmax层
  • Loss函数 优化器
    • 2 使用AlexNet模型训练图片分类 并评估准确率
    • 参考文献

Week3

【数据极客】Week3 任务

理论学习

1. 梯度下降 Gradient Descent 李宏毅课程

1.1 公式


- 学习率(Learning Rate) η 下降步长

L(θ)=[L(θ1)/(θ1)L(θ2)/(θ2)] 负梯度方向

L(θ0) 代表了在 θ0 点处的等高线的法线方向, 也是该梯度是最大上升方向, 前面加上符号就成了, 最大下降方向, 即: L(θ0)

  • θ1=θ0ηL(θ0)

θ0 点, 沿着在该点的负梯度方向上, 移动 ηL(θ0) 的距离, 最终到达 θ1 点。

1.2 调整学习率

  • 仔细调整学习率
    学习率 η 如果太大, 虽然可以加快梯度下降速度, 但是可能会错过局部最小值点, 造成反复震荡; 反之,下降速度会太慢。
  • 自适应学习率 Adaptive Learning Rates
    • 开始时候, 因为距离目标值点较远, 可以使用较大的学习率。
    • 当到达某一时刻, 距离目标点较近时候, 减小学习率。
    • E.g. 1/t decay: ηt=η/t+1
      这里的 t 代表时间, 随着时间的增长, 学习率在不断减小。
  • Adagrad

    上面提到的普通的随机梯度下降算法对于所有参数都使用了同一个更新速率。但是同一个更新速率不一定适合所有参数。比如有的参数可能已经到了仅需要微调的阶段,但又有些参数由于对应样本少等原因,还需要较大幅度的调动。

    而在Adagrad的更新规则中,学习率 η 会随着每次迭代根据历史梯度的变化而变化。

    ηt=ηt+1

    σt=1t+1ti=0(gi)2

    wt+1=wtηtσtgt

    分子分布约分之后得到 wt+1=wtηti=0(gi)2gt

    ti=0(gi)2 代表前 t 步梯度平方的累加和。

    这里分母可能为0, 所以在分母位置加上一个极小值 ϵ , 变为 wt+1=wtηti=0(gi)2+ϵgt

    可以看到算法不断的迭, 分母会越来越大, 整体的学习率会越来越小。

1.3 区别:梯度下降与随机梯度下降(Stochastic Gradient Descent)

  • 梯度下降
    • 损失函数 L=n(ŷn(b+wixni))2
      对所有训练数据误差进行求和。
  • 随机梯度下降

    • 损失函数
      某一个样本的损失 Ln=(ŷn(b+wixni))2

    θi=θi1ηLn(θi1)
    迭代得到下一个点。

1.4 特征缩放(Feature Scaling)

在我们面对多特征问题时,我们要保证这些特征都具有相似的尺度,这将帮助梯度下降算法更快的收敛。

  • 第i行(纬)的样本数据的平均值mean: mi
  • 标准差 σi
  • xri=xrimiσi

特征放缩之后所有纬度的均值为0, 方差为1

1.5 梯度下降背后的数学

梯度下降背后的数学

1.6 梯度下降的局限

  • 陷入局部最小值
  • 在高原地方,梯度值也可能会很小,可能就会提前停止, 不能到达最小点。

2. Hello World of Deep Learning - Mnist Works with Keras 李宏毅课程

Keras的底层库使用TensorFlowTheano,这两个库也称为Keras的后端。

  • 安装方法:
pip install keras
  • Mini-batch

batch_size 太小会导致训练慢,过拟合等问题,太大会导致欠拟合。所以要适当选择

  • Keras实现视频中的 Hello World of Mnist

Hello World of Deep Learning - Mnist Works with Keras

import tensorflow as tf
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras import backend as K

import numpy

Using TensorFlow backend.

# Training Data
# MNIST Data: http://yann.lecun.com/exdb/mnist/
# Keras provides data sets loading function: http://keras.io/datasets/
# 训练集,测试集
(X_train, y_train), (X_test, y_test) = mnist.load_data() # 使用Keras自带的mnist工具读取数据(第一次需要联网)

X_train = X_train.reshape(X_train.shape[0], X_train.shape[1] * X_train.shape[2]) # 由于mist的输入数据维度是(num, 28, 28),这里需要把后面的维度直接拼起来变成784维  
X_test = X_test.reshape(X_test.shape[0], X_test.shape[1] * X_test.shape[2])  
Y_train = (numpy.arange(10) == y_train[:, None]).astype(int) #把index转换成一个one hot的矩阵  
Y_test = (numpy.arange(10) == y_test[:, None]).astype(int)
print(X_train.shape)
print(Y_train.shape)
print(X_test.shape)
print(Y_test.shape)
print('Rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1]))
(60000, 784)
(60000, 10)
(10000, 784)
(10000, 10)
Rows: 60000, columns: 784
# 1. 构建网络
model = Sequential()
# 对所有像素使用全连接层 Dense
model.add(Dense(input_dim=784, output_dim=500)) # 第一层
model.add(Activation('sigmoid')) # 激活函数 sigmoid

model.add(Dense(output_dim=500)) # 第二层
model.add(Activation('sigmoid')) # 激活函数 sigmoid

model.add(Dense(output_dim=10)) # 第三层的输出为 10个类别 对应0到9
model.add(Activation('softmax'))# 激活函数 softmax
/Users/anthony/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:4: UserWarning: Update your `Dense` call to the Keras 2 API: `Dense(input_dim=784, units=500)`
/Users/anthony/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:7: UserWarning: Update your `Dense` call to the Keras 2 API: `Dense(units=500)`
/Users/anthony/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:10: UserWarning: Update your `Dense` call to the Keras 2 API: `Dense(units=10)`
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 500)               392500    
_________________________________________________________________
activation_1 (Activation)    (None, 500)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 500)               250500    
_________________________________________________________________
activation_2 (Activation)    (None, 500)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 10)                5010      
_________________________________________________________________
activation_3 (Activation)    (None, 10)                0         
=================================================================
Total params: 648,010
Trainable params: 648,010
Non-trainable params: 0
_________________________________________________________________
# 2. 构建损失方法 loss
# loss:字符串(预定义损失函数名)或目标函数,参考损失函数

# 3.1 优化方法 optimizer
#optimizer:字符串(预定义优化器名)或优化器对象,参考优化器
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
#metrics:列表,包含评估模型在训练和测试时的网络性能的指标

# 3.2 训练 得到最优参数
# batch_size 太小会导致训练慢,过拟合等问题,太大会导致欠拟合。所以要适当选择
# nb_epoch就是最多迭代的次数, shuffle就是是否把数据随机打乱之后再进行训练
# verbose是屏显模式,官方这么说的:verbose: 0 for no logging to stdout, 1 for progress bar logging, 2 for one log line per epoch.
# 就是说0是不屏显,1是显示一个进度条,2是每个epoch都显示一行数据
# validation_split就是拿出百分之多少用来做交叉验证
model.fit(X_train, Y_train, batch_size=200, nb_epoch=100, shuffle=True, verbose=1, validation_split=0.3)  
model.evaluate(X_test, Y_test, batch_size=200, verbose=1)

# nb_epoch 在新的API里面变为 epochs
/Users/anthony/anaconda3/lib/python3.6/site-packages/keras/models.py:848: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`.
  warnings.warn('The `nb_epoch` argument in `fit` '


Train on 42000 samples, validate on 18000 samples
Epoch 1/100
42000/42000 [==============================] - 3s - loss: 0.4860 - acc: 0.8681 - val_loss: 0.2842 - val_acc: 0.9185
Epoch 2/100
42000/42000 [==============================] - 3s - loss: 0.2586 - acc: 0.9250 - val_loss: 0.2413 - val_acc: 0.9299
Epoch 3/100
42000/42000 [==============================] - 3s - loss: 0.2245 - acc: 0.9341 - val_loss: 0.2152 - val_acc: 0.9372
    省略多行
Epoch 99/100
42000/42000 [==============================] - 2s - loss: 0.0401 - acc: 0.9867 - val_loss: 0.1058 - val_acc: 0.9693
Epoch 100/100
42000/42000 [==============================] - 2s - loss: 0.0400 - acc: 0.9858 - val_loss: 0.1086 - val_acc: 0.9674
 9000/10000 [==========================>...] - ETA: 0s




[0.095627619931474325, 0.97119999766349796]

卷积神经网络 CNN

3.1 普通神经网络和卷积神经网络的区别

  • 普通神经网络

常规的神经网络输入层input layer ,会经过多个隐层, 每个隐层有多个神经元组成, 每个神经元都与前一层的神经元两两相连接, 最后的输出层output layer 是全连接层, 实现分类, 输出每个类别的分值, 作为分类的判断依据。

全连接在隐层节点很多的时候,会使得权重数量过多,会存在过拟合问题。

  • 卷积神经网络

在该网络中以三维的方式排列其神经元,三个维度分别为长、宽、深度,作为卷积层的输入是三维的(3D), 输出则也是三维的(3D).

如果输入是图片, 长、宽为图片的长与宽, 深度对应于图片的三个颜色通道(红、绿、蓝)。

与普通神经网络中的全连接层相比, 卷积神经网络通过过滤器Filter,得到特征图Feature Map, 其次通过池化 Max Pooling操作, 起到了下采样的效果。

3.2 卷积网络组成结构

  • 卷积网络层级结构

卷积神经网络由一组有序的n个(卷积层+激励层+池化层)+ Full Connected Layer

Review


上图展示了 553 的卷积核在 32323 的图像上卷积的过程,将filter在整个空间位置滑动并做内积(卷积)运算。最后得到结果是Feature Map 特征图谱。

卷积层

  • 计算卷积层过滤之后的大小

输入大小 N=7 , 过滤器大小 F=3 , 滑动步长为 stride=1 , 计算该层卷积操作之后的输出结果为多少?

此时 (73)/1+1=3 , 即 77 大小的图片, 经过大小为3的过滤器, 将得到 55 大小的特征图Feature Map。

  • 局部关联, 每个神经元可以看作一个数据窗口filter

    • 窗口(receptive filed)滑动, 每个神经元连接数据窗的权重是固定的,在该神经元滑动遍历的过程中权值是共享的,一组固定的权重和不同窗口内数据做内积。
  • 步长 stride

    每次滑动数据窗口filter的单位长度。

  • 0填充边缘 Zero-Padding

    比如现在有一个 44 的数据块, 现在要用 33 的窗口,使用 stride=2 进行滑动,显然是不行的。
    使用0来填充边缘, 使得满足滑动要求。

激励层 ReLU Layer

将卷积层结果做非线性映射

更多的激活函数 Activation Function 请见上周作业。

池化层 Pooling Layer

  • 位置:位于连续的卷积层中间
  • 作用:下采样、数据压缩和参数的量、减少过拟合

在每个颜色对应的数据窗口中取最大值。

全连接层 Fully-Connected Layer (FC Layer)

和普通的神经网络中的全连接层的作用和效果是一样的, 不再赘述了。位于卷积神经网络的尾部。

4. 思考问题

4.1 Batch Normalization原理 & benefit(优点) ?

因为深层神经网络在做非线性变换前的激活输入值(就是那个x=WU+B,U是输入)随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致后向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因。

benefit:

BN的目的就是把每层神经网络任意神经元这个输入值的分布强行拉回到【均值为0方差为1的标准正太分布】而不是【正态分布】,其实就是把越来越偏的分布强制拉回比较标准的分布。

这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

4.2 如何理解卷积?

卷积核(Convolution Kernel)具有的一个属性就是局部性。即它只关注局部特征,局部的程度取决于卷积核的大小,目的是提取图像邻近像素的相似性。

4.3 如何理解卷积神经网络(CNN)中的卷积(Convolution Kernel)和池化(Pooling) & 有哪些Pooling?

  • CNN中的卷积核
    • 局部连接
    • 权值共享

目的: 减少了参数量,降低过拟合。

  • Pooling
    • 最大池化
    • 平均池化

目的:池化的目的是识别同类不同表现,最大池化的原理就是取出每个滑动窗口中最大的值(Max Pooling),这样就可以适应每个窗口内的变化,也能降低输出参数量。

4.4 Learning Rate 的如何选取,它过大/过小会产生什么影响?

  • 过大:

可能会造成反复震荡, 无法到达局部最小点。

  • 过小

训练速度太慢。

4.5 机器学习中,有哪些正则化的方法? 的是什么? Dropout的好处是 ?

  • L1 正则 Lasso

L1是向量各元素的绝对值之和。
L1正则化往往会使学到的模型很稀疏(系数权重经常为0), 可以用来做特征选择。

  • L2 正则

L2是向量各元素的平方和。
由于L2惩罚想中的系数是二次方的,L2正则化会让系数的取值变得平均。系数之和为常数时, 各系数相等时惩罚是最小的,所以L2系数趋于相同; 表征能力强的特征对应的系数是非零的。

  • L1和L2的异同点

    • 相同点:都用于避免过拟合
    • 不同点:
    • L1可以让一部分特征的系数缩小到0,从而间接实现特征选择。所以L1适用于特征之间有关联的情况。
    • L2让所有特征的系数都缩小,但是不会减为0,它会使优化求解稳定快速。所以L2适用于特征之间没有关联的情况
  • Dropout好处

Dropout是指在模型训练时随机让网络某些隐含层节点的权重不工作,不工作的那些节点可以暂时认为不是网络结构的一部分,但是它的权重得保留下来(只是暂时不更新而已),因为下次样本输入时它可能又得工作了。

由于每次用输入网络的样本进行权值更新时,隐含节点都是以一定概率随机出现,因此不能保证每2个隐含节点每次都同时出现,这样权值的更新不再依赖于有固定关系隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况。

4.6 Covariate Shift 和 Internal Covariate Shift 如何理解?

  1. Covariance shift

when the input distribution to a learning system changes, it is said to experience covariance shift.

假设x是属于特征空间的某一样本点,y是标签。covariate这个词,其实就是指这里的x,那么covariate shift可以直接根据字面意思去理解:样本点x的变化。

  1. Internal Covariate Shift

当这种现象发生在多层神经网络之间时,即前面层参数的改变,使得后面层的输入分布发生改变时,就叫Internal covariance shift。

  1. 总结

对于深度学习这种包含很多隐层的网络结构,在训练过程中,因为各层参数老在变,所以每个隐层都会面临covariate shift的问题,也就是在训练过程中,隐层的输入分布老是变来变去,这就是所谓的“Internal Covariate Shift”,Internal指的是深层网络的隐层,是发生在网络内部的事情,而不是covariate shift问题只发生在输入层。


前面层的参数变化会影响当前层的输入分布,缺点:

  • 1.大大减慢当前层的参数学习速度(当前层也是一个learning system,一旦其输入的分布改变,就要调整参数来适应这种分布);
  • 2.若使用sigmoid激活函数,当前层的输入可能会处于sigmoid函数的非线性饱和区域,进而导致梯度消失现象。在BN出现以前,通常采用ReLU(x)=max(0,x)激活函数或使用较小的learning rate来解决这个问题。

因此我们想到,如果前面层的输出activation(即当前层的输入input)的分布是一定的呢?那样就会减少下一层输入陷入sigmoid饱和非线性区域的可能,梯度不再容易消失,从而加快训练速度。


解决办法:

  • 白化 Whitening

对某一层的输出activations进行白化操作(零均值、单位方差、去相关),可以使得这些activations的分布保持恒定,从而减小internal covariance shift对下一层的影响。

  • Normalization via Mini-batch statistics
    • normalization:零均值化、单位方差
    • scale and shift:引入两个参数,从而使得BN操作可以代表一个恒等变换(相当于BN transform的输入和输出是一样的,也就是不改变输入分布)

具体可以参照以下资料:

https://zhuanlan.zhihu.com/p/26352087
http://blog.csdn.net/mao_xiao_feng/article/details/53150037
http://blog.csdn.net/mao_xiao_feng/article/details/54317852
http://blog.csdn.net/panglinzhuo/article/details/77531913
http://blog.csdn.net/zhikangfu/article/details/53391840

4.7 如何理解 Momentum ? weight decay? 它们在神经网络训练中的作用是什么?

https://www.zhihu.com/question/24529483

4.8 如何理解”过拟合overfitting”?神经网络训练,如何避免overfitting?

神经网络的过拟合的理解

因为神经网络具有很多参数,而训练过程中,如果对这些参数不加以限制,它们很可能会在训练出的模型中含带有训练数据的特性。我觉得可以说成是神经网络参数权重记住了训练数据的样子。

如何避免过拟合

  • 提前终止训练 early stop
  • 扩大训练数据量 data expending
  • 加入正则约束约束项 L1 L2
  • 随机丢弃 dropout

4.9 各种优化方法(SGD/Momentum/Adagrad/Adam等),对比优缺点?

SGD 随机梯度下降

将数据集拆分成多个批次(batch),随机抽取一个批次计算并更新参数。

  • 优点:

收敛速度快。

  • 缺点:
    • 更新参数对所有参数都采用一样的学习率。
    • 容易收敛到局部最小点

Momentum 动量

在梯度下降法中的一种加速算法。

更新时候会保留之前的更新方向,利用当前的批次再微调本次的更新参数, 因此引入一个新的变量v速度, 作为前几次梯度的累加。【参考《Tensorflow技术解析与实战》】

对于一般的SGD, 表达式可以写为 x=xαdx , x 沿着负梯度方向下降。 而带monmentum项的SGD形式如下: v=βvαdx

即: x=x+v

其中系数 β 就是动量系数, 如果上一次的动量(即 v )与这次的负梯度方向是相同的,同方向, 相当于在相同行驶方向的汽车, 踩了一脚油门, 下降速度就会加快。

Adagrad 自适应

能够为哥哥参数分配不同的学习率, 能够控制每个维度的梯度方向。如果本次更新梯度大, 学习率就衰减得快一些,如果更新时候梯度较小, 学习率衰减就慢一点。

Adam

机器之心:Adam优化算法

4.10 经典的卷积神经网络(CNN)之一,LeNet5模型详细解释?

LeNet5 就是 LeCun 网络(Net), 共有5层网络。

  • INPUT

输入图像大小为 3232 的灰度图像

  • C1卷积层

该层有6个卷积核, 卷积核大小为 55
共有 6(55+1)=156 w 参数, 其中 1 代表一个 bias, 经过卷积操作之后, 得到 28286 的特征图谱。

(NF)/stride+1=

这里 N=32 F=5 stride=1 得到 (32-5)/1 + 1 = 28

所以特征图谱尺寸为 2828

  • S2平均池化层

该层是大小的 22 的平均池化层。

通过该层降采样之后,得到特征图谱尺寸变为上一层的 12 , 即: 14146 , 再使用非线性 Sigmod 激活函数进行映射。

  • C3卷积层

该层有16个卷积核, 大小为 55 ,经过计算可以得到特征图谱为 101016

  • S4池化层

该层同S2层一样, 同样使用 22 的平均池化层,通过该层降采样之后,得到特征图谱尺寸变为上一层的 12
即: 5516

  • C5卷积层

该层有120个大小为 55 的卷积核,和前面一层的输出是同样大小的, 所以相当于构成全连接层,就是卷积核在进行卷积的过程中, 只需要遍历一次, 就能将同样大小 55 的数据块卷积完成。

  • F6
    全连接层, 含有84个隐层节点, 激活函数 Sigmoid

  • OUTPUT

输出10类分类结果, 0——>9 共10个分类结果。

  • 总结

    • Lenet5 含有三个卷积层,两个池化层,再加上1个全连接层。

    • 每个卷积层都包含: 卷积、池化、非线性激活函数映射

5. 实践任务

5.1 在MNIST手写数字数据集上,使用LeNet5模型进行训练和测试,评估准确率。

有关 LeNet5的介绍,请参照【思考问题】中的4.10回答

在MNIST 写数字数据集上,使 LeNet5模型进 训练和测试,评估准确率。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
%matplotlib inline
#Mnist数据集
# one_hot=True会使得 label由1维变位10维
mnist = input_data.read_data_sets("MNIST_Data/data/", one_hot=True)
Extracting MNIST_Data/data/train-images-idx3-ubyte.gz
Extracting MNIST_Data/data/train-labels-idx1-ubyte.gz
Extracting MNIST_Data/data/t10k-images-idx3-ubyte.gz
Extracting MNIST_Data/data/t10k-labels-idx1-ubyte.gz
img = mnist.train.images[66].reshape(28,28);
plt.imshow(img)

sess = tf.InteractiveSession()
#构造权重函数,标准差0.1, 给权重制造一些随机的噪声
def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1);
    return tf.Variable(initial)

#给偏置bias增加0.1, 防止死亡节点
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)
# 构造二维卷积函数
# tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

# input 参数
# an input tensor of shape [batch, in_height, in_width, in_channels]
# [一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],这是一个4维的Tensor,要求类型为float32和float64其中之一

# filter 参数
# 相当于CNN中的卷积核, [filter_height, filter_width, in_channels, out_channels],
# [卷积核的高度,卷积核的宽度,图像通道数,卷积核个数]
# 要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维

# strides 参数
# 卷积时在图像每一维的步长,这是一个一维的向量,长度4

# padding 参数
# 边界的处理方式,SAME代表边界加上padding让卷积的输入和输出保持同样的尺寸。
def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')

# ksize 使用 2*2 最大化池, 保留像素值最大的点
# ksize 池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],
# 因为我们不想在batch和channels上做池化,所以这两个维度设为了1,即横纵两个方向上步长为2进行遍历
def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

1. Input层

#定义 Input 向量格式
#变形函数tf.reshape将数据转换为 28*28 ,单通道颜色
# -1 代表样本数量未知 , 1 代表单通道颜色
_X = tf.placeholder(tf.float32, [None, 784])
_y = tf.placeholder(tf.float32, [None, 10])
X_image = tf.reshape(_X, [-1,28,28,1]); # 将 1*784 转换为 28*28 结构

2. 第一次卷积、池化、非线性

W_conv1 = weight_variable([5,5,1,32]) # 卷积核的尺寸;1代表单通道颜色;6代表卷积核数量,就是最后提取特征的类别6特种
b_conv1 = bias_variable([32]) # 偏置
h_conv1 = tf.nn.relu(conv2d(X_image, W_conv1) + b_conv1)# 卷积 + 非线性
print(h_conv1.get_shape()) #第一次卷积之后输出数据格式
h_pool1 = max_pool_2x2(h_conv1)#第一次最大池化
(?, 28, 28, 32)

查看第一最大池化之后, 可以看到图像大小由 282832 边为 141432

print(h_pool1.get_shape())
(?, 14, 14, 32)

3. 第二次卷积、池化、非线性

W_conv2 = weight_variable([5, 5, 32,64]) # 使用64个卷积核
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)# 第二次卷积 + 非线性
print(h_conv2.get_shape()) # 第二次卷积之后输出数据格式
h_pool2 = max_pool_2x2(h_conv2)
print(h_pool2.get_shape()) # 第二次最大池化
(?, 14, 14, 64)
(?, 7, 7, 64)

4. 全连接层、非线性

隐含节点1024个

W_fc1 = weight_variable([7*7*64, 1024])
print(W_fc1.get_shape())
b_fc1 = bias_variable([1024])
h_pool2_flatten = tf.reshape(h_pool2, [-1, 7*7*64]) # 将第二次最大池化后的结果重构为 一维向量
print(h_pool2_flatten.get_shape())
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flatten, W_fc1) + b_fc1) # 全连接层  非线性
(3136, 1024)
(?, 3136)
print(h_fc1.get_shape())
(?, 1024)

6. Dropout层

训练时随机丢弃一部分节点的数据, 减轻过拟合

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

7. 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)

8. Loss函数 & 优化器

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)
# accuracy函数
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()
# 训练20000次 每次大小为50的mini-batch 每100次训练查看训练结果 用以实时监测模型性能
for i in range(20000):
    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, train_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
}))
step 0, train_accuracy 0.08
step 100, train_accuracy 0.8
step 200, train_accuracy 0.88
step 300, train_accuracy 0.86
step 400, train_accuracy 0.94

省略很多很多行

step 19500, train_accuracy 1
step 19600, train_accuracy 1
step 19700, train_accuracy 1
step 19800, train_accuracy 1
step 19900, train_accuracy 1
test accuracy 0.9924

5.2 使用AlexNet模型,训练图片分类 ,并评估准确率。

图片分类数据集:CIFAR-10 dataset 链接:http://www.cs.toronto.edu/~kriz/cifar.html)

参考文献

http://blog.csdn.net/joshuaxx316/article/details/52062291

标准差

梯度下降背后的数学

http://www.cnblogs.com/happylion/p/4172632.html

tf.nn.conv2d是怎样实现卷积

https://www.zhihu.com/question/49376084

https://zh.wikipedia.org/wiki/%E5%8D%B7%E7%A7%AF

Dropout

防止过拟合

momentum

你可能感兴趣的:(深度学习,深度学习-Tensorflow)