tensorflow框架学习 —— CNN卷积神经网络的实现

Posted dwithy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tensorflow框架学习 —— CNN卷积神经网络的实现相关的知识,希望对你有一定的参考价值。

一、卷积神经网络

1、关于卷积神经网络的知识,这里推荐一个博客,可以通过几篇博文来了解卷积神经网络:https://www.cnblogs.com/pinard/category/894694.html

 

2、关于张量经过卷积与池化后数据各维度大小的变化:

设原图片数据维度为$batch*width*height*channel$:$batch$为图片张数,$width$为图宽,$height$为图高,$channel$为图通道数。

 

卷积:

设卷积核为$padding*cwidth*cheight$:padding层数为$padding$,卷积核宽$cwidth$,卷积核高$cheight$;卷积步长$wstride*hstride$,宽为$wstride$,高为$hstride$;卷积核个数为$cchannel$。

经过卷积后的图片张数:

$$batch^‘=batch$$

经过卷积后的宽:

$$weight^‘=(\\fracwidth+2padding-cwithwstride+1)$$

经过卷积后的高:

$$height^‘=(\\fracwidth+2padding-cheighthstride+1)$$

经过卷积后的通道数:

$$channel^‘=cchannel$$

经过卷积后的图片数据为:

$$batch^‘*width^‘*height^‘*channel^‘=batch\\ast (\\fracwidth+2padding-cwithwstride+1)\\ast (\\fracwidth+2padding-cheighthstride+1)*cchannel$$

一般情况我们设置卷积核的高=宽=f,步长为s,卷积核数为cchannel,则公式可以简化为:

$$batch^‘*width^‘*height^‘*channel^‘=batch\\ast (\\fracwidth+2padding-fstride+1)\\ast (\\fracwidth+2padding-fstride+1)*channel$$

注意,公式计算可能出现小数,所以要向下取证。

 

池化:

设池化的宽与高为$pwidth$与$pheight$,步长为$wstrid$与$hstrid$

经过卷积后的图片张数:

$$batch^‘=batch$$

经过卷积后的宽:

$$weight^‘=(\\fracwidth+2padding-pwidthwstride+1)$$

经过卷积后的高:

$$height^‘=(\\fracwidth+2padding-pheighthstride+1)$$

经过卷积后的通道数:

$$channel^‘=channel$$

池化后的数据为:

$$batch^‘*width^‘*height^‘*channel^‘=batch\\ast (\\fracwidth+2padding-pwidthwstride+1)\\ast (\\fracwidth+2padding-pheighthstride+1)\\ast channel$$

同样当我们设定池化宽=高=f,步长为stride,则公式为:

$$batch^‘*width^‘*height^‘*channel^‘=batch\\ast (\\fracwidth+2padding-widthwstride+1)\\ast (\\fracwidth+2padding-heightstride+1)\\ast channel$$

 

二、tensorflow中卷积相关内容

函数介绍:

  1、卷积的实现函数:tf.nn.conv2d (input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

  • input:输入的要做卷积的图片,要求为一个张量,shape为 [ batch, in_height, in_weight, in_channel ],其中batch为图片的数量,in_height 为图片高度,in_weight 为图片宽度,in_channel 为图片的通道数,灰度图该值为1,彩色图为3。
  • filter: 卷积核,要求也是一个张量,shape为 [ filter_height, filter_weight, in_channel, out_channels ],其中 filter_height 为卷积核高度,filter_weight 为卷积核宽度,in_channel 是图像通道数 ,和 input 的 in_channel 要保持一致,out_channel 是卷积核数量。

  • strides: 卷积时在图像每一维的步长,这是一个一维的向量,默认是[batch, height, width, channels]取决于input的data_format,一般设置[ 1, strides, strides, 1],第一位和最后一位是1。
  • padding: string类型,值为“SAME” 和 “VALID”,表示的是卷积的形式,是否考虑边界。"SAME"是考虑边界,不足的时候用0去填充周围,"VALID"则不考虑
  • use_cudnn_on_gpu: bool类型,是否使用cudnn加速,默认为true。

  这里一开始可能对input和strides传入的列表的数值设定可能不太了解为什么这么设置,这个主要有data_format决定,详情可以看一下这个博文:https://blog.csdn.net/qq_30934313/article/details/86626050

 

  2、池化的实现函数:tf.nn.max_pool(value, ksize, strides, padding, name=None)

  • 第一个参数value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape。
  • k_size:池化窗口的大小,取一个四维向量,shape为[batch, height, width, channels],一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1。
  • strides:窗口在每一个维度上滑动的步长,shape为[batch, height, width, channels],一般也是[1, stride,stride, 1]。
  • padding:string类型,值为“SAME” 和 “VALID”,表示的是卷积的形式,是否考虑边界。"SAME"是考虑边界,不足的时候用0去填充周围,"VALID"则不考虑。

 

  3、tensor数据维度设定(通常用于卷积到全连接层张量与捐局的转化):tf.reshape(tensor,shape,name=None)

  • tensor:传入的tensor类型数据。
  • shape:修改的形状,一个1*784的one-hot数据变成一个1*28*28*1的灰度图数据可以设置为[1,28,28,1],若某一个维度设置为-1表示这个维度不确定,转化会自行计算。
  • name:转化操作的名字。

 

三、代码示例

代码

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

# 读取手写字数据
mnist_data = input_data.read_data_sets(rC:\\Users\\EDZ\\.PyCharm2019.1\\config\\scratches\\MNIST_data, one_hot=True)

# 设定每个批次的数据量,如果是CPU版本的tensor数据大可能会计算不出来所以设置为50
batch_size = 50

#计算批次数
n_batch = mnist_data.train.num_examples // batch_size

#定义卷积
def x_cov_W(x,W_shape,b_shape,act=None):
    ‘‘‘
    :param x: 进行卷积的tensor
    :param W_shape: 卷积核的shape
    :param b_shape: 偏置的shape
    :param act: 激活函数
    :return: 返回一个卷积计算结果
    ‘‘‘
    #定义卷积核
    initial = tf.truncated_normal(W_shape,stddev=0.1)
    W=tf.Variable(initial)
    #定义偏置
    b=tf.constant(0.1,tf.float32,shape=b_shape)
    #返回卷积的结果,这里设置步长为宽W=1,高H=1
    if act: #没有激活函数的情况
        return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding=SAME)+ b
    else:   #有激活函数的情况
        return act(tf.nn.conv2d(x,W,strides=[1,1,1,1],padding=SAME)+ b)

#定义池化,把原来的数据高与宽缩小一半
def pool(x):
    ‘‘‘
    :param x: 需要池化的tensor
    :return: 返回一个池化结果
    ‘‘‘
    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])

#将x的one-hot数据转为图片28*28*1的张量,-1:不确定的batch即图片数;28:高;28:宽;1:channel数。
x_image=tf.reshape(x,[-1,28,28,1])

#第一层卷积,W_shape-5:图高;5:图宽;1:channel数;16:卷积核个数;b_shape-16:偏置个数,因为有16个卷积核,输出为28*28*16的图
layer1_cov=x_cov_W(x_image,[5,5,1,16],[16],tf.nn.relu)
#第一层池化,输出为14*14*32的图
layer1_pool=pool(layer1_cov)

#第二层卷积,输出为14*14*32,的图
layer2_cov=x_cov_W(layer1_pool,[5,5,16,32],[32],tf.nn.relu)
#第二层池化输出为7*7*64,的图
layer2_pool=pool(layer2_cov)

#将第二层的输出扁平化为一个one-hot的1维向量
layer2_pool_flat=tf.reshape(layer2_pool,[-1,7*7*32])

#第三层全连接层
full3_w=tf.Variable(tf.truncated_normal([7*7*32,720],stddev=0.1)) #权重矩阵:w输入为7*7*32,输出为720
full3_b=tf.constant(0.1,tf.float32,[720])  #偏置
full3_ouput=tf.nn.relu(tf.matmul(layer2_pool_flat,full3_w)+full3_b)  #激活函数为Relu

#第四层全连接层
full4_w=tf.Variable(tf.truncated_normal([720,10],stddev=0.1)) #权重矩阵:w输入为1024,输出为10
full4_b=tf.constant(0.1,tf.float32,[10])  #偏置
full4_ouput=tf.matmul(full3_ouput,full4_w)+full4_b #为了不与后面的交叉熵损失冲突无激活函数

#定义交叉熵损失函数
cross_entropy=tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=full4_ouput)

#使用Adam梯度下降法训练模型
train=tf.train.AdamOptimizer(0.001,0.9,0.999).minimize(cross_entropy)

# 初始化
init = tf.global_variables_initializer()

# 结果存放在bool型列表汇总
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(full4_ouput, 1))

# 计算准确度,并加入到总结指令
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(init)

    # 训练20代
    for epoch in range(20):
        # 每代对数据进行一轮minibatch
        for batch in range(n_batch):
            batch_x, batch_y = mnist_data.train.next_batch(batch_size)  # 每个循环读取batch_size大小批次的数据
            sess.run(train, feed_dict=x: batch_x, y: batch_y)
            acc = sess.run(accuracy, feed_dict=x: mnist_data.test.images, y: mnist_data.test.labels)  # 用测试数据计算准确度
            if batch % 99 == 0:
                print(第%d代%d批次,准确率为%.6f % (epoch + 1, batch + 1, acc))

 

 

  

以上是关于tensorflow框架学习 —— CNN卷积神经网络的实现的主要内容,如果未能解决你的问题,请参考以下文章

机器学习-随手笔记二(卷积神经网络TensorFlow和IV值计算)

TensorFlow框架之CNN卷积神经网络详解

TensorFlow实战-TensorFlow实现卷积神经网络CNN-第5章

25- 卷积神经网络(CNN)原理 (TensorFlow系列) (深度学习)

深度学习与TensorFlow 2.0卷积神经网络(CNN)

基于CNN卷积神经网络的TensorFlow+Keras深度学习的人脸识别