神经网络(NN)基础
训练 - Training
梯度消失问题 Vanishing Gradient Problem
前向传播和反向传播
前向传播就是神经网络拿到输入,然后一层一层地计算输出,最后得出预测结果。
那么,什么是“反向传播”呢?因为我们想要“教”神经网络学东西,但神经网络的结果有误,却不知道哪里错了。
所以,我们需要通过反向传播,来告诉神经网络每一层应该怎么调整。
梯度消失
举个例子,假设我们有一个简单的神经网络:
- 输入 x = 1
- 隐藏层(1个神经元)
- 输出层(1个神经元)
- 激活函数 g(x) = sigmoid(x)
假设权重:
- 输入到隐藏层的权重 w₁ = 0.5
- 隐藏层到输出层的权重 w₂ = 0.5
对于隐藏层,输入是:z₁ = x × w₁ = 1 × 0.5 = 0.5
,输出是:a₁ = sigmoid(0.5) ≈ 0.62
对于输出层,输入是来自隐藏层传递:z₂ = a₁ × w₂ = 0.62 × 0.5 = 0.31
,输出是:a₂ = sigmoid(0.31) ≈ 0.58
网络输出为 0.58,假设目标是 1,我们知道它错了。
现在,网络进行“反向传播”,每次传播回来,要乘上激活函数的导数 g'(x)。
Sigmoid 函数的导数 σ ′(x) 的最大值是 0.25,这个最大值在 x=0 时取得。
那么问题来了,如果你有很多层,每一层都乘一个 小于 1 的数(比如 0.25),那越乘越小,比如:0.25 × 0.25 × 0.25 × 0.25 × ... ≈ 接近 0
这就意味着:越前面的层,更新得越少,学不到东西,这就叫梯度消失!
非零中心问题 Not Zero-Centered Problem
激活函数
诶,前面只顾着用但忘记讲了,什么是激活函数呢?
激活函数就是神经网络中每个神经元的“小开关”,它把输入变成一个输出值,常见的像:
- Sigmoid:输出值总是介于 0 到 1,比如 0.9 或 0.1
- Tanh:输出值在 -1 到 1,比如 -0.8、0、0.9
零中心 zero-centered
其实就是以0为中心,输出结果在0的左边(比0小)或者右边(比0大)的都有,也就是输出结果既有正数也有负数。
比如 Tanh 输出可以是 -0.5,也可以是 +0.5,这叫 zero-centered。
而 Sigmoid 输出总是在 0 以上(从不为负),这就不是 zero-centered。
而本节讲的非零中心问题 Not Zero-Centered Problem,也就是说输出结果没有正负存在的话,就会出现问题。
为什么会出问题?
那么,为什么非零中心就会有问题呢?
想象你在用“梯度下降”让神经网络慢慢变聪明——你要不断调整权重(weights)去找最优值。
假设你有两个权重:w₁ 和 w₂,期望它们会不断进行学习调整。
可是,如果你的激活函数(比如 Sigmoid)输出的都是正值,你算出来的梯度也可能都是正值。
梯度 = 输出误差 × 激活函数的导数 × 输入值,这3部分的乘积影响了梯度的“方向”和“大小”。
对于Sigmoid,每层的输入值、导数都是正的,所以 w₁ 和 w₂ 就会一直 “都增加” 或者 “都减少”,导致权重更新方向不平衡,训练更慢、更难收敛。
梯度 gradient
是的,这里又出现了新词——梯度。
顾名思义,梯度就像楼梯每一个阶梯的高度一样,决定我们修改权重时要迈出的每一步的大小。也就是——现在这个权重应该变大还是变小?变多少?
假设w1的梯度为+0.02
,w2的梯度为+0.01
,那么,w1、w2权重在更新之后就会变成w1=w1-0.01
、w2=w2-0.01
。
Z型路线 zig-zag
回到“为什么会出问题?”这个问题。
正因为非零中心,导致不同权重的更新方向一致,也就是——导致梯度对不同权重的贡献方向一致(不是一起增就是一起减)。
就像你在走楼梯时,每走一阶,左右脚都在朝着同一个方向歪着走,结果就容易变成蛇形走位(锯齿形、Z 字型)。
因此,我们希望激活函数以零为中心。
激活函数的选择 Choice of Activation Function
我们在前面已经介绍过“激活函数”的概念,激活函数实际上决定了:输出值的范围、网络能不能学到复杂的模式、梯度是不是能够顺利传回来等问题。
我们有三种常见的激活函数——Sigmoid、TanH、ReLU。
它们长这样(可以提前标记一下该图,后面将参照对每个激活函数进行解析):

