1 神经网络搭建框架介绍

搭建一个完整的神经网络,通常包含导入模块、传播模块、训练模块、测试模块。下面将一一讲解每个模块的构成和搭建方法。

(1)导入模块-----------》(2)传播模块---------》(3)训练模块---------》(3)测试模块---------》(4)工程应用

2 导入模块

导入模块主要包含内容:导入所需要的数据集,载入相应的python库,常量定义,生成数据集。

数据集的获取方法:(1)网上下载开源的数据集 :仅能用于学习,直接下载,无需处理

                                 (2)网络爬虫爬取图片 :仅能用于学习,使用python的request库和beautifulsoup库

                                 (3)视频分解为图片 :通过OpenCV视频处理进行图像的分解

                                (4)自己制作收集:利用OpenCV的基本操作完成图像处理,数据集的制造。

python库,常量定义:

# -*- coding: utf-8 -*-
#此文件定义了LeNet_5的前向传播过程
import tensorflow as tf

#配置神经网络的参数
#输入节点
INPUT_NODE=784
#输出节点
OUTPUT_NODE=10
#图像大小
IMAGE_SIZE=28
#图像通道
NUM_CHANNELS=1
#标签数目
NUM_LABELS=10

#定义第一层卷积层的尺寸和深度
CONV1_DEEP=32
CONV1_SIZE=5
#定义第二层卷积层的尺寸和深度
CONV2_DEEP=64
CONV2_SIZE=5
#全连接层的节点个数
FC_SIZE=512

2 传播模块

      搭建神经网络的传播过程,以卷积神经网络为例,包含输入层,卷积层,池化层,激活函数、全连接层、softmax层;

输入层:神经网络的输入,在图像处理的卷积神经网络中一般是输入图像的像素矩阵;灰度图片深度为1;彩色图片下深度为3;(不算入神经网络的层数)

卷积层:卷积层将神经网络中的每一个小块进行更加深入的分析提取出更高维度的抽象特征。一般的小块就是卷积核的大小同时为3x3,5x5;计算卷积的时候一般需要根据实际情况考虑选择全零填充和非全零填充;

池化层;池化层不改变三维矩阵的深度仅改变三维矩阵的大小,通常有最大池化层(取区域最大值)和平均池化层(取区域平均值)

激活函数:减弱非线性,提升深层神经网络表达能力(不再是输入的线性组合,而是几乎可以逼近任意函数)

全连接层:全连接层的每一个结点都与上一层的所有结点相连,用来把前边提取到的特征综合起来。由于其全相连的特性,一般全连接层的参数也是最多的。(只有全连接层需要正则化)

softmax层:主要用于分类,计算输出概率,该样本属于各个类的概率

#定义前向传播过程
def inference(input_tensor,regularizer):
    #第一层卷积层计算
    with tf.variable_scope('layel-conv1'):
        #获取第一层的权重
        con1_weight=tf.get_variable("weight",[CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_DEEP],initializer=tf.truncated_normal_initializer(stddev=0.1))
        #获取第一层的偏值
        con1_biases=tf.get_variable("biases",[CONV1_DEEP],initializer=tf.constant_initializer(0.0))
        #计算第一层的卷积
        conv1=tf.nn.conv2d(input_tensor,con1_weight,strides=[1,1,1,1],padding='SAME')
        #添加第一层的偏值
        relu1=tf.nn.relu(tf.nn.bias_add(conv1,con1_biases))

    #第二层池化层计算 选取最大池化层
    with tf.name_scope('layer2-pool'):
        pool1=tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

    #第三层卷积层的计算
    with tf.variable_scope('layer3-conv2'):
        #获取第三层的权重
        conv2_weight=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))
        #计算第三层的卷积
        conv2=tf.nn.conv2d(pool1,conv2_weight,strides=[1,1,1,1],padding='SAME')
        #获取第三层的激活函数
        relu2=tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))

    #第四层池化层计算
    with tf.name_scope('layer4_pool2'):
        pool2=tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
        #计算输出矩阵的维度
        pool_shape=pool2.get_shape().as_list()
        #计算矩阵变为向量后的长度
        nodes=pool_shape[1]*pool_shape[2]*pool_shape[3]
        #将第四层的输出变成一个batch的输出向量
        #pool_shape[0]表示一个batch的个数(即为行数)
        reshaped=tf.reshape(pool2,[pool_shape[0],nodes])
    #定义第五层的全连接传播过程
    with tf.variable_scope('layer5-fc1'):
        #获取第五层的权重
        fcl_weights=tf.get_variable("weight",[nodes,FC_SIZE],initializer=tf.truncated_normal_initializer(stddev=0.1))
        #全连接层需要添加正则化
        if regularizer !=None:
            tf.add_to_collection('losses',regularizer(fcl_weights))
        #获取添加了正则化的偏值
        fc1_biases=tf.get_variable("biases",[FC_SIZE],initializer=tf.constant_initializer(0.1))
        #激活函数的计算
        fc1=tf.nn.relu(tf.matmul(reshaped,fcl_weights)+fc1_biases)
        #dropout函数避免过拟合问题
        #if train: fc1=tf.nn.dropout(fc1,0.5)

3 训练模块

载入搭建的神经网络传播模型,输入数据完成神经网络的训练,计算模型的最后的参数

训练模块主要包含输入输出数据的定义,损失函数,滑动平均、学习率、喂入数据、保存训练模型。

损失函数:

描述真实数据和预测数据之差的函数,用来表示预测值( y)与已知答案( y_)的差距。 在训练神经网络时,通过不断改变神经网络中所有参数,使损失函数不断减小,从而训练出更高准确率的神经网络模型,损失函数通常可以表示成损失项和正则项的和 J(w)=∑iL(mi(w))+λR(w) ;

常见的损失函数:

                         (1) quadratic+sigmoid (平方损失函数)

                         (2) cross entropy + sigmoid (交叉熵损失函数)

                         (3) softmax + log-likelihood

                        (4 )自定义损失函数

参考文献:

神经网络优化方法:

                    (1)设置学习率:控制参数更新的速度,指数衰减学习率;

                    (2)正则化:防止神经网络过拟合,分为L1正则化和L2正则化;L1正则化和L2正则化区别:L1正则化让参数变得    稀疏,即更多的参数变为0;L2正则化可导,优化方法较L1正则化简洁。

                     (3)滑动平均模型:提高模型在未知数据上的健壮力。

# -*- coding: utf-8 -*-
#此文件定义了LeNet_5的训练过程
import  os
import tensorflow as tf
import  numpy as np
from tensorflow.examples.tutorials.mnist import input_data
#加载前向传播函数
import  mnist_inference
#配置神经网络参数
BATCH_SIZE=100
LEARNING_RATE_BASE=0.01
LEARNING_RATE_DECAY=0.99
REGULARAZTION_RATE=0.0001
TRAINGING_STEPS=30000
MOVING_AVERAGE_DECAY=0.99

#模型文件的保存路径
MODEL_SAVE_PATH="data//"
MODEL_NAME="model.ckpt"

