卷积神经网络的tensorflow实现

版权声明:本文为博主原创文章,未经博主允许不得转载。    https://blog.csdn.net/happyhorizion/article/details/77894047
卷积神经网络概述
一般一个卷积神经网络由多个卷积层构成,在卷基层内部通常会有如下几个操作:
1)图像通过多个卷积核滤波,添加偏置,提取局部特征每个卷积核会映射出一个新的2D图像。
2)卷积核的滤波结果输出到激活函数中,激活函数通常选ReLU【书,参考37】
3)对激活函数的结果进行池化操作,池化就是对图像分割成不同的小区域后取平均值或最大值。一般取最大值。
上述几个步骤就构成了最常见的卷积层。在池化的后面还可以加上batch normalization等操作。
一个卷积层中可以有不同的卷积核,而每一个卷积核都对应一个滤波后映射出的新图像,同一个新图像的每一个像素都来自完全相同的卷积核。这种卷积核的权值共享可以有效降低模型负责度,减轻过拟合,减少计算量。

tensorflow实现
卷积神经网络结构
建立卷积神经网络对手写数字识别问题进行优化,构建由两个卷积层(包含池化层),两个全连接层构成的卷积神经网络。输入图像是28×28的单通道数据,输出是10×1的one_hot编码的向量。
第一层:卷积核大小是[5,5],输入通道1,输出通道32,padding选择SAME模式,激活函数为relu。
第二层:池化层,池化核大小是[2,2],步长[2,2]。
第三层:卷积核大小是[5,5],输入通道32,输出通道64,padding选择SAME模式,激活函数为relu。
第四层:池化层,设置同上。
第五层:全连接层,首先将图像数据矩阵flatten化,变成1维向量,输出维度是1024, 之后dropout掉一定的数据防止过拟合
第六层:全连接层,输出维度10,激活函数为softmax
损失函数:交叉熵

具体实现如下:

导入包和数据
首先导入需要的包和数据

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_DATA/', one_hot=True)
1
2
定义卷积核
卷积核是指定维数的张量,卷积核的大小为:[filter_height, filter_width, in_channels, out_channels]
这里用tf.Variable()定义卷积核,定义的时候会指定初始化的操作。

def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev=0.1)
    weight= tf.Variable(initial_value=initial)
return weight
1
2
3
定义偏置
def bias_variable(shape):
    initial = tf.constant(0.1,shape=shape)
    bias = tf.Variable(initial_value=initial)
    return bias
1
2
3
对输入做卷积操作
def conv_op(in_tensor, kernel, strides=[1,1,1,1], padding=’SAME’, name=’conv’):
    conv_out = tf.nn.conv2d(in_tensor,kernel,strides, padding,name=name)
return conv_out
1
2
输入的张量维度是[batch, in_height,in_width,in_channels]
在具体操作中,程序会将输入张量展开为[batch, out_height, out_width, filter_hightfilter_widthin_channels]
并将卷积核展开为[filter_heightfilter_widthin_channels, out_channels ]
输入张量展开后与卷积核的展开相乘,得到的结果的维度是:[batch, out_height, out_width, out_channels],和输入张量的维度保持一致。也就是说,在tensorflow构建的图中,张量始终都是以始终是:[batch, height,width,channels]的维度流动。
步长strides通常定义为strides=[1, dh, dw, 1], 也就是strides[0]=strides[3]=1. dh和dw分别是垂直和水平方向卷积核移动的步长。
padding就是是否要做边界填充,如果要,padding=‘SAME’,如果不用,padding=‘VALID’

叠加上偏置并输出到激活函数
h_conv1 = tf.nn.relu(conv_op(x_image, W_conv1)+b_conv1)
之后输入到激活函数,直接调用tensorflow中的tf.nn.relu()函数就可以,激活函数的输出依然是:[batch, out_height, out_width, out_channels]

tf.nn.relu(features, name = None)
输入参数:

features: 一个Tensor。数据类型必须是:float32,float64,int32,int64,uint8,int16,int8。
name: (可选)为这个操作取一个名字。
输出参数:

