Tensorflow 构建CNN

一.构建CNN准备

1.创建权重函数

def weight_variable(shape,name="w"):

  initial = tf.contrib.layers.xavier_initializer()

  return tf.get_variable(name,initializer = initial,shape=shape)

注意:权重初始化值选择xavier,这个初始化器是用来保持每一层的梯度大小都差不多相同。

2.创建偏置函数

def biases_variable(shape):

  initial = tf.constant(0.0, shape=shape)

  return tf.Variable(initial)

3.创建二维卷积函数

def conv2d(x, W,strides=[1, 1, 1, 1]):

  return tf.nn.conv2d(x, W, strides=strides,padding='SAME')

如果padding=’SAME’,则输出的卷积后图像大小与输入的大小一样。如果padding=‘VALID’,则输出的卷积后图像大小为N=(imgSize-kSize)/Strides,这里imgSize为原来图像的宽或者高,kSize为卷积核大小,Strides为卷积步长。

4.创建最大池化层函数

def max_pool_2x2(x,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1]):

  return tf.nn.max_pool(x,ksize ,strides ,padding='VALID')

同样的,如果padding=’SAME’,则输出的卷积后图像大小与输入的大小一样。如果padding=‘VALID’,则输出的卷积后图像大小为N=(imgSize-kSize)/Strides,这里imgSize为原来图像的宽或者高,kSize为卷积核大小,Strides为卷积步长。

5.定义占位符

xs = tf.placeholder(tf.float32, [None, 465, 128, 1])

ys = tf.placeholder(tf.float32, [None, 10])

定义占位符只需要知道自己输入图的大小就可以按照相应的改写。例如输入100张20X20的图则:xs = tf.placeholder(tf.float32,[None,20,20,1])。其中None表示可以输入任意多的图。

二.构建CNN结构

上图为一个卷积层的示意图,可以知道,卷积层需要突触权值,偏置(可以选择不要偏置)激活函数,最后得到输出。

1.创建卷积层,并且用relu激活

kenerl_size = [3, 3, 1, 32]

strides = [1, 1, 1, 1]

W_conv1 = weight_variable(kenerl_size,name="w1")  ##patch 3x3 ,in size 1,out size 32

b1 = biases_variable([kenerl_size[3]])

#b1=0

conv2_1 = tf.nn.relu(conv2d(xs, W_conv1)+b1)  # N x 465 x 128 x 32

假设我们需要一个3x3的卷积核去卷积输入,并且输出32层,每次卷积的步长为1.那么我们的卷积核大小就为[3, 3, 1, 32]=>>[卷积宽度,卷积高度,卷积输入,卷积输出]

卷积步长[1, 1, 1, 1]=>>[固定1,卷积步长宽度,卷积步长高度,固定1]

因为权重是要随着训练改变的,因此定义权重变量,变量的大小为卷积核的大小。

偏置是加入对应每个输出上的,因此是卷积核大小为卷积输出大小。

最后卷积用激活函数relu去激活。

2.创建池化层

池化层按照我的理解是对卷积后的结果进行降维。降维后每个通道图大小为N=(imgSize-kSize)/Strides,这里imgSize为原来图像的宽或者高,kSize为池化核大小,Strides为池化步长。

pool_2 = max_pool_2x2(x=conv2_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1])  # N x 116 x 32 x 64

3.对池化得到的结果压平用于全连接层

压平这个操作其实就是矩阵转换成一维矩阵,reshape即可,需要注意的是矩阵大小要计算准确,最后一维矩阵大小为N=high*wide*channel也就是输出通道数乘以图的宽度高度

Ft = tf.reshape(pool_2, [-1, 116 * 32 * 64])  # N x 3 x 2 x 64 =>> N x 384

4.创建全连接层

全连接是对压平后的数据再次变小,用矩阵乘法得到更新的维度再激活函数激活

# Dense layer  # 1 Dense layer(units: 100, activation: ReLu ) Dropout(rate: 30 %)

w_fc_1 = tf.Variable(tf.truncated_normal([116 * 32 * 64, 100], stddev=0.01))  # N x 384 =>> N x 100

b3 = biases_variable([100])

x = tf.nn.relu(tf.matmul(Ft, w_fc_1)+b3)

5.预测

预测也是矩阵相乘,压缩输出

out_size = tf.Variable(tf.truncated_normal([100, 10], stddev=0.01))  # N x 100 =>> N x 10

prediction_values = tf.matmul(x, out_size)

到此一个CNN构建完成,卷积池化全连接大小可以根据实际情况自行增加或者减少。最后可以看下图进行回顾。

 

三.训练模型

训练模型我们需要定义损失,优化损失方法,接下来就是训练。因为训练数据量很大我们需要对数据按照batch划分,一个一个小的batch进行训练。

