一、张量

什么是张量?

答:n 维数组;张量表示由一个数值组成的数组,这个数组可能有多个维度

具有一个轴的张量对应数学上的向量(vector)

具有两个轴的张量对应数学上的矩阵(matrix)

x = torch.arange(12)

返回:tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

x.shape

返回:torch.Size([12])

x.numel()

意思:获取张量中有多少个元素

返回:12

X = x.reshape(3, 4)

意思:改变一个张量的形状而不改变元素数量和元素值

返回:tensor([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])

张量运算:对位相加减乘除

张量拼接(cat)

dim=0 是垂直拼(行数增加),dim=1 是水平拼(列数增加)

X = torch.arange(12, dtype=torch.float32).reshape((3,4))

Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)

返回:

(tensor([[ 0., 1., 2., 3.],

        [ 4., 5., 6., 7.],

        [ 8., 9., 10., 11.],

        [ 2., 1., 4., 3.],

        [ 1., 2., 3., 4.],

        [ 4., 3., 2., 1.]]),

tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],

        [ 4., 5., 6., 7., 1., 2., 3., 4.],

        [ 8., 9., 10., 11., 4., 3., 2., 1.]]))

广播机制(重点)

当两个张量形状不同时,如果它们在某些维度长度是1,PyTorch 会自动“复制”这个维度,让形状匹配后再运算

索引和切片(像数组一样取数)

  • X[1, 2] 取第1行第2列的元素。

  • X[0:2, :] 取前两行、所有列。

  • 也可以直接赋值:X[1,2] = 9

数据预处理:
  1. 读取数据:用 pandas.read_csv() 读取 CSV 文件。

  2. 处理缺失值(NaN)

    • 数值列(如房价):用该列的平均值填充空缺。

    • 类别列(如巷子类型:Pave 或 NaN):用 独热编码(one-hot)。把一列变成两列:Alley_Pave 和 Alley_nan。是 Pave 就 (1,0),是 NaN 就 (0,1)。把文字变成了数字。

  3. 转换成张量:用 torch.tensor() 把 pandas 表格转成 PyTorch 张量,准备喂给模型。

“NaN” 项代表缺失值

线性代数:
  1. 标量:就是一个数(0维张量)。比如学习率 0.01,温度 36.5℃

  2. 向量:一列数(1维张量)。比如一个人的特征:[年龄, 收入, 贷款次数]

    • 通过下标取值,比如 x[3]

    • 长度(维度)用 len(x) 或 x.shape 获取。

  3. 矩阵:一个表格(2维张量)。比如一批人的特征,每个人一行,每个特征一列。

    • 转置(.T)就是行列互换。对称矩阵就是转置等于自己。

  4. 张量(高阶):超过2维的统称张量。彩色图片就是 3维(高×宽×通道)。

降维(求和与平均)

  • sum() 把所有元素加成一个数。

  • 指定 axis=0 按列求和(每一列加起来,行消失)。

  • 指定 axis=1 按行求和(每一行加起来,列消失)。

  • 用 keepdims=True 可以保持维度不变,方便后续广播除法(比如每行除以该行的总和)。

点积(对应位置相乘再求和):

实际意义:点积表示加权平均

矩阵-向量积(矩阵 × 向量 → 向量)

  • 矩阵的每一行和向量做点积,结果是一个新向量。

  • 意义:神经网络的一层计算就是 权重矩阵 × 输入向量 + 偏置

矩阵-矩阵乘法(矩阵 × 矩阵 → 矩阵)

  • 其实就是多次矩阵-向量积。左矩阵的每一行,去和右矩阵的每一列做点积,拼成新矩阵。

  • 深度学习里的全连接层、卷积层,底层都是这种乘法。

总结:
操作函数说明
创建全0torch.zeros((2,3))2行3列全0
创建全1torch.ones((2,3))2行3列全1
创建随机数torch.randn(3,4)标准正态分布随机数
手动创建torch.tensor([[2,1],[1,2]])用列表直接指定
改变形状x.reshape(3,4)总量不变,重新排列;可用 -1 自动算维度
按元素运算+ - * / **对应位置相加、乘等
指数运算torch.exp(x)计算 e^x
连接torch.cat((X,Y), dim=0)dim=0上下拼,dim=1左右拼
逻辑比较X == Y返回 True/False 张量
求和X.sum()所有元素加总

广播机制:两个张量形状不同时,如果某维度长度为1,会自动复制该维度,让形状匹配后再运算。

a = torch.arange(3).reshape((3,1))  # 3行1列
b = torch.arange(2).reshape((1,2))  # 1行2列
a + b  # 结果 3行2列
# a复制列 → 变3×2,b复制行 → 变3×2,再相加
写法含义
X[1,2]第1行第2列的元素
X[-1]最后一行
X[1:3]第1行到第2行(不含第3)
X[0:2, :]前两行,所有列
X[1,2] = 9给指定位置赋值
X[0:2, :] = 12前两行所有列全部赋值为12

数据预处理核心流程:

  1. pd.read_csv() 读取原始数据

  2. 处理缺失值:

    • 数值列:用均值填充 fillna(inputs.mean())

    • 类别列:用独热编码 pd.get_dummies(dummy_na=True),把文字变数字

  3. torch.tensor(inputs.values) 转成张量