Sigmoid——S曲线
正如上节的图所示,这是一条“S曲线”。
公式 | sigmoid(x) = 1 / (1 + e^(-x)) |
---|---|
输入范围 | 任意数 |
输出范围 | (0, 1)(都是正的) |
导数 (g’) | sigmoid'(x) = sigmoid(x) * (1 - sigmoid(x)) |
它其实以前很流行被用做激活函数,正因为它的输出——0~1,非常像“概率”,因为概率也是0~1,看起来有意义。
但缺点也正如同我们上面所分析的,它会有:梯度消失问题、非零中心问题,以及其含有exp(x)(exp(x) = e^x,指数函数)导致计算会变慢、效率低。
Tanh——双曲正切
tanh函数其实是sigmoid函数向下平移和收缩后的结果,是其具备了零中心的特性。
公式 | tanh(x) = (e^x - e^(-x)) / (e^x + e^(-x)) |
---|---|
输入范围 | 任意数 |
输出范围 | (-1, 1)(符合零中心) |
导数 (g’) | tanh'(x) = 1 - tanh(x)^2 |
但同样的,其也会存在梯度消失的问题(函数特性相对于Sigmoid没变,只是向下平移了),并且也用了exp(),运算慢。
ReLU——线性整流函数
ReLU 广泛应用于CNN(从AlexNet 开始),其中一个原因就是:计算特别快——它无需计算exp(x),只要对比一下大小就行。
公式 | ReLU(x) = max(0, x) |
---|---|
输入范围 | 任意数 |
输出范围 | [0, ∞) |
导数 (g’) | ReLU'(x) = 0 if x < 0, 1 if x > 0 |
除此之外,根据图像可知,它对于正值输入部分,没有梯度消失的问题。
但对于负值的输入,它直接输出是0了...导致导数也是0 → 进而使其梯度完全没了→ 神经元会鼠掉(永远不再更新)。这是它的一个缺点,也是我们常说的“ReLU 的神经元死亡问题(Dying ReLU Problem)”。
另外一个缺点就是,它不是一个零中心的激活函数。
下面是ReLU的一些变体:
名字 | 公式 | 优点 | 缺点 |
---|---|---|---|
Leaky ReLU | max(0.01x, x) | 负数部分也给一点梯度(不死) | 有点偏正 |
Parametric ReLU | max(ax, x),a 是可学习的 | 像 Leaky ReLU,但更灵活 | 增加参数 |
ReLU6 | min(max(0, x), 6) | 限制最大值,防止爆炸 | 非连续,仍非零中心 |
ELU | x (x≥0), α*(exp(x)-1)(x小于0) | 有负输出又平滑 | 要计算 exp(),慢 |
Maxout | max(w1x + b1, w2x + b2) | 更强大 | 参数量变成 2 倍 |
计算机视觉 - Vision
计算机视觉&卷积神经网络 Vision&CNN
什么是计算机视觉?
就是让电脑“看”图像和视频,并理解里面是什么东西。
就像你看到一只猫,你能立刻知道它是猫。我们希望让电脑也能像人一样做到这一点。
基于计算机视觉,我们可以联想到其在生活中的应用:
应用场景 | 举个例子 |
---|---|
图像识别 | Google Photos 识别“狗狗”或“人脸” |
视频搜索 | 快手/抖音用 AI 给你推荐内容 |
安全系统 | 人脸识别开门、刷虹膜、刷指纹 |
医学图像处理 | 识别 X 光片里的肿瘤 |
机器人 | 机器人走路需要“看清”前方障碍物 |
自动驾驶 | Tesla 自动识别红绿灯、行人、路标等 |
计算机视觉为何兴起?
- 拍照、录像变得很便宜(手机摄像头 + 网络)
- 视频内容越来越多(2022年,视频占了整个网络82%的流量)
- 每年互联网用户还增长10%
所以——我们很需要AI能处理图像/视频
计算机视觉的挑战
其实,想让计算机理解图片,是很有挑战的。
科学家常用自然动物的特性来研发新产品,我们可以想一下为何人、动物能理解视觉?
这其实要说到进化论——人类花了10万年进化出抽象思考,花2.3亿年进化走路,又花了5.4亿年进化出视觉感知。
科学家Hubel和Wiesel曾在1959年做实验,分析猫大脑的电信号,在其观察图片时,他们发现:猫的大脑是按“层”来处理图像的——比如,先看边缘和线条 → 再看形状 → 再看“对方是不是猫”等这类抽象的概念。
其实,人类也是这样分层感知图像的。所以现在的神经网络,比如 CNN(卷积神经网络)也模仿这个结构。
但计算机视觉毕竟不是生物,其还受制于图片输入的挑战,比如说:尺寸不一样、角度变化、背景杂乱、同一种东西图片差别大、光线变化、多个物体同时存在、要找出具体区域等问题。
更专业来说,举个例子,数图里的香蕉有几根,计算机视觉需要有目标计数(Object counting)的能力;找出哪里是树,哪里是地面,则需要语义分割(Semantic Segmentation);看视频里有没有人走进房间,则需要动作检测...
初识卷积神经网络 Convolutional Neural Networks (CNNs)
在1998年,Yann LeCun用CNN和反向传播算法识别了手写数字(MNIST 数据集),准确率高达 99.67%,比人类还强。
CNN正如上述所说,是通过分层来处理的,并且分为了两个板块:
第一个板块是特征提取,这里包括了卷积层(Convolutional layer)和池化层(下采样层)(Pooling (subsampling) layer)。
第二个板块是分类,这里包括了全连接层(Fully connected layer)。
第一层是输入层,用于接收原始数据。
CNN-卷积层 Convolutional layer
卷积层就像一个会滑动的小窗口,用来一块块“扫描”图片局部,通过乘法 + 偏置计算出每块区域有没有特征,然后拼成一个新图(特征图)继续传下去。
其中,“会滑动的小窗口”就叫滤波器(Filter / Kernel)。它是一组固定大小的权重(比如 3×3 的权重矩阵),负责“检查某种特征”,比如:边缘、角、亮暗变化等。
然后,通过滤波器每次滑动时候覆盖的那一块小区域就叫做局部感受野(Local Receptive Field),比如这个小窗口是 3×3,那它每次“看的”就是图片中的一个 3×3 小块。
还有一个参数共享(Parameter Sharing)的概念,意思是:同一个滤波器(也就是同一组参数)在整张图上反复使用。
卷积完了之后,会对结果立马套一个激活函数,常用的是 ReLU(把负数变0,正数保留)。图像通过卷积层,最终生成特征图(feature map)作为输出传给下一层。

