Skip to content

Commit

Permalink
Xiaowuhu/20200211 (microsoft#470)
Browse files Browse the repository at this point in the history
* refine Normalization text

* Update 05.6-标准化标签值.md

* fix bug

fix bug

* fix bug

* Update 11.1-非线性多分类实现.md
  • Loading branch information
xiaowuhu authored Mar 16, 2020
1 parent 24bfa16 commit 2d0bb66
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<!--Copyright © Microsoft Corporation. All rights reserved.
适用于[License](https://github.com/Microsoft/ai-edu/blob/master/LICENSE.md)版权许可-->

## 5.3 样本特征数据归一化
## 5.3 样本特征数据标准化

数据标准化(Normalization),又可以叫做数据归一化。

### 5.3.1 发现问题的根源

Expand All @@ -18,15 +20,15 @@
|3|0.855|4.643|
|...|...|...|

所有的X值(服务器数量除以1000后的值)都是在[0,1]之间的,而本章中的房价数据有两个特征值,一个是公里数,一个是平米数,全都是不是在[0,1]之间的,并且取值范围还不相同。我们不妨把本次样本数据也做一下这样的处理,亦即“归一化”。
所有的X值(服务器数量除以1000后的值)都是在[0,1]之间的,而本章中的房价数据有两个特征值,一个是公里数,一个是平米数,全都是不是在[0,1]之间的,并且取值范围还不相同。我们不妨把本次样本数据也做一下这样的处理,亦即“标准化”。

其实,数据归一化是深度学习的必要步骤之一,已经是大师们的必杀技能,也因此它很少被各种博客/文章所提及,以至于初学者们经常被坑。
其实,数据标准化是深度学习的必要步骤之一,已经是大师们的必杀技能,也因此它很少被各种博客/文章所提及,以至于初学者们经常被坑。

根据5.0.1中对数据的初步统计,我们是不是也可以把公里数都除以100,而平米数都除以1000呢,这样也会得到[0,1]之间的数字?公里数的取值范围是[2,22],除以100后变成了[0.02,0.22]。平米数的取值范围是[40,120],除以1000后变成了[0.04,0.12]

对本例来说这样做肯定是可以正常工作的,但是下面我们要介绍一种更科学合理的做法。

### 5.3.2 为什么要做归一化
### 5.3.2 为什么要做标准化

理论层面上,神经网络是以样本在事件中的统计分布概率为基础进行训练和预测的,所以它对样本数据的要求比较苛刻。具体说明如下:

Expand All @@ -36,65 +38,62 @@

4. 数值问题

归一化可以避免一些不必要的数值问题。因为激活函数sigmoid/tanh的非线性区间大约在[-1.7,1.7]。意味着要使神经元有效,线性计算输出的值的数量级应该在1(1.7所在的数量级)左右。这时如果输入较大,就意味着权值必须较小,一个较大,一个较小,两者相乘,就引起数值问题了。
标准化可以避免一些不必要的数值问题。因为激活函数sigmoid/tanh的非线性区间大约在[-1.7,1.7]。意味着要使神经元有效,线性计算输出的值的数量级应该在1(1.7所在的数量级)左右。这时如果输入较大,就意味着权值必须较小,一个较大,一个较小,两者相乘,就引起数值问题了。

5. 梯度更新

若果输出层的数量级很大,会引起损失函数的数量级很大,这样做反向传播时的梯度也就很大,这时会给梯度的更新带来数值问题。

6. 学习率

知道梯度非常大,学习率就必须非常小,因此,学习率(学习率初始值)的选择需要参考输入的范围,不如直接将数据归一化,这样学习率就不必再根据数据范围作调整。 对w1适合的学习率,可能相对于w2来说会太小,若果使用适合w1的学习率,会导致在w2方向上步进非常慢,会消耗非常多的时间,而使用适合w2的学习率,对w1来说又太大,搜索不到适合w1的解。
知道梯度非常大,学习率就必须非常小,因此,学习率(学习率初始值)的选择需要参考输入的范围,不如直接将数据标准化,这样学习率就不必再根据数据范围作调整。 对w1适合的学习率,可能相对于w2来说会太小,若果使用适合w1的学习率,会导致在w2方向上步进非常慢,会消耗非常多的时间,而使用适合w2的学习率,对w1来说又太大,搜索不到适合w1的解。

### 5.3.3 从损失函数等高线图分析归一化的必要性
### 5.3.3 从损失函数等高线图分析标准化的必要性

在房价数据中,地理位置的取值范围是[2,20],而房屋面积的取值范围为[40,120],二者相差太远,根本不可以放在一起计算了?

根据公式$z = x_1 w_1+x_2 w_2 + b$,神经网络想学习w1和w2,但是数值范围问题导致神经网络来说很难“理解”。图5-5展示了归一化前后的情况损失函数值的等高图,意思是地理位置和房屋面积取不同的值时,作为组合来计算损失函数值时,形成的类似地图的等高图,见图5-5,左侧为归一化前,右侧为归一化后
根据公式$z = x_1 w_1+x_2 w_2 + b$,神经网络想学习w1和w2,但是数值范围问题导致神经网络来说很难“理解”。图5-5展示了标准化前后的情况损失函数值的等高图,意思是地理位置和房屋面积取不同的值时,作为组合来计算损失函数值时,形成的类似地图的等高图,见图5-5,左侧为标准化前,右侧为标准化后

<img src="../Images/5/normalize.jpg" />

图5-5 归一化前后的损失函数等高线图的对比
图5-5 标准化前后的损失函数等高线图的对比

房屋面积的取值范围是[40,120],而地理位置的取值范围是[2,20],二者会形成一个很扁的椭圆,如左侧。这样在寻找最优解的时候,过程会非常曲折。运气不好的话,根本就没法训练。

### 5.3.4 归一化的基本概念

有三个类似的概念,归一化,标准化,中心化。

#### 归一化

把数据线性地变成[0,1][-1,1]之间的小数,把带单位的数据(比如米,公斤)变成无量纲的数据,区间缩放。
### 5.3.4 标准化的常用方法

归一化有三种方法:
- Min-Max标准化(离差标准化),将数据映射到[0,1]区间

1. Min-Max归一化:
$$x_{new}={x-x_{min} \over x_{max} - x_{min}} \tag{1}$$

2. 平均值归一化
- 平均值标准化,将数据映射到[-1,1]区间

$$x_{new} = {x - \bar{x} \over x_{max} - x_{min}} \tag{2}$$

3. 非线性归一化
- 对数转换
$$x_{new}=log(x_i) \tag{3}$$

对数转换:
$$y=log(x) \tag{3}$$
- 反余切转换
$$x_{new}=atan(x_i) \cdot 2/π \tag{4}$$

反余切转换:
$$y=atan(x) \cdot 2/π \tag{4}$$
- Z-Score法

#### 标准化
把每个特征值中的所有数据,变成平均值为0,标准差为1的数据,最后为正态分布。Z-Score规范化(标准差标准化 / 零均值标准化,其中std是标准差):

把每个特征值中的所有数据,变成平均值为0,标准差为1的数据,最后为正态分布。Z-score规范化(标准差标准化 / 零均值标准化,其中std是标准差):
$$x_{new} = (x_i - \bar{x})/std \tag{5}$$

$$x_{new} = (x - \bar{x})/std \tag{5}$$
- 中心化,平均值为0,无标准差要求

$$x_{new} = x_i - \bar{x} \tag{6}$$

#### 中心化
- 比例法,要求数据全是正值

$$
x_{new} = x_i / \sum_{i=1}^n{x_i} \tag{7}
$$

平均值为0,无标准差要求:
$$x_{new} = x - \bar{x} \tag{6}$$

### 5.3.5 如何做数据归一化
### 5.3.5 如何做数据标准化

我们再看看样本的数据,表5-5。

Expand All @@ -108,9 +107,9 @@ $$x_{new} = x - \bar{x} \tag{6}$$
|4|5.20|77|450.59|
|...|...|...|...|

按照归一化的定义,我们只要把地理位置列和居住面积列分别做归一化就达到要求了,结果如表5-6。
按照标准化的定义,我们只要把地理位置列和居住面积列分别做标准化就达到要求了,结果如表5-6。

表5-6 归一化后的样本数据
表5-6 标准化后的样本数据

|样本序号|地理位置|居住面积|价格(万元)|
|---|---|---|---|
Expand All @@ -122,8 +121,8 @@ $$x_{new} = x - \bar{x} \tag{6}$$

注意:

1. 我们并没有归一化样本的标签Y数据,所以最后一行的价格还是保持不变
2. 我们是对两列特征值分别做归一化处理的
1. 我们并没有标准化样本的标签Y数据,所以最后一行的价格还是保持不变
2. 我们是对两列特征值分别做标准化处理的

### 5.3.6 代码实现

Expand All @@ -134,7 +133,7 @@ $$x_{new} = x - \bar{x} \tag{6}$$
......
```

返回值X_new是归一化后的样本,和原始数据的形状一样。
返回值X_new是标准化后的样本,和原始数据的形状一样。

再把主程序修改一下,在ReadData()方法后,紧接着调用NormalizeX()方法:

Expand Down Expand Up @@ -206,7 +205,7 @@ Z&= -14.714 \times 15 + 395.847 \times 93 + 242.152 \\
\end{aligned}
$$

好吧,我们遇到了天价房!这是怎么回事儿?难道和我们做数据归一化有关系
好吧,我们遇到了天价房!这是怎么回事儿?难道和我们做数据标准化有关系

### 5.3.8 工作原理

Expand All @@ -224,7 +223,7 @@ def ShowResult(net, reader):
1. 为什么要在[0,1]空间中形成50x50的网格呢?
2. 50这个数字从哪里来的?

NumPy库的np.linspace(0,1)的含义,就是在[0,1]空间中生成50个等距的点,第三个参数不指定时,缺省是50。因为我们前面对样本数据做过归一化,统一到了[0,1]空间中,这就方便了我们对问题的分析,不用考虑每个特征值的实际范围是多大了。
NumPy库的np.linspace(0,1)的含义,就是在[0,1]空间中生成50个等距的点,第三个参数不指定时,缺省是50。因为我们前面对样本数据做过标准化,统一到了[0,1]空间中,这就方便了我们对问题的分析,不用考虑每个特征值的实际范围是多大了。

表5-7 三维空间线性拟合的可视化

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ params = HyperParameters(eta=0.01, max_epoch=50, batch_size=10, eps=1e-5)
|神经网络|-40.2|399.3|244.5|
|比值|19.92|78.99|5.288|

再列出归一化后的数据,如表5-9。
再列出标准化后的数据,如表5-9。

表5-9 归一化后的特征值
表5-9 标准化后的特征值

|特征|地理位置|居住面积|
|----|----|---|
Expand All @@ -72,9 +72,9 @@ params = HyperParameters(eta=0.01, max_epoch=50, batch_size=10, eps=1e-5)

### 5.4.2 还原真实的W,B值

我们唯一修改的地方,就是样本数据特征值的归一化,并没有修改标签值。可以大概猜到W的值和样本特征值的缩放有关系,而且缩放倍数非常相似,甚至可以说一致。下面推导一下这种现象的数学基础。
我们唯一修改的地方,就是样本数据特征值的标准化,并没有修改标签值。可以大概猜到W的值和样本特征值的缩放有关系,而且缩放倍数非常相似,甚至可以说一致。下面推导一下这种现象的数学基础。

假设在归一化之前,真实的样本值是$X$,真实的权重值是$W$;在归一化之后,样本值变成了$X'$,训练出来的权重值是$W'$:
假设在标准化之前,真实的样本值是$X$,真实的权重值是$W$;在标准化之后,样本值变成了$X'$,训练出来的权重值是$W'$:

$$
y = x_1 w_1 + x_2 w_2 + b \tag{y是标签值}
Expand All @@ -84,14 +84,14 @@ $$
z = x_1' w_1' + x_2' w_2' + b' \tag{z是预测值}
$$

由于训练时标签值(房价)并没有做归一化,意味着我们是用真实的房价做的训练,所以预测值和标签值应该相等,所以:
由于训练时标签值(房价)并没有做标准化,意味着我们是用真实的房价做的训练,所以预测值和标签值应该相等,所以:
$$
y == z $$
$$
x_1 w_1 + x_2 w_2 + b = x_1' w_1' + x_2' w_2' + b' \tag{1}
$$

归一化的公式是
标准化的公式是
$$
x' = {x - x_{min} \over x_{max}-x_{min}} \tag{2}
$$
Expand Down Expand Up @@ -145,7 +145,7 @@ def DeNormalizeWeightsBias(net, dataReader):
return W_real, B_real
```

X_Norm是我们在做归一化时保留下来的样本的两个特征向量的最小值和数值范围(最大值减去最小值)。
X_Norm是我们在做标准化时保留下来的样本的两个特征向量的最小值和数值范围(最大值减去最小值)。

修改主程序如下:

Expand All @@ -166,7 +166,7 @@ if __name__ == '__main__':

ShowResult(net, reader)
```
在net.train()方法返回之后,训练好的W和B的值就保存在NeuralNet类的属性里了。然后通过调用DeNormalizeWeightsBias()函数,把它们转换成真实的W_real和B_real值,就好比我们不做归一化而能训练出来的权重值一样
在net.train()方法返回之后,训练好的W和B的值就保存在NeuralNet类的属性里了。然后通过调用DeNormalizeWeightsBias()函数,把它们转换成真实的W_real和B_real值,就好比我们不做标准化而能训练出来的权重值一样

最后在推理预测时,我们直接使用了np.dot()公式,而没有使用net.inference()方法,是因为在net实例中的W和B是还原前的值,做前向计算时还是会有问题,所以我们直接把前向计算公式拿出来,代入W_real和B_real,就可以得到真实的预测值了。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

## 5.5 正确的推理预测方法

### 5.5.1 预测数据的归一化
### 5.5.1 预测数据的标准化

在上一节中,我们在用训练出来的模型预测房屋价格之前,还需要先还原W和B的值,这看上去比较麻烦,下面我们来介绍一种正确的推理方法。

既然我们在训练时可以把样本数据归一化,那么在预测时,把预测数据也做相同方式的归一化,不是就可以和训练数据一样进行预测了吗?且慢!这里有一个问题,训练时的样本数据是批量的,至少是成百成千的数量级。但是预测时,一般只有一个或几个数据,如何做归一化
既然我们在训练时可以把样本数据标准化,那么在预测时,把预测数据也做相同方式的标准化,不是就可以和训练数据一样进行预测了吗?且慢!这里有一个问题,训练时的样本数据是批量的,至少是成百成千的数量级。但是预测时,一般只有一个或几个数据,如何做标准化

我们在针对训练数据做归一化时,得到的最重要的数据是训练数据的最小值和最大值,我们只需要把这两个值记录下来,在预测时使用它们对预测数据做归一化,这就相当于把预测数据“混入”训练数据。前提是预测数据的特征值不能超出训练数据的特征值范围,否则有可能影响准确程度。
我们在针对训练数据做标准化时,得到的最重要的数据是训练数据的最小值和最大值,我们只需要把这两个值记录下来,在预测时使用它们对预测数据做标准化,这就相当于把预测数据“混入”训练数据。前提是预测数据的特征值不能超出训练数据的特征值范围,否则有可能影响准确程度。

### 5.5.2 代码实现

Expand All @@ -36,7 +36,7 @@ X_norm数组中的数据,是在训练时从样本数据中得到的最大值
|特征值1|2.02|21.96-2.02=19.94|
|特征值2|40|119-40=79|

所以,最后X_new就是按照训练样本的规格归一化好的预测归一化数据,然后我们把这个预测归一化数据放入网络中进行预测
所以,最后X_new就是按照训练样本的规格标准化好的预测标准化数据,然后我们把这个预测标准化数据放入网络中进行预测

```Python
import numpy as np
Expand Down Expand Up @@ -74,7 +74,7 @@ Z= [[486.16645199]]
```
z= 486.1051325196855
```
二者非常接近,可以说这种方法的确很方便,把预测数据看作训练数据的一个记录,先做归一化,再做预测,这样就不需要把权重矩阵还原了。
二者非常接近,可以说这种方法的确很方便,把预测数据看作训练数据的一个记录,先做标准化,再做预测,这样就不需要把权重矩阵还原了。

看上去我们已经完美地解决了这个问题,但是且慢,仔细看看loss值,还有w和b的值,都是几十几百的数量级,这和神经网络的概率计算的优点并不吻合,实际上它们的值都应该在[0,1]之间的。

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!--Copyright © Microsoft Corporation. All rights reserved.
适用于[License](https://github.com/Microsoft/ai-edu/blob/master/LICENSE.md)版权许可-->

## 5.6 对标签值归一化
## 5.6 对标签值标准化

### 5.6.1 发现问题

这一节里我们重点解决在训练过程中的数值的数量级的问题。

我们既然已经对样本数据特征值做了归一化,那么如此大数值的损失函数值是怎么来的呢?看一看损失函数定义:
我们既然已经对样本数据特征值做了标准化,那么如此大数值的损失函数值是怎么来的呢?看一看损失函数定义:

$$
J(w,b)=\frac{1}{2m} \sum_{i=1}^m (z_i-y_i)^2 \tag{1}
Expand Down Expand Up @@ -37,11 +37,11 @@ array([[-443.04543906]])

这么大的数值,需要把学习率设置得很小,比如0.001,才可以落到[0,1]区间,但是损失函数值还是不能变得很小。

如果我们像对特征值做归一化一样,把标签值也归一化到[0,1]之间,是不是有帮助呢?
如果我们像对特征值做标准化一样,把标签值也标准化到[0,1]之间,是不是有帮助呢?

### 5.6.2 代码实现

参照X的归一化方法,对Y的归一化公式如下
参照X的标准化方法,对Y的标准化公式如下

$$y_{new} = \frac{y-y_{min}}{y_{max}-y_{min}} \tag{2}$$

Expand All @@ -67,14 +67,14 @@ class SimpleDataReader(object):
- 最小值:181.38
- 平均值:420.64

归一化后,Y的数值范围是:
标准化后,Y的数值范围是:
- 最大值:1.0
- 最小值:0.0
- 平均值:0.485

注意,我们同样记住了Y_norm的值便于以后使用。

修改主程序代码,增加对Y归一化的方法调用NormalizeY():
修改主程序代码,增加对Y标准化的方法调用NormalizeY():

```Python
# main
Expand Down Expand Up @@ -103,9 +103,9 @@ z= [[0.61707273]]

虽然W和B的值都已经处于[-1,1]之间了,但是z的值也在[0,1]之间,一套房子不可能卖0.61万元!

聪明的读者可能会想到:既然对标签值做了归一化,那么我们在得到预测结果后,需要对这个结果应该做反归一化
聪明的读者可能会想到:既然对标签值做了标准化,那么我们在得到预测结果后,需要对这个结果应该做反标准化

根据公式2,反归一化的公式应该是
根据公式2,反标准化的公式应该是

$$y = y_{new}*(y_{max}-y_{min})+y_{min} \tag{3}$$

Expand Down Expand Up @@ -147,21 +147,21 @@ Z_real= [[486.33591769]]

总结一下从本章中学到的正确的方法:

1. X必须归一化,否则无法训练;
2. Y值不在[0,1]之间时,要做归一化,好处是迭代次数少;
3. 如果Y做了归一化,对得出来的预测结果做关于Y的反归一化
1. X必须标准化,否则无法训练;
2. Y值不在[0,1]之间时,要做标准化,好处是迭代次数少;
3. 如果Y做了标准化,对得出来的预测结果做关于Y的反标准化

至此,我们完美地解决了北京通州地区的房价预测问题!

### 5.6.4 总结

归纳总结一下前面遇到的困难及解决办法:

1. 样本不做归一化的话,网络发散,训练无法进行;
2. 训练样本归一化后,网络训练可以得到结果,但是预测结果有问题;
1. 样本不做标准化的话,网络发散,训练无法进行;
2. 训练样本标准化后,网络训练可以得到结果,但是预测结果有问题;
3. 还原参数值后,预测结果正确,但是此还原方法并不能普遍适用;
4. 归一化测试样本,而不需要还原参数值,可以保证普遍适用;
5. 归一化标签值,可以使得网络训练收敛快,但是在预测时需要把结果反归一化,以便得到真实值。
4. 标准化测试样本,而不需要还原参数值,可以保证普遍适用;
5. 标准化标签值,可以使得网络训练收敛快,但是在预测时需要把结果反标准化,以便得到真实值。

### 代码位置

Expand Down
Loading

0 comments on commit 2d0bb66

Please sign in to comment.