在第一篇笔记深度学习笔记(一):基于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()