MXNET:权重衰减

作者:@houkai
本文为作者原创,转载请注明出处:https://www.cnblogs.com/houkai/p/9520998.html


权重衰减是应对过拟合问题的常用方法。

L2范数正则化

在深度学习中,我们常使用L2范数正则化,也就是在模型原先损失函数基础上添加L2范数惩罚项,从而得到训练所需要最小化的函数。

L2范数惩罚项指的是模型权重参数每个元素的平方和与一个超参数的乘积。如:w1,w2是权重参数,b是偏差参数,带L2范数惩罚项的新损失函数为:

(w1,w2,b)+λ2(w12+w22),

λ调节了惩罚项的比重。

有了L2范数后,在随机梯度下降中,以单层神经网络为例,权重的迭代公式变更为:

w1w1η|B|iBx1(i)(x1(i)w1+x2(i)w2+by(i))λw1,

w2w2η|B|iBx2(i)(x1(i)w1+x2(i)w2+by(i))λw2.

η为学习率,B为样本数目,可见:L2范数正则化令权重的每一步更新分别添加了λw1λw2。这就是L2范数正则化被称为权重衰减(weight decay)的原因。

在实际中,我们有时也在惩罚项中添加偏差元素的平方和

假设神经网络中某一个神经元的输入是x1,x2,使用激活函数ϕ并输出ϕ(x1w1+x2w2+b)。假设激活函数ϕ是ReLU、tanh或sigmoid,如果w1,w2,b都非常接近0,那么输出也接近0。也就是说,这个神经元的作用比较小,甚至就像是令神经网络少了一个神经元一样。这样便有效降低了模型的复杂度,降低了过拟合。

高维线性回归实验

我们通过高维线性回归为例来引入一个过拟合问题,并使用L2范数正则化来试着应对过拟合。

生成数据集

设数据样本特征的维度为p。对于训练数据集和测试数据集中特征为x1,x2,,xn的任一样本,我们使用如下的线性函数来生成该样本的标签:

y=0.05+i=1p0.01xi+ϵ,

其中噪音项ϵ服从均值为0和标准差为0.1的正态分布。

为了较容易地观察过拟合,我们考虑高维线性回归问题,例如设维度p=200;同时,我们特意把训练数据集的样本数设低,例如20。

n_train = 20
n_test = 100

num_inputs = 200

true_w = nd.ones((num_inputs, 1)) * 0.01
true_b = 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:]

初始化模型参数

def init_params():
    w = nd.random.normal(scale=1, shape=(num_inputs, 1))
    b = nd.zeros(shape=(1,))
    params = [w, b]
    for param in params:
        param.attach_grad()
    return params

定义L2范数惩罚项

def l2_penalty(w):
    return (w**2).sum() / 2

定义训练和测试

batch_size = 1
num_epochs = 10
lr = 0.003

net = gb.linreg
loss = gb.squared_loss
def fit_and_plot(lambd):
    w, b = params = init_params()
    train_ls = []
    test_ls = []
    for _ in range(num_epochs):
        for X, y in gb.data_iter(batch_size, n_train, features, labels):
            with autograd.record():
                # 添加了 L2 范数惩罚项。
                l = loss(net(X, w, b), y) + lambd * l2_penalty(w)
            l.backward()
            gb.sgd(params, lr, 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())
    gb.semilogy(range(1, num_epochs+1), train_ls, 'epochs', 'loss',
                range(1, num_epochs+1), test_ls, ['train', 'test'])
    return 'w[:10]:', w[:10].T, 'b:', b

设置lambd=0,训练误差远小于测试(泛化)误差,这是典型的过拟合现象。

fit_and_plot(lambd=0)
# output
('w[:10]:', 
[[ 0.30343655 -0.08110731  0.64756584 -1.51627898  0.16536537  0.42101485
   0.41159022  0.8322348  -0.66477555  3.56285167]]
<NDArray 1x10 @cpu(0)>, 'b:', 
[ 0.12521751]
<NDArray 1 @cpu(0)>)

使用正则化,过拟合现象得到一定程度上的缓解。然而依然没有学出较准确的模型参数。这主要是因为训练数据集的样本数相对维度来说太小

fit_and_plot(lambd=5)
# output
('w[:10]:', 
[[ 0.01602661 -0.00279179  0.03075662 -0.07356022  0.01006496  0.02420521
   0.02145572  0.04235912 -0.03388886  0.17112994]]
<NDArray 1x10 @cpu(0)>, 'b:', 
[ 0.08771407]
<NDArray 1 @cpu(0)>)

posted @   侯凯  阅读(1233)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示