提交 a915afa5 编写于 作者: A Aston Zhang

reg done

上级 0ea6ea43
# 正则化——使用Gluon
本章介绍如何使用``Gluon``的正则化来应对[过拟合](underfit-overfit.md)问题。
## 高维线性回归数据集
我们使用与[上一节](reg-scratch.md)相同的高维线性回归为例来引入一个过拟合问题。
本节将介绍如何使用Gluon实现上一节介绍的正则化。导入实验所需的包或模块。
```{.python .input n=1}
%matplotlib inline
......@@ -17,6 +13,10 @@ from mxnet import autograd, gluon, init, nd
from mxnet.gluon import data as gdata, loss as gloss, nn
```
## 生成数据集
我们使用和上一节完全一样的方法生成数据集。
```{.python .input n=2}
n_train = 20
n_test = 100
......@@ -40,7 +40,7 @@ loss = gloss.L2Loss()
## 定义训练和测试
跟前一样定义训练模块。你也许发现了主要区别,`Trainer`有一个新参数`wd`。我们通过优化算法的``wd``参数 (weight decay)实现对模型的正则化。这相当于$L_2$范数正则化
在训练和测试的定义中,我们分别定义了两个Trainer实例。其中一个对权重参数做$L_2$范数正则化,另一个并没有对偏差参数做正则化。我们在上一节也提到了,实际中有时也对偏差参数做正则化。这样只需要定义一个Trainer实例就可以了
```{.python .input n=3}
gb.set_fig_size(mpl)
......@@ -48,10 +48,11 @@ gb.set_fig_size(mpl)
def fit_and_plot(weight_decay):
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize(init.Normal(sigma=0.01))
# 注意到这里 'wd'
net.initialize(init.Normal(sigma=1))
# 对权重参数做L2范数正则化,即权重衰减。
trainer_w = gluon.Trainer(net.collect_params('.*weight'), 'sgd', {
'learning_rate': learning_rate, 'wd': weight_decay})
# 不对偏差参数做L2范数正则化。
trainer_b = gluon.Trainer(net.collect_params('.*bias'), 'sgd', {
'learning_rate': learning_rate})
train_ls = []
......@@ -76,36 +77,26 @@ def fit_and_plot(weight_decay):
return 'w[:10]:', net[0].weight.data()[:,:10], 'b:', net[0].bias.data()
```
### 训练模型并观察过拟合
## 观察实验结果
接下来我们训练并测试我们的高维线性回归模型
以下实验结果和上一节中的类似
```{.python .input n=4}
fit_and_plot(0)
```
即便训练误差可以达到0.000000,但是测试数据集上的误差很高。这是典型的过拟合现象。
观察学习的参数。事实上,大部分学到的参数的绝对值比真实参数的绝对值要大一些。
## 使用``Gluon``的正则化
下面我们重新初始化模型参数并在`Trainer`里设置一个`wd`参数。
```{.python .input n=5}
fit_and_plot(5)
```
我们发现训练误差虽然有所提高,但测试数据集上的误差有所下降。过拟合现象得到缓解。
但打印出的学到的参数依然不是很理想,这主要是因为我们训练数据的样本相对维度来说太少。
## 小结
* 使用``Gluon```weight decay`参数可以很容易地使用正则化来应对过拟合问题。
* 使用Gluon的`wd`超参数可以使用正则化来应对过拟合问题。
* 我们可以定义多个Trainer实例对不同的模型参数使用不同的迭代方法。
## 练习
* 如何从字面正确理解`weight decay`的含义?它为何相当于$L_2$范式正则化?
* 调一调本节实验中的`wd`超参数。观察并分析实验结果。
## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/985)
......
......@@ -36,9 +36,9 @@ from matplotlib import pyplot as plt
from mxnet import autograd, gluon, nd
```
## 生成数据集
### 生成数据集
对于训练数据集和测试数据集中特征为$x_1, x_2, \ldots, x_p$的任一样本,我们使用如下的线性函数来生成该样本的标签:
设数据样本特征的维度为$p$。对于训练数据集和测试数据集中特征为$x_1, x_2, \ldots, x_p$的任一样本,我们使用如下的线性函数来生成该样本的标签:
$$y = 0.05 + \sum_{i = 1}^p 0.01x_i + \epsilon,$$
......@@ -59,13 +59,13 @@ train_features, test_features = features[:n_train, :], features[n_train:, :]
train_labels, test_labels = labels[:n_train], labels[n_train:]
```
## 初始化模型参数
### 初始化模型参数
下面我们随机初始化模型参数。之后训练时我们需要对这些参数求导来更新它们的值,所以我们需要创建它们的梯度。
下面定义函数来随机初始化模型参数,并为它们附上梯度。
```{.python .input n=5}
def init_params():
w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))
w = nd.random.normal(scale=1, shape=(num_inputs, 1))
b = nd.zeros(shape=(1,))
params = [w, b]
for param in params:
......@@ -73,30 +73,24 @@ def init_params():
return params
```
## $L_2$范数正则化
这里我们引入$L_2$范数正则化。不同于在训练时仅仅最小化损失函数(Loss),我们在训练时其实在最小化
### 定义$L_2$范数惩罚项
$$\text{loss} + \lambda \sum_{p \in \textrm{params}}\|p\|_2^2。$$
直观上,$L_2$范数正则化试图惩罚较大绝对值的参数值。下面我们定义L2正则化。注意有些时候大家对偏移加罚,有时候不加罚。通常结果上两者区别不大。这里我们演示对偏移也加罚的情况:
下面定义$L_2$范数惩罚项。这里只惩罚模型的权重参数。
```{.python .input n=6}
def l2_penalty(w):
return (w**2).sum() / 2
```
```{.python .input}
num_epochs = 10
lr = 0.003
```
## 定义训练和测试
### 定义训练和测试
下面我们定义剩下的所需要的函数。这个跟之前的教程大致一样,主要是区别在于计算`loss`的时候我们加上了L2正则化,以及我们将训练和测试损失都画了出来
下面定义如何在训练数据集和测试数据集上分别训练和测试模型。和前面几节中不同的是,这里在计算最终的损失函数时添加了$L_2$范数惩罚项
```{.python .input n=7}
batch_size = 1
num_epochs = 10
lr = 0.003
net = gb.linreg
loss = gb.squared_loss
gb.set_fig_size(mpl)
......@@ -108,6 +102,7 @@ def fit_and_plot(lambd):
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)
......@@ -124,36 +119,33 @@ def fit_and_plot(lambd):
return 'w[:10]:', w[:10].T, 'b:', b
```
## 观察过拟合
### 观察过拟合
接下来我们训练并测试我们的高维线性回归模型。注意这时我们并未使用正则化
接下来,让我们训练并测试高维线性回归模型。当`lambd`设为0时,我们没有使用正则化。结果训练误差远小于测试数据集上的误差。这是典型的过拟合现象
```{.python .input n=8}
fit_and_plot(0)
fit_and_plot(lambd=0)
```
即便训练误差可以达到0.000000,但是测试数据集上的误差很高。这是典型的过拟合现象。
### 使用正则化
观察学习的参数。事实上,大部分学到的参数的绝对值比真实参数的绝对值要大一些
下面我们使用$L_2$范数正则化。我们发现训练误差虽然有所提高,但测试数据集上的误差有所下降。过拟合现象得到一定程度上的缓解。另外,学到的权重参数的绝对值比不使用正则化时相比更接近0
## 使用正则化
下面我们重新初始化模型参数并设置一个正则化参数。
然而,即便是使用了正则化的模型依然没有学出较准确的模型参数。这主要是因为训练数据集的样本数相对维度来说太小。
```{.python .input n=9}
fit_and_plot(5)
fit_and_plot(lambd=5)
```
我们发现训练误差虽然有所提高,但测试数据集上的误差有所下降。过拟合现象得到缓解。但打印出的学到的参数依然不是很理想,这主要是因为我们训练数据的样本相对维度来说太少。
## 小结
* 我们可以使用正则化来应对过拟合问题。
* $L_2$范数正则化通常会使学到的权重参数的元素较接近0。
* $L_2$范数正则化也叫权重衰减。
## 练习
* 除了正则化、增大训练量、以及使用合适的模型,你觉得还有哪些办法可以应对过拟合现象?
* 除了正则化、增大训练量、以及使用复杂度合适的模型,你还能想到哪些办法可以应对过拟合现象?
* 如果你了解贝叶斯统计,你觉得$L_2$范数正则化对应贝叶斯统计里的哪个重要概念?
## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/984)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册