深度学习笔记(二):基于tensorflow gpu版本的深度神经网络程序总览

在第一篇笔记深度学习笔记(一):基于numpy的深度神经网络程序总览之后,又用tensorflow的gpu版本实现了一遍,果然封装很好,写起来很舒服,速度也快很多,100次epoch分分钟就结束了,效果和第一篇笔记中基于numpy的效果差不多,以下是代码,比基于numpy的代码少了一多半,后续笔记就开始记录程序结构和算法步骤了,有时间就更新。

源代码和数据:点击打开链接

# -*- coding: utf-8 -*-
"""
Created on Sat Sep 30 18:45:47 2017

@author: 董玮
"""

import argparse
import time
import numpy as np
import matplotlib.pyplot as plt

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
from tensorflow.python.framework import ops

"""
类型:抽象类
说明:规则化数据接口,一般用于数据预处理中。
"""
class interface_normalize_data(object):
    
    """
    类型:公有成员变量
    说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
    """
    epsilon = 1e-8
    
    """
    类型:抽象公有成员函数
    说明:用来规则化数据。
    参数:
        data -- 待处理的数据。
    返回值:
        data -- 处理后的数据。
    """
    def normalize_data(self, data):
        
        pass

"""
类型:实体类,继承自抽象类interface_normalize_data
说明:用于中心化数据,使数据中心在坐标原点上。
"""
class mean_normalization(interface_normalize_data):           
        
    def normalize_data(self, data):
        #计算数据每个维度的期望,并用每一条数据减去期望。
        center = data - tf.reduce_mean(data, axis = 0, keep_dims = True)
        return center

"""
类型:实体类,继承自抽象类interface_normalize_data
说明:用于中心化数据,并除以方差,使数据中心在坐标原点上,并且使每个维度之间的跨度相似。
"""  
class variance_normalization(interface_normalize_data):
    
    def normalize_data(self, data):
        center = data - tf.reduce_mean(data, axis = 0, keep_dims = True)
        #计算数据每个维度的方差。
        variance = tf.reduce_mean(tf.square(center), axis = 0, keep_dims = True)
        #除以方差并在除数上加上无穷小精度。
        vscore = center / (variance + self.epsilon)
        return vscore

"""
类型:实体类,继承自抽象类interface_normalize_data
说明:用于Z-Score统计,与上述实体类的区别是除以标准差而不是方差。
"""     
class zscore_normalization(interface_normalize_data):
    
    def normalize_data(self, data):
        center = data - tf.reduce_mean(data, axis = 0, keep_dims = True)
        variance = tf.reduce_mean(tf.square(center), axis = 0, keep_dims = True)
        #除以标准差并在除数上加上无穷小精度。
        zscore = center / tf.sqrt(variance + self.epsilon)
        return zscore
    
"""   
类型:抽象类
说明:神经网络初始化参数接口。
"""
class interface_initialize_parameters(object):
    
    """
    类型:公有成员变量
    说明:定义输入层、隐藏层、输出层每层的神经元个数。
    """
    structure = None
    
    """
    类型:公有成员变量
    说明:定义规则化功能。
    """
    regularizer = None
    
    """
    类型:公有成员变量
    说明:随机种子,用来产生随机数。
    """
    seed = 1
    
    """
    类型:抽象公有成员函数
    说明:用来初始化参数。
    """
    def initialize_parameters(self):
        
        pass

"""
类型:实体类
说明:标准的x-avier参数初始化,继承自抽象类interface_initialize_parameters
"""
class xavier_initialize_parameters(interface_initialize_parameters):
    
    """
    类型:公有成员函数
    说明:用来初始化参数。
    参数:无
    返回值:
        parameters -- 返回初始化后的参数。
    """
    def initialize_parameters(self):
        
        tf.set_random_seed(self.seed)
        parameters = {}
        
        #初始化两类参数,一种是W1、W2、W3……,另一种是b1、b2、b3……。其中数字代表层数。
        #W的维度为(当前层神经元数,前一层神经元数)。b的维度为(当前层神经元数,1)。
        for l in range(1, len(self.structure)):
            parameters["W" + str(l)] = tf.get_variable("W" + str(l), [self.structure[l-1], self.structure[l]], 
                      initializer = tf.contrib.layers.xavier_initializer(self.seed), regularizer = self.regularizer)
            
            parameters["b" + str(l)] = tf.get_variable("b" + str(l), [1, self.structure[l]], 
                      initializer = tf.zeros_initializer())
            
        return parameters

"""
类型:实体类
说明:具有batch normalization功能的x-avier参数初始化,继承自抽象类interface_initialize_parameters
"""    
class xavier_initialize_parameters_BN(interface_initialize_parameters):
    
    """
    类型:公有成员函数
    说明:用来初始化参数。
    参数:无
    返回值:
        parameters -- 返回初始化后的参数。
    """
    def initialize_parameters(self):
        
        tf.set_random_seed(self.seed)
        parameters = {}
        
        #因batch normalization需要,初始化三类参数,W1、W2、W3……,gamma1、gamma2、gamma3……,beta1、beta2、beta3……。其中数字代表层数。
        #W的维度为(当前层神经元数,前一层神经元数)。gamma与beta的维度均为(当前层神经元数,1)。
        for l in range(1, len(self.structure)):
            parameters["W" + str(l)] = tf.get_variable("W" + str(l), [self.structure[l-1], self.structure[l]], 
                      initializer = tf.contrib.layers.xavier_initializer(self.seed), regularizer = self.regularizer)
            parameters["gamma" + str(l)] = tf.get_variable("gamma" + str(l), [1, self.structure[l]], 
                      initializer = tf.ones_initializer())
            parameters["beta" + str(l)] = tf.get_variable("beta" + str(l), [1, self.structure[l]], 
                      initializer = tf.zeros_initializer())
            
        return parameters

"""
类型:抽象类
说明:定义向前向后算法。
"""
class interface_propagation(object):
    
    """
    类型:公有成员变量
    说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
    """
    epsilon = 1e-8
    
    """
    类型:公有成员变量
    说明:是否进行dropout规则化操作。
    """
    is_dropout = False
    
    """
    类型:公有成员变量
    说明:如果is_dropout为真,那么此变量存储每一层保持神经元个数的概率。
    """
    keep_prob = 1.
    
    """
    类型:公有成员变量
    说明:定义激活函数。
    """
    act_func = None

    """
    类型:抽象公有函数
    说明:向前算法。
    参数:
        training_set -- 训练集。
        training_label -- 训练标签。
        parameters -- 训练参数。
    """
    def forward_propagation(self, training_set, training_label, parameters):
        
        pass

"""
类型:具体类
说明:标准的向前算法,继承自interface_propagation。
"""  
class propagation_standard(interface_propagation):

    def forward_propagation(self, training_set, training_label, parameters):
        
        if(len(parameters) < 2):
            return None
        
        #向前算法
        A = training_set
        
        layer_number = len(parameters) // 2
        for l in range(1, layer_number):
            Z = tf.matmul(A, parameters["W"+str(l)]) + parameters["b" + str(l)]
            #激活函数
            A = self.act_func(Z)
            
            #添加dropout正则化功能
            if(self.is_dropout == True):
                A = tf.nn.dropout(A, self.keep_prob)
    
        Z = tf.matmul(A, parameters["W"+str(layer_number)]) + parameters["b" + str(layer_number)]
        
        #计算代价函数
        cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = training_label, logits = Z)) + tf.reduce_sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))
        
        return cross_entropy, Z

"""
类型:具体类
说明:带有Batch normalization的向前算法,继承自interface_propagation。
"""     
class propagation_BN(interface_propagation):
    
    def forward_propagation(self, training_set, training_label, parameters):
        
        if(len(parameters) < 2):
            return None
        
        #向前算法
        A = training_set
        
        #注意,因为Batch normalization有三个学习参数,这里要除以3取整。
        layer_number = len(parameters) // 3
        for l in range(1, layer_number):
            Z = tf.matmul(A, parameters["W"+str(l)])
            #向前算法中的Batch normalization步骤。
            Zmean = tf.reduce_mean(Z, axis = 0, keep_dims = True)
            Zcenter = Z - Zmean
            Zvariance = tf.reduce_mean(tf.square(Zcenter), axis = 0, keep_dims = True)
            Ztilde = Zcenter / tf.sqrt(Zvariance + self.epsilon)
            Z = tf.multiply(Ztilde, parameters["gamma" + str(l)]) + parameters["beta" + str(l)]
            
            #激活函数
            A = self.act_func(Z)
            if(self.is_dropout == True):
                A = tf.nn.dropout(A, self.keep_prob)
        
        #向前算法中输出层的Batch normalization步骤。
        Z = tf.matmul(A, parameters["W"+str(layer_number)])
        Zmean = tf.reduce_mean(Z, axis = 0, keep_dims = True)
        Zcenter = Z - Zmean
        Zvariance = tf.reduce_mean(tf.square(Zcenter), axis = 0, keep_dims = True)
        Ztilde = Zcenter / tf.sqrt(Zvariance + self.epsilon)
        Z = tf.multiply(Ztilde, parameters["gamma" + str(layer_number)]) + parameters["beta" + str(layer_number)]
        
        #计算代价函数
        cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = training_label, logits = Z)) + tf.reduce_sum(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))
        
        return cross_entropy, Z

