针对于过拟合现象,有两种可以解决的办法:权重衰减丢弃法。这篇文章先总结权重衰减。

一、权重衰减介绍及参数迭代方式推导

权重衰减是等价于权重衰减系数 学习率 权重衰减的方法_正则化范数正则化的。那么什么是正则化呢?

正则化是通过为模型损失函数添加惩罚项使得学习出的模型参数值较小的办法,是应对过拟合的常用手段。下面先描述权重衰减系数 学习率 权重衰减的方法_正则化范数正则化,再解释为何它叫权重衰减。

权重衰减系数 学习率 权重衰减的方法_正则化范数惩罚项是指:模型的权重参数每个元素的平方和 × 正常数。以线性回归中的损失函数

权重衰减系数 学习率 权重衰减的方法_损失函数_04


为例。将权重参数用向量权重衰减系数 学习率 权重衰减的方法_权重_05表示,带有权重衰减系数 学习率 权重衰减的方法_正则化范数惩罚项的新损失函数为

权重衰减系数 学习率 权重衰减的方法_权重衰减系数 学习率_07

其中超参数权重衰减系数 学习率 权重衰减的方法_权重_08权重衰减系数 学习率 权重衰减的方法_损失函数_09为样本个数

  • 当权重参数为0时,惩罚项最小
  • 权重衰减系数 学习率 权重衰减的方法_损失函数_10较大时,惩罚项的比重较大,这通常会使学到的权重参数元素接近于0
  • 权重衰减系数 学习率 权重衰减的方法_损失函数_11时,惩罚项完全不起作用

加入该惩罚项之后,在小批量随机梯度下降中,将参数的迭代方式推导如下:

假设新的损失函数为权重衰减系数 学习率 权重衰减的方法_权重_12,则
权重衰减系数 学习率 权重衰减的方法_权重_13

对于小批量权重衰减系数 学习率 权重衰减的方法_正则化_14来说,权重衰减系数 学习率 权重衰减的方法_权重衰减系数 学习率_15所以
权重衰减系数 学习率 权重衰减的方法_损失函数_16

于是,就有了下面新的迭代方式

权重衰减系数 学习率 权重衰减的方法_正则化_17

可见,正则化令权重权重衰减系数 学习率 权重衰减的方法_正则化_18先乘上小于1的数,再减去不含惩罚项的梯度。因此权重衰减系数 学习率 权重衰减的方法_正则化范数也成为权重衰减。权重衰减通过惩罚绝对值较大的模型参数,为需要学习的模型增加了限制,这可能对过拟合有效。


二、解决过拟合现象实验

该部分,通过高维线性回归来引入一个过拟合问题,并使用权重衰减来试着应付过拟合。该高维线性回归函数如下:
权重衰减系数 学习率 权重衰减的方法_权重衰减系数 学习率_20

其中

  • 权重衰减系数 学习率 权重衰减的方法_权重衰减系数 学习率_21表示样本特征的维度,权重衰减系数 学习率 权重衰减的方法_正则化_22表示服从均值为0、标准差为0.01的正态分布的噪音项
  • 假设权重衰减系数 学习率 权重衰减的方法_损失函数_23
  • 为了观察过拟合现象,将训练集样本数设为20,而测试集样本数为100
%matplotlib inline
import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import data as gdata, loss as gloss, nn

## 生成训练集
n_train, n_test, num_inputs = 20, 100, 200
true_w, true_b = nd.ones((num_inputs, 1)) * 0.01, 0.05

features = nd.random.normal(shape=(n_train + n_test, num_inputs))
labels = nd.dot(features, true_w) + true_b
labels += nd.random.normal(scale=0.01, shape=labels.shape)
train_features, test_features = features[:n_train, :], features[n_train:, :]
train_labels, test_labels = labels[:n_train], labels[n_train:]


## 定义:初始化参数、L2范数惩罚项函数
def init_params():
	w = nd.random.normal(scale=1, shape=(num_inputs, 1))
	b = nd.zeros(shape=(1,))
	w.attach_grad()
	b.attach_grad() # 要附上梯度
	return [w, b]
def l2_penalty(w):
	return (w**2).sum() / 2
batch_size, num_epochs, lr = 1, 100, 0.003
net, loss = d2l.linreg, d2l.squared_loss
train_iter = gdata.DataLoader(gdata.ArrayDataset(train_features, train_labels), 
													batch_size, shuffle=True)


## 定义训练及优化函数,并作图
def fit_and_plot(lambd):
	w, b = init_params()
	train_ls, test_ls = [], []
	for _ in range(num_epochs):
		for X, y in train_iter:
			with autograd.record():
				# 添加了L2范数惩罚项
				l = loss(net(X, w, b), y) + lambd * l2_penalty(w)
			l.backward()
			d2l.sgd([w, b], lr, batch_size) # 参数:要优化的参数,学习率,batch_size
		train_ls.append(loss(net(train_features, w, b),
							train_labels).mean().asscalar())
		test_ls.append(loss(net(test_features, w, b),
							test_labels).mean().asscalar())
	d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'loss',
					range(1, num_epochs + 1), test_ls, ['train', 'test'])
	print('L2 norm of w:', w.norm().asscalar())

其中,d2l.semilogy()的函数说明如下:

权重衰减系数 学习率 权重衰减的方法_正则化_24


其中参数分别表示:第一个曲线的x、yx轴的名字y轴的名字第二个曲线的x、ylegend:每个曲线对应的说明作图大小

控制fit_and_plot()函数的参数lambd,可以实现权重衰减的程度。


lamda=0时,没有实现权重衰减。由于模型的维度很高,比较复杂,所以很容易出现过拟合现象,并且此时权重参数的权重衰减系数 学习率 权重衰减的方法_正则化范数也比较大。

fit_and_plot(lambd=0)

结果如下:

权重衰减系数 学习率 权重衰减的方法_正则化_26


lambd=3时,使用了权重衰减。

fit_and_plot(lambd=3)

结果如下:

权重衰减系数 学习率 权重衰减的方法_权重衰减系数 学习率_27


可以看出,虽然训练误差有所提高,但测试集误差有所下降。所以过拟合现象得到一定程度的缓和。另外,此时权重参数权重衰减系数 学习率 权重衰减的方法_正则化范数也更小,并且比较接近0。


在利用mxnet框架的时候,通过指定gluon.Trainner中的wd(weight decay)参数,可以实现权重衰减。其中'wd': wd中的wd表示权重衰减系数权重衰减系数 学习率 权重衰减的方法_正则化_29。如下:

权重衰减系数 学习率 权重衰减的方法_损失函数_30