小言_互联网的博客

李宏毅 机器学习 2016 秋:2、Regression

348人阅读  评论(0)

二、Regression: Case Study

我们今天要讲的是 Regression,等一下我会举一个例子,来讲 Regression 是怎么做的,顺便引出一些 machine learning 里面,常见的重要观念。

那 regression 可以做什么?除了预测 PM2.5 这个任务以外,还有很多其他非常有用的 task。

举例来说,,如果你可以做一个股票预测的系统,如果你可以做一个股票预测的系统,你要做的事情就是找一个function,这个 function 的 input 可能是过去十年各种股票起伏的资料,或者是 A 公司并购 B 公司,B 公司并购 C 公司等等的资料。你希望这个 function 在 input 这些资料以后,,它的 output 是明天的道琼工业指数的点数。如果你可以预测这个的话,你就发了。

还有别的 task,比如说现在很热门的无人车、自动车。这个自动车也可以想成是一个 regression 的 problem,在这个 regression 的 problem 里面,input就是你的无人车所看到的各种 sensor,它的红外线感测的 sensor,它的影像的视讯的镜头所看到的马路上的东西等等。你的 input 就是这些 information,,output 就是方向盘的角度,比如说,要左转 50 度,还是右转 50 度,右转 50 度你就当作左转负 50 度,所以 output 也是一个 scalar。所以无人车驾驶就是一个 regression problem。input 一些 information,output 就是方向盘的角度,它是一个数值。

或者是,你可以做推荐系统。我们都知道说,YouTube 要推荐影片或者 Amazon 要推荐商品给你,那推荐系统它要做的事情,也可以想成是一个 regression 的问题。就是找一个 function,它的 input 是某一个使用者 A 和某一个商品 B,它的 output 就是使用者 A 购买商品B的可能性。如果你可以找到这样一个 function,它可以精确的预测说,使用者 A 购买商品 B 的可能性的话,那 Amazon 就会推荐使用者 A 他最有可能购买的商品。

这个是regression 的种种应用,今天我要讲的是另外一个我觉得更实用的应用,就是预测宝可梦的 CP 值。你的CP 值就是一只宝可梦的战斗力。你抓到一隻宝可梦后,比如说,这个是一只妙蛙种子,然后你给他吃一些星辰或糖果以后,他就会进化成妙蛙草,而如果他进化成妙蛙草以后,他的 CP 值就变了。为什么我们会希望能够预测宝可梦的 CP 值呢?因为如果你可以精确的预测一只宝可梦在进化以后的 CP 值的话,你就可以评估说,你是否要进化这只宝可梦。如果他是一只 CP 值比较低的宝可梦的话,你可能就把他拿去做糖果,你就不进化他,这样你就可以节省一些你的糖果的资源。你可能就会问说,为什么我们要节省糖果的资源?因为你这样可以在比较短时间内,就进化比较多强的神奇宝贝。你就会想说为什么我们要比较强的宝可梦?因为他可以去打道馆,你问为什么我们要去打道馆?其实我也不知道为什么要这样。

我们今天要做的事情,就是找一个 function。这个 function 的 input,就是某一只宝可梦,它的 output 就是这只宝可梦如果我们把它进化以后,它的 CP 值的数值是多少。这是一个 regression 的 problem,我们的 input 就是某一只宝可梦所有相关的 information,比如说,我们把一只宝可梦用 x x x 表示,它的 CP 值我们就用 x c p x_{cp} xcp 来表示。我们用下标来表示某一个完整的东西里面的某一个 component。 x c p x_{cp} xcp 代表某一只宝可梦 x x x,它在进化前的CP 值。比如说,这个妙蛙种子,它 CP 值是 14, x s x_s xs 代表这一只宝可梦 x x x,是属于哪一个物种,比如说这是妙蛙种子, x h p x_{hp} xhp 代表这一只宝可梦它的 hp 值是多少,它的生命值是多少,这个妙蛙种子的生命值是 10。 x w x_w xw 代表它的重量, x h x_h xh 代表它的高度,可以看看你抓的宝可梦是不是特别大只或特别小只,那 output 是进化后的 CP,这个进化后的 CP 值,就是一个数值,就是一个scalar,我们把它用 y y y 来表示。

怎么解这个问题呢?做 machine learning 就是三个步骤,第一个步骤就是,找一个 model,model 就是一个function set,第二个步骤就是,定义 function set 里面某一个 function,我们拿一个 function 出来,可以要evaluate 它的好坏;第三步骤就是找一个最好的 function。

首先我们就从第一个步骤开始,我们要找一个 function set,这个 function set 就是所谓的 model。在这个 task 里面,我们的 function set,应该长什么样子呢?input 一只宝可梦,output 进化后的 CP 值的 function,应该长什么样子呢?这边就先乱写一个简单的,比如说我们认为说,进化后的 CP 值 y y y,等于某一个常数项 b b b,加上某一个数值 w w w 乘上现在输入的宝可梦的 x x x,它在进化前的 CP 值,这个 x c p x_{cp} xcp 代表进化前的 CP 值,这个 y y y 是进化后的 CP 值。这个 w w w b b b 是参数, w w w b b b 可以是任何的数值。在这个 model 里面, w w w b b b 是未知的,你可以把任何的数字填进去,填进不同的数值,你就得到不同的 function。

比如说你可以有一个 f 1 f_1 f1 f 1 f_1 f1 b = 10 , w = 9 b=10, w=9 b=10,w=9,你可以有另外一个 function f 2 f_2 f2,这个 f 2 f_2 f2 b = 9.8 , w = 9.2 b=9.8, w=9.2 b=9.8,w=9.2,你有一个 f 3 f_3 f3,它是 b = − 0.8 , w = − 1.2 b= -0.8, w=-1.2 b=0.8,w=1.2,如果今天你的 w w w b b b 可以代任何值的话,其实你这个function set 里面,可以有无穷多的 function。你用这个式子 y = b + w × x c p y=b+w \times x_{cp} y=b+w×xcp 代表这些 function 所成的集合。

当然在这些 function 里面,比如说 f 1 , f 2 , f 3 f_1, f_2, f_3 f1,f2,f3 里面,你会发现有一些 function 显然不太可能是正确的,比如说 f 3 f_3 f3 不太可能是正确的。因为我们知道说 CP 值其实是正,乘以 − 1.2 -1.2 1.2 就变成是负的,所以进化以后 CP 值就变成是负的,这样显然是说不通的。这个就是我们等一下要用靠 training data 来告诉我们说,在这个 function set 里面,哪一个 function 才是合理的 function。

这个 y = b + w × x x p y=b+w \times x_{xp} y=b+w×xxp 这样子的 model,它是一种 linear 的 model。所谓的 linear 的 model 的意思是,简单来说,如果我们可以把一个 function,写成 y = b + ∑ w i x i y=b+\sum w_ix_i y=b+wixi,那它是一个 linear 的 function。这边的 x i x_i xi 指的是你 input 的 x x x 的各种 attribute,比如说你 input 宝可梦的各种不同的属性,比如说身高或体重等等。这些东西我们叫做 feature。从 input 的 object 里面抽出来的各种数值当作 function 的 input,这些东西叫做 feature,这个 w i w_i wi i叫做 weight,这个 b b b 叫做 bias。

接下来我们要收集 training data,才能够找这个 function。这是一个 supervised learning 的 task,所以我们收集的是 function 的 input 和 function 的 output。因为是 regression 的 task,所以 function 的 output 是一个数值。