概念定义代码
标量单个数字(0维)torch.tensor(3.0)
向量一维数组x = torch.arange(4)
矩阵二维数组A = torch.arange(20).reshape(5,4)
转置行列互换A.T
对称矩阵A == A.T如 [[1,2],[2,1]]
操作代码结果形状变化
全部求和A.sum()变成一个标量
按列求和(axis=0)A.sum(axis=0)行消失,剩一列
按行求和(axis=1)A.sum(axis=1)列消失,剩一行
保持维度A.sum(axis=1, keepdims=True)形状不变(比如5行变5行1列)
累加求和A.cumsum(axis=0)形状不变,每个位置变成该位置之前所有值的累加
运算公式代码形状要求
点积(向量×向量)Σ x_i * y_itorch.dot(x,y)长度相同,结果是标量
矩阵-向量积(矩阵×向量)A的每一行和x做点积torch.mv(A,x)A列数 = x长度,结果是向量
矩阵-矩阵乘法左行×右列,点积torch.mm(A,B)A列数 = B行数
  • 点积 = 加权和(如特征×权重)

  • 矩阵-向量积 = 神经网络一层的计算(权重×输入)

二、线性回归

最简单的神经网络——线性神经网络

  • 线性回归 → 用来预测一个数值(比如房价)

  • softmax回归 → 用来分类(比如判断一张图是猫、鸡还是狗)

怎么衡量预测得好不好?→ 损失函数

平方损失 = ½ × (真实值 - 预测值)²

整个训练集上的平均损失:

总损失 = (1/2n) × Σ(真实值 - 预测值)²

训练的目标就是找到一组 (w, b),让这个总损失最小。

怎么找到最优的 w 和 b?→ 两种方法
1、解析解(只适用于线性回归)

2、随机梯度下降(重点)