"""
类型:抽象类
说明:定义一个工厂类,用来生产学习模型过程中所需要的模块。
"""
class interface_factory(object):
    
    """
    类型:公有成员变量
    说明:数据预处理规则化模块。
    """
    normalizer = None
    
    """
    类型:公有成员变量
    说明:学习参数初始化模块。
    """
    initializer = None
    
    """
    类型:公有成员变量
    说明:向前学习算法模块。
    """
    propagator = None
    
    """
    类型:公有成员变量
    说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
    """
    epsilon = 1e-8
    
    """
    类型:公有成员变量
    说明:定义优化算法的学习率。
    """
    learning_rate = 1e-3
    
    """
    类型:公有成员变量
    说明:Batch normalization超参数。
    """
    beta1 = 0.9
    
    """
    类型:公有成员变量
    说明:Batch normalization超参数。
    """
    beta2 = 0.999
    
    """
    类型:公有成员变量
    说明:数据批量优化算法说需要的batch大小,即每次训练从训练集里抽样的个数。
    """
    minibatch_size = 512
    
    """
    类型:公有成员变量
    说明:epoch个数,即需要训练整个数据集多少遍。
    """
    num_epochs = 100
    
    """
    类型:公有成员变量
    说明:定义每几步衰减一次。
    """
    epoch_step = 5
    
    """
    类型:公有成员变量
    说明:衰退比率。
    """
    k = 0.09
    
    """
    类型:抽象公有成员函数
    说明:创建一个工厂,该工厂生产训练和测试数据过程中所需要的模块。
    """
    def create_workpiece(self, *arguments):
        
        pass
"""
类型:具体类
说明:工厂版本v1,不带Batch normalization功能,激活函数为relu,最后一层激活函数为softmax,代价函数用的是交叉熵损失函数,优化算法为adam,学习率为指数衰减。
"""
class factory_v1(interface_factory):
    
    """
    类型:公有成员函数
    说明:创建一个工厂,该工厂生产训练和测试数据过程中所需要的模块。
    参数:
        arguments[0] -- 数值计算精度 - epsilon
        arguments[1] -- 网络结构 - structure
        arguments[2] -- 随机种子 - seed
        arguments[3] -- 学习率 - learning_rate
        arguments[4] -- adam参数 - beta1
        arguments[5] -- adam参数 - beta2
        arguments[6] -- batch的大小 - minibatch_size
        arguments[7] -- epoch个数 - num_epochs
        arguments[8] -- 衰减步数 - epoch_step
        arguments[9] -- 衰减率 - k
    """
    def create_workpiece(self, *arguments):
        
        self.epsilon = arguments[0]
        
        self.normalizer = zscore_normalization()
        self.normalizer.epsilon = self.epsilon
        
        structure = arguments[1]
        seed = arguments[2]
        
        self.initializer = xavier_initialize_parameters()
        self.initializer.structure = structure
        self.initializer.seed = seed
        
        self.propagator = propagation_standard()
        self.propagator.epsilon = self.epsilon
        self.propagator.act_func = tf.nn.relu
        
        self.learning_rate = arguments[3]
        self.beta1 = arguments[4]
        self.beta2 = arguments[5]
        
        self.minibatch_size = arguments[6]
        self.num_epochs = arguments[7]
        
        self.epoch_step = arguments[8]
        self.k = arguments[9]
        
        return self
"""
类型:具体类
说明:工厂版本v3,带Batch normalization功能,带dropout规则化,激活函数为relu,最后一层激活函数为softmax,代价函数用的是交叉熵损失函数,优化算法为adam,学习率为指数衰减。
"""     
class factory_v2(interface_factory):
    
    """
    类型:公有成员函数
    说明:创建一个工厂,该工厂生产训练和测试数据过程中所需要的模块。
    参数:
        arguments[0] -- 数值计算精度 - epsilon
        arguments[1] -- 网络结构 - structure
        arguments[2] -- 随机种子 - seed
        arguments[3] -- 学习率 - learning_rate
        arguments[4] -- adam参数 - beta1
        arguments[5] -- adam参数 - beta2
        arguments[6] -- batch的大小 - minibatch_size
        arguments[7] -- epoch个数 - num_epochs
        arguments[8] -- 衰减步数 - epoch_step
        arguments[9] -- 衰减率 - k
        arguments[10] -- 是否进行dropout步骤 - is_dropout
        arguments[11] -- dropout保持概率 - keep_prob
    """
    def create_workpiece(self, *arguments):
        
        self.epsilon = arguments[0]
        #tf_epsilon = tf.Variable(epsilon)
        
        self.normalizer = zscore_normalization()
        self.normalizer.epsilon = self.epsilon
        
        structure = arguments[1]
        seed = arguments[2]
        
        self.initializer = xavier_initialize_parameters_BN()
        self.initializer.structure = structure
        self.initializer.seed = seed
        
        self.propagator = propagation_BN()
        self.propagator.epsilon = self.epsilon
        self.propagator.act_func = tf.nn.relu
        
        self.learning_rate = arguments[3]
        self.beta1 = arguments[4]
        self.beta2 = arguments[5]
        
        self.minibatch_size = arguments[6]
        self.num_epochs = arguments[7]
        
        self.epoch_step = arguments[8]
        self.k = arguments[9]
        
        is_dropout = arguments[10]
        keep_prob = arguments[11]
        
        self.propagator.is_dropout = is_dropout
        self.propagator.keep_prob = keep_prob
        
        return self

"""
类型:抽象类
说明:定义一个工厂类,用来生产学习模型过程中所需要的模块。
"""   
class interface_train_model(object):
    
    """
    类型:公有成员变量
    说明:学习参数。
    """
    parameters = None
    
    """
    类型:公有成员变量
    说明:训练集。
    """
    training_set = None
    
    """
    类型:公有成员变量
    说明:训练标签。
    """
    training_label = None
    
    """
    类型:公有成员变量
    说明:验证集。
    """
    validation_set = None
    
    """
    类型:公有成员变量
    说明:验证标签。
    """
    validation_label = None
    
    """
    类型:公有成员变量
    说明:测试集。
    """
    test_set = None
    
    """
    类型:公有成员变量
    说明:测试标签。
    """
    test_label = None
    
    """
    类型:公有成员变量
    说明:工厂对象。
    """
    factory = None
    
    """
    类型:抽象公有成员函数
    说明:训练模型方法。
    """
    def training_model(self, *arguments):
        
        pass