举例来说,你就抓了一只这个是杰尼龟,它进化后这个是卡咪龟,卡咪龟进化是水箭龟。这个 function 的 input 在这边就是这只杰尼龟。那我们用 x 1 x^1 x1 来表示它,我们用上标来表示一个完整的 object 的编号。刚才我们有看到用下标来表示一个完整 object 里面的 component。我们用上标来表示一个完整 object 的编号,所以这是第一个 x x x,这是一只杰尼龟,那它进化以后的 CP 是 973,所以我们 function 的 output,应该看到 x 1 x^1 x1 就 output 数值 973,那这个 973 我们用 y ^ 1 \hat{y}^1 y^1 来代表,这边用 y y y 来代表 function 的 output,用上标来代表一个完整的个体。因为我们今天考虑的 output 是 scalar,所以它其实里面没有 component,它就是一个简单的数值,但是我们未来如果在考虑 structured learning 的时候,,我们 output 的 object 可能是有 structure 的,所以我们还是会需要上标下标来表示一个完整的 output 的 object,还有它里面的 component。我们用 y ^ 1 \hat{y}^1 y^1 来表示这个数值979。

只有一只不够要收集很多,比如说再抓一只伊布,那这个伊布就是 x 2 x^2 x2,那它进化以后可以变成雷精灵,那雷精灵的 CP 值是 1420,这个 1420 就是 y ^ 2 \hat{y}^2 y^2。,我们用 hat 来代表说这个是一个正确的值,是我们实际观察到 function 该有的 output,你可能以为说这只是个例子,这不只是一个例子,我是有真正的 data 的,今天其实我是想要发表,我在神奇宝贝上面的研究成果这样。

data source:: https://www.openintro.org/stat/data/?data=pokemon

那我们就收集 10 只神奇宝贝,这 10 只宝可梦就是从编号 1 到编号 10,每一只宝可梦我们都让它进化以后,我们就知道它进化后的 CP 值,就是 y ^ 1 \hat{y}^1 y^1 y ^ 10 \hat{y}^{10} y^10 ,这个是真正的 data,你可能会问说怎么只抓 10 只呢?你不知道抓这个很麻烦吗?其实老实说这也不是我自己抓的,网路上有人分享他抓出来的数据,我拿他的数据来做一下,其实他也没有抓太多次,因为抓这个其实是很麻烦的,并不是抓来就好,你要把它进化以后,你才知道 function 的output 是多少。所以收集这个 data 并没有那么容易。所以就收集了10 只神奇宝贝。

那如果我们把这十只神奇宝贝的 information 画出来的话,这个图上每一个蓝色的点,代表一只宝可梦。然后他的 x x x 轴代表的是这一只宝可梦他的 CP 值,这个我们一抓来的时候我们就知道了,然后他的 y y y 轴代表如果你把这只宝可梦进化以后,进化后的 CP值,这个用 y ^ \hat{y} y^ 来表示。所以 10 只宝可梦,这边我们有 10 个点,这个 CP 值其实就特别高,这只其实是伊布,伊布其实不是很容易抓的,这边每一个点就是某第 n n n 只宝可梦的 CP 值跟它进化以后的 y ^ \hat{y} y^。那我们用 x c p n x^{n}_{cp} xcpn 来代表第 n n n 笔 data,他的某一个 component,也就是他的 CP 值。

接下来,有了这些 training data 以后,我们就可以定义一个 function 的好坏,我们就可以知道一个 function 是多好或者是多不好,怎么做呢?

我们这里定了一个 function set,这里面有一大堆的 function,这边我们要再定另外一个 function 叫做 loss function,我们写成大写的 L L L。他是一个很特别 function,这个 loss function 他是 function 的 function,大家知道今天我的意思吗?他的 input 就是一个 function,他的 output 就是一个数值告诉我们说,现在 input 的这个function 他有多不好,我们这边是用多不好来表示,所以这个 loss function 他是一个 function 的 function,他就是吃一个 function 当作 input,他的 output 就是这个 function 有多不好。所以你可以写成这样,这个 L L L,他的 input 就是某一个function f f f,你知道一个 function,他又是由这个 function 里面的两个参数 b b b w w w 来决定的,所以 input 这个 f f f,就等于 input 这个 f f f 里面的 b b b w w w,所以你可以说 loss function,他是在衡量一组参数的好坏,衡量一组 b b b w w w 的好坏。

那怎么定这个 loss function 呢?loss function 你其实可以随自己的喜好,定义一个你觉得合理的 function,不过我们这边就用比较常见的作法,怎么定呢?你就把这个 input 的 w w w b b b,实际地代入 y = b + w × x c p y=b+w \times x_{cp} y=b+w×xcp 这个 function 里面,你把 w w w 乘上第 n n n 只宝可梦的 CP 值,再加上这个 constant b b b,然后你就得到说,如果我们使用这一组 w w w b b b 来当作我们的 function,来预测宝可梦它进化以后的 CP 值的话,这个预测的值 y y y 的数值是多少。这个里面比较小的括号,他输出的数值是我们用现在的 function 来预测的话,我们得到的输出是什么。那 y ^ \hat{y} y^ 是真正的数值。我们把真正的数值,减掉预测的数值,再取平方,这个就是估测的误差。我们再把我们手上的 10只宝可梦的估测误差都合起来,就得到这个 loss function。那这个定义我相信你是不太会有问题的,因为它非常的直觉估测,如果我使用某一个 function,它给我们的估测误差越大,那当然这个 function 就越不好。所以我们就用估测误差来定义一个 loss function。当然你可以选择其他可能性。

再来我们有了这个 loss function 以后,如果你还是有一些困惑的话,我们可以把这个 loss function 的形状画出来。这个 loss function L ( w , b ) L(w,b) L(w,b),它 input 就是两个参数 w w w b b b,所以我们可以把这个 L ( w , b ) L(w,b) L(w,b) w w w b b b 把它做图画出来。在这个图上的每一个点,就代表着一个组 w w w b b b,也就是代表某一个 function。比如说,红色这个点就代表这个 b = − 180 , w = − 2 b=-180,w=-2 b=180w=2 的时候所得到的 function,就 y = − 180 − 2 × x c p y= -180−2 \times x_{cp} y=1802×xcp 这个 function。这图上每一个点都代表著一个 function,颜色代表了现在如果我们使用这个 function,根据我们定义的 loss function,它有多糟糕,它有多不好。这个颜色越偏红色代表数值越大,所以在这一群的 function,他们 loss 非常大,也就是它们是一群不好的 function。最好的 function 落在哪里呢?越偏蓝色代表那一个 function 越好,所以最好的 function其实落在这个位子。如果你选这个 function 的话,它是可以让你 loss 最低的一个 function。我们已经定好了我们的 loss function,接下来,我们可以衡量我们的 model 里面每一个 function 的好坏。接下来我们要做的事情就是从这个 function set 里面,挑选一个最好的 function。所谓挑选最好的 function 这一件事情,如果你想要把它写成 formulation 的话,写成 equation 的话,那写起来是什么样子呢?

它写起来就是,我们定的那个 loss function 长这样,那你要找一个 f f f,它可以让 L ( f ) L(f) L(f) 最小,这个可以让 L ( f ) L(f) L(f) 最小的 function,我们就写成 f ∗ f^* f。或者是,我们知道 f f f 是由两个参数 w w w b b b 表示,今天要做的事情就是,穷举所有的 w w w b b b,看哪一个 w w w b b b 代入 L ( w , b ) L(w,b) L(w,b),可以让这个 loss 的值最小。那这一个 w w w b b b 就是最好的 w w w b b b,那么写成 w ∗ w^* w b ∗ b^* b。或者是我们把 L L L 这个 function 列出来, L L L 这个 function 我们知道它长的就是这个样子,那我们就是把 w w w b b b,用各种不同的数值代到这个 function 里面,看哪一组 w w w b b b,可以给我们最好的结果。

