diff --git a/.gitignore b/.gitignore index e3b03421cfd47c656070481c6dd048ba3e5afd8f..2b9afd0045c9515dade1c26e290ed285ea984d63 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ build/ /chapter_gluon-basics/mydict *egg-info* dist* +utils.py diff --git a/chapter_supervised-learning/reg-scratch.md b/chapter_supervised-learning/reg-scratch.md index 3210767c2af99633949daa3001c85a450efc8f2f..b2c89b93f2110dafb9a5c72c59e23c68b51a2360 100644 --- a/chapter_supervised-learning/reg-scratch.md +++ b/chapter_supervised-learning/reg-scratch.md @@ -1,19 +1,30 @@ # 正则化——从零开始 -本章从0开始介绍如何的正则化来应对[过拟合](underfit-overfit.md)问题。 +上一节中我们观察了过拟合现象,即模型的训练误差远小于它在测试数据集上的误差。本节将介绍应对过拟合问题的常用方法:正则化。 -## 高维线性回归 -我们使用高维线性回归为例来引入一个过拟合问题。 +## $L_2$范数正则化 + +在深度学习中,我们常使用$L_2$范数正则化,也就是在模型原先损失函数基础上添加$L_2$范数惩罚项,从而得到训练所需要最小化的函数。$L_2$范数惩罚项指的是模型权重参数每个元素的平方和与一个超参数的乘积。以[“单层神经网络”](../chapter_supervised-learning/shallow-model.md)一节中线性回归的损失函数$\ell(w_1, w_2, b)$为例($w_1, w_2$是权重参数,$b$是偏差参数),带有$L_2$范数惩罚项的新损失函数为 + +$$\ell(w_1, w_2, b) + \frac{\lambda}{2}(w_1^2 + w_2^2),$$ + +其中超参数$\lambda > 0$。当权重参数均为0时,惩罚项最小。当$\lambda$较大时,惩罚项在损失函数中的比重较大,这通常会使学到的权重参数的元素较接近0。当$\lambda$设为0时,惩罚项完全不起作用。 + +有了$L_2$范数惩罚项后,在小批量随机梯度下降中,我们将[“单层神经网络”](../chapter_supervised-learning/shallow-model.md)一节中权重$w_1$和$w_2$的迭代方式更改为 + +$$w_1 \leftarrow w_1 - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_1^{(i)} (x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}) - \lambda w_1,$$ +$$w_2 \leftarrow w_2 - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}}x_2^{(i)} (x_1^{(i)} w_1 + x_2^{(i)} w_2 + b - y^{(i)}) - \lambda w_2.$$ -具体来说我们使用如下的线性函数来生成每一个数据样本 -$$y = 0.05 + \sum_{i = 1}^p 0.01x_i + \text{noise}$$ +可见,$L_2$范数正则化令权重$w_1$和$w_2$的每一步迭代分别添加了$- \lambda w_1$和$- \lambda w_2$。因此,我们有时也把$L_2$范数正则化称为权重衰减(weight decay)。 -这里噪音服从均值0和标准差为0.01的正态分布。 +在实际中,我们有时也在惩罚项中添加偏差元素的平方和。假设神经网络中某一个神经元的输入是$x_1, x_2$,使用激活函数$\phi$并输出$\phi(x_1 w_1 + x_2 w_2 + b)$。假设激活函数$\phi$是ReLU、tanh或sigmoid,如果$w_1, w_2, b$都非常接近0,那么输出也接近0。也就是说,这个神经元的作用比较小,甚至就像是令神经网络少了一个神经元一样。上一节我们提到,给定训练数据集,过高复杂度的模型容易过拟合。因此,$L_2$范数正则化可能对过拟合有效。 -需要注意的是,我们用以上相同的数据生成函数来生成训练数据集和测试数据集。为了观察过拟合,我们特意把训练数据样本数设低,例如$n=20$,同时把维度升高,例如$p=200$。 +## 高维线性回归实验 + +下面,我们通过高维线性回归为例来引入一个过拟合问题,并使用$L_2$范数正则化来试着应对过拟合。我们先导入本节实验所需的包或模块。 ```{.python .input} %matplotlib inline @@ -25,25 +36,22 @@ from matplotlib import pyplot as plt from mxnet import autograd, gluon, nd ``` -```{.python .input n=1} -n_train = 20 -n_test = 100 -num_inputs = 200 -``` - ## 生成数据集 +对于训练数据集和测试数据集中特征为$x_1, x_2, \ldots, x_p$的任一样本,我们使用如下的线性函数来生成该样本的标签: -这里定义模型真实参数。 +$$y = 0.05 + \sum_{i = 1}^p 0.01x_i + \epsilon,$$ + +其中噪音项$\epsilon$服从均值为0和标准差为0.1的正态分布。为了较容易地观察过拟合,我们考虑高维线性回归问题,例如设维度$p=200$;同时,我们特意把训练数据集的样本数设低,例如20。 ```{.python .input n=2} +n_train = 20 +n_test = 100 + +num_inputs = 200 true_w = nd.ones((num_inputs, 1)) * 0.01 true_b = 0.05 -``` -我们接着生成训练和测试数据集。 - -```{.python .input n=3} 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) @@ -51,12 +59,6 @@ train_features, test_features = features[:n_train, :], features[n_train:, :] train_labels, test_labels = labels[:n_train], labels[n_train:] ``` -当我们开始训练神经网络的时候,我们需要不断读取数据块。这里我们定义一个函数它每次返回`batch_size`个随机的样本和对应的目标。我们通过python的`yield`来构造一个迭代器。 - -```{.python .input n=4} -batch_size = 1 -``` - ## 初始化模型参数 下面我们随机初始化模型参数。之后训练时我们需要对这些参数求导来更新它们的值,所以我们需要创建它们的梯度。 @@ -94,6 +96,7 @@ lr = 0.003 下面我们定义剩下的所需要的函数。这个跟之前的教程大致一样,主要是区别在于计算`loss`的时候我们加上了L2正则化,以及我们将训练和测试损失都画了出来。 ```{.python .input n=7} +batch_size = 1 net = gb.linreg loss = gb.squared_loss gb.set_fig_size(mpl) diff --git a/chapter_supervised-learning/underfit-overfit.md b/chapter_supervised-learning/underfit-overfit.md index 103800a88725ba91d617dbbcb95c3ccff3b61fbd..2cdd2c0005eab92ffb5ecd605d2eef2bfe940c05 100644 --- a/chapter_supervised-learning/underfit-overfit.md +++ b/chapter_supervised-learning/underfit-overfit.md @@ -52,11 +52,11 @@ from mxnet.gluon import data as gdata, loss as gloss, nn ### 生成数据集 -我们先生成一个人工数据集,这样我们将知道真实的模型参数。具体来说,我们使用如下三阶多项式函数来生成训练数据集和测试数据集里的每一个样本 +我们将生成一个人工数据集。在训练数据集和测试数据集中,给定样本特征$x$,我们使用如下的三阶多项式函数来生成的该样本的标签: $$y = 1.2x - 3.4x^2 + 5.6x^3 + 5 + \epsilon,$$ -其中噪音项$\epsilon$服从均值为0和标准差为0.1的正态分布。训练数据集和测试数据集的样本数都是100。 +其中噪音项$\epsilon$服从均值为0和标准差为0.1的正态分布。训练数据集和测试数据集的样本数都设为100。 ```{.python .input} n_train = 100 diff --git a/gluonbook/utils.py b/gluonbook/utils.py index 57fdfcf072a03ec80934783f0c84d1eddcc507a9..d0069d0330101bf6322f413839d9d49ee36cdcd5 100644 --- a/gluonbook/utils.py +++ b/gluonbook/utils.py @@ -3,7 +3,7 @@ import random from time import time import matplotlib as mpl -import matplotlib.pyplot as plt +from matplotlib import pyplot as plt import mxnet as mx from mxnet import autograd, gluon, image, nd from mxnet.gluon import nn, data as gdata, loss as gloss, utils as gutils