一个Tensor,数据类型和features相同。
在tensorflow中,加法运算有好几种,例如专门的偏置叠加tf.bias_add,还有tf.add,也可以直接用a+b,具体区别见后。

池化层
池化操作是:对输入的张量进行区域扫描求最大值或者平均值。一般求最大值。tensorflow有tf.nn.max_pool()函数可以方便地实现池化操作。池化尺寸kh×kw, 步长是dh×dw,padding设置为‘SAME’。

扫描二维码关注公众号,回复: 5407107 查看本文章

def max_pool_2x2(in_tensor, ksize=[1,2,2,1], strides=[1,2,2,1],padding=’SAME’,name=’max_pooling’):
    max_pool = tf.nn.max_pool(in_tensor, ksize, strides, padding, name=name)
return max_pool
1
2
这里ksize=[1,kh,kd,1], strides=[1,dh,dw,1]

目标函数:交叉熵
 cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv),reduction_indices=[1]))
自此,就定义好了前向计算的所有操作。后向计算采用AdamOptimizer函数,学习率1e-4

最后,给出卷积操作的实现代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Jul  9 12:16:52 2017
mnist by simple cnn
@author: 
"""
 
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
 
mnist = input_data.read_data_sets('MNIST_DATA/', one_hot=True)
 
sess = tf.InteractiveSession()
 
# ======================================================== #
#                       SIMPLE CNN
# ======================================================== #
 
# define conv kernel
def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev=0.1)
    weight = tf.Variable(initial_value=initial)
    return weight
 
# define conv bias
def bias_variable(shape):
    initial = tf.constant(0.1,shape=shape)
    bias = tf.Variable(initial_value=initial)
    return bias
 
# define a simple conv operation 
def conv_op(in_tensor, kernel, strides=[1,1,1,1], padding='SAME'):
    conv_out = tf.nn.conv2d(in_tensor, kernel, strides=strides, padding=padding)
    return conv_out
 
# define max pooling operation
def max_pool_2x2(in_tensor,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME'):
    max_pool = tf.nn.max_pool(in_tensor, ksize, strides, padding)
    return max_pool
 
def simple_cnn():
    x = tf.placeholder(tf.float32, [None, 784])
    y_ = tf.placeholder(tf.float32, [None, 10])
    x_image = tf.reshape(x,[-1, 28, 28, 1]) # 28*28 pic of 1 channel
 
    # cnn structure
    w1 = [5,5,1,32]
    b1 = [32]
    w2 = [5,5,32,64]
    b2 = [64]
    wfc1 = [7*7*64,1024]
    bfc1 = [1024]
    wfc2 = [1024,10]
    bfc2 = [10]
 
    # 1st layer
    W_conv1 = weight_variable(w1)
    b_conv1 = bias_variable(b1)
    h_conv1 = tf.nn.relu(conv_op(x_image, W_conv1)+b_conv1)
    h_pool1 = max_pool_2x2(h_conv1)
    # 2nd layer
    W_conv2 = weight_variable(w2)
    b_conv2 = bias_variable(b2)
    h_conv2 = tf.nn.relu(conv_op(h_pool1, W_conv2)+b_conv2)
    h_pool2 = max_pool_2x2(h_conv2)
    # fc1
    h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])
    W_fc1 = weight_variable(wfc1)
    b_fc1 = bias_variable(bfc1)
    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1)+b_fc1)
    # drop out
    keep_prob = tf.placeholder(tf.float32)
    h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
    # fc2
    W_fc2 = weight_variable(wfc2)
    b_fc2 = bias_variable(bfc2)
    y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2)+b_fc2)
    # loss function
    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)
 
    # estimate accuarcy
    correct_prediction = tf.equal(tf.arg_max(y_conv,1), tf.arg_max(y_,1))
    accuarcy = 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%100 == 0:
            train_accuracy = accuarcy.eval(feed_dict={x:batch[0],y_:batch[1],keep_prob:1.0}) # testify, or prediction
            print('step %d, training accuarcy %g'%(i, train_accuracy))
        train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
 
    print("test accuracy %g"%accuarcy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))
    return
 
if __name__ == '__main__':
    simple_cnn()

tensorflow的一些细节点:
padding
padding的选项:

valid就是指卷积核是以整个卷积核为基础从边沿对齐图像的边沿开始,任何边沿到达图像另一边时就停止卷积运算;
same则是以卷积核的中间点为基础,中间点扫过真个图像才结束。自然,same的模式下,卷积后的输出和原输入的维度是一致的。
tf.cast
估计模型的准确度时,用到了函数tf.cast
tf.cast(x, dtype, name=None)数据类型转换,将x或者x.values转换为dtype
a=tf.constant(value=[1.1,2.3],dtype=tf.float32)
b=tf.cast(a,dtype=tf.int32)
sess = tf.Session()
print(sess.run(a)) #输出[ 1.10000002 2.29999995]
print(sess.run(b)) #输出[1 2]

tf.add(a,b)、tf.bias_add(a,b)和 a+b
1) tf.add(a, b) 与 a+b
在神经网络前向传播的过程中,经常可见如下两种形式的代码:
tf.add(tf.matmul(x, w), b)
tf.matmul(x, w) + b
简而言之,就是 tf.add(a, b) 与 a + b二者的区别,类似的也有,tf.assign 与 =(赋值运算符)的差异。
在计算精度上,二者并没有差别。运算符重载的形式a+b,会在内部转换为,a.add(b),而a.add(b)会再一次地映射为tf.add。

2. tf.nn.bias_add 与 tf.add
tf.nn.bias_add 是 tf.add 的一个特例,也即 tf.add 支持的操作比 tf.nn.bias_add 更多。二者均支持 broadcasting(广播机制),也即两个操作数最后一个维度保持一致。
除了支持最后一个维度保持一致的两个操作数相加外,tf.add 还支持第二个操作数是一维的情况。
参考:
《tensorflow实战》
http://blog.csdn.net/wangjian1204/article/details/53291619
In tensorflow what is the difference between tf.add and operator (+)?(https://stackoverflow.com/questions/37900780/in-tensorflow-what-is-the-difference-between-tf-add-and-operator)
--------------------- 
作者:lxy_Alex 
来源:CSDN 
原文:https://blog.csdn.net/happyhorizion/article/details/77894047?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

#!/usr/bin/env python2

# -*- coding: utf-8 -*-

"""

Created on Thu Mar 9 22:01:46 2017

  

@author: marsjhao

"""

  

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data

  

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

sess = tf.InteractiveSession()

  

def weight_variable(shape):

 initial = tf.truncated_normal(shape, stddev=0.1) #标准差为0.1的正态分布

 return tf.Variable(initial)

  

def bias_variable(shape):

 initial = tf.constant(0.1, shape=shape) #偏差初始化为0.1

 return tf.Variable(initial)

  

def conv2d(x, W):

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

  

def max_pool_2x2(x):

 return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],

       strides=[1, 2, 2, 1], padding='SAME')

  

x = tf.placeholder(tf.float32, [None, 784])

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

# -1代表先不考虑输入的图片例子多少这个维度,1是channel的数量

x_image = tf.reshape(x, [-1, 28, 28, 1])

keep_prob = tf.placeholder(tf.float32)

  

# 构建卷积层1

W_conv1 = weight_variable([5, 5, 1, 32]) # 卷积核5*5,1个channel,32个卷积核,形成32个featuremap

b_conv1 = bias_variable([32]) # 32个featuremap的偏置

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) # 用relu非线性处理

h_pool1 = max_pool_2x2(h_conv1) # pooling池化

  

# 构建卷积层2

W_conv2 = weight_variable([5, 5, 32, 64]) # 注意这里channel值是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)

  

# 构建全连接层1

W_fc1 = weight_variable([7*7*64, 1024])

b_fc1 = bias_variable([1024])

h_pool3 = tf.reshape(h_pool2, [-1, 7*7*64])

h_fc1 = tf.nn.relu(tf.matmul(h_pool3, W_fc1) + b_fc1)

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

  

# 构建全连接层2

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 = 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.arg_max(y_conv, 1), tf.arg_max(y_, 1))

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

  

tf.global_variables_initializer().run()

  

for i in range(20001):

 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, 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}))

猜你喜欢

转载自blog.csdn.net/zzx3163967592/article/details/83047318