1.定义损失

loss = tf.losses.softmax_cross_entropy(ys,prediction_values)

如果损失函数选择了sofmax那么我们的ys也就是标签需要定义成one-hot。比如有10个类,那么第一类0的one-hot编码为[1,0,0,0,0,0,0,0,0,0]

2.定义训练

LEARNING_RATE_BASE = 0.001

LEARNING_RATE_DECAY = 0.1

LEARNING_RATE_STEP = 300

gloabl_steps = tf.Variable(0, trainable=False)

learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE

                                         , gloabl_steps,

                                         LEARNING_RATE_STEP,

                                         LEARNING_RATE_DECAY,

                                         staircase=True)

train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss,global_step=gloabl_steps)

最小化损失minimize然后把损失函数放进去。这里学习率的定义需要注意:

曲线 初始时 上扬 [黄线]:

解决方法:初始学习率过大导致振荡,应减小学习率,并从头开始训练 。

曲线 初始时强势下降没多久归于水平 [绿线]:

解决方法:后期学习率过大导致无法拟合,应减小学习率,并重新训练后几轮 。

曲线 全程缓慢 [紫线]:

解决方法:初始学习率过小导致收敛慢,应增大学习率,并从头 开始训练 。

一般情况下,选择指数下降函数学习率学习。

四.一个完整例子

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: eric.lai 2018.11.19
"""
建立CNN方法
1.建立权重,偏移,卷积,池化函数
2.定义x,y输入输出占位符,定义防止过拟合keep_prob参数
3.定义一层卷积池化,二层卷积池化
4.定义全连接层两层
5.预测
6.损失函数
7.训练
"""


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

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

def compute_accuracy(v_xs, v_ys):
    global prediction
    y_pre = sess.run(prediction, feed_dict={xs: v_xs, keep_prob: 1})
    correct_prediction = tf.equal(tf.argmax(y_pre,1), tf.argmax(v_ys,1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    result = sess.run(accuracy, feed_dict={xs: v_xs, ys: v_ys, keep_prob: 1})
    return result

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

def biases_variable(shape):
    initial = tf.constant(0.1,shape=shape)
    return tf.Variable(initial)

def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')   #strides=[1,1,1,1] 这里第一个和最后一个都固定为1,1 ,中间参数是间隔几个像素移动,padding中  VALID(抽取的图片比原图小),SAME(抽取的图片和原来一样)

def max_pool_2x2(x):
    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME') #ksize=[1,2,2,1]这里第一个和第四位一样,中间参数是间隔几个像素移动

## 定义x,y,keep_prob占位符
xs = tf.placeholder(tf.float32,[None,784])
ys = tf.placeholder(tf.float32,[None,10])
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(xs,[-1,28,28,1])  #[n_samples,28,28,1]  -1代表输入暂时不定可以多张输入

### conv1 layer ###
W_conv1 = weight_variable([5,5,1,32])  ##patch 5x5 ,in size 1,out size 32
b_conv1 = biases_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)  #out size 28x28x32
h_pool1 = max_pool_2x2(h_conv1)                      #  out size 14x14x32

###conv2 layer  ###
W_conv2 = weight_variable([5,5,32,64])  # patch 5x5  ,in size 32 ,out size 64
b_conv2 = biases_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2) #  out size 14x14x32
h_pool2 = max_pool_2x2(h_conv2)                       # output size 7x7x64

### fc1 layer###
W_fc1 = weight_variable([7*7*64 ,1024])
b_fc1 = biases_variable([1024])
## [n_samples ,7 ,7 ,64] ->> [n_samples ,7x7x64]
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)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)

### fc2 layer###
W_fc2 = weight_variable([1024,10])
b_fc2 = biases_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

loss = tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(1000)
    print(type(batch_xs),batch_ys.shape)
    sess.run(train_step,feed_dict={xs: batch_xs, ys: batch_ys, keep_prob: 0.5})
    if i % 50 == 0:
        print(batch_xs.shape,batch_ys.shape)
        print(compute_accuracy(mnist.test.images[:1000], mnist.test.labels[:1000]))

五.最后经验总结

对于CNN训练,如果无法收敛或者震荡,应当考虑以下情况:

1.数据是否正确,数据和标签对应与否

2.数据是否归一化

3.训练的batch是否太小

4.学习率,一般地选择指数衰减法

 

参考:以上图片均为网络图片,仅作示例,侵权联系删除

 






 

GitHub 加速计划 / te / tensorflow
184.55 K
74.12 K
下载
一个面向所有人的开源机器学习框架
最近提交(Master分支:2 个月前 )
a49e66f2 PiperOrigin-RevId: 663726708 3 个月前
91dac11a This test overrides disabled_backends, dropping the default value in the process. PiperOrigin-RevId: 663711155 3 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