实现卷积神经网络
卷积图示:LE-Net5
捕获.PNG这个图可以利用来学习单通道卷积,例如下面mnist训练的数据仅仅用到黑白图片的灰度,因此是单通道。彩色的图片由3色RGB构成的三通道。
mnist训练简单的cnn
- tensorflow实现简单cnn的网络结构:
- input层
- 卷积层
- pool
- 卷积层
- pool
- 全连接层
- 输出层
- code释义
- 读取数据
数据是由28x28展开到784的数据,因此后面需要还原成28x28
import tensorflow as tf
import numpy as np
from sklearn import preprocessing
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(r'D:\PycharmProjects\HandWritingRecognition\TF\data',
one_hot=True) # getdata
sess = tf.InteractiveSession()
# 样本定义
x = tf.placeholder(dtype=tf.float32, shape=[None, 784])
# 真实值
y_ = tf.placeholder(dtype=tf.float32, shape=[None, 10])
- 权重和偏执的初始化
# 定义初始权重函数
def init_weights(shape):
# 服从截断的正态分布, 方差为0.1
initial = tf.truncated_normal(shape=shape, stddev=0.1)
return tf.Variable(initial_value=initial)
# 定义偏置的初始值
def init_bias(shape):
initial = tf.constant(value=0.1, shape=shape)
return tf.Variable(initial)
- 卷积
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)除去name参数用以指定该操作的name,与方法有关的一共五个参数:
-
input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
-
filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
-
strides:卷积在图像每一维的步长,这是一个一维的向量,长度4,[batch, in_height, in_width, in_channels]
-
padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式
same:相同卷积,在kernel提取进行卷积时候边缘会有损失,same保证输出维度和输入维度的一致,那么就会在边缘填充0,然后再计算卷积以保证维度的一致。
valid:有效卷积,与上面相反,不做填充。strides=1行/列关系:output_row = input_row - kernel_row + 1 -
use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
-
结果返回一个Tensor,这个输出,就是我们常说的feature map
# 定义一个2D的单通道卷积层
def conv2d(x, W):
# stage=1,卷积仅仅导致边缘损失padding=“same”代表用0来填充保证输入和输出的图片像素一致
# 2d to 4d
return tf.nn.conv2d(input=x, filter=W, strides=[1, 1, 1, 1], padding="SAME")
- 池化
-
value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape
-
ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1
-
strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
-
padding:和卷积类似,可以取'VALID' 或者'SAME'
-
返回一个Tensor,类型不变,shape仍然是[batch, height, width, channels]这种形式
# 定义pool函数,maxpool用来降为提取显著的特征
def max_pool_2x2(x):
# 两个维度采取边缘填充0,stride=2:那么图像维度行列都变为原来的1/2
return tf.nn.max_pool(value=x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
- input转化
# 要把数据转化为28x28的图片
x_image = tf.reshape(x, [-1, 28, 28, 1]) # -1:类似于numpy,后面的1:代表通道
- 构建卷积和池化层
# 定义第一个卷积层, 定义32个单通道5x5的核,提取32个特征
W_conv1 = init_weights(shape=[5, 5, 1, 32])
b_conv1 = init_bias(shape=[32])
# 第一层卷积层的输出
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1) # 图像变成14x14 x 32
# 定义第二层卷积层
W_conv2 = init_weights(shape=[5, 5, 32, 64]) # 单通道变成32,提起64个特征,定义5x5核
b_conv2 = init_bias(shape=[64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2) # 7x7 x 64
# h_pool2转化为1维度的数据
num = 7 * 7 * 64
h_pool2_flat = tf.reshape(h_pool2, [-1, num])
一个卷积层输出每个特征是14 x 14,一共有32个kernel滤波提取32个特征。
7 全连接层
# 隐藏节点设定为1024:全连接层
W_fc1 = init_weights([num, 1024])
b_fc1 = init_weights([1024])
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(x=h_fc1, keep_prob=keep_prob)
- 输出层
# 全连接输出层
W_fc2 = init_weights([1024, 10])
b_fc2 = init_weights([10])
h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
y = tf.nn.softmax(h_fc2)
- 训练模型
# loss function
loss = tf.reduce_mean(
- tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]) # 先计算求和每行的交叉熵,然后去每个样本的交叉熵均值
)
# train
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.global_variables_initializer().run() # 图的所有变量初始化
# 训练模型
for i in range(3000):
batchX, batchY = mnist.train.next_batch(100)
train_step.run(feed_dict={x: batchX, y_: batchY, keep_prob: 0.75})
# print(h_pool2_flat.shape)
if i % 100 == 0:
print(sess.run(loss, feed_dict={x: batchX, y_: batchY, keep_prob: 0.75}))
# test
print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
- output
iteration 300: 0.1200
iteration 600: 0.9200
iteration 900: 0.9200
iteration 1200: 1.0000
iteration 1500: 0.9800
iteration 1800: 0.9600
iteration 2100: 1.0000
iteration 2400: 0.9600
iteration 2700: 1.0000
2017-11-14 16:24:17.311788: W C:\tf_jenkins\home\workspace\rel-win\M\windows-gpu\PY\36\tensorflow\core\common_runtime\bfc_allocator.cc:217] Allocator (GPU_0_bfc) ran out of memory trying to allocate 2.59GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
2017-11-14 16:24:17.312383: W C:\tf_jenkins\home\workspace\rel-win\M\windows-gpu\PY\36\tensorflow\core\common_runtime\bfc_allocator.cc:217] Allocator (GPU_0_bfc) ran out of memory trying to allocate 1.34GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
2017-11-14 16:24:17.820643: W C:\tf_jenkins\home\workspace\rel-win\M\windows-gpu\PY\36\tensorflow\core\common_runtime\bfc_allocator.cc:217] Allocator (GPU_0_bfc) ran out of memory trying to allocate 3.90GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
test data accuracy: 0.985
CNN进阶
再次之前需要补一补一些正则化的知识(后面会采用正则化的方法避免过度拟合):http://blog.csdn.net/zouxy09/article/details/24971995。这个绝对是深度好文,讲解L0,L1,L2正则化方法以及对比区别。
- 网络结构
- 卷积层
- 最大池化
- LRN
- 卷积层
- 最大池化层
- 全连接层
- 全连接层
- logits
-
LRN
全名叫局部响应归一化,结合ReLu这种单侧抑制激活函数上能有效的提高模型的繁华能力,下面两篇博文能解释该方法的操作机理,比较简单!
http://blog.csdn.net/hduxiejun/article/details/70570086
http://www.jianshu.com/p/bf398d78aedc -
多通道的核是怎样的?
数据是10种类别的物品的彩色图片,3通道CNN模型。理解起来也比较容易参考下http://blog.csdn.net/u014114990/article/details/51125776即可。 -
code释义
网友评论