动手学深度学习课程笔记
- 每个程序员都应该知道的延迟数字
杂项
-
炼丹步骤
-
1.建立网络 2. 损失函数 3. 优化器(根据反向传播求得梯度 用优化器更具体的来更新参数) 4. 从训练集取出数据,进行训练,先梯度清0,算损失,反向传播,然后优化
- 找paper
- 注意广播机制可能会改变张量的形状
- 使用切片机制实现对张量的原地操作
- 机器学习的核心就是处理缺失数据
- 矩阵乘法其实是在做一个空间变换
- 机器学习求解核心思想:求解梯度变换最快的方向
- 机器学习主要关注np问题
正向传播和反向传播
- 正向就是求复合函数的值
- 反向就是求偏导数和梯度
- 数学中的求导就是反向传播的方向
- 代码中正向积累的中间值只有在明确声明需要且调用了反向积累时才会计算,因为计算它 too expensive
- 课程中默认向量是列向量
- A.sum(axis=0)对矩阵某一维度进行求和,第0维是竖着的,对应默认向量是列向量
- 范数(英语:Norm),是具有“长度”概念的函数。在线性代数、泛函分析及相关的数学领域,是一个函数,其为向量空间内的所有向量赋予非零的正长度或大小。另一方面,半范数(英语:seminorm)可以为非零的向量赋予零长度。
- 神经网络层数->看带权重的层有几层
深度学习基础
线性回归
-
超参数
-
学习率就是每次下降的步长,一次下降多少
- 偏大导致震荡偏小导致学习速度慢
-
b就是批量大小,控制每次随机采样个数。
batchSize
(批量大小)指的是在一次前向传播与反向传播过程中所使用的样本数量。在训练深度学习模型时,通常不会将整个数据集一次性输入到模型中进行训练,而是把数据集划分成若干个小的批次(batch),每个批次包含batchSize
个样本。 -
batchSize宜小不宜大。小的话有噪音,噪音可以增强泛化能力。过大的话求解就针对这个训练集了
- shuffle 随机取是可以保证所有样本都取一遍的,不放回
- 统计模型 损失函数长什么样 - 优化模型 用什么样的算法来求解 - 我们并不关心收敛的速度,而是收敛到哪一个位置,次优解可以有很多个 - 生成器生成数据是懒惰类型,不是一下全都生成,节省内存 - 线性模型的训练就是在找最适合的w和b。w是各参数的权重,b是偏移量
SoftMax回归
- 对分类问题,如果类别间有自然顺序,可以转化为回归问题
- softmax函数能够将未规范化的预测变换为非负数并且总和为1,同时让模型保持
可导的性质。
损失函数
优化较平滑
- 使用对数似然即使用负对数对softmax后的概率进行处理的目的是给错误的类添加更大的惩罚从而使得正确的类更加显著
对于交叉熵损失,我们只会得到独热编码为1时的那个类的概率,只关心对正确类的预测值的置信度- 交叉熵损失可以很好的反映预测的概率和实际概率之间的差异
图片分类数据集
- 训练的瓶颈可能在数据读取,在训练之前要batchMark测试一下,数据读取最好比训练要快
softMax回归手动实现
- 训练softmax回归循环模型与训练线性回归模型非常相似:先读取数据,再定义模型和损失函数,然后使用优化算法训练模型。大多数常见的深度学习模型都有类似的训练过程。
多层感知机
感知机
- 感知机就是在线性模型的基础上套一层激活函数,使得输出由线性变为非线性
多层感知机
- 隐藏层大小是超参数 代表隐藏层个数
- 这里b2=R是因为这里是单隐藏层,只需要一个偏置即可
激活函数
- 主要用于避免层数塌陷,给模型增加非线性性。如果隐藏层只有一层,不加激活函数,一个感知机就退化成线性模型了
- 解决了x=0处不好求导的问题,是0-1分布的soft版本
- 解决了x=0处不好求导的问题,是-1-1分布的soft版本
- 好处是不用求指数,算得快。最常用
多类分类
- 和之前的softMax没有本质区别
- 模型设计最好是金字塔型
代码实现
- 交叉熵函数自带softMax
QA
模型选择 + 过拟合和欠拟合
模型选择
- 训练数据集 用于调整权重、偏置等模型参数
- 验证数据集 用于调整超参数(模型训练之前需要手动设置的参数,它们不能通过模型的训练过程自动学习得到,而是需要通过在验证集上进行实验和调优来确定。超参数的选择会影响模型的学习速度、复杂度和泛化能力等。)
要独立于训练数据集,不能参与训练(会导致验证结果虚高) - 测试数据集用于测试模型最终训练结果,不可以在这个数据集上训练
- 数据集大小不够的解决方法
- 用于确定超参数,然后在此基础上重新训练模型
- 直接找选定超参数后K折里精度最好(或随便)的一折,选择该模型,不再重新训练。
- 每折得出的模型都用上,对测试集使用后求均值
过拟合、欠拟合
- 首先模型容量得高,然后再去控制误差。一定的过拟合是可以承受的
- 模型复杂度可以通过VC维来量化,就是这个模型所完美分类一个数据集的最大的大小
QA
- 神经网络是不那么直观,但是编程性比较好的一种框架
-
调参数其实就是在调超参数,欠拟合、过拟合就是在暗示什么样的参数是好的
-
超参数的设计靠
- 经验
- 一个一个试,根据上一个的效果优化下一个
- 随机选取
-
如果数据集比较小且不均衡,验证数据集最好均衡一下
-
其实不然,应该考虑现实世界是什么样子的,如果现实世界ushijie也是不均衡的,那就保留这种不均衡,保证在主流部分的精确性
- 如果只是采样偏差,可以对小的那个进行加权
- CNN(空间信息)本质上是一个mlp,RNN同理(时序信息。都是通过神经网络来描述对问题的理解
- 艺术、工程、科学
- 如果在验证数据集上loss发生了先下降在上升,就是发生了过拟合
权重衰退
- 最常见用于处理过拟合的方法
- 缩小模型的容量
- 限制参数的个数
- 限制参数的域
先把当前的权重做一次缩小,再做梯度下降- 权重衰退就是在正常梯度更新的基础上对更新幅度做一个缩放
丢弃法
- 在层之间加入噪音
- 作用在全连接隐藏层的输出上
- 正则项b只在训练中使用,会对权重产生影响
- 在推理中dropout直接返回输入
- 缩小隐藏层个数(不是隐藏层层数)效果不如隐藏层个数偏大+大dropout率
QA
- 由于使用了随机丢弃导致dropout有随机性。通过固定randonSeed可以使结果可重复
数值稳定性
模型初始化、激活函数(听不懂)
- 归一化的定义是将数据按照一定的规则进行变换,使其落入一个特定的区间或满足特定的统计特性。其主要目的是消除数据特征之间的量纲差异和尺度差异,让不同特征在数值上具有可比性。例如,在一个数据集中,特征 A 的取值范围是 1 到 1000,而特征 B 的取值范围是 0 到 1,若直接对数据进行分析或建模,特征 A 可能会因其较大的数值范围而对结果产生过大的影响,归一化可以解决这个问题。
- 权重初始化
- 权重初始化时的方差是根据输入和输出维度来确定
- 保证均值为0,方差是固定范围内的一个数
QA
- 数学底蕴很重要
- 限制的特征的范围,是在不损失模型的表达性的基础上的。主要目的是方便硬件处理,不会出现梯度爆炸和消失
- 所有的深度学习都是在解决数值稳定性的问题
kaggle预测房价实战
- 用log来缩放一下数值较大的特征
- adam优化函数相对sgd来说对学习率没那么敏感
- 不可以在浅层网络上调参数然后运用到深层网络上,因为层数也是一个超参数。但是可以先用小容量数据来调
卷积神经网络
16 PyTorch 神经网络基础
- Sequential对象其实就是一个拿来装Linear (),ReLu()等方法(网络的层)的顺序容器
- 可以通过net[x]来访问x层
- 将复杂的网络模块化、多个模块嵌套构建最终的网络
- apply函数的功能是将传入的函数应用到指定的module上,不只是初始化,做什么都行
- 复用同一层可以达到共享权重的目的
- 80%的时间 做数据,20%的时间调模型。好的数据的重要性远大于模型
-
要有阶段性目标 要做什么、要获得什么成长
-
通过 net.state_dict() 可以直接将整个网络的全貌打印出来
- python列表推导式
- 为什么共享参数是个好主意?
解答:
1. 节约内存:共享参数可以减少模型中需要存储的参数数量,从而减少内存占用。
2. 加速收敛:共享参数可以让模型更加稳定,加速收敛。
3. 提高泛化能力:共享参数可以帮助模型更好地捕捉数据中的共性,提高模型的泛化能力。
4. 加强模型的可解释性:共享参数可以让模型更加简洁明了,加强模型的可解释性。
19 卷积层
卷积
- 图片匹配原则
- 平移不变形
- 局部性
- 卷积是一种特殊的全链接层
- 卷积核就是那个W(权重)
- 全连接层:像 “全班大讨论”—— 每个人的发言都被所有人听到,信息全面但嘈杂。
- 卷积层:像 “小组讨论”—— 每个人只和前后左右的同学交流,聚焦局部信息,效率更高。
- 池化层:像 “小组代表发言”—— 每组选一个代表总结观点,压缩信息但保留关键特征。
卷积层
- 动画里使用的是3*3的核
- 相当于利用卷积核将高维的输入映射为低维的输出
- 图中的星型计算就是上节定义的二维交叉计算
- 那个输出()()指的是 高 宽 是输出矩阵的大小
- 选用不同的核函数可以对图像进行不同的处理
- 卷积核:有正有负和为0是边缘检测、全为正和为1是均值滤波、高斯权重的均值滤波是高斯平滑/模糊
- 卷积和交叉相关是中心对称的关系。
- 实际实现的是交叉相关
- 气象地图多一个时间轴
- 核矩阵大小控制着局部性。大一点看到的部分多一点
- 卷积解决了之前随着输入变大权重矩阵变得特别大的问题。因为核函数是固定大小的
QA
- 窄而深的模型效果很多时候比宽而浅的好。对卷积和全链接层都是
- 全链接层最大的问题是权重W矩阵的高度(高指的是参数矩阵的行数)取决于输入矩阵的宽。当输入维度太大就炸了
- 全连接层输入层要为每个输入分配权值,而卷积是共享权值。不管输入维度多大,核的大小是固定的
20 卷积层里的填充和步幅
- 填充和步幅是卷积中的两个超参数
- 有一个问题是输入不能小于卷积核大小
- 卷积核通常不会选用很大的
- 解决方法
填充
- 要注意在pytorch中的padding指的是一边的,等于这里的p/2
步幅
QA
- 核大小通常是最关键的参数
- 步幅是为了减小输出 可以加速卷积的速度
- 填充的主要目的,是为了让卷积核更多地识别到边缘信息,而不是为了控制输入输出大小
- kernel边长通常为奇数。padding=kernel-1,而padding是分在图片上下的,kernel为奇数,padding就可以对半分。
- 第一层如果是3x3的filter的话,第二层中一块3x3的区域就包含了输入中一块5x5的区域的信息(stride=1)。卷积核小就把层数弄深一点
- 机器学习本质上是信息筛选过滤压缩
- 较大的卷积核配上较浅的网络可以等效小而深的,但是时间复杂度和核的高*宽相关。因此较大的卷积核训练会比较贵
21 卷积层里的多输入多输出通道
- 对每个输出通道都有一个自己的三维卷积核
- 输入和输出通道间没有太多相关性
- 输入是前一层的超参数
- 这里针对的是多输入多输出通道卷积层的介绍
- 多输出层依赖三维卷积核,该层做完卷积每个通道对应位置也相加,第三维维度大小对应对输出通道通道数
QA
-
“不同通道的卷积核是一样的”,其实是不同通道的同一个输出通道的卷积核是一样的
-
”每个通道的卷积核是不一样的“,是因为有多少个输出通道就有多少种卷积核
- 这里针对二维卷积,对加上深度的图像不适用
- 卷积层参数共享指的是整个图像用同一个卷积核来扫描,和全连接网络相比共享了参数
22 池化层
- 和核差不多,不过一个是计算一个是选最大值输出
- 允许边缘有抖动,增强特征的平移不变形
- 步幅和窗口大小相同意味着投影不会有重叠
- 池化是在每个通道上做的,不会把通道合并
23 经典卷积神经网络 LeNet
- 每个通道的信息可以认为是一个空间的pattern
- 一般的训练策略是高宽减半通道数翻倍
-
像素密度增大了,就是说输出通道数增加,每个同位置像元包含,多个通道信息,一个通道可理解为提取出一个特征信息。
- 多输出通道
-
16组,每组有6个卷积核 分别与6个通道的输入 进行互相关运算然后相加,最后把16个叠在一起
-
输出通道可以认为是匹配了某一种特定的模式
24 深度卷积神经网络 AlexNet
- dense:稠密层也称做全连接层,就是把特征提取成一维帮助最后分类
25 使用块的网络 VGG
-
VGG(Visual Geometry Group)的核心思想是通过堆叠多个小卷积核(如 3×3)的卷积层来替代大卷积核(如 7×7、5×5)的卷积层,从而在保持相同感受野的同时减少参数量,并通过增加网络深度提升特征提取能力。
-
vgg使用块替换掉了alexnet的卷积层
- 不要过度设计,尽量用简单的模型
26 网络中的网络 NiN
- 全连接层的问题
- 特别占用参数空间
- 过拟合
- nin的思想就是完全不要全连接层
- 1*1的卷积层等价于全连接层
- 最大池化层的作用是将高宽减半
- 最后应该是1000个通道, 每个通道一张图。 对每张图求平均, 就是1000个数。代表1000个类别的评分。
- 1×1 卷积层除了可实现通道维度变换等,还能引入非线性。因为 1×1 卷积层后一般会跟着激活函数(比如 ReLU ),每个像素经过 1×1 卷积计算以及激活函数处理,就给单个像素的特征变换增添了非线性,
- softmax 写在了traning中,所以网络定义中不需要再加softmax层 CrossEntropyLoss里面有Softmax
27 含并行连结的网络 GoogLeNet / Inception V3
28 批量归一化
- 在做很深的网络的时候这个是必须的层
- 批量规范化是在卷积层或全连接层之后、相应的激活函数之前应用的。
- 一般来说,BatchNorm可以在卷积层和全连接层之间使用,也可以在激活函数之前或之后使用。但是,并不是所有的层都需要使用BatchNorm,有时候使用过多的BatchNorm反而会降低模型性能。
- 批量归一化和暂退法一般是直接进行替换,不会同时用,因为二者都是起到正则项的作用
- 在反向传播过程中,梯度通过链式法则从输出层传递到输入层,由于链式法则的乘积形式,如果每一层的梯度范数小于1,那么经过多层的乘积后,梯度会指数级减小,从而导致梯度消失。
- 为什么会变化?
- 每一层的方差和均值的分布都不一样
- 固定住,使每一层都符合某一个分布
- 但是计算总体损失的时候是逐个sample再求mean的,如果这些samples都符合某个分布会更方便
- gama 和 beita 是通过学习得到的新的均值和方差
QA
- 模型稳定的情况下收敛不会变慢
29 残差网络 ResNet
29.2 ResNet为什么能训练出1000层的模型
计算机视觉
36 数据增广
- 增强一般在训练时使用、一般为在线生成且是随机进行增强
- 增强要合理
- 训练集的选取主要由实际会碰到的情况来决定。当部署的环境没有那么奇怪的结果可以不用考虑这种增强
- 图片增广不改变数据分布,改变方差
- mixup增广比较有效
37 微调
- 迁移学习是指将从一个任务(源任务)中学习到的知识或经验,迁移应用到另一个不同但相关的任务(目标任务)中,以提升目标任务的学习效率或性能,避免从零开始训练的机器学习方法论。其核心在于利用任务间的相关性实现知识复用,尤其适用于目标任务数据量少或标注成本高的场景。
- 给不是迁移过来的层使用更大的学习率
- 预训练模型的权重拿来用而不固定,你在你这个数据集上训练会有变化的,只是训练的epoch可以更少,模型更快收敛
- 尽量从微调开始进行训练
QA
- 越是接近输入 特征越通用
41 物体检测和数据集
QA
- 标注的时候先自己标一些然后通过迁移学习等方法训练一个模型,再把那些置信度低的类拿出来多标几张再训练模型
42 锚框
- 算法对边框位置的一个猜测
- 生成高质量的锚框很关键
- 总结:1.如何生成锚框 2.如何判断锚框有效 3.每个类保留一个锚框进行预测
- 处理训练样本三个重点:1.产生大量锚框,像素点*(s+r-1) 2.基于iou和label数据给锚框分类和偏移 3.nms精简非背景锚框,确保一个锚框对应一个目标
43 树叶分类竞赛技术总结
-
学术界更关心模型,工业界关心数据
-
实战时碰到的一些坑
- 标准化不是 “必须” 的操作,其效果高度依赖数据与模型的匹配度。当你的数据分布与标准化参数(如 ImageNet 的均值 / 标准差)不兼容时,去掉标准化或使用自定义统计量,反而能让模型更好地学习数据特征,从而提升精度。
- 如果要加标准化那训练集测试集等都得加,不然导致数据分布不同
44 物体检测算法:R-CNN,SSD,YOLO
- 区域卷积神经网络
- 主要思想是做多个分辨率下的检测
- 图片大,锚框不变,检测小物体
- 图片小,锚框不变,检测大物体
- 与之前的区别是没有rpn网络了,直接在生成的所有锚框上去预测
- yolo
- 尽量让锚框不重叠
- 第三点为了解决多物体重叠问题
45 SSD实现(非常困难)
- 锚框信息通过loss进入神经网络
46 语义分割和数据集
- 目标检测分割太过粗糙,需要更细致的分割
- 语义分割是像素级别的分割
- 语义分割处理时不好做缩放处理,因为新多出来的像素和标号不好对应
47 转置卷积
- 无法通过padding进行有效的增大高宽
- 对语义分割来说,是对像素级的pixel进行分割,如果通过卷积的话,分辨率不停减小,不利于进行语义分割,因此需要另一种操作子
- 操作和卷积差不多相反
- 超参数一样的前提下,转置卷积相当于把对应卷积的输出变成输入的大小。注意是形状上的还原,而不是值的还原
QA
47.2 转置卷积是一种卷积
48 全连接卷积神经网络 FCN
- k是通道数,等价于有多少类
- 这节代码中的使用pretrain模型的方式值得学习。
- 先取出pretrain模型中的参数,去除掉不要的层的参数
- 把模型结构解包去除不要的层再丢进新的网络
- 如此就得到了一个不含最后全连接层的网络
### 49 样式迁移
- 将样式图片的样式迁移到内容图片上,得到合成图片
- 看上去有三个cnn,其实只有一个,后两个网络是第一个的复制
- 目标是训练一个cnn,使得图片输入进网络时,在某一层的输入上匹配上内容图片,在某一层的输入上匹配上样式图片
- 样式匹配指的是 通道之间的统计分布和通道内的统计分布匹配的上
- 风格转移的损失函数是内容损失、风格损失、总变化损失的加权和
- 这里的权重是老中医,目标是使这三个字在差不多一致的范围内,不要有数量级误差
- 训练是直接对着结果图片进行训练,最小化结果图片和风格图片、内容图片的损失。
50 课程竞赛:牛仔行头检测
- 解决类别不平衡
- 调整采样
- 权重
循环神经网络
51 序列模型
- 自回归模型(Autoregressive Model,简称 AR 模型)是一种用变量自身的历史数据来预测其未来值的时间序列模型。
- 核心思想就是求解 F 函数
- 需要训练两个模型,一个是算 h^ ,一个是算 x^
52 文本预处理
- 将文本当做一个时序序列
- 核心思想是怎么把词变成可以训练的东西
- token的常见单位划分
- word 词
- char 字
-
注意常见错误
-
使用特定模型时,未配套使用该模型训练时依赖的字典(词表)。
具体来说,模型的训练基于特定的字典(包含其识别的词汇、字符及对应编码),若使用其他字典,会导致输入文本的编码与模型预期不匹配,进而引发语义理解偏差、推理错误等问题。例如,用 BERT 模型却用了 Word2Vec 的词表,会因词汇映射不一致导致模型无法正确解析输入。
53 语言模型
马尔可夫假设是简化序列概率计算的常用方法,核心是“未来状态仅依赖于近期有限历史状态”,在自然语言处理的N元语法场景里,用于缓解长序列因数据不足导致的概率估计难题:
- 问题背景:长文本序列(如很长的单词序列)因文本量有限,完整序列出现次数少(甚至≤1 ),难直接算概率。
- 假设核心:认为一个元素的概率,仅与前面有限个(而非全部)元素相关,以此简化计算。比如二元语法中,某单词概率只依赖前一个单词;三元语法依赖前两个,依此类推。
- 实际作用:让长序列概率计算更可行,通过“截断”历史依赖,用短序列组合估计长序列概率,是语言模型、文本生成等任务的基础简化思路 。
- 两种不同的data_iter构造思路
- 使用随机抽样生成一个小批量子序列 批量之间的关系是随机的
- 使用顺序分区生成一个小批量子序列 批量之间是顺序关系 可以拿到更多空间信息
54 循环神经网络 RNN
- RNN本质也是MLP
- 计算损失时是比较ot和xt之间的损失,但是xt是用来更新ht+1的
- Whx是隐藏层的权重
- 最简单的RNN是通过whh来存储时序信息的
- 语言模型说白了就是一个分类问题,预测一个长为n的序列就做n次评估,即n次交叉熵的平均
- 困惑度就是平均交叉熵取指数
- 当困惑度为K时。可以认为下一个词有K种可能,相对平均交叉熵更加直观
- g是所有层的梯度放在一起构成的向量
- 保证长度永远不会超过sita
- 从具体时间点来看其实就是一个多分类问题
- pytorch的rnn层不包括输出层。要自己加
- 嵌入表示(Embedding)
56 门控循环单元(GRU)
- 解决隐藏序列中不是所有信息同等重要、RNN隐藏信息无法做的太长的问题
- 激活函数使用的是sigmoid
- 等价于一个全连接层
- 点圈代表按元素乘法
- Rt属于0~1,是一个可以学习的参数。当Rt的元素趋近于0时相当于忘记对应的隐藏状态
- Zt的取值范围为0~1,取1时相当于不更新隐藏状态
在 PyTorch 中,@
符号表示矩阵乘法运算,类似于 NumPy 中的 @
运算符,也等价于 PyTorch 中的 torch.matmul()
函数。
它主要用于两个张量(Tensor)之间的矩阵乘法操作,具体行为会根据张量的维度自动调整:
- 对于两个二维张量(矩阵),
@
执行标准的矩阵乘法((n×m) 矩阵 × (m×p) 矩阵 = (n×p) 矩阵) - 对于高维张量,
@
会在最后两个维度上执行矩阵乘法,前面的维度被视为批次维度
示例:
import torch
# 二维矩阵乘法
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
c = a @ b # 等价于 torch.matmul(a, b)
print(c)
# 输出:
# tensor([[19, 22],
# [43, 50]])
需要注意的是,@
与 *
运算符不同,*
在 PyTorch 中表示元素-wise 乘法(哈达玛积),而 @
才是真正的矩阵乘法。
57 长短期记忆网络(LSTM)
- RNN、GRU、LSTM 的本质区别就在于是如何更新 H
58 深层循环神经网络
- nn.lstm 本身是不带输出层的
59 双向循环神经网络
60 机器翻译数据集
61 编码器-解码器架构
62 序列到序列学习(seq2seq)
- 因为编码时几乎是都可以看到整个句子,所以可以做双向
-
细节在于解码器的输入由编码器最后一层隐藏层的输出加上解码器的输入构成
- 编码器最后一层隐藏层的输出用于初始化解码器的第一层的参数
-
n-gram是n个词的意思,比如p1就是match一个词的个数占所有词的比例
- Pn 就是预测序列中长为 n 的序列在标签序列中出现的个数
- bleu越大越好
- 在数学中,“exp” 表示以自然常数 e(约等于 2.71828)为底的指数函数 。即对于任意实数 x ,\(\exp(x)=e^x\) 。
- 实际句子的长度超出预设句子的长度,超出部分直接就截掉了,不会放入下一个句子。因此,预设句子长度时先分析数据找一个能覆盖大多数长度的预设。
63 束搜索
- 介于贪心和穷举之间
- 选当前最好的 K 个。要注意是存每步时的最好的 K 个,不是存每个情况的 K 个
- 大家别搞错了,这不是对每个分支贪心。是对分出来的结果再全局取前k个,完全有可能第二个分支独占了前k个概率最高的,然后分支1就废弃了
- 一个句子的概率总是要低于他的子句子,候选的概率总是低于 1 的
注意力机制
64 注意力机制
-
在侦探工作中,我们经常面临大量的线索,每个线索都由一个属性(key)和其价值(value)组成。这些线索可能包括目击者证词、凶器、不在场证明等,而它们的价值可能各不相同,有的线索价值可能是正的,有的可能是负的,因为某些线索可能会误导调查。
如果我们不采用注意力机制,我们可能需要对所有线索进行平等的调查,这可能导致我们在不重要的线索上花费过多的时间和精力。数学上,这种做法相当于将所有线索的价值简单相加,由于价值有正有负,最终的总价值可能并不高,无法有效指导我们的调查。
然而,通过使用注意力机制,我们可以更加智能地处理这些线索。首先,我们会计算每个线索的属性(key)与我们当前关注的问题(query)之间的相关性。例如,凶器和目击者证词很可能与破案有很高的相关性。然后,我们会将那些与问题高度相关的线索的价值(value)进行加权求和,这样不仅可以保证我们集中精力在最重要的线索上,而且可以提高我们得到有价值信息的可能性。
- 非参意味着不用学参数
- \(K\) 是一个函数,用于衡量 \(x\) 与 \(x_i\) 之间的距离
- \(\frac{K(x-x_i)}{\sum_{j=1}^nK(x-x_j)}\) 每一项都表示该项的相对重要性
- 加权之后对 \(y_i\) 求和,代表选择那些和 \(x\) 较近的 \(x_i\)
- 非参的好处是不需要学,只要有足够多的数据就能弄出来。问题是实际情况下不会有那么多数据
65 注意力分数
66 使用注意力机制的seq2seq
67 自注意力
- 对自注意力机制,它将 \(x_i\) 又当 k 又当 q 又当 v 这样对每个序列抽取特征得到 y
- 给定序列是一个长为 n 的序列,每个 \(x_i\) 是一个长为 d 的向量
- 自注意力将 \(x_i\) 同时作为 key 、value 和 query ,以此来对序列抽取特征
- 基本上可以认为给定一个序列,会对序列中的每一个元素进行输出,也就是说,每个查询都会关注所有的键-值对并生成一个注意力输出
-
自注意力之所以叫做自注意力,是因为 key,value,query 都是来自于自身,\(x_i\) 既作为 key ,又作为 value ,同时还作为 query (self-attention 中的 self 所强调的是 key,value,query 的取法)
-
自注意力适合处理比较长的文本
- CNN、RNN、自注意力都可以用来处理序列
- CNN 如何处理序列:给定一个序列,将其看作是一个一维的输入(之前在处理图片时,图片具有高和宽,而且每个像素都具有 chanel 数,也就是特征数),如果用 CNN 做序列的话,经过一个 1d 的卷积(只有宽没有高)之后,将每个元素的特征看作是 channel 数,这样就可以用来处理文本序列了
- k:窗口大小,每次看到的长度为 k
- n:长度
- d:dimension,每个 x 的维度(长度)
- 并行度:每个输出( yi )可以自己并行做运算,因为 GPU 有大量的并行单元,所以并行度越高,计算的速度就越快
- 最长路径:对于最长的那个序列,前面时刻的信息通过神经元传递到后面时刻,对应于计算机视觉中的感受野的概念(每一个神经元的输出对应的图片中的视野)
-
卷积神经网络和自注意力都拥有并行计算的优势,而且自注意力的最大路径长度最短。但是因为自注意力的计算复杂度是关于序列长度的二次方,所以在很长的序列中计算会非常慢
-
纯用自注意力机制做序列模型的问题是没有位置信息,会导致问题
- 和 CNN / RNN 不同,自注意力并没有记录位置信息
CNN 中其实是有记录位置信息的,从输出可以反推出输入所在的窗口的位置,窗口大小可以看成是位置信息
RNN 本身就是序列相关的,它是通过逐个的重复地处理词元 对于自注意力来说,如果将输入进行随机打乱,对应输出的位置可能会发生变化,但是每个输出的内容不会发生变化
所以如果是想纯用自注意力机制来做序列模型的话,没有位置信息的话可能会出现问题,所以可以通过加入位置编码来加入位置信息 - 为了使用序列的顺序信息,通过在输入表示中添加位置编码将位置信息注入到输入里
位置编码不是将位置信息加入到模型中,一旦位置信息加入到模型中,会出现各种问题(比如在 CNN 中就需要看一个比较长的序列,RNN 中会降低模型的并行度)
P 中的每个元素根据对应的 X 中元素位置的不同而不同,相当于对位置进行编码 - P 的元素具体计算如下:
对于 P 中的每一列,奇数列是一个 cos 函数,偶数列是一个 sin 函数,不同的列之间的周期是不一样的
68 Transformer
-
ffn实际上就是一个全连接 卷积层-relu-卷积层
是的,你理解得已经很接近了 👍 我们可以更精确一点来看 FFN 在 Transformer 里的作用:
## 1. FFN 的形式
在每个位置上:
$$
\text{FFN}(z_t) = W_2 \, \sigma(W_1 z_t + b_1) + b_2
$$
其中 $z_t$ 是经过 **Self-Attention + 残差 + LayerNorm** 处理后的向量(已经带有位置信息)。
---
## 2. 作用拆解
FFN 不是单纯地“再加一次位置信息”,它的作用主要有:
### (1)非线性特征变换
- Self-Attention 是一个线性加权求和机制,本身是线性的。
- 如果没有 FFN,整个模型可能只是线性函数叠加,不够强大。
-
FFN 引入 非线性激活函数(如 ReLU、GELU),让模型能学到更复杂的模式。
👉 类似于 CNN 里卷积层后面接 ReLU 的作用。
### (2)提升表示能力
- Self-Attention 主要在「不同 token 之间」传递和融合信息。
-
FFN 则在「单个 token 内部」进行维度提升和降维(比如从 \(d\) → \(4d\) → \(d\)),让每个 token 的表示更丰富。
👉 相当于对每个 token 单独做一个“全连接神经网络处理”。
### (3)结合位置信息,生成位置敏感表示
- 输入到 FFN 的向量 \(z_t = x_t + p_t + \text{上下文信息}\)。
- FFN 虽然参数共享,但因为输入不同位置的向量不同(包含位置信息),输出自然也不同。
-
因此它能区分不同位置,并对每个位置进行合适的非线性映射。
## 3. 一个直观比喻
- Self-Attention:像是一张“信息交换的会议桌”,不同位置的 token 在这里互相传递消息。
-
FFN:像是每个 token 回到自己的办公室后,对接收到的信息做内部加工、升级表达,再返回给下一个层使用。
## 4. 总结一句话
FFN 的作用是:
> **对每个 token(含位置信息和上下文信息)的表示,独立地进行非线性特征变换和维度扩展,从而提升模型表达能力。**
---
要不要我给你写一个 **简化的代码例子(PyTorch版)**,直观展示 Self-Attention + FFN 的区别?
-
对于自注意力层来说,什么形状的东西进去就是什么样的出来, shape 不会改变
-
transformer 编码器和解码器都不会改变输入形状
69 BERT预训练
-
输入变成两个句子拼接。 QA 等 NLP 任务通常是
对的 ✅,你理解得非常准确了。
更完整一点说:
-
预训练阶段
-
BERT 的产出是 一个模型(不是两个)。
- 在训练时,这个模型会同时优化 MLM 任务和 NSP 任务。
- 具体做法是:同一个输入同时送进 BERT,分别接两个小输出头(一个是 MLM 的词预测头,一个是 NSP 的句子预测头),然后把两个任务的 loss 加起来一起反向传播。
-
所以最后得到的 BERT,参数里已经蕴含了“单句子语义 + 句子关系”的知识。
-
下游使用(Fine-tuning)
-
我们一般只用 BERT 的主体(Transformer 编码器部分)。
- MLM 和 NSP 的预测头可以扔掉,换成你自己的下游任务头。
- 这样 BERT 作为一个通用语义特征提取器,就能适配各种 NLP 任务。
所以一句话总结: 👉 BERT 预训练的结果 = 一个单一模型,它的参数是在 MLM + NSP 的双任务训练下学到的。
要不要我帮你画一张结构示意图(左边是预训练:MLM+NSP → BERT,右边是下游任务:BERT+分类器/CRF/...)?这样一眼就能看出“产出是一个模型”的意思。
- 数据 模型 训练
70 BERT微调
- python 是非常慢的,碰到性能瓶颈时考虑数据预处理的问题
71 目标检测竞赛总结
smote
SMOTE(Synthetic Minority Over-sampling Technique,合成少数类过采样技术)是一种常用于解决数据集中类别不平衡问题的方法,在机器学习和数据挖掘领域应用广泛。在你提供的PPT中,当提到 “有同学使用了SMOTE” 时,就是在处理类别样本严重不足的情况 。下面详细介绍SMOTE的原理和操作步骤:
原理
SMOTE不是简单地对少数类样本进行复制,而是通过分析少数类样本的分布,人工合成新的少数类样本,使得数据集的类别分布更加均衡,从而提升模型对少数类样本的学习效果,避免模型过度偏向多数类样本。
操作步骤
- 确定少数类样本:首先需要明确数据集中的少数类,即样本数量较少的类别。
- 计算距离:对于每个少数类样本,计算它与其他少数类样本之间的距离(一般使用欧氏距离等度量方式),然后根据距离确定每个少数类样本的k个最近邻(k是一个超参数,需要根据实际情况进行设置)。
- 生成合成样本:对于每个少数类样本,从它的k个最近邻中随机选择一个或多个邻居,在该样本和选中的邻居之间随机生成新的样本点。例如,对于少数类样本 \(x_i\),选择它的一个最近邻 \(x_j\),通过以下公式生成合成样本 \(x_{new}\): [ x_{new} = x_i + \delta \times (x_j - x_i) ] 其中,\(\delta\) 是一个在 \([0, 1]\) 之间的随机数。通过多次执行这个过程,可以生成多个新的少数类样本,增加少数类样本在数据集中的占比。
优点
- 避免过拟合:相比于简单复制少数类样本,SMOTE生成的是新的、但与原始少数类样本相关的样本,能扩充数据的多样性,减少因简单重复数据导致的过拟合问题。
- 提升模型性能:有助于改善分类模型在少数类上的表现,提高模型对少数类样本的识别能力,在一些实际应用场景(如欺诈检测、疾病诊断等少数类样本很重要的场景)中非常有价值。
缺点
- 计算成本较高:需要计算样本之间的距离并生成新样本,在大规模数据集上计算开销较大。
- 边界模糊问题:可能会在少数类和多数类之间生成一些模糊边界的样本,当数据分布复杂时,合成的样本可能会混入多数类样本区域,导致模型在分类时产生混淆。
总之,SMOTE是一种有效缓解数据不平衡问题的技术,但在实际应用中,也需要结合具体的数据集和任务需求,合理调整相关参数,或与其他方法(如欠采样多数类、结合集成学习等)结合使用,以达到更好的效果。
以下以信用卡欺诈检测为例,介绍SMOTE方法的具体使用过程
背景
在信用卡交易数据中,正常交易的数量远远大于欺诈交易的数量,属于典型的类别不平衡问题。假设我们有一个包含10000条信用卡交易记录的数据集,其中只有100条是欺诈交易(少数类),而9900条是正常交易(多数类)。如果直接使用这个数据集训练分类模型(如逻辑回归模型),模型往往会过度关注正常交易,导致对欺诈交易的识别能力很差。
使用SMOTE方法的步骤
-
数据准备 将数据集划分为特征矩阵
X
和标签向量y
。特征矩阵X
包含每笔交易的相关信息,比如交易金额、交易时间、交易地点、持卡人近期消费习惯等多个特征;标签向量y
表示交易是否为欺诈,1代表欺诈交易,0代表正常交易。 -
导入库并实例化SMOTE对象 在Python中,可以使用
imblearn
库来实现SMOTE方法,代码如下:
from imblearn.over_sampling import SMOTE
import pandas as pd
import numpy as np
# 假设已经加载好了数据,X是特征矩阵,y是标签向量
# 这里只是示例代码,实际中需要根据具体数据加载方式获取X和y
X = pd.read_csv('transaction_features.csv')
y = pd.read_csv('transaction_labels.csv')['label']
smote = SMOTE(random_state=42) # 设置随机种子,保证结果可复现
- 应用SMOTE生成新的数据集
在这一步中,SMOTE
算法会分析少数类(欺诈交易)样本的分布情况。比如,对于每一个欺诈交易样本,它会找到其 k
个最近邻(假设设置 k=5
),然后在该样本和其最近邻样本之间随机生成新的样本点。最终,得到经过过采样后的特征矩阵 X_resampled
和标签向量 y_resampled
,此时欺诈交易样本的数量会增加,数据集的类别不平衡程度得到缓解。
- 训练模型 使用经过SMOTE处理后的数据集来训练分类模型,比如逻辑回归模型:
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_resampled, y_resampled, test_size=0.2, random_state=42)
# 初始化并训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train, y_train)
# 在测试集上进行预测并评估模型性能
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))
通过SMOTE方法,原本严重不平衡的信用卡交易数据集变得相对平衡,使得模型在训练时能够更好地学习到欺诈交易样本的特征,从而提升对欺诈交易的检测能力,减少欺诈交易漏判的情况。
72 优化算法
QA
【完结】73 - 课程总结和进阶学习
QA
- 用一个代码是工作,看懂一个代码是学习。学习比工作更难