前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >卷积神经网络处理图像识别(二)

卷积神经网络处理图像识别(二)

作者头像
用户6021899
发布2019-11-23 08:54:24
7170
发布2019-11-23 08:54:24
举报

本篇介绍卷积神经网络之前向传播的基本实现。

本篇中卷积神经网络的结构为:

卷积层->池化层->卷积层->池化层->全连接层->全连接层

其中的全连接层还引入了dropout的概念。dropout在训练时会随机将部分节点的输出改为0(使神经元以一定概率失活)。dropout可以避免过拟合(overfitting)问题。

代码和注释中有详细的介绍:

代码语言:javascript
复制
import  tensorflow as tf
#基于MNIST 数据集,稍作更改便可应用于其他数据集。#MNIST 数据集信息,IMAGE_HEIGHT = 28IMAGE_WIDTH = 28NUM_CHANNELS = 1#颜色通道数NUM_LABELS =10#神经网络参数#INPUT_NODE = IMAGE_HEIGHT*IMAGE_WIDTHOUTPUT_NODE = NUM_LABELS#第1层卷积层的尺寸(5x5)和深度CONV1_SIZE = 5CONV1_DEEP = 32#第2层卷积层的尺寸(5x5)和深度CONV2_SIZE = 5CONV2_DEEP = 64#第一个全连接层的节点个数FC1_SIZE = 520
def inference(input_tensor, train, regularizer, avg_class, reuse = True):    '''卷积神经网络前向传播,参数train用于区分训练过程和测试过程'''       #第一层,卷积层    with tf.variable_scope('layer1-conv1', reuse =reuse):        #权重矩阵        conv1_weights = tf.get_variable("weight", [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],                                        initializer = tf.truncated_normal_initializer(stddev = 0.1))        #偏置矩阵        conv1_biases = tf.get_variable("bias", [CONV1_DEEP], initializer = tf.constant_initializer(0.0))               #过滤器x,y向步长均为1 (strides的第2,3个元素)。strides的第1,第4个元素只能为1        #全0填充 padding='SAME';不填充则用padding='VALID'        conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides =[1,1,1,1], padding='SAME')        #添加偏置        conv1 = tf.nn.bias_add(conv1, conv1_biases)        #ReLU引入非线性        relu1 = tf.nn.relu(conv1)        #输出矩阵shape 为 IMAGE_HEIGHTXIMAGE_WIDTHXCONV1_DEEP, 即28x28x32          #第二层,池化层(下采样)    with tf.variable_scope('layer2-pool1', reuse =reuse):        #使用最大池化层,过滤器的尺寸为2X2, 过滤器x,y向步长均为2,全零填充        pool1 = tf.nn.max_pool(relu1, ksize=(1,2,2,1), strides =[1,2,2,1], padding='SAME')#输出矩阵shape 为 14x14x32$$$$           #第三层,卷积层    with tf.variable_scope('layer3-conv2', reuse =reuse):        #权重矩阵        conv2_weights = tf.get_variable("weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP],                                        initializer = tf.truncated_normal_initializer(stddev = 0.1))        #偏置矩阵        conv2_biases = tf.get_variable("bias", [CONV2_DEEP], initializer = tf.constant_initializer(0.0))               #过滤器x,y向步长均为1 (strides的第2,3个元素)。strides的第1,第4个元素只能为1        #全0填充 padding='SAME';不填充则用padding='VALID'        conv2 = tf.nn.conv2d(pool1, conv2_weights, strides =[1,1,1,1], padding='SAME')        #添加偏置        conv2 = tf.nn.bias_add(conv2, conv2_biases)        #ReLU引入非线性        relu2 = tf.nn.relu(conv2)        #输出矩阵shape ,我们仅改变了深度,即14X14X64             #第四层,池化层(下采样)    with tf.variable_scope('layer4-pool2', reuse =reuse):         #使用最大池化层,过滤器的尺寸为2X2, 过滤器x,y向步长均为2,全零填充        pool2 = tf.nn.max_pool(relu2, ksize=(1,2,2,1), strides =[1,2,2,1], padding='SAME')#        #输出矩阵shape 为 7X7X64
代码语言:javascript
复制
    #第五层,(第1个)全连接层    #全连接层的输入格式为向量,张量需要展平。    #get_shape().as_list()可以计算(最后一个池化层)各维度大小,返回到一个列表    # 因每层神经网络的输入输出都为一个batch(一同训练的一批样本)的张量,pool_shape[0]为一个batch中样本的个数    #而inference函数前面都不用考虑batch    pool_shape = pool2.get_shape().as_list()    nodes =  pool_shape[1] * pool_shape[2] * pool_shape[3] #得到第一个全连接层的输入节点数    #注意    #pool_shape[0]这里不如用-1 。    # -1(自动调整)可以适应 placeholder中batch size 为None,测试集,验证集batch不匹配的问题(测试集batch为batchsize,验证集为整个集样本数)    #reshaped = tf.reshape(pool2,[pool_shape[0], nodes]) # X的第一维size传入None时会报错    reshaped = tf.reshape(pool2,[-1, nodes]) #注意这里的中括号,与numpy.reshape()不同    #这里引入了dropout的概念。dropout在训练时会随机将部分节点的输出改为0。dropout可以避免过拟合(overfitting)问题    #dropout 一般只在全连接层使用    with tf.variable_scope('layer5_fc1', reuse =reuse):        #权重        fc1_weights =  tf.get_variable("weight", [nodes, FC1_SIZE, ],                                       initializer = tf.truncated_normal_initializer(stddev = 0.1))               #只有全连接层的权重需要加入正则化,也是为了避免过拟合        if regularizer != None:            tf.add_to_collection('losses', regularizer(fc1_weights))                   #偏置        fc1_biases = tf.get_variable('bias', [FC1_SIZE], initializer=tf.constant_initializer(0.0))        #平均移动模型        if avg_class != None:            fc1_weights = avg_class.average(fc1_weights)            fc1_biases = avg_class.average(fc1_biases)        #加权        fc1 = tf.matmul(reshaped, fc1_weights) + fc1_biases        #ReLU激活        fc1 = tf.nn.relu(fc1)        if train:            fc1 = tf.nn.dropout(fc1, 0.5) #每个神经元 以 50% 概率被抑制          #第六层,(第2个,最后一个)全连接层    #输出长度为10 (因为只有十个类别)的向量。之后无需引入激活函数。输出通过Softmax()就得到了分类的结果    with tf.variable_scope('layer6_fc2', reuse =reuse):        #权重        fc2_weights =  tf.get_variable("weight", [FC1_SIZE, NUM_LABELS, ],                                       initializer = tf.truncated_normal_initializer(stddev = 0.1))               #只有全连接层的权重需要加入正则化,也是为了避免过拟合        if regularizer is not None:            tf.add_to_collection('losses', regularizer(fc2_weights))                   #偏置        fc2_biases = tf.get_variable('bias', [NUM_LABELS], initializer=tf.constant_initializer(0.0))               #平均移动模型        if avg_class is not None:            fc2_weights = avg_class.average(fc2_weights)            fc2_biases = avg_class.average(fc2_biases)                   #加权        logit = tf.matmul(fc1, fc2_weights) + fc2_biases
    #返回最后一层全连接层的输出    return logit    # 通过tf.argmax()即可得到的分类结果

由于此卷积神经网络的待训练参数比较多,所以训练(卷积神经网络的训练下篇会介绍)起来比较慢。若是电脑性能不太好,可以适当减少参数数量,比如可以增大卷积层和池化层的过滤器的尺寸和移动步长,以及减少全连接层的节点数。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档