"""
类型:具体类
说明:定义深度神经网络。
"""
class deep_neural_networks(interface_train_model):

    """
    类型:初始化函数
    说明:初始化工厂对象。
    """
    def __init__(self, factory):
        self.factory = factory
    
    def training_model(self, *arguments):
        
        #重置图计算步骤,恢复默认状态。
        ops.reset_default_graph()
        
        #定义占位符,用来输入数据
        X = tf.placeholder(tf.float32, shape=(None, self.training_set.shape[1]))
        Y = tf.placeholder(tf.float32, shape=(None, self.training_label.shape[1]))
        
        #定义深度神经网络结构
        self.factory.initializer.structure = np.append(np.array([self.training_set.shape[1]]), self.factory.initializer.structure)
        num_minibatches = int(self.training_set.shape[0] / self.factory.minibatch_size) + 1
        
        #定义数据预处理步骤
        if(self.factory.normalizer != None):
            normalize_result = self.factory.normalizer.normalize_data(X)
        
        #定义学习参数及超参数初始化步骤
        self.parameters = self.factory.initializer.initialize_parameters()
        seed = self.factory.initializer.seed
        
        #定义向前算法步骤
        cross_entropy, ZL = self.factory.propagator.forward_propagation(X, Y, self.parameters)
        
        global_step = tf.Variable(0, trainable = False)
        
        #定义学习率衰减
        learning_rate_target = tf.train.natural_exp_decay(self.factory.learning_rate, global_step, self.factory.epoch_step * self.training_set.shape[0], self.factory.k, staircase=True)
        
        #定义优化算法
        optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate_target, beta1 = self.factory.beta1, beta2 = self.factory.beta2, epsilon = self.factory.epsilon).minimize(cross_entropy, global_step = global_step)

        #定义计算精度
        correct_prediction = tf.equal(tf.argmax(ZL, 1), tf.argmax(Y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
        
        costs = []
        training_accuracies = []
        validation_accuracies = []
        
        #在验证集上表现最好的学习参数
        best_parameters = {}
        #最好学习参数时,训练集的精度
        best_training_acc = 0.
        #最好学习参数时,验证集的精度
        best_validation_acc = 0.
            
        init = tf.global_variables_initializer()
        
        #执行计算图
        with tf.Session() as sess:
            
            start = time.clock()
            sess.run(init)
            
            #数据在计算图中的预处理步骤
            if(self.factory.normalizer != None):
                self.training_set = sess.run(normalize_result, feed_dict={X: self.training_set})
                self.validation_set = sess.run(normalize_result, feed_dict={X: self.validation_set})
            
            #epoch学习过程
            for iter_epoch in range(1, self.factory.num_epochs + 1):
                cost = 0
                
                #minibatch学习过程
                for iter_batch in range(1, num_minibatches + 1):
                    seed += 1
                    (minibatch_X, minibatch_Y) = self.__random_mini_batches(self.factory.minibatch_size, seed)
                    _ , minibatch_cost = sess.run([optimizer, cross_entropy], feed_dict={X: minibatch_X, Y: minibatch_Y})
                    cost += minibatch_cost
                
                cost /= num_minibatches
                costs.append(cost)
                training_acc = accuracy.eval(feed_dict={X: self.training_set, Y: self.training_label})
                training_accuracies.append(training_acc)
                validation_acc = accuracy.eval(feed_dict={X: self.validation_set, Y: self.validation_label})
                validation_accuracies.append(validation_acc)
                
                if(validation_acc > best_validation_acc):
                    best_training_acc = training_acc
                    best_validation_acc = validation_acc
                    best_parameters = sess.run(self.parameters)
                
                print ("Cost after epoch %i: %f" % (iter_epoch, cost))
                print ("Training accuracy after epoch %i: %f" % (iter_epoch, training_acc))
                print ("Validation accuracy after epoch %i: %f" % (iter_epoch, validation_acc))
                
            end = time.clock()
            
            self.factory.initializer.seed = seed
            self.parameters = best_parameters
                
            plt.plot(np.squeeze(costs))
            plt.ylabel('cost')
            plt.xlabel('epochs')
            plt.title("Learning rate of Start step =" + str(self.factory.learning_rate))
            plt.show()
            
            plt.plot(np.squeeze(training_accuracies))
            plt.ylabel('training accracy')
            plt.xlabel('epochs')
            plt.title("Learning rate of Start step =" + str(self.factory.learning_rate))
            plt.show()
            
            plt.plot(np.squeeze(validation_accuracies))
            plt.ylabel('validation accracy')
            plt.xlabel('epochs')
            plt.title("Learning rate of Start step =" + str(self.factory.learning_rate))
            plt.show()
            
            print ("Accuracy of total Training set: %f%%" % (best_training_acc * 100))
            print ("Accuracy of total Validation set: %f%%" % (best_validation_acc * 100))
            print ("Training of total Time: %f Minutes" % ((end - start) / 60))
    

    """
    从训练数据集和标签集中随机抽取minibatch。
    参数:
        X_train -- 训练数据集。
        Y_train -- 训练标签集。
        minibatch_size -- minibatch尺寸。
        seed -- 随机种子。
    返回值:
        元组 -- 返回一个minibatch,包括训练数据和对应的标签数据。
    """
    def __random_mini_batches(self, minibatch_size, seed):
        
        np.random.seed(seed)
        shuffle_array = np.random.randint(0, self.training_set.shape[0], minibatch_size)
        return (self.training_set[shuffle_array, :], self.training_label[shuffle_array, :])   

def main():
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--data_dir', type=str, default='/tmp/tensorflow/mnist/input_data',
                        help='Directory for storing input data')
    FLAGS, unparsed = parser.parse_known_args()
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
    
    struct = [512, 256, 128, 64, 32, 16, 10]
    factory = factory_v2()
    factory.create_workpiece(1e-8, struct, 1, 1e-3, 0.9, 0.999, 512, 100, 5, 0.009, False, 0.8)
    
    dnn = deep_neural_networks(factory)
    dnn.training_set = mnist.train.images
    dnn.training_label = mnist.train.labels
    dnn.validation_set = mnist.test.images
    dnn.validation_label = mnist.test.labels
    dnn.training_model()

main()

运行结果:
深度学习笔记(二):基于tensorflow gpu版本的深度神经网络程序总览_第1张图片


你可能感兴趣的:(机器学习,深度学习,Andrew,Ng,deeplearning.ai,python,深度学习,神经网络)