以上是一个步长为1的滤波器,代表着每次滤波器的那个窗口移动1格,最终我们得到一个6*6的特征图。
填充 Padding
在上面我们观察到,原始图像经过滤波器后,得出的结果矩阵会比输入的要小。而Padding 的意思是:在图片的边缘“补一圈零”,让卷积之后的图不变小。
加上Padding后,我们卷积层的输出矩阵大小变为:(N+2P-F)/S+1,其中N = 输入图大小,F = 滤波器大小,P = padding 大小,S = 步长 stride。
CNN-池化层 Pooling layer
池化层 = “信息压缩层”,通常是紧跟在卷积层之后使用的,它们是一前一后配合使用,像搭档一样,一个提取特征,一个简化特征。
具体来说,它会用一个小窗口(比如 2×2)在图像上滑动,每次只保留一小块里的最大值或平均值,从而把图像缩小、简化。
池化层不用到激活函数,因为它本质是“取最大值”或“取平均值”,这个操作本身就是非线性的,不用额外加激活函数。
池化有以下好处:
- 减少数据量:减少图片尺寸,加快总流程速度,节省内存。
- 减少参数,防止过拟合。
- 实现“位置不敏感”(Translation Invariance)。比如说,如果猫在图片中稍微移动了位置,池化后还是能够认出来,因为池化层会把附近的一堆值“压缩成一个代表值”(比如最大值),这样就不关心你这个“亮点”原来具体在哪,只关心在不在就行。
CNN-全连接层 Dense layer
全连接层(Fully Connected Layer),也称为密集连接层(Dense Layer),是深度学习神经网络中的一种基本层类型,其每一个神经元都和前一层的所有输出相连接。
Dense(全连接)层就是把前面 CNN 找到的所有“特征”拉成一条线,然后统一做最终判断,比如“这是不是一只猫”。
通过前面所说的卷积层、池化层,我们实现了对图片的一块块扫描(卷积),提取出了特征(哪些地方有耳朵、眼睛),然后用池化压缩、简化这些信息,这些都保留了空间结构(比如耳朵在猫的上方,腿在猫的下方)。
到了最后一步,我们不再关心这些特征的具体位置,而是只想知道:“有没有耳朵?有没有眼睛?那就是猫!”
所以我们把这些信息,全都“拉平”成一条向量(flatten),然后送给全连接层判断。
ImageNet
ImageNet 是一个超级大的图片库,里面有超过 1400 万张图片,而且每张图片都标注好了这是什么东西。
我们期待AI学会“看图说话”,就需要将ImageNet这种带有很多标签的图像喂给AI进行训练。
由此也有了,ImageNet Challenge竞赛,这是一个图像分类的世界级比赛,谁的 AI 模型在这上面得分高,谁就是图像识别界的佼佼者。
常见的模型有AlexNet 2012, ZFNet 2013, VGNet 2014, GoogLeNet 2014, ResNet 2015, ReduNet 2022等,我们这里只抽一些来讲。
VGNet 2014
VGGNet 是牛津大学的一个研究团队(VGG = Visual Geometry Group)在 2014 年提出的一个深度卷积神经网络模型。
重点特点是:用很多个小的 3x3 卷积层,一层一层叠得很深,结构非常规整、漂亮,像“堆乐高”。
GoogLeNet 2014
GoogLeNet 用 Inception 模块聪明组合不同大小的卷积核,同时又节省计算资源,是 AlexNet 的升级加强版。
你可以想象 Inception 模块是这样的场景:图片里有大猫、有小狗、有细节、有整体……你用 1x1、3x3、5x5 的卷积“眼睛”去看,看完再把结果拼起来,就能看清楚不同尺寸的特征。
ResNet 2015
我们总结一下前面的两个模型:
- VGNet(2014)是简单粗暴的堆卷积。它堆很多 3×3 的卷积,网络很深(16或19层),但结构很整齐,结果很好,但参数超级多(138M 参数!)——很占内存,也难训练。
- GoogLeNet / Inception v1(2014)是聪明节省资源。用Inception模块来并行试不同的卷积(1x1、3x3、5x5)+ pooling,一次搞定多个尺度特征。然后把结果 concat(拼在一起),这样网络自己决定用哪个。用了大量的 1x1卷积 来降低通道数,降低计算量。
虽然 VG 和 GoogLeNet 都是深网络,但“更深≠更好”,层数越多,更会导致梯度消失、优化困难、训练误差反而变大了!
而ResNet利用“残差”连接,如果说传统网络是输入 x → 网络 → 输出 H(x)
,那么ResNet就是输出 = F(x) + x
,其中F(x)就是残差,代表ResNet只学习变化的内容。如果F(x)=0,则输出
直接等于了x
,这就说明网络优化后至少不会比原来的差,这就避免了“越深越差”的问题!
Visualizing and Understanding CNN
这是一篇 Zeiler 和 Fergus 在 2013 年的论文,其目的是帮助我们看懂 CNN(卷积神经网络)到底“看”到了什么。
遮挡敏感性测试 Occlusion Sensitivity
我们很好奇,网络是否真正识别了物体?

