-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
115 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
我们要找到一个 model function,通过调整它的参数,可以生成任何形状的函数,也就是说这个函数拥有无限的潜力。 | ||
|
||
我们的目标函数可能没有任何规律,如下图所示: | ||
|
||
<img width=300 src="https://github.com/ascoders/imageStore/assets/7970947/8bbd53da-c15c-4fb2-9b20-3efc96f9b75a"> | ||
|
||
那么怎么样找到一个 model function,拥有成长为(通过调参)上图函数的潜力呢? | ||
|
||
## 启动函数 | ||
|
||
接下来,假设我们能写出以下函数 - Hard Sigmoid: | ||
|
||
<img width=200 src="https://github.com/ascoders/imageStore/assets/7970947/6ef716f4-91dd-4168-a83d-91483331d276"> | ||
|
||
通过叠加多个不同的 Hard Sigmoid 可以匹配到上图复杂函数: | ||
|
||
<img width=400 src="https://github.com/ascoders/imageStore/assets/7970947/73337ee7-ecfe-4e15-bf86-08f3055eb055"> | ||
|
||
> 上图叠加后不等于原图,但很直观。实际上这 5 条线叠加起来后,每到下一个台阶都会受到上一条 Hard Sigmoid 函数尾部常量的叠加,位置会产生偏移,但这是可以通过调整线条位置解决的。可以肯定的是,可以通过叠加多条 Hard Sigmoid 函数实现上图效果。 | ||
实际上除了 Hard Sigmoid 外,还有 Sigmoid、RELU 等等多种函数可以通过叠加实现任意函数,这种函数称为 “启动函数”。每一种函数都有明确表达式,比如 Sigmoid: | ||
|
||
<img width=200 src="https://github.com/ascoders/imageStore/assets/7970947/8af35ac9-f6d5-48c0-b1d8-018eb9f905f6"> | ||
|
||
当 x 趋向于正无穷时,y 趋向于 c,当 x 趋向于负无穷时,y 趋向于 0。Hard Sigmoid 可以通过 Sigmoid 来近似。 | ||
|
||
另外因为 optimization 阶段需要对 loss function 求导,启动函数也要参与求导,所以启动函数的导数越容易计算,且计算量越小,它在机器学习中就越占优势。 | ||
|
||
比如 Sigmoid 为什么用自然对数 e 为底数呢?因为它的导数可以通过自身得出: | ||
|
||
<img width=180 src="https://github.com/ascoders/imageStore/assets/7970947/21b9fd37-c42c-494a-bdf7-6bc57e372497"> | ||
|
||
即根据当前函数的值进行一个减法与乘法,就能得到导数的值,非常巧妙。 | ||
|
||
先就此打住,我们回到找通用 model function 的问题,如何利用启动函数生成可以逼近一切函数的 model function? | ||
|
||
## 一个变量时的 model function | ||
|
||
根据启动函数的思考,我们发现通过叠加 n 条启动函数就可以逼近一切函数,因此我们要找的 model function 就是由 n 条启动函数组成的巨大函数。 | ||
|
||
以 Sigmoid 函数为例,它拥有 c、w 和 b 三个未知参数。它们与未知数 x 的运算关系是:w 乘以 x,加上 b,最后乘以 c。 | ||
|
||
当然,不同的启动函数未知参数数量也不同,但大致我们可以认为,与未知数 x 的运算分为三大类: | ||
|
||
1. 第一大类是 w 参数,与 x 相乘关系,决定了 x 的权重。 | ||
2. 第二大类是 b 参数,与 x 相加关系,决定了偏移量。 | ||
3. 第三大类是启动函数运算,比如通过 Sigmoid 以自然对数 e 为底进行了一系列变换,让结果变成平滑曲线,最后再乘以 c,等等。 | ||
|
||
**所以我们可以抽象理解为,对于变量 x 都至少要经过 w 的权重调整,以及 b 的偏移调整,最后再做一系列启动函数变化(最后的系数 c 也可以带入,但为了后续画图方便这里忽略 c)。** | ||
|
||
那么对于变量 x 来说,要形成上图多条启动函数叠加,每个启动函数会拥有自己不同的 w 与 b 参数: | ||
|
||
<img width=400 src="https://github.com/ascoders/imageStore/assets/7970947/a459dcab-33a0-455a-9bba-4966635219fb"> | ||
|
||
另一方面,以上只是入参只有 x 一个变量的情况,但实际上输入不一定只有一个变量,比如图像识别入参数量就是图片像素点乘以 rgb 的个数,ChatGPT 入参是输入文字的 token 个数,一旦入参从一个变成两个,函数图像就从二维图形变成了三维: | ||
|
||
<img width=400 src="https://github.com/ascoders/imageStore/assets/7970947/9c708f59-2382-4b87-9077-b9eb0d2282e2"> | ||
|
||
如果入参继续增加,这个函数将变得更加高维,人类我发想象出它的图像,但从数学上来讲,我们是在求解一个很高维的函数。 | ||
|
||
## 多个变量时的 model function | ||
|
||
假设输入有 m 个变量,从 `x₁` `x₂` 一直到 `xₘ`,每个变量叠加 n 个启动函数,也就是 `x₁` 在每个启动函数都有 n 个 w 与 b 参数,以此类推,一共有 `n x m` 个 w 与 b 参数。 | ||
|
||
画成图之后会发现,对于每一个启动函数,叠加了 n 个常量 b,所以我们可以把这些常量求和看成是一个参数,简化函数的参数: | ||
|
||
<img width=450 src="https://github.com/ascoders/imageStore/assets/7970947/94113d55-4c56-486c-b402-24dcfcc73a57"> | ||
|
||
写成函数式就是(我们忽略了最后一步 Sigmoid 操作,只是为了简化写法): | ||
|
||
<img width=400 src="https://github.com/ascoders/imageStore/assets/7970947/00410d21-ab20-4e02-936f-8c98d130f650"> | ||
|
||
最终要求解的 `y = y₁ + y₂ .. + yₙ`,我们发现,这个值正好等于以下两个矩阵的点积(忽略对常数 b 的计算): | ||
|
||
<img width=340 src="https://github.com/ascoders/imageStore/assets/7970947/465eee87-7089-46ac-b7dc-7a3048fbceed"> | ||
|
||
而矩阵运算可以利用 GPU 并行执行,也就是无论未知数变量 m 或者启动函数数量 n 为多少,计算的时间复杂度都是常数 O(1),这也是为什么机器学习必须用 GPU 计算的原因,不是 CPU 算不了,而是计算速度被矩阵运算甩了好几个数量级。 | ||
|
||
## 神经网络的深度 | ||
|
||
之所以机器学习和神经网络这两个名词总是一起出现,是因为神经网络是目前机器学习最好的架构。而我们上面提到的 model function 就是一个神经网络,它的深度只有一层。 | ||
|
||
之所以叫神经网络,是因为把输入的 m 个未知变量当做信号刺激,把 n 个计算节点看作神经节点的话,它和人脑的神经网络接收电信号的过程很像,只不过它只有一层网络,这一层有 n 个神经元。 | ||
|
||
如果我们把神经网络拓展到 p 层呢?我们把神经网络画出两层,以便于理解 p 层神经网络的架构: | ||
|
||
<img width=600 src="https://github.com/ascoders/imageStore/assets/7970947/46d3e9ae-e3ce-42a5-9514-a4e3b1eaf128"> | ||
|
||
即把每层网络的输出作为下一层网络的输入,就可以无限增加神经网络的深度了。注意每一次各个点的参数 w 与 b 都不一样,每一层的节点数量也可以不同。 | ||
|
||
如果把每个神经网络抽象为一个点,从左到右画,神经网络就可以抽象为下图: | ||
|
||
<img width=300 src="https://github.com/ascoders/imageStore/assets/7970947/0d73ec07-f559-4fb3-82f0-5a603f0ef6fc"> | ||
|
||
实验证明,神经网络层级越深,每个节点的神经元越多,一般来说这个神经网络的潜力越大,效果越小。但相应的,越复杂的神经网络越难 training。 | ||
|
||
## 总结 | ||
|
||
从模拟任意函数的角度,我们发现通过启动函数的无限叠加,理论上可以逼近一切函数。而面对真实世界的输入,我们可以构造矩阵计算来解决。 | ||
|
||
如果问题的复杂度太高,一层神经网络往往不会有很好的效果,但我们惊讶地发现,通过让神经网络变得越来越深,往往能取得更好的效果,因为也许这能模拟人脑各神经元之间处理神经信号的特征。 | ||
|
||
至于为什么神经网络越深效果越好,以下是 ChatGPT 给的回答: | ||
|
||
> 1. 表示能力:深度神经网络能够学习更复杂的特征表示。在神经网络中,每一层都在对输入数据进行一种变换,更深的网络意味着可以进行更多的变换,从而捕捉到更高层次的、更复杂的数据特征和抽象。这使得深度神经网络在处理复杂任务时,如图像识别、语音识别或自然语言处理等,表现得更为出色。 | ||
> | ||
> 2. 层次化特征学习:深度神经网络通过多层次的方式学习数据特征,底层网络学习简单的特征(如边缘和角落),而更高层的网络则基于底层特征学习更复杂的特征(如物体的部分和整体结构)。这种层次化的学习方式模仿了人类大脑处理信息的方式,提高了模型的学习效率和效果。 | ||
> | ||
> 3. 端到端学习:深度学习模型能够直接从原始数据到最终的任务结果之间建立复杂的映射,而不需要人工设计特征或复杂的预处理步骤。随着网络深度的增加,这种端到端的映射能力变得更加强大。 | ||
> | ||
> 然而,深度神经网络并非没有缺点。随着网络深度的增加,也会带来一些挑战,如梯度消失或梯度爆炸问题、过拟合、以及更高的计算成本和内存需求。因此,虽然深度神经网络在很多任务上表现出色,但设计和训练这样的网络需要谨慎和精细的技术,如残差连接(ResNet)、批量归一化、Dropout等技术,以及更高效的优化算法。 | ||
有一点是可以肯定的,即因为网络深度的增加,确实会带来如 ChatGPT 所说的一系列问题,而这也是许多机器学习领域的专家研究的方向,在之后的章节中,我们会提到具体代码实现以及部分优化思路。我们下一篇就来介绍,如何设计该神经网络的代码。 |