步骤:

  1. 随机初始化 w 和 b(比如随机给个初始值)

  2. 每次从训练数据中随机抽一小批(叫小批量随机梯度下降

  3. 计算这批样本的损失,并求出梯度(也就是损失对w和b的偏导)

  4. 让 w 和 b 沿着梯度相反的方向走一小步(减去 梯度 × 学习率)

  5. 重复第2~4步,直到损失不再下降

关键超参数(需要手动设定的):

  • 学习率 η:每一步走多大(步子太大容易跳过最优解,步子太小训练太慢)

  • 批量大小 |B|:每次抽多少个样本一起算

这两个值不是学出来的,是你自己调的,所以叫超参数

调参是选择超参数的过程

线性回归 = 一个单层神经网络

把线性回归画成神经网络就是:

  • 输入层:每个特征是一个输入节点

  • 输出层:一个输出节点

  • 没有隐藏层

所以它叫“单层神经网络”。

三、Softmax回归

回归分类
输出一个连续数值一个离散类别
例子房价预测(输出多少钱)手写数字识别(输出0~9中的某一个)
损失函数均方损失(L2 Loss)交叉熵损失
线性回归softmax回归
输出一个数值多个类别的概率
典型场景预测房价图片分类
损失函数平方损失交叉熵损失

核心思想:输入一张图片(像素值作为特征),输出它属于每个类别的概率,概率最高的那个就是预测结果

独热编码(one-hot)
把类别标签变成向量:

  • 猫 = [1, 0, 0]

  • 鸡 = [0, 1, 0]

  • 狗 = [0, 0, 1]

softmax运算(把任意数变成概率)

  • 先取指数(保证正数)

  • 再除以总和(保证加起来等于1)

  • 结果就是概率

Softmax回归为线性模型

损失函数:交叉熵损失(衡量两个概率分布的差距)—— 分类问题最常用的损失之一

含义:

损失 = -log(预测正确的类别的概率)

  • 预测越准(概率越接近1),损失越接近0

  • 预测越离谱(概率接近0),损失趋于无穷大

三种损失函数

损失函数公式特点
L2 Loss(均方损失)½·(y - y')²对离群点敏感,梯度大
L1 Loss(绝对值损失)|y - y'|对离群点鲁棒,但在0处不可导
交叉熵损失-Σy_i·log(ŷ_i)分类问题标准选择

分类问题用交叉熵,回归问题用L2或L1

Softmax及其导数:

大白话:梯度 = 预测概率 - 真实标签。也就是说,模型预测多了就减,预测少了就加,和线性回归的梯度形式一样(预测值 - 真实值)。

概念公式
未归一化输出o = X·W + b
Softmaxp_j = exp(o_j) / Σexp(o_k)
交叉熵损失(单个样本)l = -log(p_正确类别)
交叉熵损失(批量)L = -(1/n)·Σlog(p_正确类别)
梯度∂L/∂o = softmax(o) - y
总结:
线性回归:
形式公式
单个样本(标量形式)ŷ = w₁x₁ + w₂x₂ + ... + w_d·x_d + b
单个样本(向量形式)ŷ = <w, x> + b
整批样本(矩阵形式)ŷ = X·w + b(X是 n×d 矩阵,每行一个样本)
损失函数(平方损失)

l(ŷ, y) = ½ × (ŷ - y)²

即:平方损失 = ½ × (真实值 - 预测值)²

整个训练集上的平均损失:

L(w,b) = (1/2n) × Σ(ŷⁱ - yⁱ)²

训练目标:最小化损失函数

求解方法:
方法公式/步骤适用场景
解析解(公式法)w* = (XᵀX)⁻¹Xᵀy仅限线性回归,一步算出最优解
随机梯度下降(SGD)每步:w ← w - η × (1/|B|) × Σ梯度所有模型通用,深度学习核心算法

随机梯度下降的超参数:

  • 学习率 η:每一步走多大(太大跳过最优解,太小训练太慢)

  • 批量大小 |B|:每次抽多少个样本一起算

随机梯度下降的更新

w ← w - (η/|B|) · Σ xⁱ · (ŷⁱ - yⁱ)
b ← b - (η/|B|) · Σ (ŷⁱ - yⁱ)

本质:沿着让损失下降的方向,微调 w 和 b

Softmax回归:
线性回归Softmax回归
输出一个连续数值多个类别的概率
典型场景房价预测图片分类(猫/鸡/狗)
损失函数平方损失交叉熵损失
输出激活无(直接输出)softmax(转成概率)

Softmax公式:

作用:把任意数值(可正可负、和不为1)转换成合法的概率分布

交叉熵损失(分类问题的标准损失)

l = -log(预测正确的类别的概率)

梯度:

∂损失/∂o_j = softmax(o)_j - y_j

梯度 = 预测概率 − 真实标签(独热编码)

名称公式
线性回归模型ŷ = X·w + b
平方损失l = ½·(ŷ - y)²
解析解w* = (XᵀX)⁻¹Xᵀy
SGD更新w ← w - (η/|B|)·Σ∇L
Softmaxp_j = exp(o_j) / Σexp(o_k)
交叉熵损失l = -Σ y_j·log(ŷ_j)
交叉熵的梯度∇ = softmax(o) - y
概念:

分类问题的输出:输出 i 为预测为 i 的置信度

使用 softmax 来得到每个类的预测置信度

使用交叉熵来衡量预测和标号的区别

四、感知机

单层感知机

二分类模型,输出只有两个值:+1 或 -1(或者 1 或 0)

模型输出类型典型场景
线性回归连续实数预测房价
Softmax回归概率分布(多类)图像分类
感知机+1/-1(二分类)垃圾邮件判断

感知机的训练算法:

  • 拿一个样本,算一下预测对不对

  • 如果分错了,就把权重往“正确方向”调一点点

  • 一直重复,直到所有样本都分对

损失函数是 max(0, -y·<w,x>)(也就是“分对了损失为0,分错了损失为正”)

收敛定理

如果数据是线性可分的(能用一条直线分开),感知机保证在有限步内找到分类线

重点:感知机不能解决异或问题(XOR)

原因:XOR的四个点在对角线上,无法用一条直线分开(线性不可分)。感知机只能画直线,所以永远搞不定

多层感知机(MLP)

如何解决异或问题?

答:加一个单层隐藏层

核心思想:单层感知机只能画一条直线,但如果先做一次变换再分类,就能处理非线性问题。

流程:输入 x → 隐藏层(变换)→ 输出层(分类)

公式:

h = σ(W₁·x + b₁)     # 隐藏层,σ是激活函数
o = w₂ᵀ·h + b₂       # 输出层

注意:激活函数必须为【非线性激活函数】

为什么?

非线性激活函数能使整个模型变成非线性的,能拟合 XOR 这类问题

常用激活函数
激活函数公式输出范围特点
ReLUmax(x, 0)[0, +∞)最常用,计算简单,缓解梯度消失
Sigmoid1/(1+e⁻ˣ)(0, 1)早期常用,现在少用(梯度消失问题)
Tanh(1-e⁻²ˣ)/(1+e⁻²ˣ)(-1, 1)比Sigmoid好一点,仍然有梯度消失

ReLU优势:正半轴梯度恒为1,缓解梯度消失

使用 softmax 来处理多分类问题:

对于多分类问题,如果有k个类别,只需要在输出层用softmax

多隐藏层(深度神经网络)

超参数

  • 隐藏层数(深度)

  • 每层隐藏单元数(宽度)

总结&习题:
概念要点
感知机二分类线性模型,训练=错误驱动更新,不能处理XOR
感知机损失max(0, -y·<w,x>),等价于批量=1的SGD
收敛条件数据线性可分,步数≤(r²+1)/ρ²
XOR问题线性不可分,感知机搞不定 → 第一次AI寒冬
MLP感知机 + 隐藏层 + 非线性激活函数
激活函数必要性否则多层叠加=一层(线性),无法处理非线性问题
常用激活函数ReLU(最流行)、Sigmoid、Tanh
多分类MLP隐藏层 + softmax输出层
超参数隐藏层数、每层隐藏单元数

Q1:多层感知机的 “隐藏层” 有什么作用?

隐藏层的作用是提取数据的“中间特征”,并通过非线性激活函数让模型具备拟合复杂非线性关系的能力。

重点:

  • 隐藏层位于位于输入层和输出层之间,可以将原始输入重新组合成更高层次的抽象特征
  • 同时通过非线性激活函数(如ReLU,Sigmoid)使模型具备解决非线性问题的能力(如异或问题
  • 隐藏层数量(深度)和每层的大小(宽度)决定了模型的容量。通过增加隐藏层可以使模型拟合更加复杂的函数,从而增加模型的表达能力

Q2:写出 ReLU 函数的公式,与 Sigmoid 函数相比有什么优势?

  1. 缓解梯度消失正半轴梯度恒为1,深层网络也能有效训练,而Sigmoid在两端饱和、梯度趋近于0。

  2. 计算简单只做比较运算,没有指数运算,训练速度更快。

  3. 引入稀疏性:部分神经元输出为0,让模型更高效、更具鲁棒性

概念:

感知机为二分类模型,不能处理异或问题,他的求解算法等价于使用批量大小为1的梯度下降

五、模型选择(概念重点)

概念定义通俗理解
训练误差模型在训练数据上的误差练习题时的正确率
泛化误差模型在新数据上的误差高考题时的正确率
数据集用途特点通俗理解
训练集训练模型参数(w和b)平时做题
验证集选择超参数(学习率、层数等)训练集分出一部分作为验证集模拟考(用来调整复习策略)
测试集只测一次,评估最终模型高考(只用一次,决定最终成绩)
K折交叉验证

数据不够多的时候使用这个方法

概念定义简单记通俗理解
欠拟合训练误差泛化误差都很大训练误差大,泛化误差大练习题都不及格 → 根本没学会
过拟合训练误差很低,但泛化误差很高训练误差小,泛化误差大练习题满分 → 高考不及格(死记硬背)
恰到好处训练误差和泛化误差都低练习题不错,高考也不错 → 真学会了
模型的容量

容量 = 模型拟合各种函数的能力

容量特点后果
低容量太简单,学不到数据规律欠拟合
高容量太复杂,连噪声都记住了过拟合

模型容量的影响:1)经验;2)VC维

数据复杂度

模型的容量要跟数据复杂度匹配

因素说明
样本个数数据越多,能支撑的模型越复杂
每个样本的元素个数特征维度越高,数据越复杂
时间/空间结构图像、序列数据比普通表格数据复杂
多样性数据变化越丰富,越复杂
  • 数据简单 + 模型太复杂 → 过拟合

  • 数据复杂 + 模型太简单 → 欠拟合

总结:
概念关键点
训练误差练习题正确率
泛化误差高考正确率(我们真正关心的)
验证集用来调超参数,不参与训练
测试集只用一次,最终评估
K折交叉验证数据少时用,K=5或10,报告平均误差
欠拟合训练误差高 → 模型太简单
过拟合训练误差低、泛化误差高 → 模型太复杂
模型容量拟合能力大小,受参数数量和参数范围影响
VC维理论衡量模型复杂度,深度学习中实际不常用
数据复杂度样本数、特征数、结构多样性等
习题:

1、什么是过拟合和欠拟合?

  • 过拟合:模型在训练集上的误差低,但是在测试集上的误差高
  • 欠拟合:模型在训练集上的误差高,在测试集上的误差也高

2、什么是训练误差和验证误差?

  • 训练误差:模型在训练数据集上计算出的误差
  • 验证误差:模型在验证数据集上计算出的误差(验证数据集:一个用来评估模型好坏的数据集,通常从训练集上单独拿出50%作为验证集)

3、怎么通过训练误差和泛化误差判断是否过拟合?

  • 训练误差高 + 泛化误差高 = 欠拟合
  • 训练误差低 + 泛化误差高 = 过拟合

六、权重衰退

核心思想:控制模型容量

两种方法:

权重衰退通过 L2 正则项使得模型参数不会过大,从而控制模型的复杂度,从而提高模型的泛化能力

正则项权重是控制模型复杂度的超参数

权重衰退 = L2正则化,L2正则化就是在损失函数里加 λ·||w||² 这一项

七、丢弃法

一个好的模型应该对输入数据的扰动具有鲁棒性。

核心思想:给数据加一些噪声,让模型学会在“不完美”的情况下也能正确预测

丢弃法:在层之间加入噪声

训练时,每个神经元有p的概率“被关闭”(输出为0),剩下的神经元要“加班”——输出值除以(1-p),保证总体平均水平不变

丢弃法的作用位置:通常将丢弃法作用在隐藏全连接层的输出上

总结(重要)

权重衰退(L2 正则化)

概念内容
核心公式新损失 = 原损失 + (λ/2)·||w||²
参数更新w ← (1-ηλ)·w - η·∂ℓ/∂w(先衰退再更新)
λ的作用λ越大,参数被压缩得越小,模型容量越低
本质限制参数大小 → 控制模型复杂度 → 防止过拟合
代码实现简洁版:optimizer = SGD(params, weight_decay=wd)

丢弃法(dropout)

概念内容
核心公式以p概率置0,以1-p概率除以(1-p)
关键性质保持期望不变(无偏扰动)
使用位置通常在全连接层的隐藏层输出上
训练/推理训练时开启,推理时关闭
p的作用p越大,丢弃越多,正则化越强
代码实现简洁版:nn.Dropout(p)

对比:

权重衰退丢弃法
作用方式惩罚大参数随机删除神经元
正则化机制限制参数范围引入噪声扰动
本质L2正则化集成学习近似

两者都是通过限制模型复杂度来防止过拟合,且可以组合使用

Q:丢弃法会丢弃整个神经元(对)

八、数值稳定性

神经网络中的梯度函数

损失ℓ关于第t层参数Wᵗ的梯度 = (∂ℓ/∂hᵈ) · (∂hᵈ/∂hᵈ⁻¹) · ... · (∂hᵗ⁺¹/∂hᵗ) · (∂hᵗ/∂Wᵗ)

数值稳定性常见的两个问题:1)梯度消失;2)梯度爆炸

1)梯度爆炸(使用ReLu作为激活函数)

触发条件:使用ReLU激活函数时,权重矩阵特征值 > 1

导致的问题:

问题说明
值超出范围梯度变成inf(无穷大)或NaN(非数字)
对16位浮点数尤为严重16位浮点数范围只有6e-5到6e4,很容易溢出
对学习率极其敏感学习率太大→梯度爆炸;太小→训练不动
需要不断调学习率训练过程中可能要频繁调整

判断方法:如果训练时损失突然变成NaN(Not a Number),大概率是梯度爆炸了

2)梯度消失(使用Sigmoid作为激活函数)

触发条件:使用Sigmoid激活函数(或其他导数<1的激活函数)

如何造成梯度消失?

回顾梯度是什么:梯度 = 损失上升最快的方向 + 变化的幅度

导致的问题:

问题说明
梯度变成0参数完全停止更新
底部层几乎不训练靠近输入的层梯度为0,只有靠近输出的层能训练
无法让网络更深加再多层也没用,因为前面都"死"了
不管怎么调学习率都没用因为梯度本身就是0,调大学习率也救不了

深度网络 = 大量连乘 → 数值要么爆炸(>1累乘)要么消失(<1累乘)→ 训练失败

那么如何让训练更加稳定?

让梯度值在一个合理的范围内?

解决方法:(主要:梯度裁剪;梯度归一化;权重初始化;采用合适的激活函数)

策略代表技术核心思路
1. 将乘法变加法ResNet、LSTM用"加法"连接代替"乘法"连接
2. 归一化梯度裁剪、梯度归一化把梯度限制在合理范围
3. 合理的权重初始化Xavier/Kaiming初始化让权重"恰到好处"
4. 合适的激活函数ReLU、调整后的Sigmoid避免导数极端值

权重初始化:

核心目标:让每一层的输出和梯度的方差保持一致

总结:
梯度爆炸梯度消失
现象梯度→∞梯度→0
典型原因权重过大 × ReLUSigmoid激活函数(导数≤0.25)
后果损失变成NaN底部层不更新
对学习率极其敏感怎么调都没用

深度网络训练像传话游戏——信息从最后一层传到最前面,每传一层都要乘一次。乘的数>1就爆炸(ReLU+大权重),乘的数<1就消失(Sigmoid),根本训不动。解决办法是合理初始化权重(让每层方差一致)和选对激活函数(ReLU比Sigmoid好)

九、层和块

1)什么是层(layer)?

层是神经网络中最基本的数据处理单元,接收一个张量,经过某种变换,输出一个新的张量

本质:层就是一个函数——输入一个张量,输出另一个张量。你可以把任何数据处理操作封装成"层"。

2)什么是块(block)?

块是一个或多个层(或子块)的容器,是比"层"更大、更灵活的组织单位。

在PyTorch中,nn.Module就是"块"。所有东西都是nn.Module的子类

class MLP(nn.Module):          # 这就是一个"块"
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(20, 256)   # 子层1
        self.out = nn.Linear(256, 10)      # 子层2

    def forward(self, X):
        return self.out(F.relu(self.hidden(X)))   # 定义数据如何流过子层
组件作用类比
__init__注册子层("买积木")列出三明治的配料清单
forward定义数据流向("告诉你怎么拼")说明配料怎么组合

nn.Module最重要的能力是什么?

答:它能够递归地找到所有子模块的参数

3、Sequential

nn.Sequential是一个特殊的块,它按顺序串联子层,数据依次流过每一层。

Sequential的基本原理:

步骤做什么代码
1接收子层__init__(self, *args) 接收所有传入的层
2注册子层self._modules[block] = block_modules是PyTorch自动追踪子模块的字典)
3顺序执行forward中遍历_modules,依次调用每一层
总结:
概念定义特点
最小的处理单元接收张量→输出张量(如Linear、ReLU)
层的容器/组合继承nn.Module,可嵌套,包含__init__forward
Sequential特殊的块自动按顺序执行子块,forward不需要手写

十、卷积(非常重要)

全连接层:上一层的全部神经元全部连到下一层的每个神经元上面

全连接层处理图片参数太多(一张12M像素的图需要36亿个参数)→ 我们根据两个原则(平移不变性、局部性)改造全连接层 → 得到卷积层 → 参数大大减少,且能检测图像中的边缘等特征

记:对全连接层使用平移不变性局部性得到卷积层

卷积的两个原则:平移不变性 & 局部性

1)平移不变性:检测同一个特征的卷积核应该能在图像的任何位置使用

2)局部性:判断一个像素是什么,只需要看它周围一小块区域,不需要看整张图

步骤做了什么效果
全连接层每个输出和所有输入相连参数爆炸 💥
平移不变性同一权重在不同位置复用参数大幅减少 ✅
局部性只用周围小区域的输入参数进一步减少 ✅
卷积层两者结合参数可控,能泛化 🎯

理解:Kernel 扫描 Input 的全部位置,得出 output

二维互相关运算的计算方式:卷积核在输入上"滑动",在每个位置,核与覆盖区域逐元素相乘后求和

二维交叉相关 (基本)== 二维卷积

总结:

卷积层通过将输入和核矩阵进行交叉相关,加上偏置项后得到输出

核矩阵的偏置项可学习的参数

核矩阵的大小超参数

习题:

1、MLP的前向传播,反向传播是怎么样的

  • 前向传播:数据从输入层进入,经过每一层的计算,最后输出预测结果
  • 反向传播:从输出层开始,把"损失"往前传,计算每一层的参数应该怎么调整。
    通过链式求导法则,将前向传播得到的预测损失从输出层反向逐层向输入层传递,计算梯度,再结合梯度下降法更新所有参数,从而最小化模型预测误差

2、卷积层的优势(相对于全连接层),能解决什么问题

解决的问题:全连接层处理大尺寸图像时参数爆炸

卷积层的优势

  • 参数大幅减少(基于"局部性"原则)
层类型连接方式参数数量示例
全连接层每个输出连接所有输入输入维度 × 输出维度36M×100 = 36亿
卷积层每个输出只连接局部区域核大小(不随输入尺寸变化)3×3 = 9
  • 保留空间结构(基于"平移不变性"原则)
    • 全连接层:把图片展平成一维 → 丢失了像素之间的位置关系
    • 卷积层:保持二维结构 → 相邻像素一起处理,能识别局部特征
  • 平移不变性
    • 同一套参数(核)在所有位置共享使用

3、怎么用卷积层进行参数共享

参数共享 = 一个卷积核(一组权重)在输入图像的所有位置使用

4、卷积层计算参数量的大小

基本公式:卷积层参数量 = (核高 × 核宽 × 输入通道数) × 输出通道数 + 输出通道数(偏置)

计算:

MLP 的输入层有 256 个神经元,隐藏层有 128 个神经元,输出层有 10 个神经元,忽略偏置,求参数数量并写出计算过程

相关公式:

1)输入层到隐藏层之间的权重参数数量(不包括偏置):公式输入维度 × 输出维度

2)隐藏层的偏置参数数量:公式输出神经元数(每个输出神经元对应一个偏置)

3)隐藏层 → 输出层的权重参数数量:公式输入维度(隐藏层大小)× 输出维度(类别数)

4)输出层的偏置参数数量:公式输出神经元数

5)整个MLP的总参数数量:总参数 = (1) + (2) + (3) + (4)

概念公式/要点
全连接层前向Z = X·W + bŶ = σ(Z)
全连接层反向∂L/∂W = Xᵀ·∂L/∂Z∂L/∂X = ∂L/∂Z·Wᵀ
卷积层前向核在输入上滑动,逐元素乘后求和
卷积层反向用翻转核做卷积(transposed convolution)
卷积层优势①参数少(局部性) ②保留空间结构 ③平移不变性
参数共享同一核在所有位置使用 → 公式中v不依赖(i,j)
参数量公式k_h × k_w × C_in × C_out + C_out

卷积层相比于全连接层的核心优势是参数共享(同一核在所有位置使用)+局部连接(只关注邻域),这使得参数量从输入×输出骤降到核大小×通道数,能处理大尺寸图像,且具备平移不变性

十一、填充(Padding)& 步幅(Stride)& 通道数

卷积核在输入上滑动时,怎么滑(步幅)、边缘怎么处理(填充)、输入输出有多少层(通道数)——这三个因素共同决定了卷积层的输出形状和参数量

1、填充

为什么要填充?

答:每次卷积操作都会让输出尺寸变小

  • 经过几层后,图像变得太小,无法继续做卷积

  • 边缘像素只被卷积核"扫过"一次,中心像素被扫过多次 → 边缘信息丢失

填充定义:填充在输入周围添加额外的行与列,来控制输出形状的减少量

不填充的正常输出尺寸:

输出尺寸 = 输入尺寸 - 核尺寸 + 1

怎么做填充?

做法:在输入图像的周围添加额外的行/列(通常填0)

原始 5×5 图像 → 填充1圈 → 7×7 → 用3×3核 → 输出仍为5×5

输出尺寸公式:

输出高度 = n_h - k_h + p_h + 1
输出宽度 = n_w - k_w + p_w + 1

其中 p_h 是上下填充的总行数,p_w 是左右填充的总列数

  • 通常取 p_h = k_h - 1p_w = k_w - 1(这样输入输出尺寸不变)

  • 如果 k_h 是奇数:上下各填充 p_h/2

  • 如果 k_h 是偶数:上填充 ⌊p_h/2⌋,下填充 ⌈p_h/2⌉

最常见配置kernel_size=3, padding=1 → 输入输出尺寸不变

2、步幅

为什么要步幅?

目的:更快地缩小特征图的尺寸

步幅的定义:步幅是每次滑动核窗口时的行与列的大小,可以成倍快速地减少输出形状

步幅 = 卷积核每次滑动的行数/列数

注:p 为填充;s 为步幅

填充和步幅都是卷积层的超参数

3、多个输入&输出通道
1)多个输入通道

无论有多少输入通道,输出总是单通道的

每个输入通道具有独立的二维卷积核,所有通道结果加起来得到一个输出通道的结果

2)多个输出通道

每个输出通道有独立的三维卷积核

输出通道数是卷积层的超参数

3)1×1卷积核

作用:融合通道

总结:
情况公式(输出尺寸)
无填充,步幅1(n - k + 1) × (n - k + 1)
有填充p,步幅1(n - k + p + 1) × (n - k + p + 1)
有填充p,步幅s(完整版)⌊(n - k + p + s) / s⌋ × ⌊(n - k + p + s) / s⌋
p=k-1时(简化版)⌊(n + s - 1) / s⌋ × ⌊(n + s - 1) / s⌋
n能被s整除(n/s) × (n/s)
概念公式
输入到输出的映射每个输出通道 = 所有输入通道 × 对应核 求和
卷积核形状c₀ × cᵢ × k_h × k_w
输出形状c₀ × m_h × m_w
参数量c₀ × cᵢ × k_h × k_w + c₀(含偏置)
1×1卷积参数量c₀ × cᵢ + c₀
练习:

1、输入32×32×3,核3×3,输出通道64,填充1,步幅2 → 输出形状是什么?参数量是多少?

卷积层输出尺寸公式:

输出高度 = ⌊(输入高度 - 核高度 + 2×填充高度 + 步幅高度) / 步幅高度⌋
输出宽度 = ⌊(输入宽度 - 核宽度 + 2×填充宽度 + 步幅宽度) / 步幅宽度⌋

输出高度:16;输出宽度:16;输出通道:64

答案:输出形状为 32 * 32 * 64

卷积层参数量公式:

参数量 = 核高 × 核宽 × 输入通道数 × 输出通道数 + 输出通道数(偏置)

如果题目说有偏置,每个输出通道有1个偏置

答案:参数量为 3 * 3 * 3 * 64 + 64

卷积层输出形状由 输入尺寸、核大小、填充、步幅 共同决定;参数量只取决于 核大小×输入通道数×输出通道数(+偏置),与输入图像尺寸无关

十二、池化层

卷积层负责"找特征",池化层负责"压缩信息+增加鲁棒性";LeNet则是"卷积层提取特征 → 池化层压缩 → 全连接层分类"这一经典范式的开山之作

为什么要有池化层

作用是什么?

缓解卷积层对位置的敏感性

  • 在卷积层之后加一个池化层

两种池化层:

1)二维最大池化:返回滑动窗口中的最大值
2)二维平均池化:返回滑动窗口中的平均值
池化类型操作特点适用场景
最大池化取窗口内最大值保留最强特征,平移不变性好最常用
平均池化取窗口内平均值保留背景/整体信息深层网络、全连接层前
池化层和卷积层的相同点
  • 都有窗口大小填充步幅这些超参数

池化层和卷积层的不同点
  • 没有可学习的参数

  • 输出通道数 = 输入通道数

注:卷积层一共有两个可以学习的参数:卷积核(权重)和偏置项

池化层 = 汇聚层

重点LeNet(第一个卷积神经网络)

核心架构(如图)

输入:1×28×28(MNIST灰度图)
    ↓
【卷积层C1】nn.Conv2d(1, 6, kernel_size=5, padding=2)
    6个5×5卷积核,填充2→尺寸不变
    输出:6×28×28
    ↓ Sigmoid激活
【池化层S2】nn.AvgPool2d(kernel_size=2, stride=2)
    2×2窗口,步幅=2→高宽减半
    输出:6×14×14
    ↓
【卷积层C3】nn.Conv2d(6, 16, kernel_size=5)
    16个5×5卷积核,无填充→10×10
    输出:16×10×10
    ↓ Sigmoid激活
【池化层S4】nn.AvgPool2d(kernel_size=2, stride=2)
    输出:16×5×5
    ↓
【展平】Flatten
    16×5×5 = 400 → 展平成一维向量
    ↓
【全连接层C5】nn.Linear(400, 120)
    400 → 120
    ↓ Sigmoid激活
【全连接层F6】nn.Linear(120, 84)
    120 → 84
    ↓ Sigmoid激活
【输出层】nn.Linear(84, 10)
    84 → 10(10个类别)

对该图片的理解:

1)图中从左到右第二个卷积层,写出输入通道数量、输出通道数量、卷积核形状。

输入通道 = 6,输出通道 = 16,卷积核形状 5 * 5

2)LeNet 使用卷积层和汇聚层(池化层)结合的方式,有什么作用?

卷积层负责“提取特征”,池化层负责“压缩信息+增加鲁棒性”——两者结合,让模型既能有效提取图像特征,又能减少计算量、防止过拟合。

先使用卷积层来学习图片空间信息,然后使用全连接层来转换到类别空间(重要)

卷积层的优势:1)参数共享;2)局部连接;3)平移不变性

3)LeNet 末端都是全连接层,分析其作用,为什么全连接层的参数最多?

核心作用:将“空间特征”转换为“类别决策”

为什么参数多?

全连接层是“密集连接”,全连接层的参数量公式

参数量 = 输入维度 × 输出维度 + 输出维度(偏置)

十三、AlexNet

AlexNet为在LeNet上的改进

改进1:激活函数从Sigmoid换成ReLU
激活函数LeNetAlexNet
使用SigmoidReLU
问题梯度消失(深层网络很难训练) 缓解梯度消失
速度慢(需要指数运算)✅ 快(只做比较运算)
改进2:使用最大池化(MaxPooling)而非平均池化
池化方式LeNetAlexNet
使用平均池化最大池化
效果平滑特征✅ 保留最强特征(边缘、纹理更清晰)
改进3:在全连接层后引入Dropout(丢弃法)

"隐藏全连接层后加入了丢弃层" → 防止过拟合

改进4:数据增强

对训练图像进行随机裁剪、水平翻转、颜色变换等

相当于"凭空"增加了训练数据量,防止过拟合

架构对比

总结:

AlexNet是更大更深的LeNet,10倍的参数个数,260倍的计算复杂度

引入了丢弃法;ReLU;最大池化;数据增强

题目:

1、AlexNet 和 LeNet 的核心技术的主要差别是什么,并分析这些差别的作用。

主要差别:

1)激活函数不同:LeNet 使用 Sigmoid / Tanh 激活函数,AlexNet 改用 ReLU

作用:Sigmoid 容易导致梯度消失;而ReLU 可以有效缓解梯度消失这个问题

2)池化方式不同:LeNet 使用平均池化,AlexNet 改用 最大池化

作用:平均池化会平滑特征,可能稀释重要特征;而最大池化会保留窗口内的最强信号,使特征表达更突出,有利于复杂图像的特征提取

3)LeNet 没有使用正则化,AlexNet 在全连接层后引入了 Dropout(丢弃法)

作用:引入 Dropout 可以有效缓解过拟合,从而提高模型的泛化能力

4)AlexNet 有更多卷积层、深度和参数量

作用:更深的神经网络可以学习更复杂的特征层次

5)AlexNet 使用了随机裁剪、水平翻转、颜色变换数据增强技术

作用:提高泛化能力

十四、VGG

VGG的核心思想:更大更深的AlexNet

更多卷积层;将卷积层组合成块

VGG 使用可重复使用的卷积块来构建深度卷积神经网络

不同卷积块个数和超参数可以得到不同复杂度的变种

十五、序列模型(有前后关系的数据模型)

序列数据的特点是"前后有关联"→ 我们需要对"过去→未来"建模 → 两种经典方案:马尔科夫假设(只看最近τ个)和潜变量模型(用隐变量概括整个历史)

序列数据:有顺序

时序模型中,当前数据跟之前观察到的数据相关

自回归模型使用自身的过去数据来预测未来

1、序列建模的统计工具
A、马尔可夫假设

核心思想当前只跟最近τ个数据点相关,更早的数据可以忽略。

p(x_t | x₁,...,x_{t-1}) ≈ p(x_t | x_{t-τ},...,x_{t-1})

通俗理解:预测明天天气,不需要看过去100天的全部数据,看最近3~5天就够了

τ的选择

  • τ太小:信息不够,模型欠拟合

  • τ太大:包含太多无关信息,过拟合且计算量大

B、潜变量模型

核心思想引入一个潜变量 h_t来"概括"所有历史信息

h_t = f(x₁, x₂, ..., x_{t-1})   # 潜变量浓缩了所有过去
x_t = p(x_t | h_t)                # 当前只依赖于潜变量

对比项马尔科夫模型潜变量模型
依赖范围最近τ个观测值全部历史(通过潜变量)
内存需求τ个值1个潜变量向量
计算复杂度低(窗口固定)中(需要更新隐状态)
例子AR模型RNN(循环神经网络)

十六、循环神经网络(RNN)(重点)

专门用来处理序列数据(如文本、时间序列)的神经网络

前学的全连接层和卷积层,每个输入都是独立处理的(图片之间没有先后关系)。但文本、语音等序列数据前后有关联——RNN通过引入隐藏状态(hidden state) 来"记住"之前看到的信息,让网络具有记忆能力

上一章(序列模型)讲了两种处理序列数据的方案——马尔科夫假设(只看最近τ个值)和潜变量模型(用隐变量概括全部历史)。RNN就是潜变量模型的神经网络实现——用循环连接让网络自己学习如何"概括"历史信息

1、潜变量自回归模型
  • 引入潜变量 h_t 来概括所有过去信息

  • h_t = f(x₁, x₂, ..., x_{t-1})

  • x_t = p(x_t | h_t)

2、循环神经网络

核心公式:

隐藏状态更新:h_t = φ(W_hh · h_{t-1} + W_hx · x_{t-1} + b_h)

输出计算:

o_t = φ(W_ho · h_t + b_o)

  • 如果没有 h_{t-1} 这一项,每个时刻的输入都是独立的 → 就是普通的MLP

  • 加上 h_{t-1} 后,网络有了"记忆"——当前时刻的输出依赖于上一个时刻的隐藏状态

参数讲解:

参数形状作用
W_hh隐藏大小 × 隐藏大小从前一时刻的隐藏状态到当前隐藏状态(记忆传递
W_hx隐藏大小 × 输入大小从输入到隐藏状态(输入处理
W_ho输出大小 × 隐藏大小从隐藏状态到输出(输出生成
b_h隐藏大小隐藏层的偏置
b_o输出大小输出层的偏置
网络类型参数共享方式效果
MLP无共享(每层独立参数)参数量随层数增长
CNN空间上共享(同一核在图像所有位置使用)参数量与图像尺寸无关
RNN时间上共享(同一组参数在所有时间步使用)参数量与序列长度无关

RNN的参数共享让它可以处理任意长度的序列

3、RNN 在语言模型中的应用

语言模型的任务:给定前几个词,预测下一个词

4、困惑度(perplexity)

定义:困惑度(Perplexity)是衡量语言模型好坏的指标,是交叉熵损失的指数形式

困惑度 = exp(平均交叉熵损失)

平均交叉熵 = (1/n) × Σ -log p(真实词 | 前面的词)

通俗解释:困惑度 = 模型在预测下一个词时,平均有多少个"候选词"让它犹豫不决

困惑度值含义
1完美模型(每次都100%猜对)
10平均在10个词之间犹豫(不错)
100平均在100个词之间犹豫(较差)
无穷大最差情况(完全随机瞎猜)
5、梯度裁剪
1)为什么需要梯度裁剪?

RNN在时间上展开后,相当于一个很深的网络(深度 = 序列长度)

反向传播时,梯度要沿着时间步逐层回传

这会导致连乘效应(回忆之前学的"数值稳定性"章节):

  • 如果梯度 > 1 → 梯度爆炸

  • 如果梯度 < 1 → 梯度消失

2)什么是梯度裁剪?

核心思想:如果梯度的长度超过阈值θ,就把它"缩回来"。

方法效果问题
调小学习率整体更新步长变小正常梯度也变小了,训练变慢
梯度裁剪只压缩过大的梯度✅ 正常梯度不受影响,异常梯度被限制
问题原因解决方案
梯度爆炸连乘导致梯度指数级增长梯度裁剪
梯度消失连乘导致梯度指数级衰减使用LSTM/GRU
总结:

循环神经网络的输出 取决于:当前输入 & 前一时间的隐变量

运用到语言模型中时,RNN 根据当前词预测下一时刻的词

困惑度 —— 用于衡量语言模型的好坏

公式含义
h_t = φ(W_hh·h_{t-1} + W_hx·x_{t-1} + b_h)隐藏状态更新(记忆传递)
o_t = φ(W_ho·h_t + b_o)输出计算
去掉 W_hh·h_{t-1}退化成MLP(无记忆)
对比项MLPCNNRNN
适用数据表格数据图像序列(文本、语音)
参数共享✅(空间)✅(时间
记忆能力✅(通过h_t)
输入长度固定固定可变
概念定义通俗理解
隐藏状态 h_t压缩了所有历史信息的向量大脑的"短期记忆"
循环连接h_{t-1} → h_t 的连接把记忆传给下一时刻
参数共享所有时间步用同一组W同一套"大脑"处理每个时刻
困惑度exp(平均交叉熵)猜词时平均有几个候选
梯度裁剪限制梯度最大值给梯度加"限速器"

RNN = 带记忆的MLP。它通过隐藏状态 h_t 记住历史信息,用同一组参数在所有时间步共享,从而能处理任意长度的序列。去掉循环连接就退化成普通MLP。语言模型中用困惑度衡量好坏(越低越好),用梯度裁剪防止梯度爆炸。

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