def train(mnist):
    #准备输入数据
    x=tf.placeholder(tf.float32,[BATCH_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS],name='x-input')
    y_=tf.placeholder(tf.float32,[None,mnist_inference.OUTPUT_NODE],name='y-input')
    #定义正则化的方法L2
    regularizer=tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
    #前向传播求出y
    y=mnist_inference.inference(x,regularizer)
    # 定义训练的轮数,需要用trainable=False参数指定不训练这个变量,
    # 这样同时也可以避免这个变量被计算滑动平均值??????????
    global_step=tf.Variable(0,trainable=False)
    #定义损失函数、学习率、滑动平均
    #滑动平均
    # 给定滑动平均衰减速率和训练轮数,初始化滑动平均类
    # 定训练轮数的变量可以加快训练前期的迭代速度
    variable_averages=tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
    # 用tf.trainable_variable()获取所有可以训练的变量列表,全部使用滑动平均
    variable_averages_op=variable_averages.apply(tf.trainable_variables())
    #交叉熵
    #softmax函数获取分类的概率分布
    cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=tf.argmax(y_,1))
    # 获取总损失平均值
    cross_entropy_mean=tf.reduce_mean(cross_entropy)
    #损失函数
    # 给损失加上正则化的损失
    # 使用get_collection获取losses集合的全部值的列表,然后用add_n求列表的所有值的和
    loss=cross_entropy_mean+tf.add_n(tf.get_collection('losses'))
    #指数学习率
    learning_rate=tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,mnist.train.num_examples/BATCH_SIZE,LEARNING_RATE_DECAY)
    #训练方法 随机梯度下降法
    # 优化损失函数
    # global_step初始值为0,在loss更新后会+1,用来记录更新的次数
    # 返回值是训练之后的梯度,会随着global_step递增
    train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
    # 反向传播更新参数之后需要更新每一个参数的滑动平均值,用下面的代码可以一次完成这两个操作
    with tf.control_dependencies([train_step,variable_averages_op]):
        train_op=tf.no_op(name="train")

    saver=tf.train.Saver()
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINGING_STEPS):
            xs,ys=mnist.train.next_batch(BATCH_SIZE)
            #喂入数据
            reshaped_xs=np.reshape(xs,(BATCH_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS))
            _,loss_value,step=sess.run([train_op,loss,global_step],feed_dict={x:reshaped_xs,y_:ys})
            #打印结果
            if i %100 ==0:
                print("After %d training step(s),loss on training batch is %g." % (step,loss_value))
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step=global_step)

def main(argv=None):
    mnist=input_data.read_data_sets("",one_hot=True)
    train(mnist)

if __name__ == '__main__':
        tf.app.run()

4 测试模块

加载训练完成的模型完成测试数据的计算,包含测试数据输入输出的格式定义,正确率的定义,模型加载、模型保存、测试结果打印。

#模块加载
import time
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_inference
import mnist_train

# 加载的时间间隔。
EVAL_INTERVAL_SECS = 10

#定义测试函数
def evaluate(mnist):
    with tf.Graph().as_default() as g:
        #输入数据和标签数据占位
        x = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
        y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')
        validate_feed = {x: mnist.validation.images, y_: mnist.validation.labels}
         #计算神经网络输出
        y = mnist_inference.inference(x, None)
        #计算准确率
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
         #通过重命名的方式加载模型,不需要在前向传播中调用滑动平均获取平均值
        variable_averages = tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DECAY)
        variables_to_restore = variable_averages.variables_to_restore()        
         saver = tf.train.Saver(variables_to_restore)

        while True:
            with tf.Session() as sess:
                #寻找最新模型的文件名,
                ckpt = tf.train.get_checkpoint_state(mnist_train.MODEL_SAVE_PATH)
                if ckpt and ckpt.model_checkpoint_path:
                    #加载模型
                    saver.restore(sess, ckpt.model_checkpoint_path)
                    #通过文件名获取加载时的迭代轮数
                    global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                    accuracy_score = sess.run(accuracy, feed_dict=validate_feed)
                    print("After %s training step(s), validation accuracy = %g" % (global_step, accuracy_score))
                else:
                    print('No checkpoint file found')
                    return
            time.sleep(EVAL_INTERVAL_SECS)

def main(argv=None):
    mnist = input_data.read_data_sets("../../../datasets/MNIST_data", one_hot=True)
    evaluate(mnist)

if __name__ == '__main__':
    main()

5 工程应用

如果训练的模型测试精度满足要求,则可将此模型用于实际的应用中。