从初中物理到大模型原理(二)
上篇文章:从初中物理到大模型原理(一)
下两篇
从初中物理到大模型原理(三)
从初中物理到大模型原理(四)
一、神经网络和多层感知机
之前简单的带出了神经网络 和 多层感知机,这里描述一下概念。
神经网络是一种受生物神经系统启发而设计的计算模型,广泛应用于机器学习和人工智能领域。它通过模拟人脑中神经元之间的连接与信息传递机制,实现对复杂数据(如图像、声音、文本等)的学习和推理。我们还是用上一篇最后的表达式: O = f ( W ∗ X + b ) \mathbf{O} = f(\mathbf{W} * \mathbf{X} + \mathbf{b}) O=f(W∗X+b) 其中 O \mathbf{O} O 代表输出, W \mathbf{W} W代表权重, X \mathbf{X} X代表输入, b \mathbf{b} b代表偏置。
神经网络的基本结构是:
- 输入层:接受参数,比如上文提到的力,弹性系数等
- 隐藏层:做非线性的变换,提取特征,比如是好还是坏
- 输出层:分类结果
这个只有三层的网络,我们统一称之为:单隐层神经网络。
所谓多层感知机,就是加了多个隐藏层,有的是线性变换,有的是非线性变换,也有交替出现的,比较常见的是
- 输入层:接受参数,假设为 8 * 10 的矩阵
- 隐藏层:权重为 10 * 20 的矩阵,输出形状为 8 * 20
- 隐藏层:RELU激活函数
- 隐藏层:权重 20 * 10 的矩阵,输出形状为 8 * 10
- 隐藏层:RELU激活函数
- 输出层:权重为 10 * 4 的矩阵,输出形状为 8 * 4
这个模型,我们可以简单的想象成,有8根弹簧,10个输入分别表示这个弹簧的不同参数(比如:生产厂家,材料,弹性系数,所受外力等等等等),通过这个模型的计算,可以得出这8个弹簧在当前的10个输入条件下,是好还是坏。
下面,我们用Pytorch框架简单实现以下上面这个模型
import torch
from torch import nn
net = nn.Sequential(nn.Linear(10, 20, bias=False),
nn.ReLU(),
nn.Linear(20, 10, bias=False),
nn.ReLU(),
nn.Linear(10, 4, bias=False))
X = torch.randn(8, 10)
Y = net(X)
多层感知机(MLP) 是一种经典的前馈神经网络,由输入层、至少一个隐藏层和输出层组成。它通过堆叠多个“神经元层”并引入非线性激活函数,能够解决单层感知机无法处理的非线性可分类问题,是深度学习的基础模型之一。
这里另外介绍一个定理,叫万能逼近定理,它的核心结论是:一个包含至少一层隐藏层且使用非线性激活函数的MLP,可以逼近任意连续函数。
这里再留一个问题,我们在设计模型的时候,是用一个层数少,但是很宽的,还是层数多,相对较窄的模型呢?(同样的,我们后面再讨论)
二、大模型
大模型其实是大语言模型(Large Language Model 称 LLM ),大模型就是一个复杂的多层感知机,在某些层中间添加了更多的运算,学到了更多的权重(参数),我们通常说的32B,就是320亿个参数。
我们简单描述一下大模型的计算过程,假设我们现在有一句话:从初中物理到大模型原理,我们现在需要用:从初中物理到大模型原 这十个字来预测第十一个字 理。
首先,我们需要一个词库,一个囊括了世界上所有的字的词库,一个假设只有100个字的词库(GPT-2是50257个),这个词库里包含了"去我从额的······人法国初撒地方中热······退热物结果回复理儿童到吧大特······给意和模鳄型啊······包就看含了键······原"等等共100个,我们把每个词都称为一个token;
然后,我们用简单的0-99来代表这100字所处的位置,称为tokenId(GPT-2使用了tiktoken.get_encoding(“gpt2”).encode(“XXXXXX”)来计算),那么我们就得到了一个向量
x
=
(
2
,
28
,
32
,
⋅
⋅
⋅
,
99
)
\mathbf{x} = (2,28,32,···,99)
x=(2,28,32,⋅⋅⋅,99) 分别表示 从初中物理到大模型原,那么在计算后,我们很希望模型可以直接返回
y
=
55
y = 55
y=55 代表理,但通常来讲是不太可能的。
简单来说 从初中物理到大模型原型 和 从初中物理到大模型原理 看起来都很合理,我们需要想办法让返回结果是 理,而不是 型。
是时候来讨论一下上一篇提到的一个问题了,我们用什么方式来表达输出值,第一种用一个变量的1或者0来代表好坏,还有一种是用(1,0)代表好,(0,1)代表坏,那么哪个方式更适合呢? 很显然是第二种合适。从概率的角度去看,如果词库共有100个字,那么理论上我们预测的字肯定在这里面,也就是说每一个字都有可能性,大数定律告诉我们,当数量足够大时,频率就等于概率。我们肯定会选概率最大的那个字。假设我们在预测后面的11,12,13,14个字的时候,如果每一步都选概率最大的,那么结果一定是概率最大的吗?答案是不一定。这里就涉及到贪心算法在搜索上的应用。我们举一个极端的例子来说明一下这个问题(注意:以下的概率只是为了说明问题,不代表真实的概率!!!!)
假设第一个字是"食",而我们的词库只有10个字,后面的概率请看下图:
如果我们每一步都选概率最大的,那么结果是"食物不够"=
0.3
∗
0.4
∗
0.5
=
0.06
0.3*0.4*0.5=0.06
0.3∗0.4∗0.5=0.06, 但是,我相信大家也看了,如果选择"食屎啦你",那么结果就是
0.1
∗
0.9
∗
0.9
=
0.08
0.1*0.9*0.9=0.08
0.1∗0.9∗0.9=0.08,整体效果是更好的。虽然例子有点极端,但大概就是这么个意思。所以就有了束搜索的算法,就是每次计算的结果,返回概率相对比较大的几个候选,而不是概率最大的候选。所以,如果我们用一个变量来表示,显然是无法满足的,因此在上面这个例子中,词库有10个字的情况下,最好的结果就是用10个数来表示每个字出现的概率。
当然正常情况下,预测结果肯定不是"食屎啦你",但是,假设我在加一个条件"张学友",那么预测结果看起来就比较正常了,如果我再加上《旺角卡门》那么几乎可以确定"食"的预测结果就是"食屎啦你"。
所以,输入的数据对输出的结果很重要,而且不同的输入也会产生不同的输出。看起来这是一句废话。可我们怎么在不知道结果的情况下,衡量这种不同呢?我们现在来讨论以下上一篇文章中的另外一个问题 在只有数据点的情况下,每个点对最后形成的直线的影响怎么衡量?或者说每个点怎么估计自己离最后那条直线的距离? 我们来看下面的图,这个图里有100个点:这些数据,通过线性模型训练,将来会得到一条直线,采用均方误差作为损失函数时,
(
y
−
w
x
−
b
)
(y-wx-b)
(y−wx−b)的大小,就代表了这个点对将来形成的直线的影响。我们考虑一个比较极端的情况,假设有99个点比较集中,有一个点比较远,那么这根直线将来势必会距离这99个点更近一些。对,我要说的其实就是注意力机制:用相对距离代表影响程度的权重。
所以现在的问题就是怎么衡量距离,或者说,怎么衡量点与点之间关系。
在直角坐标系中,我们随便取两个点
x
1
=
(
1
,
0
)
x_1=(1,0)
x1=(1,0)
x
2
=
(
1
,
1
)
x_2=(1,1)
x2=(1,1) 。再从原点出发,得到了两个向量
x
1
=
(
1
,
0
)
\mathbf{x_1} = (1,0)
x1=(1,0)
x
2
=
(
1
,
1
)
\mathbf{x_2} = (1,1)
x2=(1,1),向量的点积使用
x
1
⋅
x
2
\mathbf{x_1}·\mathbf{x_2}
x1⋅x2 来表示,点积的几何含义就是
x
1
\mathbf{x_1}
x1 在
x
2
\mathbf{x_2}
x2 上的投影,用 |
x
1
\mathbf{x_1}
x1||
x
2
∣
c
o
s
θ
\mathbf{x_2}|cos\theta
x2∣cosθ来表示,这就衡量了
x
1
x_1
x1 和
x
2
x_2
x2 的关系,数学上用
x
1
⋅
x
2
=
x
1
x
2
+
y
1
y
2
\mathbf{x_1}·\mathbf{x_2}=x_1x_2 + y_1y_2
x1⋅x2=x1x2+y1y2 来计算,上面这个例子点积的计算结果就是
1
1
1
那么,在大模型里是怎么计算的呢?我们下一篇做一个详细的讨论。然后用代码做一个简单的实现。
think twice code once