于是,就有了这个测试,它用一个灰色方块,遮挡图片的某一小块区域,观察 CNN 是否还能正确预测。
比如,原图是狗,用灰块遮住耳朵/眼睛/身体某个部位,如果遮住某块区域后预测准确率大幅下降,说明这块区域是 CNN 非常“在意”的。
重复这个过程,滑动这个遮挡块,把整张图都测一遍,得到一个“热图”:亮的区域代表不重要(遮住也能预测),暗的区域代表很重要(遮住后预测就错),这就叫做显著性图(Saliency Map)。
梯度上升法可视化神经元 Gradient Ascent
我们还期望知道,神经元到底关注什么?
梯度上升(Gradient Ascent)法创建一张“假的图片”,让它能激活网络中的某个神经元最强。

简单来说,举个例子,随便弄一张黑色图片(全是0)作为输入,然后正向传播计算这个图激活神经元的值(比如:图像是“狗”的概率分数),再反向传播,计算改变哪些像素能让得分变高。这时,微调图像像素,让它越来越“像”神经元想看到的样子,并不断重复这个过程进行像素微调,最终得到一张“合成图”,可能是一个狗的轮廓、键盘、大象等等。
这说明:网络是通过某些特定图案来认物体的,而不是瞎猜。
最强激活图块 Maximally Activating Patches
我们还可以用最强激活图块法,来测试每层的神经元到底关注啥。
网络里的每个神经元都对一些图案特别敏感,比如第 N 层的某个神经元可能特别喜欢看到“轮胎”。
在这个方法中,我们用很多图片去喂CNN,找到那些让某个神经元“反应最快”的图块,然后把这些图块(patches)显示出来。
通过观察结果,我们可以看到:越往后面的层,看到的图案越复杂,比如:第一层 → 只看到边缘、角落等基本图形,第五层 → 可能能看到狗脸、汽车、沙发。
如何找到相似图片?
最简单的方法,我们可以使用“像素空间”(Similarity Measures / Euclidean distance),也就是,比较图片的每个像素,像素值越接近越相似(欧几里得距离)。但这种方法只能找出看起来很相似的图片,但也许实际上图片的内容根本无关,如下所示:

这时,我们可以使用“特征空间”,我们把图片输入到CNN,取最后一层的feature vector(比如4096堆),然后用向量距离(比如欧几里得距离)比较图片的特征向量,这样以来,我们就可以避免颜色、角度、大小等干扰因素,确保只关注“图像内容”本身。
对抗样本 Adversarial Images
对抗样本就是:“一张肉眼看不出变化的图片,但能让 AI 模型(如 CNN)认错。”

比如我们原图是一只熊猫,CNN预测正确。
这个时候,我们在图像里加入一点点“噪音”,CNN 却把这张图认成 🐒 长臂猿(gibbon)。
为什么CNN容易被骗?
因为人类识别熊猫靠的是抽象特征(黑眼圈、大白脸、毛发),而CNN是靠像素之间的微妙数学关系,所以稍微动一动像素,就可能严重影响模型的判断。
这么一来,对抗样本可能严重威胁机器学习的结果,比如:自动驾驶车看不出停车牌,对抗样本把“停车标志”变得像“限速标志”,车就会不停下来。又或者安检机器识别错武器,把一把刀加入噪音使CNN看起来像雨伞,安检就放行了。
如何制作对抗样本?
对抗样本是我们知道了模型的内部结构、权重和参数,因此专门设计对抗扰动去欺骗它,也被称为白盒攻击(White-box attack)。
白盒攻击最常见的方法是快速梯度符号法——FGSM(Fast Gradient Sign Method),其用于快速生成对抗样本(欺骗模型)。
其公式为:
adv_x = x + ε × sign(∇x J(θ, x, y))
,其中:
x:原图 y:原来的标签(比如“猫”) J():损失函数,衡量模型输出错得多严重 ∇x J:告诉我们“动哪些像素能让模型出错最多” sign():只取方向(加还是减) ε:扰动强度(越小越不容易被肉眼看出来) adv_x:最终得到的对抗图片
当我们想要故意攻击模型,使其识别为指定的错误类别,这种过程也叫做目标攻击(Targeted Attack)。
只有神经网络会被骗吗?
其实不是,很多机器学习模型都会被骗,比如linear models,SVM,k-nn等等。
甚至是人脑,其实也会被骗。还记得互联网刚兴起的时候,就有许多视觉错觉的图片,这就是一种对人类大脑的“对抗样本”。
如何防御对抗样本攻击?
办法很简单:在训练的时候,加入对抗样本当作正常样本来训练模型。
比如,原图(猫)→ label 猫,对抗图(被修改过的猫)→ 也标注为猫。
经过反复训练,模型会学会“这个猫虽然加了噪音,也是猫”,从而增强鲁棒性。
深度生成模型 - Deep Generative Models
生成对抗网络 (GAN) Generative Adversarial Network
GAN 是一种用神经网络生成“假数据”的方法,训练过程像玩游戏:两个网络互相对抗。
GAN里面有两个网络:
名字 | 作用 | 类比 |
---|---|---|
Generator(生成器) | 制造“假货”图片(比如假人脸、假猫) | 造假者 |
Discriminator(判别器) | 判断图片是真货还是假货 | 鉴定专家 |
他们互相斗争——生成器想办法骗过判别器,判别器想办法识破生成器的伪装。
其目标就是当判别器输出为 0.5 时,表示它完全分不清真假 —— 成功!