如果你修过线性代数的话,其实这个对你来说应该完全不是问题,对不对?这个是有 closed-form solution 的,像我相信你可能不记得它长什么样子了,所谓的 closed-form solution 意思是说,你只要把 10 只宝可梦的 CP 值,跟他们进化后的 y ^ \hat{y} y^,你只要把这些数值代到某一个 function 里面,它 output 就可以告诉你最好的 w w w b b b 是什么。如果你修过线代的话,其实你理论上是应该是知道要怎么做的。我假设你已经忘记了,那我们要教你另外一个做法,这个做法叫做 gradient descent。

这边要强调的是,gradient descent 不是只适用于解这一个 function,解这一个 function 是比较容易的,你有修过线代你其实就会了。但是 gradient descent 它厉害的地方是,只要你这个 L L L 是可微分的,不管它是什么function,gradient descent 都可以拿来处理这个 function,都可以拿来帮你找可能是比较好的 function 或者是参数。

那我们来看一下 gradient descent 是怎么做?我们先假设一个比较简单的 task,在这个比较简单的 task 里面,我们的 loss function L ( w ) L(w) L(w),它只有一个参数 w w w。那这个 L ( w ) L(w) L(w) 必然是不需要是我们之前定出来的那个 loss function,它可以是任何 function,只要是可微分的就行了。

那我们现在要解的问题是找一个 w w w,让这个 L ( w ) L(w) L(w) 最小,这件事情怎么做呢?那暴力的方法就是,穷举所有 w w w 可能的数字,把所有 w w w 可能的数值,从负无限大到无限大,一个一个值都代到 loss function 里面去,试一下这个 loss function 的 value,你就会知道说哪一个 w w w 的值,可以让 loss 最小。如果你做这件事的话,你就会发现说,比如说这里这个 w w w 的值,可以让 loss 最小。但是这样做是没有效率的,怎么做比较有效率呢?这就是 gradient descent 要告诉我们的。

这个作法是这样子的:我们首先随机选取一个初始的点,比如这边随机选取的是 w 0 w^0 w0,其实你也不一定要随机选取,其实有可能有一些其他的方法,可以让你找的值是比较好的,这个之后再提。现在就想成是,随机选取一个初始的点 w 0 w^0 w0,接下来,在这个初始的 w 0 w^0 w0 这个位置,我们去计算一下 w w w 这个参数,我们要计算在 w = w 0 w=w^0 w=w0 这个位置,参数 w w w 对 loss function 的微分。

如果你对微分不熟的话,反正我们这边要找的就是切线斜率。如果今天切线斜率是负的的话,显然左边 loss 是比较高的,右边 loss 是比较低的,那我们要找 loss 比较低的 function,所以你应该增加 w 0 w^0 w0 值,反之,如果今天算出来的斜率是正的,代表跟这条虚线反向,也就是右边高左边低的话,那我们显然应该减少 w w w 的值,把我们的参数往左边移动,把我们的参数减小。

或者是,假如你对微分也不熟切线也不熟的话,那你就想成是有一个人站在 w 0 w^0 w0 这个点,他往前后各窥视了一下,看一下他往左边走一步 loss 会减少,还是往右边走一步 loss 会减少,如果往右边走一步 loss 会减少的话,那他就会往右边走一步。总之在这个例子里面,我们的参数是增加的,会往右边移动。

那怎么增加呢,应该要增加多少呢?这边的增加量,我们写成有关 gradient descent 的 theory,我们留到下次再讲,我们今天就讲一下它的操作是什么样子。

如果我们往右边踏一步的话,应该要踏多少呢?这个踏一步的 step size,取决于两件事。第一件事情是现在的微分值有多大。现在的 d L / d w dL/dw dL/dw 有多大,如果微分值越大,代表现在在一个越陡峭的地方,那它的移动的距离就越大,反之就越小。那还取决于另外一件事情,这个另外一件事情,是一个常数项 η \eta η,我们把它叫做 learning rate。这个 learning rate 决定说,我们今天踏一步,不只是取决于我们现在微分值算出来有多大,还取决于我们一个事先就定好的数值。这个 learning rate 是一个事先定好的数值,如果这个事先定好的数值你给它定大一点的话,那今天踏出一步的时候,参数更新的幅度就比较大,反之参数更新的幅度就比较小。如果参数更新的幅度比较大的话,你 learning rate大一点的话,那学习的效率,学习的速度就比较快。所以这个参数 η \eta η,我们就称之为 learning rate。

所以,现在我们已经算出,在 w 0 w^0 w0 这个地方,我们应该把参数更新 η \eta η 乘上 d L / d w dL/dw dL/dw,所以你就把原来的参数 w 0 w^0 w0 减掉 η \eta η 乘以 d L / d w dL/dw dL/dw,这边会有一项减的,因为如果我们这个微分算出来是负的的话,要增加这个 w w w 的值,如果算出来是正的的话,要减少 w w w 的值,所以这一项微分值,跟我们的增加减少是反向的,所以我们前面需要乘以一个负号。

那我们把 w 0 w^0 w0 更新以后,变成 w 1 w^1 w1,接下来就是重复刚才看到的步骤,重新去计算一次在 w = w 1 w=w^1 w=w1 这个地方所算出来的微分值。假设这个微分值算出来是这样子的,,这个微分值仍然建议我们,应该往右移动我们的参数,只是现在移动的幅度,可能是比较小的,因为这个微分值,相较于前面这一项,是比较小的。那你就把 w 1 − η ⋅ d L / d w w^1−\eta \cdot dL/dw w1ηdL/dw,然后变成 w 2 w^2 w2。那这个步骤就反覆不断地执行下去,经过非常非常多的 iteration 后,假设经过 t t t 次的更新,这个 t t t 是一个非常大的数字,最后你会到一个 local minimum 的地方。所谓 local minimum 的地方,就是这个地方的微分是 0,所以你接下来算出的微分都是 0 了,所以你的参数接下来就会卡在这边,没有办法再更新了。

这件事情你可能会觉得不太高兴,因为这边其实有一个 local minimum,你找出来的跟 gradient descent 找出来的 solution,它其实不是最佳解。你只能找到 local minimum,你没有办法找到 global minimum。但幸运的是,这件事情在 regression 上面,不是一个问题。因为在 regression 上面,在 linear regression 上面,它是没有 local minimum,等下这种事情我们会再看到。

今天我们刚才讨论的是,只有一个参数的情形,那如果是有两个参数呢?我们今天真正要处理的事情,是有两个参数的问题,也就是 w w w b b b

从一个参数推广到两个参数,其实是没有任何不同的。首先你就随机选取两个初始值, w 0 w^0 w0 b 0 b^0 b0,接下来你就计算在 w = w 0 , b = b 0 w=w^0, b=b^0 w=w0,b=b0 的时候, w w w 对 loss 的偏微分,你在计算 w = w 0 , b = b 0 w=w^0, b=b^0 w=w0,b=b0 的时候, b b b L L L 的偏微分。接下来,你计算出这两个偏微分之后,你就分别去更新 w 0 w^0 w0 b 0 b^0 b0 这两个参数,你就把 w 0 w^0 w0 减掉 η \eta η 乘上 w w w L L L 的偏微分得到 w 1 w^1 w1。你就把 b 0 b^0 b0 减掉 η \eta η 乘上 b b b L L L 的偏微分得到 b 1 b^1 b1。这个步骤你就反复的持续下去,接下来,你算出 b 1 b^1 b1 w 1 w^1 w1 以后,你就再计算一次 w w w L L L 的偏微分,只是现在是计算 w = w 1 , b = b 1 w=w^1, b=b^1 w=w1,b=b1 时候的偏微分。接下来你有了 w 1 w^1 w1 b 1 b^1 b1 以后,你就计算 w 1 w^1 w1 b 1 b^1 b1 w = w 1 , b = b 1 w=w^1,b=b^1 w=w1,b=b1 的时候, w w w L L L 的偏微分,还有 w 1 w^1 w1 b 1 b^1 b1 w = w 1 , b = b 1 w=w^1,b=b^1 w=w1,b=b1 的时候, b b b L L L 的偏微分。接下来你就更新参数,你就把 w 1 w^1 w1 减掉 η \eta η 乘上算出来的微分值,你就得到 w 2 w^2 w2。你把 b 1 b^1 b1 减掉 η \eta η 乘上微分值就得到 b 2 b^2 b2。你就反复进行这个步骤,最后你就可以找到一个 loss 相对比较小的 w w w 值跟 b b b 的值。

这边要补充说明的是,所谓的 gradient descent 的 gradient 指的是什么呢?其实 gradient 就是这个倒三角 ∇ L \nabla L L,我知道大家已经很久没有学微积分了,所以我猜你八成不记得 ∇ L \nabla L L 是什么。这个 ∇ L \nabla L L 就是,,你把 w w w L L L 的偏微分和 b b b L L L 的偏微分排成一个 vector,这一项就是 gradient。因为我们在整个 process 里面,我们要计算 w w w L L L 的偏微分和 b b b L L L 的偏微分,这个就是 gradient。所以这门课如果没必要的话,我们就尽量不要把这个大家不熟悉的符号弄出来。只是想要让大家知道说 gradient 指的就是这个东西。

那我们来 visualize 一下刚才做的事情。刚才做的事情像是这样,有两个参数 w w w b b b,这两个参数决定了一个function 长什么样。那在这个图上的颜色代表 loss function 的数值。越偏蓝色代表 loss 越小,那我们随机选取一个初始值,是在左下角红色的点这个地方。接下来,你就去计算,在红色这个点, b b b 对 loss 的偏微分还有 w w w 对loss 的偏微分,然后你就把参数更新,这个 η \eta η 乘上 b b b 对 loss 的偏微分。还有 η \eta η 乘上 w w w 对 loss 的偏微分。如果你对偏微分比较不熟的话,其实这个 gradient 的方向,其实就是等高线的法线方向。那我们就可以更新这个参数,从这个地方,到这个地方。接下来你就再计算一次偏微分,这个偏微分告诉你说现在应该往这个方向更新你的参数。你就把你的参数从这个地方移到这个地方。接下来它再告诉你说,应该这样子走,然后你就把参数从这个地方再更新到这个地方。

那 gradient descent 有一个让人担心的地方就是如果今天你的 loss function 长的是这个样子,如果今天 w w w b b b 对这个 loss L L L,它看起来是这个样子,那你就麻烦了。这个时候如果你的随机取捨值是在这个地方,那按照gradient 建议你的方向,你走走走走走,就找到这个 function。如果你随机取捨的地方是在这个地方,那根据gradient 的方向,你走走走就走到这个地方。所以变成说这个方法你找到的结果,是看人品的。这个让人非常非常的担心,但是在 linear regression 里面,你不用太担心。为什么呢?因为在 linear regression 里面,你的这个loss function L L L,它是 convex。如果你定义你 loss 的方式跟我在前几页投影片讲的是一样的话,那一个 loss 是convex 的。如果你不知道 convex 是什么的话,换句话说,它是没有 local 的 optimal 的位置,或者是,如果我们把图画出来的话,它长的就是这样子。它的等高线就是一圈一圈椭圆形的。所以它是没有 local optimal 的地方,所以你随便选一个起始点,根据 gradient descent 所帮你找出来的最佳的参数,你最后找出来的都会是同一组参数。

我们来看一下它的 formulation。其实这个式子是非常简单的,假如你要实际算一下 w w w L L L 的偏微分和 b b b L L L 的偏微分,这个式子长的是什么样子呢?这个 L L L 我们刚才已经看到了,它是长这个样子。它是估测误差的平方和,如果我们把它对 w w w 做偏微分,我们得到什么样的式子呢?这个其实非常简单,我相信有修过微积分的人都可以秒算。你就把这个 2 移到左边,你要对 w w w 做偏微分,你就先把括号里面这一项先做偏微分,你把 2 移到左边,你得到这样子的结果。接下来考虑括号里面的部分,括号里面的部分只有 − w ⋅ x c p n - w \cdot x^n_{cp} wxcpn 这一项是跟 w w w 有关的,所以如果你把括号里面的 equation 对 w w w 做偏微分的话,你得到的值就是 − x c p n - x^n_{cp} xcpn,所以 ∂ L / ∂ w \partial L / \partial w L/w w w w L L L 的偏微分它的式子就是长这样,如果你要算 b b b L L L 的偏微分的话,也非常简单,你就把 2 移到前面,然后你再把这个括号里面的值,对 b b b 做偏微分。括号里面只有 − b -b b 这一项跟我们要做偏微分的这个 b b b 有关,所以对 b b b 做偏微分得到的值是 − 1 -1 1,然后就结束了。所以有了 gradient descent,你就知道说怎么算偏微分,那你就可以找一个最佳的 function。

那结果怎么样呢?我们的 model 长这样,然后费尽一番功夫以后,你找出来的最好的 b b b w w w,根据 training data 分别是 b = - 188.4 , w = 2.7 b= -188.4,w=2.7 b=188.4,w=2.7 ,如果你把这一个 function: y = b + w × x x p y=b+w \times x_{xp} y=b+w×xxp,把它的 b b b w w w 值画到图上的话,它长的是这个样子。这一条红色的线,那你可以计算一下,你会发现说这一条红色的线,没有办法完全正确的评定所有的宝可梦的进化后的 CP 值。如果你想要知道说他做的有多不好的话,或者是多好的话,你可以计算一下你的error。你的 error 就是,你计算一下每一个蓝色的点跟这个红色的点之间的距离,第一个蓝色的点跟这个红色的线的距离是 e 1 e^1 e1,第二个蓝色的点跟红色的线的距离是 e 2 e^2 e2,以此类推,所以有 e 1 e^1 e1 e 10 e^{10} e10。那平均的 training data 的 error,就是 ∑ n = 1 10 e n \sum^{10}_{n=1}e^n n=110en 。这边算出来是 31.9,但是这个并不是我们真正关心的,因为你真正关心的是 generalization 的 case。也就是说,假设你今天抓到一只新的宝可梦以后,如果使用你现在的 model 去预测的话,那做出来你估测的误差到底有多少。

所以真正关心的是,那些你没有看过的新的 data,这边我们叫做 testing data,它的误差是多少。所以这边又抓了另外 10 只宝可梦当作 testing data。这 10 只宝可梦跟之前拿来做训练的 10 只,不是同样的 10 只。这新抓的 10 只跟刚才看到的 10 只的分布,其实是还满像的,它们就是这个图上的 10 个点。那你会发现说,我们刚才在训练资料上找出来这条红色的线,其实也可以大致上预测,在我们没有看过的宝可梦上,它的进化后的 CP 值。如果你想要量化它的错误的话,那就计算一下它的错误。它错误算出来是 35.0。这个值是比我们刚才在 training data 上看到的 error 还要稍微大一点,因为可以想想看我们最好的 function 是在 training data 上找到的,所以在 testing data 上面算出来的 error,本来就应该比 training data 上面算出来的 error 还要稍微大一点,有没有办法做得更好呢?

如果你想要做得更好的话,接下来你要做的事情就是,重新去设计你的 model。如果你观察一下 data 你会发现说,在原进化前的 CP 值特别大的地方,还有进化前的 CP 值特别小的地方,预测是比较不准的。那你可以想想看说,任天堂在做这个游戏的时候,它背后一定是有某一支程式,去根据某一些 hidden 的 factor,比如说,去根据原来的 CP 值和其他的一些数值,generate 进化以后的数值。所以到底它的 function 长什么样子,从这个结果看来,那个 function 可能不是这样子一条直线,它可能是稍微更复杂一点,所以我们需要有一个更复杂的 model。

举例来说,我们这边可能需要引入二次式。我们今天,可能需要引入 ( x c p ) 2 (x_{cp})^2 (xcp)2 这一项,我们重新设计了一个model,这个 model 它写成 y = b + w 1 × x c p + w 2 × ( x c p ) 2 y=b+w_1 \times x_{cp} + w_2 \times (x_{cp})^2 y=b+w1×xcp+w2×(xcp)2,我们加了后面这一项,如果我们有了这个新的function,你可以用我们刚才讲得一模一样的方式,去 define 一个 function 的好坏,然后用 gradient descent 找出一个在你的 function set 里面最好的 function。根据 training data 找出来的最好的 function 是 b = − 10.3 , w 1 = 1.0 , w 2 = 2.7 × 1 0 − 3 b=−10.3, w_1=1.0, w_2=2.7×10^{-3} b=10.3,w1=1.0,w2=2.7×103,如果我们把这个最好的 function 画在图上的话,它长的是这个样子。你就会发现说,现在我们有了这条新的曲线,我们有了这个新的 model,它的预测在 training data 上面看起来是更准一点。在 training data 上面你得到的 average error 现在是 15.4 15.4 15.4。但我们真正关心的是 testing data,那我们就把同样的 model,再 apply 到 testing data 上。我们在 testing data 上 apply 同样这条红色的线,然后去计算它的 average error。那我们现在得到的是 18.4 18.4 18.4,在刚才如果我们没有考虑 ( x c p ) 2 (x_{cp})^2 (xcp)2 的时候算出来的 average error是 30 左右,现在有考虑平方项得到的是 18.4 18.4 18.4

那有没有可能做得更好呢?比如说我们可以考虑一个更复杂的 model。我们引入不只是 ( x c p ) 2 (x_{cp})^2 (xcp)2,我们引入 ( x c p ) 3 (x_{cp})^3 (xcp)3。所以我们现在的 model 长的是这个样子。你就用一模一样的方法,你就可以根据你的 training data,找到在这一个 function set 里面最好的一个 function。那找出来是这样 b = 6.4 , w 1 = 0.66 , w 2 = 4.3 × 1 0 − 3 , w 3 = − 1.8 × 1 0 − 6 b=6.4, w_1=0.66, w_2=4.3×10^{-3} ,w_3=-1.8×10^{-6} b=6.4,w1=0.66,w2=4.3×103,w3=1.8×106,所以你发现 w 3 w_3 w3 其实是它的值比较小,它可能是没有太大的影响,作出来的线其实跟刚才看到的二次的线是没有太大的差别,那这个时候 average error 算出来是 15.3 15.3 15.3,如果你看 testing data 的话,testing data 算出来的 average error 是 18.1 18.1 18.1。跟刚刚二次的,有考虑 ( x c p ) 2 (x_{cp})^2 (xcp)2 的结果比起来是稍微好一点点。刚才前一页是 18.3 18.3 18.3,有考虑三次项后是 18.1 18.1 18.1,是稍微好一点点。那有没有可能是更复杂的 model 呢?或许在宝可梦的那个程式背后,它产生进化后的 CP 值用的是一个更复杂的一个 function。或许它不只考虑了三次,或者它不只考虑了 ( x c p ) 3 (x_{cp})^3 (xcp)3,或许它考虑的是四次方也说不定。

或许它考虑的是四次方也说不定,那你就用同样的方法,再把这些参数 : b , w 1 , w 2 , w 3 b, w_1, w_2, w_3 b,w1,w2,w3 w 4 w_4 w4 都找出来,那你得到的 function 长这个样子。你发现它在 training data 上它显然可以做得更好,在 input 的 CP 值比较小的这些宝可梦,这些显然是一些绿毛虫之类的东西,它在这边是 predict 更准的。所以现在的 average error 是 14.9 14.9 14.9,刚才三次的是 15.3 15.3 15.3,现在四次的时候在 training data 上是 14.9 14.9 14.9,但是我们真正关心的是 testing,我们真正关心的是如果没有看过的宝可梦,我们能够多精确的预测它进化后的 CP 值。所以我们发现说,如果我们看没有看过的宝可梦的话,我们得到的 average error 是多少呢?

我们得到的 average error 其实是 28.8 28.8 28.8,前一页做出来已经是 18.3 18.3 18.3 了,就我们用三次的时候,在 testing data 上面做出来已经是 18.3 18.3 18.3 了,但是我们换了一个更复杂的 model 以后,做出来是 28.8 28.8 28.8,结果竟然变得更糟了!我们换了一个更复杂的 model,在 training data 上给我们比较好的结果,但在 testing data 上,看起来结果是更糟的。

那如果换再更复杂的 model 会怎样呢?有没有可能是五次式,有没有可能它背后的程式是如此的复杂,原来的 CP 值的一次、两次、三次、四次到五次,那这个时候,我们把最好的 function 找出来,你会发现它最好的 function 在 training data上长得像是这样子。,你会发现它最好的function在training data上长得像是这样子。,你会发现它最好的function 在 training data 上长得像是这样子。这个是一个合理的结果吗?你会发现说,在原来的 CP 值是500 左右,500 左右可能就是伊布之类的东西。在原来的 CP 值是 500 左右的宝可梦,根据你现在的 model 预测出来,它的 CP 值竟然是负的。但是在 training data 上面,我们可以算出来的 error 是 12.8 12.8 12.8,比我们刚才用四次式得到的结果又再更好一些。那在 testing 的结果上是怎样呢?

如果我们把这个我们找出来的 function,apply 到新的宝可梦上面,你会发现结果怎么烂掉了啊,至少这一只大概是伊布吧,这只伊布,它预测出来进化后的 CP 值,是非常的不准。照理说有 1000 多,但是你的 model 却给它一个负的预测值。所以算出来的 average error 非常大,有 200 多。所以当我们换了一个更复杂的 model,考虑到五次的时候,结果又更加糟糕了。

所以到目前为止,我们试了五个不同的 model。那这五个 model,如果你把他们分别的在 training data 上面的average error 都画出来的话,你会得到这样子的一张图。从高到低,也就是说,如果你考虑一个最简单的model,这个时候 error 是比较高的;model 稍微复杂一点,error 稍微下降;然后 model 越复杂,在这个training data 上的 error 就会越来越小。那为什么会这样呢?这件事情倒是非常的直觉,非常容易解释。

假设黄色的这个圈圈,我们故意用一样的颜色,黄色这个圈圈代表这一个式子,有考虑三次的式子,所形成的function space。那四次的式子所形成的 function space,就是这个绿色的圈圈。它是包含黄色的圈圈的,这个事情很合理,因为你只要把 w 4 w_4 w4 设为 0,是四次的这个式子就可以变成三次的式子。所以三次的式子都包含在这个四次的式子里面,黄色的圈圈都包含在绿色的圈圈里面。那如果我们今天考虑更复杂的五次的式子的话,它又可以包含所有四次的式子。所以今天如果你有一个越复杂的 model,它包含了越多的 function 的话,那理论上你就可以找出一个 function,它可以让你的 error rate 越来越低。你的 function 如果越复杂,你的 candidate 如果越多,你当然可以找到一个 function,让你的 error rate 越来越低。当然这边的前提就是,你的 gradient descent 要能够真正帮你找出 best function 的前提下,你的 function 越复杂,可以让你的 error rate 在 training function 上越低。

但是在 testing data 上面,看起来的结果是不一样的。在 training data 上,你会发现说 model 越来越复杂你的error 越来越低,但是在 testing data 上,在到第三个式子为止,你的 error 是有下降的。但是到第四个和第五个的 function 的时候,error 就暴增。然后把它的图试著画在左边这边。蓝色的是 training data 上对不同 function的 error,橙色的是 testing data 上对不同 function 的 error。你会发现说,今天在五次的时候,在 testing 上是爆炸的,它就突破天际没办法画在这张图上。那所以我们今天,得到一个观察,虽然说越复杂的 model 可以在training data 上面给我们越好的结果,但这件事情也没有什么,因为越复杂的 model 并不一定能够在 testing data 上给我们越好的结果。这件事情就叫做 overfitting。就复杂的 model 在 training data 上有好的结果,但在testing data 上不一定有好的结果。这件事情就叫做 overfitting。比如当我们用第四个和第五个式子的时候,我们就发生 overfitting 的情形。

那为什么会有overfitting这个情形呢?为什么更复杂的 model 它在 training 上面得到比较好的结果,在 testing 上面不一定得到比较好的结果呢?这个我们日后再解释。但是你其实是可以想到很多很直观的,在训练的时候得到比较好的结果,但在测试的时候不一定会得到比较好的结果。比如说,你有没有考过驾照?考驾照不是都要去那个驾训班吗,驾训班不是都在那个场内练习吗,你在场内练习不是都很顺,练习非常非常多次以后,你就会得到很奇怪的技能。你就学到说,比如说,当我后照镜里面看到路边小丸子的贴纸对到正中间的时候,就把方向盘左转半圈这样子。你就学到这种技能,所以你在测试训练的时候,在驾训班的时候你可以做得很好,但在路上的时候你就做不好。像我就不太会开车,虽然我有驾照,所以我都在等无人驾驶车出来。

所以 overfitting 是很有可能会发生的。所以 model 不是越复杂越好,我们必须选一个刚刚好,没有非常复杂也没有很复杂的 model,你要选一个最适合的 model。比如说在这个 case 里面,当我们选一个三次式的时候,可以给我们最低的 error。所以如果今天可以选的话,我们就应该选择三次的式子来作为我们的 model,来作为我们的function set。

你以为这样就结束了吗?其实还没有,刚才只收集了 10 只宝可梦,其实太少了,当我们收集到 60 只宝可梦的时候,你会发现说刚才都是白忙一场。你仔细想 : 当我们收集 60 只宝可梦,你把它的原来的 CP 值和进化后的 CP 值画在这个图上,你会发现说他们中间有一个非常奇妙的关系。它显然不是什么一次二次三次一百次式,显然都不是,中间有另外一个力量,这个力量不是 CP 值它在影响着进化后的数值,到底是什么呢?其实非常的直觉,就是宝可梦的物种。

这边我们把不同的物种用不同的颜色来表示,蓝色是波波,波波进化后是比比鸟,比比鸟进化是大比鸟。这个黄色的点是独角虫,独角虫进化后是铁壳蛹,铁壳蛹进化后是大针蜂。然后绿色的是绿毛虫,绿毛虫进化是铁甲蛹,铁甲蛹进化是巴大蝴。红色的是伊布,伊布可以进化成雷精灵、火精灵或水精灵等等,你可能说怎么都只有这些路边就可以见到的,因为抓乘龙快龙是很麻烦的,所以就只有这些而已。所以刚才只考虑 CP 值这件事,只考虑进化前的 CP 值显然是不对的。因为这个进化后的 CP 值受到物种的影响其实是很大的。或者是比原来的 CP 值产生非常关键性的影响。所以我们在设计 model 的时候,刚才那个 model 设计的是不好的。刚才那个 model 就好像是,你想要海底捞针,从 function set 里面捞出一个最好的 model,那其实里面 model 通通都不好,所以针根本就不在海里,所以你要重新设计一下你的 function set。我们的 function set, input x x x 跟 output y y y,这个 input 宝可梦和 output 进化后的 CP 值有什么关系呢?

它的关系是这样,如果今天输入的宝可梦 x x x,它的物种是属于波波的话,这个 x s x_s xs 代表说这个 input x x x 的物种,那他的输出 y = b 1 + w 1 × x c p y=b_1+w_1\times x_{cp} y=b1+w1×xcp。那如果它是独角虫的话, y = b 2 + w 2 × x x p y=b_2+w_2 \times x_{xp} y=b2+w2×xxp。如果它是绿毛虫的话,就是 b 3 + w 3 × x c p b_3+w_3 \times x_{cp} b3+w3×xcp。如果它是伊布的话,就用另外一个式子。也就是不同的物种,我们就看它是哪一个物种,我们就代不同的 linear function,然后得到不同的 y y y 作为最终的输出。你可能会问一个问题说,你把 if 放到整个function 里面,这样你不就不是一个 linear model 了吗?function 里面有 if 你搞得定吗?你可以用微分来做吗?你可以用刚才的 gradient descent 来算参数对 loss function微分吗?其实是可以的。这个式子你可以把它改写成一个 linear function。

写起来就是这样,这个有一点复杂但没有关系。我们先来观察一下 δ \delta δ 这个 function。如果你有修过信号的处理,我想应该知道 δ \delta δ 这个 function 是指什么。今天这个 δ \delta δ 这个 function 的意思是说, δ ( x x = Pidgey ) \delta(x_x=\text{Pidgey}) δ(xx=Pidgey) 的意思就是说,假如我们今天输入的这只宝可梦是比比鸟的话,这个 δ \delta δ function 它的 output 就是 1。反之如果是其他种类的宝可梦的话,它 δ \delta δ function 的 output 就是 0。所以我们可以把刚才那个有 if 的式子,写成像这边这个样子。你的宝可梦进化后的 CP 值,等于 b 1 × δ ( Pidgey ) b_1 \times \delta(\text{Pidgey}) b1×δ(Pidgey) 这样子,然后加上 w 1 × δ ( Pidgey ) w_1 \times \delta(\text{Pidgey}) w1×δ(Pidgey),这只宝可梦的 CP 值,加上 b 2 × δ ( 独角虫 ) b_2 \times \delta(\text{独角虫}) b2×δ(独角虫),加上 w 2 × δ ( 独角虫 ) w_2 \times \delta(\text{独角虫}) w2×δ(独角虫),再乘上它的 CP 值,然后接下来考虑绿毛虫,然后接下来考虑伊布。你可能会想说这个跟刚刚那个式子哪里一样了呢?你想想看,假如我们今天输入的那一只神奇宝贝是比比鸟的话,意味着这两个 function 会是1,这两个 δ \delta δ function 如果 input 是比比鸟的话就是 1,其他 δ \delta δ function 就是 0。那乘上 0 的项,其实就变成 y = b 1 + w 1 × x x p y=b_1+w_1\times x_{xp} y=b1+w1×xxp,所以对其他种类的宝可梦来说也是一样。所以当我们设计这个 function 的时候,我们就可以做到我们刚才在前一页 design 的那一个有 if 的 function。那事实上这一个 function,它就是一个 linear function。怎么说呢?前面这个 b 1 , w 1 b_1, w_1 b1,w1 b 4 , w 4 b_4, w_4 b4,w4 就是我们的参数,而后面这一项 δ \delta δ 或者是 δ ⋅ x x p \delta \cdot x_{xp} δxxp ,不同的 δ \delta δ 跟不同的 δ × x c p \delta \times x_{cp} δ×xcp ,就是后面这个 x i x_i xi 这一项 feature。

这个蓝色框框里面的这些,其实就是feature。所以这个东西它也是 linear model。那有了这些以后,我们做出来的结果怎么样呢?

这个是在 training data 上的结果,在 training data 上面,我们知道不同种类的宝可梦,它用的参数就不一样。所以不同种类的宝可梦,它的线是不一样的,它的 model 的那条 line 是不一样的。蓝色这条线是比比鸟的线,绿色这条线是绿毛虫的线,黄色独角虫的线跟绿毛虫的线其实是重叠的,红色这条线是伊布的线。所以就发现说,当我们分不同种类的宝可梦来考虑的时候,我们的 model 在 training data 上面可以得到更低的 error。你发现说现在这几条线,是把 training data fit 得更好,如果说我们这么做有考虑到宝可梦的种类的时候,我们得到的 average error 是 3.8 3.8 3.8,在 training data 上。

但我们真正在意的是,它能不能够预测新看到的宝可梦,也就是 testing data 上面的结果。那在 testing data 上面,它的结果是这个样子:一样是这三条线,发现说它也把在 testing data 上面的那些宝可梦 fit 得很好。然后它的 average error 是 14.3 14.3 14.3,这比我们刚才可以做好的 18 点多还要更好。但是如果你再观察这个图的话,感觉应该是还有一些东西是没有做好的。我仔细想想看,我觉得伊布这边应该就没救了。因为我认为伊布会有很不一样的CP 值是因为进化成不同种类的精灵。所以如果你没有考虑这个 factor 的话,应该就没救了。但是我觉得这边有一些还没有 fit 很好的地方,有一些值还是略高或略低于这条直线。所以这个地方搞不好还是有办法解释的。当然有一个可能是,这些略高略低于我们现在找出来这个蓝色绿色线的这个 model 的变化,这个 difference 其实来自于random 的数值,就是每次那个宝可梦的程式产生进化后的 CP 值的时候,它其实有加一个 random的参数。但也有可能是其实不是 random 的参数,它还有其他的东西在影响著宝可梦进化后的 CP 值。

有什么其他可能的参数呢?比如说,会不会进化后的 CP 值是跟 weight 有关系的?会不会进化后的 CP 值是跟它的高度有关系的?会不会进化后的 CP 值是跟它的 HP 有关系的?其实我们不知道,我又不是大木博士我怎么会知道这些事情,所以如果你有 domain knowledge 的话,你就可能可以知道说,你应该把什么样的东西加到你的model 里面去。但是我又没有 domain knowledge,那怎么办呢?没关系,有一招就是把你所有想到的东西,通通塞进去,我们来弄一个最复杂的 function,然后看看会怎样?

这个 function 我写成这样:如果它是比比鸟的话,它的 CP 值我们就先计算一个 y ′ y' y,这个 y ′ y' y 不是最后这个 y y y,这个 y ′ y' y 还要做别的处理才能够变成 y y y。我们就说,如果这个是比比鸟的话,这其实不是比比鸟,这应该是波波,因为比比鸟是进化后的。这只应该是波波。那 y ′ = b 1 + w 1 × x c p + w 5 × ( x c p ) 2 y'=b_1+w_1 \times x_{cp}+w_5 \times (x_{cp})^2 y=b1+w1×xcp+w5×(xcp)2,我们就是不只要考虑 CP 值,也要考虑 CP 值的平方。如果是绿毛虫,用另外一个式子。如果是独角虫,用另外一个式子。如果是伊布,用另外一个式子。最好我们再把 y ′ y' y 做其他的处理,我们把 y ′ y' y,再加上 HP 值,它的生命值乘上 w 9 w_9 w9,再加上生命值的平方乘上 w 10 w_{10} w10,再加上高度乘上 w 11 w_{11} w11,再加上高度的平方乘上 w 12 w_{12} w12,再加上它的 weight 乘上 w 13 w_{13} w13,再加上 weight 平方乘上 w 14 w_{14} w14,这些东西合起来才是最后 output 的 y y y

所以这整个式子里面,其实也没有很多个参数,就是 14 + 4 = 18 14+4=18 14+4=18,跟几百个参数比起来,其实也不是一个太复杂的 model。那我们现在有个这么复杂的 function,在 training data 上我们得到的 error,期望应该就是非常的低。我们果然得到一个非常低的 error,这个 function 你可以把它写成线性的式子,就跟刚才一样,这边我就不解释了。那这么一个复杂的 function,理论上我们可以得到非常低的 training error。training error 算出来是 1.9 1.9 1.9,那你可以期待你在 testing set 上,也算出很低的 training error 吗?倒是不见得,这么复杂的 model,很以可能会 overfitting。你很有可能会得到,在 testing data 上得到很糟的数字。我们今天得到的数值很糟是 102.3 102.3 102.3 这样子,结果坏掉了怎么办呢?如果你是大木博士的话,你就可以删掉一些你觉得没有用的 input,然后就得到一个简单的 model,避免overfitting 的情形。但是我不是大木博士,所以我有用别的方法来处理这个问题。这招叫做 regularization。

regularization 要做的事情是,我们重新定义了 step 2 的时候,我们对一个 function 是好还是坏的定义。我们重新 redefine 我们的 loss function。把一些 knowledge 放进去,让我们可以找到比较好的 function。什么意思呢?

假设我们的 model in general 写成这样: y = b + ∑ w i x i y=b+\sum w_ix_i y=b+wixi,我们原来的 loss function 它只考虑了 error 这件事。原来的 loss function 只考虑了 prediction 的结果减掉正确答案的平方,只考虑了 prediction 的 error。那 regularization 它就是加上一项额外的 term,这一项额外的 term 是 λ ∑ ( w i ) 2 \lambda \sum(w_i)^2 λ(wi)2 λ \lambda λ 是一个常数,这个是等一下我们要手调一下看要设多少。那 ∑ ( w i ) 2 \sum (w_i)^2 (wi)2 就是把这个 model 里面所有的 w i w_i wi,都算一下平方以后加起来。那这个合起来才是我们的 loss function。前面这一项我们刚才解释过,所以我相信你是可以理解的。error 越小就代表当然是越好的 function,但是,为什么我们期待一个参数的值越小,参数的值越接近 0 的 function 呢?

这件事情你就比较难想像。为什么我们期待一个参数值接近 0 的 function 呢?当我们加上这一项的时候,我们就是预期说我们要找到的那个 function,它的那个参数越小越好。当我们加上这一项的时候,你知道参数值比较接近 0 的 function,它是比较平滑的。

所谓的比较平滑的意思是,当今天的输入有变化的时候,output 对输入的变化是比较不敏感的。为什么参数小就可以达到这个效果呢?你可以想想看,假设这个是我们的 model,现在 input 有一个变化,比如说我们对某一个 x i x_i xi 加上 Δ x i \Delta x_i Δxi,这时候对输出会有什么变化呢?这时候输出的变化,就是 w i Δ x i w_i\Delta x_i wiΔxi,你的输入变化 Δ x i \Delta x_i Δxi,输出就是 w i Δ x i w_i \Delta x_i wiΔxi ,你会发现说如果今天你的 w i w_i wi 越小越接近 0 的话,它的变化就越小。如果 w i w_i wi 越接近 0 的话,输出对输入就越不 sensitive。所以今天 w i w_i wi 越接近 0,我们的 function 就是一个越平滑的 function。

现在的问题就是,为什么我们喜欢比较平滑的 function?这可以有不同的解释,你可以这样想,如果我们今天有一个比较平滑的 function 的话,那平滑的 function 对输入是比较不敏感的。所以今天如果我们的输入被一些杂讯所干扰的话,如果今天杂讯干扰的我们的输入,在我们测试的时候,那一个比较平滑的 function,它会受到比较少的影响,而给我们一个比较好的结果。

接下来我们就要来看看说,如果我们加入了 regularization 的项,对我们最终的结果会有什么样的影响?这个是实验的结果。我们就把 λ \lambda λ 从 0、1、10 一直调到 100000,我们现在 loss 有两项,一项是考虑 error,一项是考虑多smooth, λ \lambda λ 值越大代表考虑 smooth 的那个 regularization 那一项它的影响力越大,所以当 λ \lambda λ 值越大的时候,我们找到的 function 就越平滑。如果我们看看在 training data 上的 error 的话,我们会发现说,如果 function 越平滑,我们在 training data 上得到的 error 其实是越大的。但是这件事情是非常合理的,因为当 λ \lambda λ 越大的时候,我们就越倾向于考虑 w w w 本来的值,我们就倾向考虑 w w w 的值而减少考虑我们的 error。所以今天如果 λ \lambda λ 越大的时候,我们考虑 error 就愈少,所以我们本来在 training data 上得到的 error 就越大。

但是有趣的是,虽然在 training data 上得到的 error 就越大,但是在 testing data 上面得到的 error 可能是会比较小。比如说我们看这边的例子,原来 λ = 0 \lambda=0 λ=0,就是没有 regularization 的时候 error 是 102 102 102 λ = 1 \lambda=1 λ=1 就变成 68 68 68,到 10 就变成 25 25 25,到 100 就变成 11.1 11.1 11.1,但是 λ \lambda λ 太大的时候,到 1000 的时候,error 又变大变成 12.8 12.8 12.8 一直到 26.8 26.8 26.8。那这个结果是合理,我们比较喜欢比较平滑的 function,比较平滑的 function 它对 noise 比较不 sensitive,所以当我们增加 λ \lambda λ 的时候,你的 performance 是越来越好,但是我们又不喜欢太平滑的 function,因为最平滑的function 是什么?最平滑的 function 就是一条水平线啊,一条水平线是最平滑的 function。如果你的 function 是一条水平线的话,那它啥事都干不成,所以如果今天 function 太平滑的话,你反而会在 testing set 上又得到糟糕的结果。

所以现在的问题就是,我们希望我们的 model 多 smooth呢?我们希望我们今天找到的 function 有多平滑呢?这件事情就变成是你们要调 λ \lambda λ 来解决这件事情,你必须要调整 λ \lambda λ 来决定你的 function 的平滑程度。比如说你可能调整一下参数以后发现说,今天 training 都随著 λ \lambda λ 增加而增加,testing 随著 λ \lambda λ 先减少后增加。在这个地方有一个转折点,是可以让我们的 testing error 最小,你就选 λ = 100 \lambda=100 λ=100 来得到你的 model。

这边还有一个有趣的事实,很多同学其实都知道 regularization,你有没有发现,这边我没有把 b b b 加进去,为什么呢?事实上很多人可能不知道这件事,在做 regularization 的时候,其实是不需要考虑 bias 这一项的。首先,如果你自己做实验的话你会发现,不考虑 bias,performance 会比较好。再来为什么不考虑 bias 呢?因为我们今天预期的是,我们要找一个比较平滑的 function。你调整 bias 的这个 b b b 的大小,跟一个 function 的平滑的程度是没有关系的。调整 bias 值的大小时你只是把 function 上下移动而已,对 function 的平滑程度是没有关系的。总之,搞了半天以后,我最后可以做到,我们的 testing error 是 11.1 11.1 11.1

我们就说一下今天的 conclusion:首先感谢大家来参加我对宝可梦研究的发表会,那我今天得到的结论就是,宝可梦进化后的 CP 值,跟他进化前的 CP 值,还有它是哪个物种,是非常有关系的。知道这两件事情几乎可以决定进化后的 CP 值。但是我认为,可能应该还有其他的 factors。我们刚刚看到说我们加上其他什么高度啊体重啊 HP 以后,是有比较好的,如果我们加入 regularization 的话。不过我 data 有点少,所以我没有那么 confident 就是了。

然后再来呢就是,我们今天讲了 gradient descent 的作法,就是告诉大家怎么做,那我们以后会讲它的原理还有技巧。我们今天讲了 overfitting 和 regularization,介绍一下表象上的现象,未来会讲更多它背后的理论。再来最后我们有一个很重要的问题,首先我觉得我这个结果应该还满正确的,因为你知道网路上有很多的 CP 的预测器,那些 CP 的预测器你在输入的时候,你只要输入你的宝可梦的物种和它现在的 CP 值,它就可以告诉你进化以后的 CP 值。所以我认为你要预测进化以后的 CP 值,应该是要知道原来的 CP 值和它的物种就可以知道大部分。不过我看那些预测器预测出来的误差,都是给你一个 range,它都没有办法给你一个更准确的预测。如果考虑更多的 factor 更多的 input,比如说 HP 什么啊,或许可以预测的更准就是了。

但最后的问题就是,我们在 testing data 上面,在我们 testing 的 10 只宝可梦上,我们得到的 average error 最后是 11.1 11.1 11.1。如果我把它做成一个系统,放到网路上给大家使用的话,你觉得如果我们看过没有看到的 data,那我们得到的 error 会预期高过 11.1 11.1 11.1 还是低于 11.1 11.1 11.1,还是理论上期望值应该是一样的。你知道我的 training data 是里面只有四种,里面都没有什么乘龙卡比之类的,我们就假设使用者只能够输入那四种,它不会输入乘龙卡比这样。在这个情况下,你觉得如果我们今天把这个系统放到线上,给大家使用的话,我们今天得到的 CP 值,会比我今天在 testing set 上看到的高还是低还是一样?我们之后会解释,我们今天其实用了 testing set 来选 model,就我们今天得到的结果其实是,如果我们真的把系统放在线上的话,预期应该会得到比我们今天看到的 11.1 11.1 11.1 还要更高的 error rate,这个时候我们需要 validation 观念来解决这个问题,这个我们就下一堂课再讲。

课程链接:https://speech.ee.ntu.edu.tw/~hylee/ml/2016-fall.html


转载:https://blog.csdn.net/weixin_37179744/article/details/117537277
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场