在看完了Andrew Ng教授的deeplearning.ai课程和李飞飞教授的cs231n课程后,总觉得应该写点笔记将学习过程记录下来,但内容不少,需要时间慢慢整理,故先将学习成果记录下来,是一段深度神经网络的程序,基于python科学计算库numpy的。还有一段代码是基于tensorflow的,在 深度学习笔记(二):基于tensorflow gpu版本的深度神经网络程序总览 中有代码。虽然tensorflow很是方便,但是总觉得封装太好,只看代码根本学习不到什么,用numpy写一遍深度神经网络后,掌握知识的程度感觉好很多。废话不多说,先贴出代码来,代码中有注释,数据集用的是经典的数字手写体识别库mnist,后续笔记会对应具体公式和算法详细记录。
源代码及数据下载链接:点击打开链接
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 26 16:03:41 2017
@author: 董玮
"""
import argparse
import time
import copy
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
"""
类型:抽象类
说明:规则化数据接口,一般用于数据预处理中。
"""
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):
#计算数据每个维度的期望,并用每一条数据减去期望。
data = data - np.mean(data, axis = 1, keepdims = True)
return data
"""
类型:实体类,继承自抽象类interface_normalize_data
说明:用于中心化数据,并除以方差,使数据中心在坐标原点上,并且使每个维度之间的跨度相似。
"""
class variance_normalization(interface_normalize_data):
def normalize_data(self, data):
data = data - np.mean(data, axis = 1, keepdims = True)
#计算数据每个维度的方差。
variance = np.mean(np.square(data), axis = 1, keepdims = True)
#除以方差并在除数上加上无穷小精度。
data = data / (variance + self.epsilon)
return data
"""
类型:实体类,继承自抽象类interface_normalize_data
说明:用于Z-Score统计,与上述实体类的区别是除以标准差而不是方差。
"""
class zscore_normalization(interface_normalize_data):
def normalize_data(self, data):
data = data - np.mean(data, axis = 1, keepdims = True)
variance = np.mean(np.square(data), axis = 1, keepdims = True)
#除以标准差并在除数上加上无穷小精度。
data = data / np.sqrt(variance + self.epsilon)
return data
"""
类型:抽象类
说明:神经网络初始化参数接口。
"""
class interface_initialize_parameters(object):
"""
类型:公有成员变量
说明:用来定义输入层、隐藏层、输出层每层的神经元个数。
"""
structure = 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):
np.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)] = np.random.randn(self.structure[l], self.structure[l-1]) / np.sqrt(self.structure[l-1]/2)
parameters["b" + str(l)] = np.zeros((self.structure[l], 1))
return parameters
"""
类型:实体类
说明:具有batch normalization功能的x-avier参数初始化,继承自抽象类interface_initialize_parameters
"""
class xavier_initialize_parameters_BN(interface_initialize_parameters):
"""
类型:公有成员函数
说明:用来初始化参数。
参数:无
返回值:
parameters -- 返回初始化后的参数。
"""
def initialize_parameters(self):
np.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)] = np.random.randn(self.structure[l], self.structure[l-1]) / np.sqrt(self.structure[l-1]/2)
parameters["gamma" + str(l)] = np.ones((self.structure[l], 1))
#parameters["gamma" + str(l)] = np.random.randn(self.structure[l], 1) / np.sqrt(self.structure[l]/2)
parameters["beta" + str(l)] = np.zeros((self.structure[l], 1))
return parameters
"""
类型:抽象类
说明:计算激活函数的值和激活函数的梯度值
"""
class interface_activation(object):
"""
类型:公有成员变量
说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
"""
epsilon = 1e-8
"""
类型:抽象公有成员函数
说明:计算激活函数的值。
"""
def activate_function(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算激活函数的梯度值。
"""
def derivation_activate_function(self, *arguments):
pass
"""
类型:抽象类
说明:计算代价函数的值和代价函数的梯度值
"""
class interface_cost(object):
"""
类型:公有成员变量
说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
"""
epsilon = 1e-8
"""
类型:抽象公有成员函数
说明:计算代价函数并返回代价值。
"""
def cost_function(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算代价函数的梯度并返回梯度值。
"""
def derivation_cost_function(self, *arguments):
pass
"""
类型:具体类
说明:relu激活函数,继承自interface_activation。
"""
class relu(interface_activation):
"""
类型:公有成员函数
说明:计算relu函数的值。
参数:
Z -- 每一层(不包括最后一层)的线性值。
返回值:
A -- 激活值。
"""
def activate_function(self, *arguments):
Z = arguments[0]
A = np.maximum(Z, 0)
return A
"""
类型:公有成员函数
说明:计算relu函数的梯度值。
参数:
dA -- 每一层(不包括最后一层)激活值的梯度值。
返回值:
A -- 线性值的梯度值。
"""
def derivation_activate_function(self, *arguments):
dA = arguments[0]
A = arguments[1]
dZ = dA * np.where(A > 0, 1, 0)
return dZ
"""
类型:具体类
说明:softmax代价函数,继承自interface_activation。
"""
class softmax(interface_cost):
"""
类型:公有成员函数
说明:计算softmax代价函数的代价值与输出层(最后一层)的激活值。
参数:
ZL -- 输出层(最后一层)的线性值。
Y -- 数据标签。
loss -- 如果需要L1或L2正则化,则此参数计算了正则化的代价值。
返回值:
cost -- 代价值。
AL -- 输出层(最后一层)的激活值。
"""
def cost_function(self, *arguments):
ZL = arguments[0]
Y = arguments[1]
loss = arguments[2]
AL = np.exp(ZL) / (np.sum(np.exp(ZL), axis=0, keepdims=True) + self.epsilon)
cost = -np.sum(Y * np.log(AL + self.epsilon)) / Y.shape[1] + loss
return cost, AL
"""
类型:公有成员函数
说明:计算softmax代价函数的梯度值与输出层(最后一层)的线性梯度值。
参数:
AL -- 输出层(最后一层)的激活值。
Y -- 数据标签。
返回值:
dZL -- 输出层(最后一层)的线性值的梯度值。
"""
def derivation_cost_function(self, *arguments):
AL = arguments[0]
Y = arguments[1]
dZL = (AL - Y) / Y.shape[1]
return dZL
"""
类型:抽象类
说明:定义神经网络训练过程中所需要的规则化功能。
"""
class interface_regularization(object):
"""
类型:公有成员变量
说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
"""
epsilon = 1e-8
"""
类型:抽象公有成员函数
说明:向前算法中所需要的规则化动作。
"""
def forward_regularization(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算代价函数中所需要的规则化动作。
"""
def cost_regularization(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:向后算法中所需要的规则化动作。
"""
def backward_regularization(self, *arguments):
pass
"""
类型:具体类
说明:batch normalization功能,继承自interface_regularization
"""
class batch_normlizer(interface_regularization):
"""
类型:公有成员函数
说明:batch normalization功能的向前算法。
参数:
Z -- 每一层的线性值。
返回值:
Zcenter -- Z的中心化计算,使期望位于坐标的原点。
Zvariance -- Z的方差。
Ztilde -- Z-score标准化后的Z数值。
"""
def forward_regularization(self, *arguments):
Z = arguments[0]
Zmean = np.mean(Z, axis = 1, keepdims = True)
Zcenter = Z - Zmean
Zvariance = np.mean(np.square(Zcenter), axis = 1, keepdims = True)
Ztilde = Zcenter / np.sqrt(Zvariance + self.epsilon)
return Zcenter, Zvariance, Ztilde
"""
类型:公有成员函数
说明:batch normalization不需要此步骤,设置为空函数。
"""
def cost_regularization(self, *arguments):
pass
"""
类型:公有成员函数
说明:batch normalization功能的向后算法。
参数:
dZnorm -- 每一层batch normalization线性值的梯度值。
gamma -- batch normalization的参数。
Zcenter -- Z的中心化计算,使期望位于坐标的原点。
Zvariance -- Z的方差。
返回值:
dZ -- 每一层线性值的梯度值。
"""
def backward_regularization(self, *arguments):
dZnorm = arguments[0]
gamma = arguments[1]
Zcenter = arguments[2]
Zvariance = arguments[3]
dZtilde = np.multiply(dZnorm, gamma)
dZvariance = np.sum(np.multiply(np.multiply(dZtilde, Zcenter), np.power(Zvariance+self.epsilon, -3/2)/-2), axis=1, keepdims=True)
dZmean = np.sum(np.multiply(dZtilde, -1/np.sqrt(Zvariance + self.epsilon)), axis=1, keepdims=True)
dZ = np.multiply(dZtilde, 1/np.sqrt(Zvariance + self.epsilon)) + np.multiply(dZvariance, 2*Zcenter/Zcenter.shape[1])
+ np.multiply(dZmean, 1/Zcenter.shape[1])
return dZ
"""
类型:具体类
说明:dropout功能,继承自interface_regularization
"""
class dropout(interface_regularization):
"""
类型:公有成员变量
说明:以概率keep_prob随机删除当前层的神经元节点。
"""
keep_prob = 1.
"""
类型:公有成员函数
说明:dropout向前算法,以概率keep_prob随机删除当前层的神经元节点。
参数:
A -- 当前层的激活值
返回值:
D -- 掩码矩阵。
A -- 随机删除神经元节点后的激活值。
"""
def forward_regularization(self, *arguments):
A = arguments[0]
D = np.random.rand(A.shape[0], A.shape[1])
D = (D < self.keep_prob)
A = np.multiply(A, D)
A = A / self.keep_prob
return D, A
"""
类型:公有成员函数
说明:dropout不需要此步骤,设置为空函数。
"""
def cost_regularization(self, *arguments):
pass
"""
类型:公有成员函数
说明:dropout向后算法,和向前算法相同,删除向前算法中对应的已删除神经元节点。
参数:
dA -- 当前层神经元的激活值的梯度值。
D -- 掩码矩阵。
返回值:
dA -- 随机删除神经元节点后的激活值的梯度。
"""
def backward_regularization(self, *arguments):
dA = arguments[0]
D = arguments[1]
dA = np.multiply(dA, D)
dA = dA / self.keep_prob
return dA
"""
类型:具体类
说明:L2正则化功能,继承自interface_regularization
"""
class L2(interface_regularization):
"""
类型:公有成员变量
说明:设置参数lambda,决定权值规则化在代价函数中所占的比重。
"""
lambd = 0.
"""
类型:公有成员函数
说明:L2规则化不需要此步骤,设置为空函数。
"""
def forward_regularization(self, *arguments):
pass
"""
类型:公有成员函数
说明:在代价函数中计算L2规则化的权重。
参数:
parameters -- 学习参数。
layer_number -- 层数(包含输入层、隐藏层、输出层)。
m -- 数据的数量。
返回值:
loss -- 代价函数中L2正则化所占的比重。
"""
def cost_regularization(self, *arguments):
parameters = arguments[0]
layer_number = arguments[1]
m = arguments[2]
total = 0.
for l in range(1, layer_number+1):
total += np.sum(np.square(parameters["W"+str(l)]))
total /= 2 * m
return self.lambd * total
"""
类型:公有成员函数
说明:在向后算法中计算L2规则化的权重。
参数:
W -- 当前层的学习参数。
m -- 数据的数量。
返回值:
dloss -- 向后算法中L2规则化权重部分的梯度。
"""
def backward_regularization(self, *arguments):
W = arguments[0]
m = arguments[1]
return self.lambd * W / m
"""
类型:具体类
说明:L1正则化功能,继承自interface_regularization
"""
class L1(interface_regularization):
"""
类型:公有成员变量
说明:设置参数lambda,决定权值规则化在代价函数中所占的比重。
"""
lambd = 0.
"""
类型:公有成员函数
说明:L1规则化不需要此步骤,设置为空函数。
"""
def forward_regularization(self, *arguments):
pass
"""
类型:公有成员函数
说明:在代价函数中计算L1规则化的权重。
参数:
parameters -- 学习参数。
layer_number -- 层数(包含输入层、隐藏层、输出层)。
m -- 数据的数量。
返回值:
loss -- 代价函数中L1正则化所占的比重。
"""
def cost_regularization(self, *arguments):
parameters = arguments[0]
layer_number = arguments[1]
m = arguments[2]
total = 0.
for l in range(1, layer_number+1):
total += np.sum(np.abs(parameters["W"+str(l)]))
total /= m
return self.lambd * total
"""
类型:公有成员函数
说明:在向后算法中计算L1规则化的权重。
参数:
W -- 当前层的学习参数。
m -- 数据的数量。
返回值:
dloss -- 向后算法中L1规则化权重部分的梯度。
"""
def backward_regularization(self, *arguments):
W = arguments[0]
m = arguments[1]
#此处求梯度利用绝对值求导。
return self.lambd * np.sign(W) / m
"""
类型:抽象类
说明:定义向前向后算法。
"""
class interface_propagation(object):
"""
类型:公有成员变量
说明:定义一个空字典,用来存储规则化功能,可以存储多个规则化器regularizer。
"""
regularizer = {}
"""
类型:公有成员变量
说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
"""
epsilon = 1e-8
"""
类型:公有成员变量
说明:定义一个空字典,用来存储激活函数;激活函数的梯度函数;代价函数;代价函数的梯度函数。
"""
functor = {}
"""
类型:保护成员变量
说明:定义一个空字典,用来记录在向前算法中产生的中间结果。
"""
_intermediate_caches = {}
"""
类型:抽象公有函数
说明:向前算法。
参数:
training_set -- 训练集。
training_label -- 训练标签。
parameters -- 训练参数。
"""
def forward_propagation(self, training_set, training_label, parameters):
pass
"""
类型:抽象公有函数
说明:向后算法。
参数:
training_set -- 训练集。
training_label -- 训练标签。
parameters -- 训练参数。
"""
def backward_propagation(self, training_set, training_label, parameters):
pass
"""
类型:具体类
说明:标准的向前向后算法,继承自interface_propagation。
"""
class propagation_standard(interface_propagation):
def forward_propagation(self, training_set, training_label, parameters):
caches = self._intermediate_caches
cost = None
if(len(parameters) < 2):
return cost, caches
#向前算法
caches["A0"] = training_set
Z = 0.
layer_number = len(parameters) // 2
for l in range(1, layer_number):
Z = np.dot(parameters["W"+str(l)], caches["A"+str(l-1)]) + parameters["b" + str(l)]
#激活函数
caches["A"+str(l)] = self.functor["activation"].activate_function(Z)
#添加dropout正则化功能
if("dropout" in self.regularizer.keys()):
caches["D"+str(l)], caches["A"+str(l)] = self.regularizer["dropout"].forward_regularization(caches["A"+str(l)])
Z = np.dot(parameters["W"+str(layer_number)], caches["A"+str(layer_number-1)]) + parameters["b" + str(layer_number)]
#添加L1、L2正则化功能
loss = 0.
if("L2" in self.regularizer.keys()):
loss += self.regularizer["L2"].cost_regularization(parameters, layer_number, training_set.shape[1])
if("L1" in self.regularizer.keys()):
loss += self.regularizer["L1"].cost_regularization(parameters, layer_number, training_set.shape[1])
#计算代价函数
cost, caches["A"+str(layer_number)] = self.functor["cost"].cost_function(Z, training_label, loss)
return cost
def backward_propagation(self, training_set, training_label, parameters):
caches = self._intermediate_caches
grad_parameters = {}
#向后算法。
layer_number = len(parameters) // 2
#代价函数的梯度计算。
dZ = self.functor["cost"].derivation_cost_function(caches["A"+str(layer_number)], training_label)
for l in reversed(range(1, layer_number+1)):
grad_parameters["dW"+str(l)] = np.dot(dZ, caches["A"+str(l-1)].T)
#添加L1、L2正则化功能。
if("L2" in self.regularizer.keys()):
grad_parameters["dW"+str(l)] += self.regularizer["L2"].backward_regularization(parameters["W"+str(l)], training_set.shape[1])
if("L1" in self.regularizer.keys()):
grad_parameters["dW"+str(l)] += self.regularizer["L1"].backward_regularization(parameters["W"+str(l)], training_set.shape[1])
grad_parameters["db"+str(l)] = np.sum(dZ, axis=1, keepdims=True)
if(l > 1):
dA = np.dot(parameters["W"+str(l)].T, dZ)
#添加dropout正则化功能。
if("dropout" in self.regularizer.keys()):
dA = self.regularizer["dropout"].backward_regularization(dA, caches["D"+str(l-1)])
#激活函数的梯度计算。
dZ = self.functor["activation"].derivation_activate_function(dA, caches["A"+str(l-1)])
return grad_parameters
"""
类型:具体类
说明:带有Batch normalization的向前向后算法,继承自interface_propagation。
"""
class propagation_BN(interface_propagation):
def forward_propagation(self, training_set, training_label, parameters):
caches = self._intermediate_caches
cost = None
if(len(parameters) < 2):
return cost, caches
caches["A0"] = training_set
Z = 0.
#注意,因为Batch normalization有三个学习参数,这里要除以3取整。
layer_number = len(parameters) // 3
for l in range(1, layer_number):
Z = np.dot(parameters["W"+str(l)], caches["A"+str(l-1)])
#向前算法中的Batch normalization步骤。
caches["Zcenter"+str(l)], caches["Zvariance"+str(l)], caches["Ztilde"+str(l)] = self.regularizer["batch_normlizer"].forward_regularization(Z)
Z = np.multiply(parameters["gamma" + str(l)], caches["Ztilde"+str(l)]) + parameters["beta" + str(l)]
caches["A"+str(l)] = self.functor["activation"].activate_function(Z)
if("dropout" in self.regularizer.keys()):
caches["D"+str(l)], caches["A"+str(l)] = self.regularizer["dropout"].forward_regularization(caches["A"+str(l)])
Z = np.dot(parameters["W"+str(layer_number)], caches["A"+str(layer_number-1)])
caches["Zcenter"+str(layer_number)], caches["Zvariance"+str(layer_number)], caches["Ztilde"+str(layer_number)] = self
.regularizer["batch_normlizer"].forward_regularization(Z)
Z = np.multiply(parameters["gamma" + str(layer_number)], caches["Ztilde"+str(layer_number)]) + parameters["beta" + str(layer_number)]
loss = 0.
if("L2" in self.regularizer.keys()):
loss += self.regularizer["L2"].cost_regularization(parameters, layer_number, training_set.shape[1])
if("L1" in self.regularizer.keys()):
loss += self.regularizer["L1"].cost_regularization(parameters, layer_number, training_set.shape[1])
cost, caches["A"+str(layer_number)] = self.functor["cost"].cost_function(Z, training_label, loss)
return cost
def backward_propagation(self, training_set, training_label, parameters):
caches = self._intermediate_caches
grad_parameters = {}
#注意,因为Batch normalization有三个学习参数,这里要除以3取整。
layer_number = len(parameters) // 3
dZnorm = self.functor["cost"].derivation_cost_function(caches["A"+str(layer_number)], training_label)
for l in reversed(range(1, layer_number+1)):
grad_parameters["dgamma"+str(l)] = np.sum(np.multiply(dZnorm, caches["Ztilde"+str(l)]), axis=1, keepdims=True)
grad_parameters["dbeta"+str(l)] = np.sum(dZnorm, axis=1, keepdims=True)
#向前算法中的Batch normalization步骤。
dZ = self.regularizer["batch_normlizer"]
.backward_regularization(dZnorm, parameters["gamma" + str(l)], caches["Zcenter"+str(l)], caches["Zvariance"+str(l)])
grad_parameters["dW"+str(l)] = np.dot(dZ, caches["A"+str(l-1)].T)
if("L2" in self.regularizer.keys()):
grad_parameters["dW"+str(l)] += self.regularizer["L2"].backward_regularization(parameters["W"+str(l)], training_set.shape[1])
if("L1" in self.regularizer.keys()):
grad_parameters["dW"+str(l)] += self.regularizer["L1"].backward_regularization(parameters["W"+str(l)], training_set.shape[1])
if(l > 1):
dA = np.dot(parameters["W"+str(l)].T, dZ)
if("dropout" in self.regularizer.keys()):
dA = self.regularizer["dropout"].backward_regularization(dA, caches["D"+str(l-1)])
dZnorm = self.functor["activation"].derivation_activate_function(dA, caches["A"+str(l-1)])
return grad_parameters
"""
类型:抽象类
说明:定义优化算法。
"""
class interface_optimization(object):
"""
类型:公有成员变量
说明:规则化数据过程中,定义一个无穷小精度,用来防止数据计算中的非法操作。
"""
epsilon = 1e-8
"""
类型:公有成员变量
说明:定义优化算法的学习率。
"""
learning_rate = 1e-3
"""
类型:抽象公有成员函数
说明:定义优化算法的初始化工作。
"""
def initialization(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:定义优化算法的计算步骤。
"""
def optimization(self, *arguments):
pass
"""
类型:具体类
说明:标准的梯度下降算法。
"""
class gradient_descent_standard(interface_optimization):
def initialization(self, *arguments):
pass
def optimization(self, *arguments):
parameters = arguments[0]
grads = arguments[1]
L = len(parameters) // 2
for l in range(1, L+1):
parameters["W"+str(l)] = parameters["W"+str(l)] - self.learning_rate * grads["dW"+str(l)]
parameters["b"+str(l)] = parameters["b"+str(l)] - self.learning_rate * grads["db"+str(l)]
return parameters
"""
类型:具体类
说明:带有Batch normalization的梯度下降算法。
"""
class gradient_descent_BN(interface_optimization):
def initialization(self, *arguments):
pass
def optimization(self, *arguments):
parameters = arguments[0]
grads = arguments[1]
L = len(parameters) // 3
for l in range(1, L+1):
parameters["W"+str(l)] = parameters["W"+str(l)] - self.learning_rate * grads["dW"+str(l)]
parameters["gamma" + str(l)] = parameters["gamma"+str(l)] - self.learning_rate * grads["dgamma"+str(l)]
parameters["beta"+str(l)] = parameters["beta"+str(l)] - self.learning_rate * grads["dbeta"+str(l)]
return parameters
"""
类型:具体类
说明:标准的adam算法。
"""
class adam_standard(interface_optimization):
__v = {}
__s = {}
__t = 0
beta1 = 0.9
beta2 = 0.999
def initialization(self, *arguments):
parameters = arguments[0]
v = self.__v
s = self.__s
self.__t = 0
L = len(parameters) // 2
for l in range(1, L+1):
v["dW" + str(l)] = np.zeros(parameters["W" + str(l)].shape)
v["db" + str(l)] = np.zeros(parameters["b" + str(l)].shape)
s["dW" + str(l)] = np.zeros(parameters["W" + str(l)].shape)
s["db" + str(l)] = np.zeros(parameters["b" + str(l)].shape)
def optimization(self, *arguments):
parameters = arguments[0]
grads = arguments[1]
v = self.__v
s = self.__s
self.__t += 1
v_corrected = {}
s_corrected = {}
L = len(parameters) // 2
for l in range(1, L+1):
v["dW" + str(l)] = self.beta1 * v["dW" + str(l)] + (1-self.beta1) * grads['dW' + str(l)]
v["db" + str(l)] = self.beta1 * v["db" + str(l)] + (1-self.beta1) * grads['db' + str(l)]
v_corrected["dW" + str(l)] = v["dW" + str(l)] / (1 - np.power(self.beta1, self.__t))
v_corrected["db" + str(l)] = v["db" + str(l)] / (1 - np.power(self.beta1, self.__t))
s["dW" + str(l)] = self.beta2 * s["dW" + str(l)] + (1-self.beta2) * np.power(grads['dW' + str(l)], 2)
s["db" + str(l)] = self.beta2 * s["db" + str(l)] + (1-self.beta2) * np.power(grads['db' + str(l)], 2)
s_corrected["dW" + str(l)] = s["dW" + str(l)] / (1 - np.power(self.beta2, self.__t))
s_corrected["db" + str(l)] = s["db" + str(l)] / (1 - np.power(self.beta2, self.__t))
parameters["W" + str(l)] = parameters["W" + str(l)]
- self.learning_rate * (v_corrected["dW" + str(l)] / (np.sqrt(s_corrected["dW" + str(l)]) + self.epsilon))
parameters["b" + str(l)] = parameters["b" + str(l)]
- self.learning_rate * (v_corrected["db" + str(l)] / (np.sqrt(s_corrected["db" + str(l)]) + self.epsilon))
return parameters
"""
类型:具体类
说明:带有Batch normalization的adam算法。
"""
class adam_BN(interface_optimization):
__v = {}
__s = {}
__t = 0
beta1 = 0.9
beta2 = 0.999
def initialization(self, *arguments):
parameters = arguments[0]
v = self.__v
s = self.__s
self.__t = 0
L = len(parameters) // 3
for l in range(1, L+1):
v["dW" + str(l)] = np.zeros(parameters["W" + str(l)].shape)
v["dgamma" + str(l)] = np.zeros(parameters["gamma" + str(l)].shape)
v["dbeta" + str(l)] = np.zeros(parameters["beta" + str(l)].shape)
s["dW" + str(l)] = np.zeros(parameters["W" + str(l)].shape)
s["dgamma" + str(l)] = np.zeros(parameters["gamma" + str(l)].shape)
s["dbeta" + str(l)] = np.zeros(parameters["beta" + str(l)].shape)
def optimization(self, *arguments):
parameters = arguments[0]
grads = arguments[1]
v = self.__v
s = self.__s
self.__t += 1
v_corrected = {}
s_corrected = {}
L = len(parameters) // 3
for l in range(1, L+1):
v["dW" + str(l)] = self.beta1 * v["dW" + str(l)] + (1-self.beta1) * grads['dW' + str(l)]
v["dgamma" + str(l)] = self.beta1 * v["dgamma" + str(l)] + (1-self.beta1) * grads['dgamma' + str(l)]
v["dbeta" + str(l)] = self.beta1 * v["dbeta" + str(l)] + (1-self.beta1) * grads['dbeta' + str(l)]
v_corrected["dW" + str(l)] = v["dW" + str(l)] / (1 - np.power(self.beta1, self.__t))
v_corrected["dgamma" + str(l)] = v["dgamma" + str(l)] / (1 - np.power(self.beta1, self.__t))
v_corrected["dbeta" + str(l)] = v["dbeta" + str(l)] / (1 - np.power(self.beta1, self.__t))
s["dW" + str(l)] = self.beta2 * s["dW" + str(l)] + (1-self.beta2) * np.power(grads['dW' + str(l)], 2)
s["dgamma" + str(l)] = self.beta2 * s["dgamma" + str(l)] + (1-self.beta2) * np.power(grads['dgamma' + str(l)], 2)
s["dbeta" + str(l)] = self.beta2 * s["dbeta" + str(l)] + (1-self.beta2) * np.power(grads['dbeta' + str(l)], 2)
s_corrected["dW" + str(l)] = s["dW" + str(l)] / (1 - np.power(self.beta2, self.__t))
s_corrected["dgamma" + str(l)] = s["dgamma" + str(l)] / (1 - np.power(self.beta2, self.__t))
s_corrected["dbeta" + str(l)] = s["dbeta" + str(l)] / (1 - np.power(self.beta2, self.__t))
parameters["W" + str(l)] = parameters["W" + str(l)]
- self.learning_rate * (v_corrected["dW" + str(l)] / (np.sqrt(s_corrected["dW" + str(l)]) + self.epsilon))
parameters["gamma" + str(l)] = parameters["gamma" + str(l)]
- self.learning_rate * (v_corrected["dgamma" + str(l)] / (np.sqrt(s_corrected["dgamma" + str(l)]) + self.epsilon))
parameters["beta" + str(l)] = parameters["beta" + str(l)]
- self.learning_rate * (v_corrected["dbeta" + str(l)] / (np.sqrt(s_corrected["dbeta" + str(l)]) + self.epsilon))
return parameters
"""
类型:抽象类
说明:定义决策方法。
"""
class interface_decision(object):
epsilon = 1e-8
"""
类型:公有成员变量
说明:定义决策计算中的激活函数。
"""
activation = None
"""
类型:抽象公有成员函数
说明:定义预测方法。
"""
def prediction(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:定义计算精度的方法。
"""
def accuracy(self, *arguments):
pass
"""
类型:具体类
说明:定义标准的决策方法。
"""
class decider_standard(interface_decision):
def prediction(self, *arguments):
decision_set = arguments[0]
parameters = arguments[1]
A = decision_set
layer_number = len(parameters) // 2
for l in range(1, layer_number):
A = self.activation.activate_function(np.dot(parameters["W"+str(l)], A) + parameters["b" + str(l)])
ZL = np.dot(parameters["W"+str(layer_number)], A) + parameters["b" + str(layer_number)]
AL = np.exp(ZL) / np.sum(np.exp(ZL), axis=0, keepdims=True)
return np.argmax(AL, 0)
def accuracy(self, *arguments):
decision_set = arguments[0]
decision_label = arguments[1]
parameters = arguments[2]
bool_array = np.equal(self.prediction(decision_set, parameters), np.argmax(decision_label, 0))
acc = np.sum(bool_array == True) / len(bool_array)
return acc
"""
类型:具体类
说明:定义带Batch normalization的决策方法。
"""
class decider_BN(interface_decision):
def prediction(self, *arguments):
decision_set = arguments[0]
parameters = arguments[1]
A = decision_set
layer_number = len(parameters) // 3
for l in range(1, layer_number):
Z = np.dot(parameters["W"+str(l)], A)
Zmean = np.mean(Z, axis=1, keepdims=True)
Zvariance = np.mean(np.square(Z - Zmean), axis=1, keepdims=True)
Ztilde = (Z - Zmean) / np.sqrt(Zvariance + self.epsilon)
Znorm = np.multiply(parameters["gamma" + str(l)], Ztilde) + parameters["beta" + str(l)]
A = self.activation.activate_function(Znorm)
ZL = np.dot(parameters["W"+str(layer_number)], A)
Zmean = np.mean(ZL, axis=1, keepdims=True)
Zvariance = np.mean(np.square(ZL - Zmean), axis=1, keepdims=True)
Ztilde = (ZL - Zmean) / np.sqrt(Zvariance + self.epsilon)
Znorm = np.multiply(parameters["gamma" + str(layer_number)], Ztilde) + parameters["beta" + str(layer_number)]
AL = np.exp(Znorm) / np.sum(np.exp(Znorm), axis=0, keepdims=True)
return np.argmax(AL, 0)
def accuracy(self, *arguments):
decision_set = arguments[0]
decision_label = arguments[1]
parameters = arguments[2]
bool_array = np.equal(self.prediction(decision_set, parameters), np.argmax(decision_label, 0))
acc = np.sum(bool_array == True) / len(bool_array)
return acc
"""
类型:抽象类
说明:定义学习率衰减方法。
"""
class interface_learning_rate(object):
"""
类型:公有成员变量
说明:定义每几步衰减一次。
"""
epoch_step = 10
"""
类型:公有成员变量
说明:衰退比率。
"""
k = 0.1
"""
类型:保护成员变量
说明:迭代次数,用于自加操作。
"""
_t = 0
def learning_rate_decay(self, *arguments):
pass
"""
类型:具体类
说明:指数学习率衰减方法。
"""
class exponential_decay(interface_learning_rate):
def learning_rate_decay(self, *arguments):
recent_epoch = arguments[0]
learning_rate = arguments[1]
if(recent_epoch % self.epoch_step == 0):
self._t += 1
learning_rate = learning_rate * np.exp(-self.k * self._t)
return learning_rate
"""
类型:具体类
说明:除以t的学习率衰减方法。
"""
class div_t_decay(interface_learning_rate):
def learning_rate_decay(self, *arguments):
recent_epoch = arguments[0]
learning_rate = arguments[1]
if(recent_epoch % self.epoch_step == 0):
self._t += 1
learning_rate = learning_rate / (1 + self.k * self._t)
return learning_rate
"""
类型:抽象类
说明:定义一个工厂类,用来生产学习模型过程中所需要的模块。
"""
class interface_factory(object):
"""
类型:公有成员变量
说明:数据预处理规则化模块。
"""
normalizer = None
"""
类型:公有成员变量
说明:学习参数初始化模块。
"""
initializer = None
"""
类型:公有成员变量
说明:向前向后学习算法模块。
"""
propagator = None
"""
类型:公有成员变量
说明:优化算法模块。
"""
optimizer = None
"""
类型:公有成员变量
说明:决策模块。
"""
decider = None
"""
类型:公有成员变量
说明:学习率衰减模块。
"""
decay_rater = None
"""
类型:公有成员变量
说明:数据批量优化算法说需要的batch大小,即每次训练从训练集里抽样的个数。
"""
minibatch_size = 512
"""
类型:公有成员变量
说明:epoch个数,即需要训练整个数据集多少遍。
"""
num_epochs = 100
"""
类型:抽象公有成员函数
说明:创建一个工厂,该工厂生产训练和测试数据过程中所需要的模块。
"""
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):
epsilon = arguments[0]
self.normalizer = zscore_normalization()
self.normalizer.epsilon = 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 = epsilon
self.propagator.functor["activation"] = relu()
self.propagator.functor["activation"].epsilon = epsilon
self.propagator.functor["cost"] = softmax()
self.propagator.functor["cost"].epsilon = epsilon
learning_rate = arguments[3]
beta1 = arguments[4]
beta2 = arguments[5]
self.optimizer = adam_standard()
self.optimizer.epsilon = epsilon
self.optimizer.learning_rate = learning_rate
self.optimizer.beta1 = beta1
self.optimizer.beta2 = beta2
self.decider = decider_standard()
self.decider.epsilon = epsilon
self.decider.activation = relu()
self.minibatch_size = arguments[6]
self.num_epochs = arguments[7]
epoch_step = arguments[8]
rate_k = arguments[9]
self.decay_rater = exponential_decay()
self.decay_rater.epoch_step = epoch_step
self.decay_rater.k = rate_k
return self
"""
类型:具体类
说明:工厂版本v2,带Batch normalization功能,激活函数为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
"""
def create_workpiece(self, *arguments):
epsilon = arguments[0]
self.normalizer = zscore_normalization()
self.normalizer.epsilon = 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 = epsilon
bn = batch_normlizer()
bn.epsilon = epsilon
self.propagator.regularizer = {'batch_normlizer': bn}
self.propagator.functor["activation"] = relu()
self.propagator.functor["activation"].epsilon = epsilon
self.propagator.functor["cost"] = softmax()
self.propagator.functor["cost"].epsilon = epsilon
learning_rate = arguments[3]
beta1 = arguments[4]
beta2 = arguments[5]
self.optimizer = adam_BN()
self.optimizer.epsilon = epsilon
self.optimizer.learning_rate = learning_rate
self.optimizer.beta1 = beta1
self.optimizer.beta2 = beta2
self.decider = decider_BN()
self.decider.epsilon = epsilon
self.decider.activation = relu()
self.minibatch_size = arguments[6]
self.num_epochs = arguments[7]
epoch_step = arguments[8]
rate_k = arguments[9]
self.decay_rater = exponential_decay()
self.decay_rater.epoch_step = epoch_step
self.decay_rater.k = rate_k
return self
"""
类型:具体类
说明:工厂版本v3,带Batch normalization功能,带dropout规则化,激活函数为relu,最后一层激活函数为softmax,代价函数用的是交叉熵损失函数,
优化算法为adam,学习率为指数衰减。
"""
class factory_v3(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保持概率 - keep_prob
"""
def create_workpiece(self, *arguments):
epsilon = arguments[0]
self.normalizer = zscore_normalization()
self.normalizer.epsilon = 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 = epsilon
bn = batch_normlizer()
bn.epsilon = epsilon
self.propagator.regularizer['batch_normlizer'] = bn
self.propagator.functor["activation"] = relu()
self.propagator.functor["activation"].epsilon = epsilon
self.propagator.functor["cost"] = softmax()
self.propagator.functor["cost"].epsilon = epsilon
learning_rate = arguments[3]
beta1 = arguments[4]
beta2 = arguments[5]
self.optimizer = adam_BN()
self.optimizer.epsilon = epsilon
self.optimizer.learning_rate = learning_rate
self.optimizer.beta1 = beta1
self.optimizer.beta2 = beta2
self.decider = decider_BN()
self.decider.epsilon = epsilon
self.decider.activation = relu()
self.minibatch_size = arguments[6]
self.num_epochs = arguments[7]
epoch_step = arguments[8]
rate_k = arguments[9]
self.decay_rater = exponential_decay()
self.decay_rater.epoch_step = epoch_step
self.decay_rater.k = rate_k
d = dropout()
d.epsilon = epsilon
d.keep_prob = arguments[10]
self.propagator.regularizer['dropout'] = d
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 prediction(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算训练集精度。
"""
def training_accuracy(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算验证集精度。
"""
def validation_accuracy(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:计算测试集精度。
"""
def test_accuracy(self, *arguments):
pass
"""
类型:抽象公有成员函数
说明:训练模型方法。
"""
def training_model(self, *arguments):
pass
"""
类型:具体类
说明:定义深度神经网络。
"""
class deep_neural_networks(interface_train_model):
"""
类型:初始化函数
说明:初始化工厂对象。
"""
def __init__(self, factory):
self.factory = factory
def prediction(self, *arguments):
return self.factory.decider.prediction(self.test_set, self.parameters)
def training_accuracy(self, *arguments):
return self.factory.decider.accuracy(self.training_set, self.training_label, self.parameters)
def validation_accuracy(self, *arguments):
return self.factory.decider.accuracy(self.validation_set, self.validation_label, self.parameters)
def test_accuracy(self, *arguments):
return self.factory.decider.accuracy(self.test_set, self.test_label, self.parameters)
def training_model(self, *arguments):
#定义深度神经网络结构
self.factory.initializer.structure = np.append(np.array([self.training_set.shape[0]]), self.factory.initializer.structure)
#定义一轮epoch需要多少batch
num_minibatches = int(self.training_set.shape[1] / self.factory.minibatch_size) + 1
#定义数据预处理步骤
if(self.factory.normalizer != None):
self.training_set = self.factory.normalizer.normalize_data(self.training_set)
self.validation_set = self.factory.normalizer.normalize_data(self.validation_set)
#定义学习参数及超参数初始化步骤
self.parameters = self.factory.initializer.initialize_parameters()
seed = self.factory.initializer.seed
self.factory.optimizer.initialization(self.parameters)
costs = []
training_accuracies = []
validation_accuracies = []
#在验证集上表现最好的学习参数
best_parameters = {}
#最好学习参数时,训练集的精度
best_training_acc = 0.
#最好学习参数时,验证集的精度
best_validation_acc = 0.
start = time.clock()
#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)
cost += self.factory.propagator.forward_propagation(minibatch_X, minibatch_Y, self.parameters)
grads = self.factory.propagator.backward_propagation(minibatch_X, minibatch_Y, self.parameters)
self.factory.optimizer.optimization(self.parameters, grads)
if(self.factory.decay_rater != None):
self.factory.optimizer.learning_rate = self.factory.decay_rater.learning_rate_decay(iter_epoch, self.factory.optimizer.learning_rate)
cost /= num_minibatches
costs.append(cost)
training_acc = self.training_accuracy()
training_accuracies.append(training_acc)
validation_acc = self.validation_accuracy()
validation_accuracies.append(validation_acc)
if(validation_acc > best_validation_acc):
best_training_acc = training_acc
best_validation_acc = validation_acc
best_parameters = copy.deepcopy(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 =" + str(self.factory.optimizer.learning_rate))
plt.show()
plt.plot(np.squeeze(training_accuracies))
plt.ylabel('training accracy')
plt.xlabel('epochs')
plt.title("Learning rate =" + str(self.factory.optimizer.learning_rate))
plt.show()
plt.plot(np.squeeze(validation_accuracies))
plt.ylabel('validation accracy')
plt.xlabel('epochs')
plt.title("Learning rate =" + str(self.factory.optimizer.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[1], 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.01)
dnn = deep_neural_networks(factory)
dnn.training_set = mnist.train.images.T
dnn.training_label = mnist.train.labels.T
dnn.validation_set = mnist.test.images.T
dnn.validation_label = mnist.test.labels.T
dnn.training_model()
main()
运行结果: