官方学习文档:https://linklearner.com/activity/16/14/55
往期task01链接:https://mp.csdn.net/mp_blog/creation/editor/141535616
李宏毅老师对应视频课程可供食用:https://www.bilibili.com/video/BV1JA411c7VT/?p=3
机器学习基础
线性模型
w 跟 b 的值上期task01结尾已经找出来的,w=0.97,b等于100,这组 w 跟 b 可以让损失小到 480。接下来使用这个函数预测未来的观看次数。
从 2021 年开始每一天都拿这个函数去预测次日的观看人次:用 2020 年的 12 月 31 日的观看人次预测 2021 年 1 月 1 日的观看人次,用 2021 年 1 月 1 日的观看人次预测 1 月 2 日的观看人次,以此类推每天都做这件事,一直做到 2 月 14 日,得到平均的值。
结果表明,在 2021 年没有看过的数据上,平均误差值用 L′ 来表示,它是580 人左右,所以在有看过的数据上,在训练数据上,误差值是比较小的,在没有看过的数据上(即在2021 年的数据上),看起来误差值是比较大的。
如图 1.6 所示,横轴是代表的是时间,0 这个点代表的是 2021 年 1 月 1 日,最右边点代表的是 2021 年 2 月 14 日,纵轴就是观看的人次,这边是用千人当作单位。红色线是真实的观看人次,蓝色线是机器用这个函数预测出来的观看人次。蓝色的线几乎就是红色的线往右平移一天而已,这是因为根据给定的函数机器几乎就是拿前一天的观看人次来预测隔天的观看人次。
这个真实的数据有一个很神奇的现象,它是有周期性的,它每隔 7 天就会有两天特别低(周五和周六),两天观看的人特别少,每隔 7 天,就是一个循环。目前的模型不太行,它只能根据前一天的数据来预测,如果一个模型参考前 7 天的数据来进行预测,也许预测的会更准,所以我们就要修改一下模型。通常一个模型的修改,往往来自于对这个问题的理解,即领域知识。
一开始,对问题完全不理解的时候,随便写一个:
接下来我们观察了真实的数据以后,得到一个结论是:每隔 7 天有一个循环。所以要把前 7 天的观看人次都列入考虑,对之前的模型进行改善:
其中 代表第 j 天的观看测试,也就是 7 天前的数据,分别乘上对应的权重,加起来,再加上偏置得到预测的结果。
使用该模型预测,用梯度下降算出 w 跟 b 的最优值如表 1.1 所示。其在训练数据上的最低损失是 380,而只考虑 1 天的模型在训练数据上的损失是 480。在没有看到的数据上的损失是 490,考虑 1 天的误差是 580。因为其考虑了比较多的信息,在训练数据上应该要得到更好的、更低的损失。
机器的逻辑是前一天跟要预测的隔天的数值的关系很大,所以 是 0.79,不过它知道,如果是前两天前四天前五天,它的值会跟未来要预测的,隔天的值是成反比的,所以 w2, w4, w5最佳的值(让训练数据上的损失为 380 的值)是负的。但是 w1, w3, w6, w7 是正的,考虑前 7天的值,其实可以考虑更多天,本来是考虑前 7 天,可以考虑 28 天,即:
28 天是一个月,考虑前一个月每一天的观看人次,去预测隔天的观看人次,训练数据上是 330。在 2021 年的数据上,损失是 460,看起来又更好一点。如果考虑 56 天,即:
结果显示,这样在训练数据上损失是 320,在没看过的数据上损失还是 460。考虑更多天没有办法再更降低损失了。看来考虑天数这件事,也许已经到了一个极限。
这些模型都是把输入的特征 x 乘上一个权重,再加上一个偏置就得到预测的结果,这样的模型称为线性模型(linear model)。接下来会看如何把线性模型做得更好。
分段线性曲线
线性模型也许过于简单,x1 跟 y 可能中间有比较复杂的关系,如图 1.7 所示。对于线性模型,x1 跟 y 的关系就是一条直线,随着 x1 越来越高,y 就应该越来越大。设定不同的 w可以改变这条线的斜率,设定不同的 b 可以改变这一条蓝色的直线跟 y 轴的交叉点。但是无论如何改 w 跟 b,它永远都是一条直线。但现实中也许在 x1 小于某一个数值的时候,前一天的观看次数跟隔天的观看次数是成正比;也许当 x1 大于一个数值的时候,x1 太大,前天观看的次数太高,隔天观看次数就会变少;也许 x1 跟 y 中间,有一个比较复杂的、像红色线一样的关系。但不管如何设置 w 跟 b,永远制造不出红色线,永远无法用线性模型制造红色线。显然线性模型有很大的限制,这一种来自于模型的限制称为模型的偏差,无法模拟真实的情况。
所以需要写一个更复杂的、更有灵活性的、有未知参数的函数。红色的曲线可以看作是一个常数再加上一群 Hard Sigmoid 函数。Hard Sigmoid 函数的特性是当 x 轴的值小于某一个阈值(某个定值)的时候,大于另外一个定值阈值的时候,中间有一个斜坡。所以它是先水平的,再斜坡,再水平的。所以红色的线可以看作是一个常数项加一大堆的蓝色函数(Hard Sigmoid)。常数项设成红色的线跟 x 轴的交点一样大。常数项怎么加上蓝色函数后,变成红色的这一条线?
蓝线 1 函数斜坡的起点,设在红色函数的起始的地方,斜坡的终点设在第一个转角处,让第 1 个蓝色函数的斜坡和红色函数的斜坡的斜率是一样的,这个时候把 0+1 就可以得到红色曲线左侧的线段。接下来,再加第 2 个蓝色的函数,它的斜坡就在红色函数的第一个转折点到第 2 个转折点之间,让第 2 个蓝色函数的斜率跟红色函数的斜率一样,这个时候把 0+1+2,就可以得到红色函数左侧和中间的线段。接下来第 3 个部分,第 2 个转折点之后的部分,就加第 3 个蓝色的函数,第 3 个蓝色的函数坡度的起始点设的跟红色函数转折点一样,蓝色函数的斜率设的跟红色函数斜率一样,接下来把 0+1+2+3 全部加起来,就得到完整红色的线。
所以红色线,即分段线性曲线(piecewise linear curve)可以看作是一个常数,再加上一堆蓝色的函数。分段线性曲线可以用常数项加一大堆的蓝色函数组合出来,只是用的蓝色函数不一定一样。要有很多不同的蓝色函数,加上一个常数以后就可以组出这些分段线性曲线。如果分段线性曲线越复杂,转折的点越多,所需的蓝色函数就越多。
此外,也许要考虑的 x 跟 y 的关系不是分段线性曲线,而是如图 1.9 所示的曲线。可以在这样的曲线上面,先取一些点,再把这些点点起来,变成一个分段线性曲线。而这个分段线性曲线跟原来的曲线,它会非常接近,如果点取的够多或点取的位置适当,分段线性曲线就可以逼近这一个连续的曲线,就可以逼近有角度的、有弧度的这一条曲线。 所以可以用分段线性曲线去逼近任何的连续的曲线,而每个分段线性曲线都可以用一大堆蓝色的函数组合起来。也就是说,只要有足够的蓝色函数把它加起来,就可以变成任何连续的曲线。
假设 x 跟 y 的关系非常复杂也没关系,就想办法写一个带有未知数的函数。
直接写 HardSigmoid 不是很容易,但是可以用一条曲线来理解它,用 Sigmoid 函数来逼近 Hard Sigmoid,Sigmoid 函数因为其长得像是 S 型而得名。如图 1.10 所示。Sigmoid 函数的表达式为:
其横轴输入是 x1,输出是 y,c 为常数。
当 x1 正的非常大的时候,这一条就会收敛在高度为 c 的地方。如果 x1 负的非常大的时候,分母的地方就会非常大,y的值就会趋近于 0。
为了简洁,简化了指数的部分,蓝色函数的表达式为:
调整这里的 b、w 和 c 可以制造各种不同形状的 Sigmoid 函数,用各种不同形状的 Sigmoid函数去逼近 Hard Sigmoid 函数。如图 1.11 所示,如果改 w,就会改变斜率,就会改变斜坡的坡度。如果改了 b,就可以把这一个 Sigmoid 函数左右移动;如果改 c,就可以改变它的高度。所以只要有不同的 w 不同的 b 不同的 c,就可以制造出不同的 Sigmoid 函数,把不同的Sigmoid 函数叠起来以后就可以去逼近各种不同的分段线性函数;分段线性函数可以拿来近似各种不同的连续的函数。
如图 1.12 所示,红色这条线就是 0 加 1+2+3,而 1、2、3 都是蓝色的函数,其都可写成 Sigmoid函数的形式,只是 1、2、3 的 w、b、c 不同。对应的表达式为:
这里的求和就是把不同的蓝色的函数相加,再加一个常数 b。假设里面的 b 跟 w 跟 c都是未知的,那么就可以设定不同的b 跟 w 跟 c,就可以制造不同的蓝色的函数,相加后就可以逼近各式各样不同的连续函数。
此外,我们可以不只用一个特征 x1,可以用多个特征代入不同的 c, b, w,组合出各种不同的函数,从而得到更有灵活性(flexibility)的函数,如图 1.13 所示。用 j 来代表特征的编号。如果要考虑前 28 天,j 就是 1 到 28。
直观来讲,先考虑一下 j 就是 1、2、3 的情况,就是只考虑 3 个特征。对于咱们这个案例就是只考虑前一天、前两天跟前三天的情况, x1 、x2、x3就分别代表前一天、前两天、前三天的观看次数,每一个 i 就代表了一个蓝色的函数。每一个蓝色的函数都用一个 Sigmoid 函数来比近似它,1,2,3 代表有个 Sigmoid 函数。
wij 代表在第 i 个 Sigmoid 里面,乘给第 j 个特征的权重,w 的第一个下标代表是现在在考虑的是第一个 Sigmoid 函数。为了简化起见,括号里面的式子为:
我们可以用矩阵跟向量相乘的方法,写一个比较简洁的写法。
r1, r2, r3 分别通过 Sigmoid 函数得到 a1, a2, a3,即:
因此蓝色虚线框里面做的事情,是从 x1, x2, x3 得到了 a1, a2, a3,如图 1.14 所示。
接下来每个a再乘上对应的c在相加,在加上b即为最后的y,用线性代数来表示,即:
接下来,如图 1.15 所示,x 是特征,绿色的 是一个向量,灰色的 b 是一个数值。W, , , b是未知参数。把这些东西通通拉直,“拼”成一个很长的向量,我们把 W 的每一行或者是每一列拿出来。无论是拿行或拿列都可以,把 W 的每一列或每一行“拼”成一个长的向量,把 , , b” 拼” 上来,这个长的向量直接用 θ 来表示。所有的未知的参数,一律统称 θ。
Q: 优化是找一个可以让损失最小的参数,是否可以穷举所有可能的未知参数的值?
A:只有 w 跟 b 两个参数的前提之下,可以穷举所有可能的 w 跟 b 的值,所以在参数很少的情况下。甚至可能不用梯度下降,不需要优化的技巧。但是参数非常多的时候,就不能使用穷举的方法,需要梯度下降来找出可以让损失最低的参数。
Q:刚才的例子里面有 3 个 Sigmoid,为什么是 3 个,能不能 4 个或更多?
A:Sigmoid 的数量是由自己决定的,而且 Sigmoid 的数量越多,可以产生出来的分段线性函数就越复杂。Sigmoid 越多可以产生有越多段线的分段线性函数,可以逼近越复杂的函数。Sigmoid 的数量也是一个超参数(自己设定的)。
接下来要定义损失。之前是 L(w, b),因为 w 跟 b 是未知的。现在未知的参数很多了,再把它一个一个列出来太累了,所以直接用 θ 来统设所有的参数,所以损失函数就变成 L(θ)。损失函数能够判断 θ 的好坏,其计算方法跟刚才只有两个参数的时候是一样的。
先给定 θ 的值,即某一组 W, b, cT, b 的值,再把一种特征 x 代进去,得到估测出来的 y,再计算一下跟真实的标签之间的误差 e。把所有的误差通通加起来,就得到损失。
接下来下一步就是优化。
要找到 θ 让损失越小越好,可以将损失最小的一组 θ 称为 θ* 。一开始要随机选一个初始的数值 θ0。接下来计算每一个未知的参数对 L 的微分,得到向量 g,即可以让损失变低的函数:
假设有 1000 个参数,这个向量的长度就是 1000,这个向量也称为梯度,∇L 代表梯度。L(θ0) 是指计算梯度的位置,是在 θ 等于 θ0 的地方。计算出 g 后,接下来跟新参数。
参数有 1000 个,那么θ0、g、θ1 都是1000 维的向量。 整个操作就是这样,如图1.16所示,由 θ0 算梯度,根据梯度去把 θ0 更新成 θ1,再算一次梯度,再根据梯度把 θ1 再更新成 θ2,以此类推,直到不想做(即达到设定的更新次数上限)或者计算出梯度为 0 ,导致无法再更新参数为止。不过在实现上几乎不太可能梯度为 0,通常会停下来就是我们不想做了。
为什么在实际的机器学习和深度学习应用中,梯度为零的情况在高维空间中几乎不可能出现呢?
- 在高维空间中,损失函数的形状非常复杂,包含大量的局部最小值、鞍点和鞍谷。这意味着在大多数情况下,梯度不会同时在所有维度上都为零。
- 参数的随机初始化通常会导致初始梯度不为零。在优化过程中,即使某些维度上的梯度接近零,其他维度上的梯度可能仍然较大,从而推动参数继续更新。
- 梯度下降是一个动态过程,参数的更新是连续的。即使在某些迭代中某些维度上的梯度接近零,随着优化的进行,其他维度上的梯度变化可能会导致这些维度上的梯度再次变得不为零。
- 许多优化算法(如动量法、Adam 等)通过累积历史梯度信息或自适应地调整学习率,使得参数更新更加平滑和稳定,从而减少了梯度为零的可能性。
- 正则化技术(如L1/L2正则化)和数据中的噪声都会引入梯度的波动,使得梯度在所有维度上同时为零的概率极低。
因此,在实际应用中,梯度为零的情况非常罕见,优化过程通常会因为达到预定的迭代次数上限或者梯度变得非常小(但不为零)而停止。这种停止条件是基于实际应用中的经验设定的,而不是因为梯度严格为零。
但实现上有个细节的问题,实际使用梯度下降的时候,如图 1.17 所示,会把 N 笔数据随机分成一个一个的批量(batch)。每个批量里面有 B 笔数据。本来是把所有的数据拿出来算一个损失,现在只拿一个批量里面的数据出来算一个损失,记为 L1 跟 L 以示区别。
假设 B 够大,也许 L 跟L1 会很接近。所以实现上每次会先选一个批量,用该批量来算 L1,根据 L1 来算梯度,再用梯度来更新参数,接下来再选下一个批量算出 L2,根据 L2 算出梯度,再更新参数,以此类推。
所以并不是直接拿 L 来算梯度,实际上是拿一个批量算出来的 L1, L2, L3 来计算梯度。更新跟回合不同,把所有的批量都看过一次,称为一个回合(epoch),每次更新一次参数叫做一次更新。
更新跟回合的差别,举个例子,假设有 10000 笔数据,即 N 等于 10000,批量的大小是设 10,也就 B 等于 10。10000 个样本(example)形成了 1000 个批量,所以在一个回合里面更新了参数 1000 次,一个回合并不只更新参数一次。
第 2 个例子,假设有 1000 个数据,批量大小(batch size)设 100,批量大小和 Sigmoid的个数都是超参数。1000 个样本,批量大小设 100,1 个回合总共更新 10 次参数。
所以做了一个回合的训练其实不知道它更新了几次参数,有可能 1000 次,也有可能 10 次,取决于它的批量数。
模型变形
其实还可以对模型做更多的变形,不一定要把 Hard Sigmoid 换成 Soft Sigmoid。HardSigmoid 可以看作是两个修正线性单元(Rectified Linear Unit,ReLU)的加总,ReLU 的图像有一个水平的线,走到某个地方有一个转折的点,变成一个斜坡,其对应的公式为:
max(0, b + wx1) 是指看 0 跟 b + wx1 谁比较大,比较大的会被当做输出。通过 w, b, c 可以挪动其位置和斜率。把两个 ReLU 叠起来就可以变成 Hard 的 Sigmoid,想要用 ReLU,就把 Sigmoid 的地方,换成max(0, bi + wijxj )。
如图 1.19 所示,2 个 ReLU 才能够合成一个 Hard Sigmoid。要合成 i 个 Hard Sigmoid,需要 i 个 Sigmoid,如果 ReLU 要做到一样的事情,则需要 2i 个 ReLU。
因此表示一个 Hard 的 Sigmoid 不是只有一种做法。在机器学习里面,Sigmoid 或 ReLU 称为激活函数(activation function)。
当然还有其他常见的激活函数,但 Sigmoid 跟 ReLU 是最常见的激活函数,接下来的实验都选择用了 ReLU,显然 ReLU 比较好,实验结果如图 1.20 所示。如果是线性模型,考虑56 天,训练数据上面的损失是 320,没看过的数据 2021 年数据是 460。连续使用 10 个 ReLU作为模型,跟用线性模型的结果是差不多的,
但连续使用 100 个 ReLU 作为模型,结果就有显著差别了,100 个 ReLU 在训练数据上的损失就可以从 320 降到 280,有 100 个 ReLU 就可以制造比较复杂的曲线,本来线性就是一直线,但 100 个 ReLU 就可以产生 100 个折线的函数,在测试数据上也好了一些. 接下来使用 1000 个 ReLU 作为模型,在训练数据上损失更低了一些,但是在没看过的数据上,损失没有变化。
接下来可以继续改模型,如图 1.21 所示,就是把 x 乘上 w 加 b当成a,再通过激活函数(类似迭代)。同样的事情再反复地多做几次,这样可以把 x 做这一连串的运算产生 a,接下来把 a 做同样的运算产生 a′。反复多做的次数又是另外一个超参数。
注意,w, b 和 w′, b′ 不是同一个参数,是增加了更多的未知的参数。
每次使用 100 个 ReLU,输入 56 天前的数据。如图 1.22 所示,如果做两次,损失降低很多,280 降到 180。如果做 3 次,损失从 180 降到 140,在没看过的数据上,从 430 降到了 380。
通过 3 次 ReLU 的实验结果如图 1.23 所示。横轴就是时间,纵轴是观看次数。红色的线是真实的数据,蓝色的线是预测出来的数据。观察红色数据发现,每隔一段时间,就会有两天的低点,在低点的地方,机器的预测还算是蛮准确的。但是,机器有时高估了真实的观看人次,尤其是在红圈标注的这一天,这一天实际上有一个很明显的低谷,但是机器没有预测到,它是晚一天才预测出低谷。这天最低点就是除夕。但因为机器只知道看前 56 天的值,来预测下一天会发生什么事,所以它不知道那一天是除夕。
如图 1.24 所示,Sigmoid 或 ReLU 称为神经元(neuron),很多的神经元称为神经网络(neural network)。人脑中就是有很多神经元,很多神经元串起来就是一个神经网络,跟人脑是一样的。人工智能就是在模拟人脑。
神经网络不是新的技术,80、90 年代就已经用过了,后来为了要重振神经网络的雄风,所以需要新的名字。每一排称为一层,称为隐藏层(hiddenlayer),很多的隐藏层就“深”,这套技术称为深度学习。
所以人们把神经网络越叠越多越叠越深,2012 年的 AlexNet 有 8 层它的错误率是 16.4%,两年之后 VGG 有 19 层,错误率在图像识别上进步到 7.3 %。这都是在图像识别上一个基准的数据库(ImageNet)上面的结果,后来 GoogleNet 有 22 层,错误率降到 6.7%。而残差网络(Residual Network,ResNet)有 152 层,错误率降到 3.57%。
刚才只做到 3 层,应该要做得更深,现在网络都是叠几百层的,深度学习就要做更深。但4 层在训练数据上,损失是 100,在没有看过 2021 年的数据上,损失是 440。在训练数据上,3 层比 4 层差,但是在没看过的数据上,4 层比较差,3 层比较好,如图 1.25 所示。在训练数据和测试数据上的结果是不一致的,这种情况称为过拟合(overfitting)。
但是做到目前为止,还没有真的发挥这个模型的力量,2021 年的数据到 2 月 14 日之前的数据是已知的。要预测未知的数据,选 3 层的网络还是 4 层的网络呢?假设今天是 2 月 26日,今天的观看次数是未知的,如果用已经训练出来的神经网络预测今天的观看次数,就要选 3层的,虽然 4 层在训练数据上的结果比较好,但在没有看过的数据的结果更重要。应该选一个在训练的时候,没有看过的数据上表现会好的模型,所以应该选 3 层的网络。深度学习的训练会用到反向传播(BackPropagation,BP),其实它就是比较有效率、算梯度的方法。
机器学习框架
我们会有一堆训练的数据以及测试数据如下式所示,测试集就是只有 x 没有 y。
训练集就要拿来训练模型,训练的过程是 3 个步骤:
- 先写出一个有未知数 θ 的函数,θ 代表一个模型里面所有的未知参数。fθ(x) 的意思就是函数叫 fθ(x),输入的特征为 x;
- 定义损失,损失是一个函数,其输入就是一组参数,去判断这一组参数的好坏;
- 解一个优化的问题,找一个 θ,该 θ 可以让损失的值越小越好。定义损失的值最小的 θ 为θ∗,即:
有了 θ∗ 以后,就把它拿来用在测试集上,也就是把本来 fθ(x)里面有一些未知的参数用 θ∗ 来取代,输入是测试集,输出的结果存起来,上传到Kaggle 就结束了。
感谢您的学习,让我们共同探索机器学习的奥秘!我们下期再见!
标签:函数,Sigmoid,AI,李宏毅,Datawhale,参数,ReLU,梯度,数据 From: https://blog.csdn.net/MrBlackmzq/article/details/141642807