如上图所示,判别器D对于输入x(真实图像),D(x)=0,代表其认为这是假的,所以这个时候要修改判别器的参数。
判别器D对于输入G(z)(假图像),D(G(z))=0,代表判别器成功识别出假图,这个时候需要修改生成器的参数;D(G(z))=1,代表判别器成功被生成的假图所欺骗,这个时候需要修改判别器的参数;
当然,如果D(G(z))在0~1范围,这个时候判别器和生成器的参数都需要修改。
判别器(Discriminator)训练
我们通过输入一些真实样本和生成器生成的样本作为输入进行训练,并通过反向传播(backpropagation)修改权重,目标是最小化分类的错误。
生成器(Generator)训练
用随机变量z生成图片G(z),并让判别器判断G(z),希望它误判为真(即D(G(z))=1)。通过反向传播(backpropagation)修改生成器的权重,使得G(z)接近真实图像。目标是最大化判别器的错误。
损失函数 Loss Function
“损失”= 模型做错的程度——模型越笨、越不准,损失越大;模型越聪明、越准确,损失越小。
对于判别器的损失:
max_D{ log(D(x)) + log(1 - D(G(z))) }
其中,对于判别器,我们希望
log(D(x))
越大越好(即,给真实图打高分更好),log(1 - D(G(z)))
也越大越好(即,给假图打低分更好)。对于生成器的损失:
min_G{ log(1 - D(G(z))) }
对于总体目标:
min_G max_D{ [ log(D(x)) + log(1 - D(G(z))) ]}
GAN常见的问题
第一个是:模式崩溃(Mode Collapse)
即,生成器只会画一种图(比如总是画猫脸朝右),不会画多种图,因为其只学会了一种骗判别器的方法。
第二个是:不收敛(Non-Convergence)
即,训练中两个网络像“零和博弈”,你赢我输,导致 GAN 在训练时可能一直互斗,模型不稳定。
第三个是:图像失真(Distorted Figures)
即,有时候图像生成怪异、扭曲,表示训练不充分或设计不合理。
自然语言处理(NLP) - Natural Language Processing
我们梳理一下,最开始我们讲的NN神经网络,其中涵盖了许多方向。比如,Vision就是视觉方向,用于处理图片等信息,CNN常用于Vision来识别图像特征;GAN则是一种生成对抗网络的技术,可以用在Vision,来生成对抗样本调节模型;而本节讲的NLP则是语言方向的应用,用于处理文本、语言等方向,比如ChatGPT这类。
所以,简单说,NLP就是让计算机能“理解人类的语言”。
注意力机制 Attention
“Attention” 就是“注意力机制”。想象你在翻译一句长句子:He likes to eat rice.
普通的神经网络,比如 LSTM,有一个大问题:忘记前面说了什么。当网络解码到“吃饭”的时候,前面的“likes”已经忘了……
如果没有注意力机制,模型只能依赖“最后一句话的信息”,可能会忘记前面的内容。
Attention 就像人类的大脑一样:每次翻译一个词的时候,就去原句里“扫一眼”,看看哪个词最相关。
其原理是,通过给输入句子里的每个词 打分 + 分配注意力:
Encoder会将英文的每个词变成向量,比如:
英文词 向量 hi He h1 likes h2 to h3 eat h4 Decoder在翻译中文“喜欢”的时候,使用状态s标识。比如Decoder当前状态是s_t。
计算英文每个词对现在这个s_t的相关性(匹配程度)。
e1 = match(s_t, h1) e2 = match(s_t, h2) e3 = match(s_t, h3) e4 = match(s_t, h4)
这表示 “我现在在翻译‘喜欢’,那英文里哪些词跟它最相关?”
用 softmax 把这些分数变成“注意力分布”
a1, a2, a3, a4 = softmax(e1, e2, e3, e4)
假设likes的注意力分数a2为0.7,是最大,那我们应该将注意力放在likes上。
生成一个“上下文向量” = a1·h1 + a2·h2 + a3·h3 + a4·h4
这个向量就是综合加权结果,告诉 Decoder:“这是你要翻译‘喜欢’时应该关注的英文信息”。
Transformer模型
Transformer 是 Google 在 2017 年发明的一个深度学习模型,最初是为了自然语言处理(NLP)设计的,现在也广泛用在图像处理(Computer Vision)里,比如 ChatGPT 和 Midjourney 背后都用了这个技术。
它的核心论文叫:《Attention is All You Need》
整体架构
Transformer 是一个“编码器-解码器(Encoder-Decoder)结构”,分两大块:
- 编码器(Encoder):负责读懂输入,比如翻译时的英文句子。
- 解码器(Decoder):负责一步步生成输出,比如翻译后的中文句子。
推理阶段 Inference
以翻译为例,它是怎么一步步生成中文句子的呢?
步骤 1:输入转换成 Embedding,喂给编码器(Encoder)
- 我们把句子 “I love AI” 转成数字向量,叫 Embedding。
- 然后送进一堆编码器(Encoder Stack)。
步骤 2:编码器处理这个句子,理解它的含义
- 编码器就像一个“理解机器”。
- 它看每个词之间的关系(用 Attention)来理解句子的真实意思。
- 输出:对这句话的“深层理解表示”。
步骤 3:解码器准备开始翻译,第一步先输入 <s>(开始符号)
- <s> 就像“开始说话”的信号(Start of Sentence)。
- 把 <s> 转成 Embedding,然后送进解码器。
步骤 4:解码器用两部分信息来猜第一个词
解码器的“脑子”有两个来源:
- 自己之前看到的输出(现在只有 <s>)
- 编码器输出的“整句含义”
这两个信息一起进来,它开始猜:“第一个翻译的词应该是啥?”
步骤 5:输出层把 decoder (解码器)的结果转成“猜的词的概率”
比如:“我”:80%、“你”:10%、“它”:5%。
用 softmax 选出概率最大的词作为翻译的第一个词。
步骤 6:把刚刚预测出来的词(比如“我”)加到 decoder 的输入里
下一轮 decoder 输入就是:[<s>, 我]
然后再去猜第二个词,比如:“爱”
再下一轮是:[<s>, 我, 爱] → 猜 “人工智能”
步骤 7:重复刚刚的流程,直到翻译完
训练阶段 Training
还是以翻译为例,训练的目标是,模型学习如何从英文猜出正确的中文,每次输出一个字。
步骤 1:输入句子变成 Embedding,送入编码器(Encoder)
- 先把英文 I love AI → 转换成数字向量(Embedding)
- 喂进 Encoder Stack,让它理解这句话的“意思”。
步骤 2:Encoder 理解这句话,输出“含义表示”
Encoder 会处理句子所有词之间的关系,输出一句话的理解结果(我们叫它“隐藏表示”)。
步骤 3:把目标句子(“我 爱 人工智能”)右移一位后,送入 Decoder
比如:目标句子是:
<s> 我 爱 人工智能
右移一位就变成:
<s> 我 爱
,目标要预测的是后面的人工智能
Decoder 要学会:每次看 <s> → 猜 “我”,再看 <s> 我 → 猜 “爱”,再看 <s> 我 爱 → 猜 “人工智能”。
步骤 4:Decoder 一边看目标句的开头,一边看 Encoder 的理解结果
步骤 5:输出层把 decoder 的结果转成“词的概率”
步骤 6:计算损失 Loss,反向传播(Backpropagation)
计算“预测值”和“真实答案”的差距,叫做 Loss(损失)。
然后用这个差距来反向调整整个模型的参数(叫反向传播),让它下次预测得更准。
Teacher Forcing训练
其实前面讲的Training阶段就是Teacher Forcing训练的一个例子。
Teacher Forcing就是用正确的词去喂给AI,而不是依靠AI推测出的词再喂回去。也就是,训练的时候,不管 AI 猜得对不对,都直接告诉它正确答案,让它用“对的词”继续学下去。
不用Teacher Forcing会发生什么呢?
比如:我 爱 人工智能
,AI把爱
猜成了喜欢
,然后把喜欢
喂回去,让它继续“将错就错”。
这样会导致:
- 错误越滚越大。假设第一个词就错了,下面就会在错的基础上继续猜。
- 太慢了。如果一个词一个词地跑,每次都要等前面的词预测完,速度非常慢。而Teacher Forcing可以一次性并行地预测整个句子的所有词。
BERT模型
BERT(Bidirectional Encoder Representations from Transformers),基于 Transformer 的双向编码表示。
BERT 是一种基于 Transformer 的模型,是 Google 提出的一个强大的自然语言理解模型,它可以理解句子里的每个词是啥意思、跟其他词的关系。
整体架构
Transformer 有两个部分:Encoder 和 Decoder,BERT 只用了 Encoder,专注于理解(而不是生成)。
预训练方式
BERT使用两种“填空题”练习法训练模型。
第一种是,Masked Language Model(MLM),也就是随机把句子里 15% 的词遮住(变成 [MASK]),让模型猜出被遮住的词。
第二种是,Next Sentence Prediction(NSP),给模型两句话,问它第二句话是不是第一句的下一句。其中,输入数据一半是真的(顺序对),一半是随机拼的,这个任务帮助模型理解句子之间的关系。
应用
BERT 就像一台“语言理解引擎”,我们可以在它上面加一个小层,来做各种任务。比如:
- 文本分类(比如情感分析、新闻分类等)
- 命名实体识别(NER)
- 问答系统(QA)
大语言模型 - LLMs
模型大小 Model Size
Transformer 模型有多少个参数?
Transformer 的“模型大小”(Model Size)= 各个部分的参数加起来
符号 | 含义 | 举例 |
---|---|---|
E | 每个 token 的向量长度(Embedding size) | 比如 768、1024 |
H | 注意力头的数量(Number of heads) | 比如 12 个头 |
EH | 等于 E × H(总共 attention 用了多少空间) | 768×12=9216 |
对于Encoder模块:
其结构大概是:输入 → 多头注意力 → 加残差 & 标准化 → 前馈神经网络 → 加残差 & 标准化
对于多头注意力(Multi-head Attention),其用到了Wq、Wk、Wv、Wo这四个矩阵,每个大小是E × E,所以参数量=4E² + 4E(E² 是矩阵,E 是偏置项)。
对于前馈神经网络(Feed-forward),其为一个小型的2层神经网络:E → EH → E,用到了H × H和H × E两个矩阵,所以参数量=2EH + E + H(E + H是偏置项)。
对于标准化层(Layer Norm),其只要每个 token 加一个缩放和偏移的常数:2 × E,所以总参数为2E。
所以对于Encoder模块,其总参数为:4E² + 2EH + 9E + H(其中包含每层有 2 个 LayerNorm,位于Attention 后 + FeedForward 后),近似值为4E² + 2EH。
对于Decoder模块:
其多了一个组件:Masked Multi-head Attention,所以相比于Encoder模块,其多了一个Multi-head Attention,同时也伴随着多了一个Layer Norm,共三个(分别位于Masked-Attention后 + Cross-Attention 后 + FeedForward 后)。
所以对于Decoder模块,其总参数为:2*(4E² + 4E) + (2EH + E + H) + 3*(2E) = 8E² + 2EH + 15E + H,近似值为8E² + 2EH。
剪枝和蒸馏 Pruning and distillation
这里用GPT画了个流程图:
剪枝 Pruning
意思就是:把 没用的部分剪掉(就像修树一样)。
具体来说,一般剪掉Attention Head(多头注意力里的“某几头”不重要,直接剪掉)、宽度/Channel(隐藏维度 H、embedding 维度 E 太宽,缩小它们)、深度/Layer(总共32层,删掉一半,变成16层,只保留连续的一段)。
如何定义不重要呢?
可以用小数据集跑一次前向,只看前向计算的影响,然后打分 → 排名 → 选出“重要的部分”。
就像一个厨师一样,做了一份菜,我们把配料一个个试着关掉一个,尝一口菜,看看有没有变化。
蒸馏 Distillation
意思是:让一个小模型学习大模型的行为,就像老师教学生。
具体来说:在Embedding 输出中,学习词的表示方式;在Attention / FFN 输出中,学习中间的每层输出(Block Loss);在最终输出 Logits中,学习最终预测哪个词(Logit Loss)。
基准指标 Benchmark metrics
LLM(大语言模型)要想评估“聪不聪明”,得像学生一样参加考试。这些“考试”就叫做 benchmarks(基准测试)。
这些“考试”有六大类:
名字 | 中文意思 | 测什么? |
---|---|---|
HellaSwag | 语境常识判断 | 看模型是否知道日常生活中“最合理”的事 |
WinoGrande | 常识+指代判断 | 看模型能不能理解“谁是谁” |
MMLU | 多学科知识 | 像大学生一样考法律、医学、历史等 |
ARC | 抽象推理能力 | 解决看起来“人类轻松但AI难”的问题 |
GSM8K | 小学数学题 | 多步算术推理(文字题) |
MBPP | Python 编程 | 看模型能否写出对的函数来解决问题 |
LoRA微调和量化 LoRA fine-tuning and quantization
LoRA是什么
LoRA 是一种让“大模型变得容易微调(fine-tune)”的方法:
不直接改动原模型,而是偷偷在旁边加一个“小补丁”,这块补丁参数少、训练快,还不会破坏原本学到的知识。
为何需要LoRA
传统的微调方式有几个大问题:
- 你要改动模型里的所有参数,这太大了(LLM 动辄上百亿参数)
- 太耗内存、时间、钱(需要多个GPU,训练几天)
- 用的数据少时,模型容易过拟合,反而变差
- 想用这个模型做别的任务,得再训一遍,很麻烦
所以:我们希望只“小修小补”,不要“大动干戈”!
微调 Fine-tuning
微调其实就是拿一个已经训练好的大模型(比如 GPT),再喂一些你的新数据,让它适应新的任务或领域。这种方式比从头训练模型要快很多。
LoRA核心思想
LoRA其实就是没有动原来模型的参数,只在旁边加一个低秩矩阵,像一个可调节的外挂一样做调整。
假设模型中的某个权重矩阵为W0,LoRA不改W₀,而是加一个更新项 ΔW,让新的权重 = W₀ + ΔW。
而 ΔW 不直接训练,而是写成 ΔW = B × A,这样就只需要训练B和A两个小矩阵即可。
举个例子,如果说原来的输出是:h = W₀ x,那LoRA后,输出为h' = W₀ x + BAx(多了个补丁BA)。
量化 Quantization
量化的目标是减小内存和计算量。
我们思考:我真的需要那么高的精度吗?模型的每个数字都要到小数点后面6位甚至更多?其实不需要!
于是,我们可以把原来的高精度数字(FP32)“压缩”成低精度的整数,比如 Int8(8位整数)。
但注意!量化是有损压缩,可能会导致误差,如果压缩不当,还会影响模型效果。
对于LoRA,采用量化可以更进一步降低内存使用,甚至能让消费级显卡也能训练上大的模型。
提示词 Prompting
相信大家对Prompt已经很熟悉了,在日常使用ChatGPT中,我们会使用各种Prompt来让AI完成我们想做的事。
就像你对一个人说:“请帮我画一只科学家的猫”,AI 就会画出来。
Prompt类型
简单提示(Simple Prompt): 类似问答型的提问,如:彩虹有多少种颜色?
指令提示(Instruction Prompt):
给出一个任务,AI 按你的意思完成。如:写一首鼓励人的诗,让我开心。
复杂提示(Complicated Prompt):
包含表格、多个问题、信息抽取。如:下面是一个公司表格,问:哪家公司员工最多?
提示词的设计艺术 Prompt Engineering
我们怎么问问题、怎么给指令,才能让 AI 给出最好的答案呢?
我们可以用CO-STAR 框架这个写提示词的万能模板:
这是一个六步法:
缩写 | 含义 | 解释 |
---|---|---|
C | Context | 背景:你要做什么? |
O | Objective | 目标:你想 AI 做什么? |
S | Style | 风格:写作风格、模仿谁? |
T | Tone | 语气:温柔?专业?有说服力? |
A | Audience | 受众:给谁看?老人?小孩?专家? |
R | Response | 回复格式:比如生成一个 Facebook 帖子 |
比如:我在做一个吹风机广告,帮我写个广告发 Facebook,卖吹风机给中老年人,模仿 Dyson 的风格。
上下文学习 In-Context Learning(ICL)
ICL被称为小样本学习(few-shot learning / few-shot prompting),和“微调模型”不同,ICL 不用重新训练模型,直接在 Prompt 里放例子就行了。
比如:
AI 根据前两个例子,就能猜出:“Good meal!” 是 Positive。
思维链 Chain of Thought (CoT)
思维链就是让 AI 一步一步思考,就像做数学题一样写出过程,准确率大增,比如:
思维链提高了 LLM 进行复杂推理的能力,可以让其有更高水平的数学能力。
零样本思维链 Zero-Shot Chain of Thought
Zero-Shot Chain of Thought是连例子都不给,就一句提示语让 AI 自己慢慢推理。
提示语通常是:“Let’s think step by step.”、“Let’s break this down.”、“Let’s solve this logically.”...
自我一致性 Self-Consistency
AI 有时每次想的答案不同,那怎么办?
我们可以让 AI 多次回答,再投票选出多数答案(就像民主投票)。
但缺点是:计算量大(每次都让 AI 再算 5~10 遍)。
草稿链 Chain of Draft
草稿链是不让 AI 想那么多文字,而是直接用公式、缩略步骤来推理,又快又准。
比如:
提示词微调 Prompt-Tuning/P-Tuning
Prompt-Tuning(提示微调)是一种非常省参数的微调方法,意思是:
不用把整个大模型(几百亿参数)重新训练,只训练一小块,结果也能不错!
假设 LLM 是一个超级聪明的助理,但你不能改它大脑(太大了),只能在它“听见问题”之前加点引导。
具体来说,就是在前面加一个小模型:这个小模型不干别的,就负责把任务目标变成一段「特殊提示语」(虚拟 tokens)加在问题前面。
整体流程如下: