神经网络实践之初始化权重参数
前言
在机器学习的应用层面中,已经了解了神经网络中的一些有关实践层面的一些参数包括方差,偏差,权重初始化,几种正则化的方法,和梯度检验等相关知识,本篇文章是深度学习课程的配套作业,将会通过代码实现深度学习应用层面的一些参数配置,提高神经网络的性能。
初始化权重参数
神经网络的第一项任务就是初始化权重参数,一些好的初始化权重参数有利于提高网络性能和加快网络训练速度。
利用python
实现初始化权重的过程如下所示:
- 导入相关包
首先,需要导入相关初始化权重参数用到的相关库,并且完成一些数据可视化的基本设置,如下代码所示:
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
# 绘图的一些默认参数
%matplotlib inline
plt.rcParams['figure.figsize'] = (7.0, 4.0) #设置图片m默认大小
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
- 加载数据集并可视化
这些数据集是通过调用sklearn
库生成的一些随机数据,这些随机数据按照颜色分为两类的二维随机数据,这些训练数据分为训练集和测试集,在二维图形中大致按照圆形分布,具体实现如下代码所示:
def load_dataset():
np.random.seed(1)
train_X, train_Y = sklearn.datasets.make_circles(n_samples=300, noise=.05)
np.random.seed(2)
test_X, test_Y = sklearn.datasets.make_circles(n_samples=100, noise=.05)
# 可视化数据
plt.scatter(train_X[:, 0], train_X[:, 1], c=train_Y, s=40, cmap=plt.cm.Spectral);
train_X = train_X.T
train_Y = train_Y.reshape((1, train_Y.shape[0]))
test_X = test_X.T
test_Y = test_Y.reshape((1, test_Y.shape[0]))
return train_X, train_Y, test_X, test_Y
对于神经网络模型,将会利用三种不同的方式实现权重参数的随机初始化,并比较这三种初始化方式的优劣,具体如下所示:
搭建神经网络模型
在完成参数初始化之前,首先完成整个网络模型的搭建。整个网络模型的结构是一个三层的神经网络,整个神经网络模型的实现过程,在一步步构建一个神经网络中有详细的介绍,在此不再多做说明。只考虑每次设置不同的权重参数初始化方式,比较模型性能。
def model(X, Y, learning_rate = 0.01, num_iterations = 15000, print_cost = True, initialization = "he"):
"""
三层神经网络的模型结构: LINEAR->RELU->LINEAR->RELU->LINEAR->SIGMOID.
参数:
X -- 输入数据 矩阵形状是(2, 样本数量)
Y -- 输出标签,1代表红点,0代表蓝点,向量形状 (1, 样本数量)
learning_rate -- 梯度下降的学习率
num_iterations -- 运行梯度下降的迭代次数
print_cost -- 打印出每1000次迭代之后的损失
initialization -- 初始化权重参数的方式选择
("zeros","random" or "he")
返回值:模型学习的参数
"""
grads = {}
costs = [] # to keep track of the loss
m = X.shape[1] # number of examples
layers_dims = [X.shape[0], 10, 5, 1]
# 初始化参数字典
if initialization == "zeros":
parameters = initialize_parameters_zeros(layers_dims)
elif initialization == "random":
parameters = initialize_parameters_random(layers_dims)
elif initialization == "he":
parameters = initialize_parameters_he(layers_dims)
# 梯度下降的循环次数
for i in range(0, num_iterations):
# 前向传播: LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID.
a3, cache = forward_propagation(X, parameters)
# 计算损失
cost = compute_loss(a3, Y)
# 反向传播.
grads = backward_propagation(X, Y, cache)
# 参数更新
parameters = update_parameters(parameters, grads, learning_rate)
# 打印出每1000次迭代的损失
if print_cost and i % 1000 == 0:
print("Cost after iteration {}: {}".format(i, cost))
costs.append(cost)
# 绘制模型损失图像
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
return parameters
0初始化
0初始化,也就是将所有的权重参数设为0,具体实现代码如下所示:
def initialize_parameters_zeros(layers_dims):
"""
参数说明:
layer_dims -- 神经网络的层数,一个列表,其中的值代表这一层的单元数量,长度代表神经网络的层数
Returns:
返回一个存储参数的python字典
WL -- 权重矩阵的形状 (layers_dims[L], layers_dims[L-1])
bL -- 偏置向量的形状 (layers_dims[L], 1)
"""
parameters = {}
L = len(layers_dims)
for l in range(1, L):
parameters['W' + str(l)] = np.zeros((layers_dims[l],layers_dims[l-1]))
parameters['b' + str(l)] = np.zeros((layers_dims[l],1))
return parameters
运行以上代码后,输出结果如下所示:
采用参数0初始化之后的梯度下降过程如下所示,可以看出,将初始化参数全部设为0之后,运行多次梯度下降算法之后,损失值一直保持不变,训练集和测试集的输出全是0,分类精度只有0.5,说明权重参数0初始化并不是一种可行的办法。
随机初始化
权重参数的随机初始化即是将每一层的权重参数初始化为随机高斯分布(取值范围为),并将其乘以10,偏置参数初始化为0,具体的实现代码如下所示:
def initialize_parameters_random(layers_dims):
np.random.seed(3) #固定随机种子
parameters = {}
L = len(layers_dims)
for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layers_dims[l],layers_dims[l-1])*10
parameters['b' + str(l)] = np.zeros((layers_dims[l],1))
return parameters
运行一下代码,并输出模型损失和性能如下所示:
parameters = model(train_X, train_Y, initialization = "random")
print ("On the train set:")
predictions_train = predict(train_X, train_Y, parameters)
print ("On the test set:")
predictions_test = predict(test_X, test_Y, parameters)
可以看出,随着梯度下降跌打次数的增加,损失逐渐下降,并且训练集和测试集的精度分别达到了0.83和0.86
输出集和测试集的输出分别如下所示:
运行以下代码,绘制出决策边界如下所示:
plt.title("Model with large random initialization")
axes = plt.gca()
axes.set_xlim([-1.5,1.5])
axes.set_ylim([-1.5,1.5])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
注意:
-
可以看出,刚开始迭代时,损失非常高,达到了正无穷,这是因为刚开始设置的权重参数非常大,对于
sigmoid
函数来说,很容易导致输出接近0或者1,从而导致最后的损失函数中的 -
初始化参数过大或者过小可能会导致梯度爆炸或者梯度消失,可能会导致训练速度减慢。
-
如果对该网络进行更长时间的训练,训练精度可能会更高,但是会花费更长的时间。
He初始化
He初始化是2015年以它的发明者命名的,这种初始化方法采用了对权重使用比例因为的方法,也就是对权重参数乘以比例因子的方法,具体实现方式如下所示:
def initialize_parameters_he(layers_dims):
np.random.seed(3)
parameters = {}
L = len(layers_dims) - 1
for l in range(1, L + 1):
parameters['W' + str(l)] = np.random.randn(layers_dims[l],layers_dims[l-1])*np.sqrt(1/layers_dims[l-1])
parameters['b' + str(l)] = np.zeros((layers_dims[l],1))
return parameters
输出结果如下所示:
梯度下降过程中的迭代如下所示,随着迭代次数的增加,损失一直在降低,并且训练集和测试集的精度分别达到了99%和93%:
最后,绘制决策边界如下所示: