banner
Fight4354

Fight4354

AI,Chem,Science,Study,Share,Hobby,LLM,Life,Sport

Pytorch学习记录

近期在看李沐大神的动手学深度学习课程,在此,记录一些重要知识点,不要让知识到处飘,让知识汇总起来。

1、PyTorch 的 backward 必须是标量#

import torch
x = torch.arange(4.0,requires_grad=True)
y = 2 * torch.dot(x,x)
y.backward()
# 默认情况下,PyTorch会累积梯度,需要清除之前的值
# 对非标量调用 'backward' 需要传入一个 'gradient' 参数,该参数指定微分函数
x.grad.zero_()  # 清除之前x的梯度
y = x * x  # 这里的y不是一个标量,这是一个向量
print(y)
# 等价于y.backward(torch.ones(len(x)))
y.sum().backward() # y.sum()后就讲向量转为标量了,对标量求导
x.grad

🔹 关键点:PyTorch 的 backward 必须是标量

在 PyTorch 中,.backward() 的设计是基于 链式法则,主要针对标量(单个输出值)对输入的梯度。

如果你调用 y.backward(),这里的 y 必须是一个标量,因为:

xy=yx\nabla_x y = \frac{\partial y}{\partial x}
  • xy\nabla_x y 叫做 y 关于 x 的梯度(gradient)

  • yx\frac{\partial y}{\partial x}y 对 x 的偏导数

但是到底它具体是什么,取决于 $y$ 和 $x$ 的维度。


🔸 情况 1:y 是标量,x 是向量

假设:

  • xRnx \in \mathbb{R}^n

  • yRy \in \mathbb{R}

那么:

xy=[yx1yx2yxn]Rn\nabla_x y = \begin{bmatrix} \frac{\partial y}{\partial x_1} \\ \frac{\partial y}{\partial x_2} \\ \vdots \\ \frac{\partial y}{\partial x_n} \end{bmatrix} \in \mathbb{R}^n

也就是:

一个长度为 nn 的向量,表示 y 对每个 x 分量的偏导数。

这正是机器学习里最常用的情况,比如 ** loss 对权重的梯度 **。


🔸 情况 2:y 是向量,x 是向量

假设:

  • xRnx \in \mathbb{R}^n

  • yRmy \in \mathbb{R}^m

那么:

yx=JRm×n\frac{\partial y}{\partial x} = J \in \mathbb{R}^{m \times n}

这个矩阵 JJ 叫做 Jacobian 矩阵,它的 (i,j)(i, j) 元素是:

Jij=yixjJ_{ij} = \frac{\partial y_i}{\partial x_j}

2、Jacobian 矩阵#

Jacobian 矩阵是:

一个向量函数对输入向量的偏导矩阵

假设:

  • 输入:xRnx \in \mathbb{R}^n

  • 输出:y=f(x)Rmy = f(x) \in \mathbb{R}^m

Jacobian:

J(x)=yx=[y1x1y1xnymx1ymxn]Rm×nJ(x) = \frac{\partial y}{\partial x} = \begin{bmatrix} \frac{\partial y_1}{\partial x_1} & \cdots & \frac{\partial y_1}{\partial x_n} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_m}{\partial x_1} & \cdots & \frac{\partial y_m}{\partial x_n} \\ \end{bmatrix} \in \mathbb{R}^{m \times n}

直观上:

  • ii 行:yiy_i 对所有 xjx_j 的偏导。

  • 描述:输入变量小变动对每个输出变量的线性影响。

3、Hessian 矩阵#

Hessian 矩阵是:

一个标量函数对输入向量的二阶偏导矩阵

假设:

  • 输入:xRnx \in \mathbb{R}^n

  • 输出:y=f(x)Ry = f(x) \in \mathbb{R}

Hessian:

H(x)=2yx2=[2yx122yx1x22yx2x12yx22]Rn×nH(x) = \frac{\partial^2 y}{\partial x^2} = \begin{bmatrix} \frac{\partial^2 y}{\partial x_1^2} & \frac{\partial^2 y}{\partial x_1 \partial x_2} & \cdots \\ \frac{\partial^2 y}{\partial x_2 \partial x_1} & \frac{\partial^2 y}{\partial x_2^2} & \cdots \\ \vdots & \vdots & \ddots \\ \end{bmatrix} \in \mathbb{R}^{n \times n}

但是当 yy 是一个 向量,梯度其实是 Jacobian 矩阵,不是单个梯度向量:

Jij=yixjJ_{ij} = \frac{\partial y_i}{\partial x_j}

4、pytorch 中 dtype 和 type 的区别#

先放结论:

dtype 是张量内元素的具体数值类型,type 是张量对象本身的 Python 类型(包含设备信息)。

它们关注的层面完全不一样。


📍 1️⃣ dtype 是什么?

  • 指:张量里每个元素的存储类型。

  • 举例:

    • torch.float32 → 单精度浮点数

    • torch.int64 → 64 位整数

    • torch.bool → 布尔类型

看代码:

x = torch.tensor([1, 2, 3], dtype=torch.float32)
print(x.dtype)  # 输出:torch.float32

它只告诉你「这个张量的元素用什么格式存储」。


📍 2️⃣ type 是什么?

  • 指:张量对象在 PyTorch 中的全名,包括数据类型和设备。

  • 举例:

    • torch.FloatTensor → float32 的 CPU 张量

    • torch.cuda.FloatTensor → float32 的 GPU 张量

    • torch.IntTensor → int32 的 CPU 张量

看代码:

x = torch.tensor([1, 2, 3])
print(x.type())  # 输出:torch.IntTensor(或你的系统默认类型)

它告诉你「这个张量对象在 PyTorch 系统里的完整类型名」。


📍 ⚠ 关键区别

对比项dtypetype
关注点元素的数值类型张量对象的完整 PyTorch 类型(包括设备信息)
举例torch.float32, torch.int64torch.FloatTensor, torch.cuda.FloatTensor
主要用途精度、存储、计算相关区分不同张量类别,调试 / 检查用
改变方式.to(dtype).float().type()(更换整个类型对象)

5、Soft Label vs Hard Label#

通常我们训练分类模型,用的标签是:
hard label(硬标签)
比如,对于 3 分类任务,真实标签:

类别 A → [1, 0, 0]
类别 B → [0, 1, 0]
类别 C → [0, 0, 1]

这种标签完全是 独热编码 (one-hot),只认对与错。


soft label(软标签) 则是:

每个类别对应一个概率,而不是硬性的 0 或 1。

比如:

对于某张图片,soft label → [0.7, 0.2, 0.1]

这表示:

  • 有 70% 概率是类别 A

  • 20% 概率是类别 B

  • 10% 概率是类别 C

换句话说,标签也 “承认模糊性”,不是全或无。


6、softmax 回归和 logistic 回归#

** 📦 共同点 **

本质都是分类模型
✅ 都用线性函数 + 激活(sigmoid 或 softmax)
✅ 都用交叉熵(cross entropy)作为损失函数

但它们用在不同的任务上。


🌟 主要区别


项目Logistic 回归Softmax 回归
任务类型二分类(binary classification)多分类(multi-class classification)
输出层激活函数sigmoid(单值输出 0~1)softmax(向量输出,每个类别概率)
输出维度1 维C 维(C = 类别数)
目标标签0 或 1one-hot 编码,比如 [0,0,1,0]
决策方式输出 > 0.5 判为正类最大概率的类别作为预测结果


📊 Logistic 回归细节

  • 假设你有:

    • 输入特征 xx

    • 权重 ww 和偏置 bb

  • 模型计算:
    y^=σ(wTx+b)\hat{y} = \sigma(w^T x + b)
    其中 sigma\\sigma 是 sigmoid 函数。

输出 haty\\hat{y} 是一个概率值(0 到 1),代表正类的概率。

损失函数:
Binary Cross Entropy=[ylog(y^)+(1y)log(1y^)]\text{Binary Cross Entropy} = -[y \log(\hat{y}) + (1-y)\log(1-\hat{y})]


📊 Softmax 回归细节

  • 假设你有:

    • 输入特征 xx

    • 权重矩阵 WW(shape: num_features × num_classes)

    • 偏置 bb

  • 模型计算:
    y^i=ezijezj\hat{y}_i = \frac{e^{z_i}}{\sum_j e^{z_j}}
    其中 z=WTx+bz = W^T x + b

输出 $\hat {y}$ 是一个长度为 C 的向量,每个元素是对应类别的概率。

损失函数:
Cross Entropy=iyilog(y^i)\text{Cross Entropy} = -\sum_i y_i \log(\hat{y}_i)


** 🧠 为什么 logistic 回归不能直接用在多分类?**

因为 sigmoid 只输出一个值,而多分类需要输出多个类别的概率,且这些概率要满足:

总和为 1,互相排斥。

这就是 softmax 的设计目的。


总结一句话

Logistic 回归 ≈ 2 类 softmax 特例
Softmax 回归 = 多分类推广版 logistic 回归


7、似然和概率#

🌟 什么是似然函数?

简单说:

似然函数(likelihood function)是给定模型参数下,观察到数据的概率。

你可以理解为:
模型假设有某个参数 → 在这个参数下,生成我们现在手上这批数据的 “可能性” 有多大。


📊 和概率的区别?

很多人容易混:
✅ 概率:已知参数,算事件的可能性。
✅ 似然:已知数据,换着看哪个参数下更可能生成这些数据。

虽然数学公式长得一样,但用途反过来了。



🏗️ 数学表达

假设:

  • 数据:x1,x2,...,xnx_1, x_2, ..., x_n

  • 参数:thetatheta

概率

P(xθ)P(x | \theta)

似然函数

L(θx)=P(xθ)L(\theta | x) = P(x | \theta)

区别在于:

  • 概率:θ\theta 固定,看 xx

  • 似然:xx 固定,看 θ\theta



🌟** 举个简单例子 **

假设你有一个硬币,抛了 10 次,结果有 7 次正面。
我们想估计硬币正面的概率 pp


模型假设
抛硬币次数:10
正面概率:pp
事件:7 次正面


似然函数

L(p)=Cp7(1p)3L(p) = C \cdot p^7 (1-p)^3

其中:

  • CC 是组合数(固定值,不影响最大化)。

  • 核心是:

    给定 pp,生成这个数据(7 正 3 反)的概率。


🌟 最大似然估计(MLE)

通常我们用:

找到让似然函数最大的参数。

在这个例子里:

  • 最大化 p7(1p)3p^7 (1-p)^3

  • 最优 p=7/10=0.7p^* = 7 / 10 = 0.7

这就是最大似然估计。



🔥 在机器学习中

机器学习里的很多训练,其实都是:

用最大似然,去拟合参数。

比如:

  • 回归模型 → 高斯分布的最大似然

  • 分类模型 → softmax 下的最大似然

  • 神经网络 → 交叉熵损失,其实就是最大似然推导出来的



总结一句话

似然函数 = 在给定参数下,观察到当前数据的概率(把它看作参数的函数)。

最大化似然,就是找最可能生成数据的参数。

8、感知机#

感知机(Perceptron) 是一种非常基础的 二分类线性模型,可以看作是神经网络的最早形式(单层、无隐藏层)。

它的主要特点和要点是:

基本形式
感知机就是用一个权重向量 w 和偏置 b,去对输入特征向量 x 做线性组合,再经过一个符号函数(sign function),决定输出是 +1 还是 -1。

公式:
  f(x) = sign(w·x + b)

目标
找到一组 w, b,让所有样本能被一个超平面分开(即线性可分)。

训练算法

  • 初始化权重和偏置(通常为零或小值)。

  • 对每个误分类样本,更新权重:
      w ← w + η * y * x
      b ← b + η * y
    这里 η 是学习率,y 是真实标签(+1 或 -1)。

  • 持续迭代,直到所有样本都被正确分类(或达到最大迭代次数)。

局限性(硬伤):

  • 只能处理线性可分的问题。非线性数据(比如 XOR 问题)它完全无能为力。

  • 没有概率输出,只是硬分类。

  • 容易受噪声和异常值影响。

意义和历史地位
虽然现在深度学习早已超越感知机,但感知机是神经网络发展的起点。当年 Minsky 和 Papert 在 1969 年写的《Perceptrons》一书指出它不能解决 XOR 问题,这直接导致 AI 寒冬的到来。直到多层网络(MLP)和反向传播算法出现,才打破了这个局限。

9、多层感知机#

二分类问题公式
image

image

二分类问题公式与多分类问题区别在于 w2w_2的形状为mkm*k。(k 为类别个数)

每一层隐藏层都需要一个激活函数(非线性函数),如果没有激活函数,就相当于一个大的线性函数。
输出层可以不需要激活函数。

多层感知机多分类问题与 Softmax 回归的区别,在于多了隐藏层,其余均相同。

代码

import torch
from torch import nn

# 构建模型,隐藏层包含256个隐藏单元,并使用了ReLU激活函数
net = nn.Sequential(nn.Flatten(),nn.Linear(784,256),nn.ReLU(),nn.Linear(256,10))

代码解释
nn.Sequential() 用来按顺序堆叠一系列子模块(层、激活函数等),自动组织前向传播。换句话说:它就是一个有序容器,把你想要的网络模块按顺序包起来。
nn.Flatten()把输入的多维张量展平成一维向量。
对 MNIST 来说,输入图像 shape 是 [batch_size, 1, 28, 28](灰度图),Flatten 后变成 [batch_size, 784],方便接入全连接层。

10、激活函数#

Sigmoid 函数#

Sigmoid 激活函数 定义为:

σ(x)=11+ex\sigma(x) = \frac{1}{1 + e^{-x}}

输出范围
(0, 1) —— 把任意实数映射到 0 和 1 之间。

图像特征

output

  • S 形曲线(所以叫 sigmoid,sigmoid = S 型)。

  • 中心对称于 (0, 0.5)。

  • xx 很大或很小时,梯度接近 0 —— 梯度消失。

优点

  • 可以解释为概率(尤其适合二分类最后一层)。

  • 光滑、连续、可微。

缺点(致命的)

  • 梯度消失:当 xx 很大或很小时,导数接近 0,反向传播几乎没法更新权重。

  • 输出不以 0 为中心:这会让梯度更新时收敛变慢,因为正负梯度不对称。

  • 容易饱和:输入太大或太小都会被压平。

现在的主流做法

  • 除了二分类最后一层,隐藏层几乎都不用 sigmoid,而是用 ReLU 或更先进的变体。

  • 如果是二分类,最后一层用 sigmoid,损失函数用 binary cross entropy。

Tanh 函数#

tanh(双曲正切)激活函数 定义:

tanh(x)=exexex+ex\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}

输出范围
(-1, 1) —— 把任意实数压缩到 -1 到 1 之间。

图像特征

output

  • S 形曲线(跟 sigmoid 类似,但上下对称)。

  • 中心对称于 (0, 0)(这比 sigmoid 好,输出均值更接近 0,有助于优化收敛)。

  • xx 很大或很小时,也会出现梯度消失。

优点

  • 相比 sigmoid,输出以 0 为中心,对梯度更新更友好。

  • 光滑、连续、可微。

缺点(核心问题)

  • 和 sigmoid 一样,容易饱和 → 梯度消失。

现在的主流做法

  • 在某些需要对称输出的模型(比如 RNN)中,tanh 仍然有用。

  • 但对于深层神经网络的隐藏层,现代主流还是用 ReLU 及其改进版。

ReLU 函数#

ReLU(Rectified Linear Unit)激活函数 定义:

ReLU(x)=max(0,x)\text{ReLU}(x) = \max(0, x)

输出范围
[0,+)[0, +\infty)

图像特征

output

  • x<0x < 0,输出 0。

  • x0x \geq 0,输出 xx
    简单、直接,一条折线。

优点

  • 计算简单,收敛快。相比于 Sigmoid 函数和 Tanh 函数,这俩均需要指数运行,指数运算偏贵。

  • 不容易出现梯度消失(因为正区间梯度恒为 1)。

  • 稀疏激活(很多神经元输出 0,这有助于简化模型)。

缺点

  • 死亡 ReLU 问题:如果某个神经元在训练中被卡进负区间(输出一直为 0),它可能再也更新不了(因为负区间梯度为 0)。

  • 对输入值不对称(只保留正值)。

现代改进版

  • Leaky ReLU:负区间给一个很小的斜率。

  • Parametric ReLU (PReLU):让负区间的斜率可学习。

  • ELU、GELU、Swish:进一步改进。

11、模型复杂度#

image

12、正则化#

在机器学习中,正则化方法就是一种用来防止模型过拟合、提高模型泛化能力的技术集合。 它通过在模型的学习过程中引入一些 “惩罚” 或 “限制”,来约束模型的复杂度,使得模型不会过于 “完美” 地拟合训练数据中的每一个细节(尤其是噪声),从而能够更好地适应新的、未见过的数据。
只在训练中使用,预测时不需要。

正则化是什么?

一句话:正则化通过在损失函数里加入 “约束 / 惩罚”,主动限制模型自由度,逼它学到简洁泛化好的规律,而不是死记硬背训练集里的噪声。

数学上常写成

minθ  L(θ;X,y)  +  λΩ(θ)\min_{\theta}\; \mathcal{L}(\theta;\,X,y)\;+\;\lambda\,\Omega(\theta)
  • L\mathcal{L}:原始经验损失(交叉熵、MSE …)

  • Ω\Omega:正则项(越大表示模型越 “复杂”)

  • λ\lambda:正则强度;λ=0\lambda=0 退化成无正则,λ\lambda\to\infty 则把模型压到极简

核心作用

目标解释
抑制过拟合减小方差,提升对未见样本的鲁棒性
数值稳定避免权重爆炸或矩阵奇异
可解释性稀疏化或结构化约束让特征 / 子网络更易阅读
防共线在高维共线特征下仍能给出唯一解

L1 正则化 (Lasso Regression)#

✅** 1. L1 正则化是什么?**

一句话定义:

L1 正则化就是在损失函数中加入 所有权重绝对值的和 作为惩罚项。

它的目标是:

让某些不重要的权重 自动变成 0,从而让模型 “更简单”。


2. 数学形式(简洁地看)

普通损失函数是:

Loss=模型误差(比如交叉熵)\text{Loss} = \text{模型误差(比如交叉熵)}

加上 L1 正则化后,变成:

Losstotal=原始误差+λwi\text{Loss}_{\text{total}} = \text{原始误差} + \lambda \sum |w_i|

其中:

  • wiw_i 是每个权重参数

  • λ\lambda 是控制惩罚强度的超参数(越大,越 “狠”)


3. L1 的最大特点:让部分权重变为 0(稀疏化)

这就是 L1 和 L2 的关键区别:

所以如果你希望模型自动挑出重要特征、丢掉垃圾特征,L1 正则是理想选择。


4. 举个例子(想象)

你在做一个房价预测任务,有 100 个输入特征,但实际上只有 5 个有用。

如果你用 L1 正则,训练后模型可能只保留这 5 个特征的权重,其余 95 个直接变成 0。
这相当于模型自动做了特征选择


总结一句话

L1 正则化 = 惩罚权重绝对值 → 促使部分参数变 0 → 自动选择重要特征。

L2 正则化(权重衰退)(Ridge Regression)#

一句话定义

L2 正则化 是在损失函数中加入 模型参数平方的惩罚项
用来抑制权重过大,避免过拟合


数学形式

设模型的原始损失函数为:

Loss=L(y^,y)\text{Loss} = L(\hat{y}, y)

加上 L2 正则后,变成:

Losstotal=L(y^,y)+λwi2\text{Loss}_{\text{total}} = L(\hat{y}, y) + \lambda \sum w_i^2

其中:

  • λ\lambda:正则化强度(超参数)一般取10210310410^{-2}、10^{-3}、10^{-4}

  • wi2\sum w_i^2:所有权重的平方和(就是 L2 范数)

image

image


实际效果(直觉)

没有 L2 的情况:

  • 模型可能会疯狂放大某个权重,导致对训练数据拟合得很好,但泛化很差。

有了 L2 正则:

  • 模型 “更保守”,不轻易拉大参数

  • 模型对输入的波动更稳定(泛化能力更强)


在 PyTorch 中怎么用?

L2 正则 = 权重衰退,所以 PyTorch 中你只要在优化器里加:

optimizer = torch.optim.SGD(model.parameters(), lr=0.1, weight_decay=1e-4)

这个 weight_decay 参数其实就是 λ\lambda!默认就是 L2 正则。


在 sklearn 中怎么用?

from sklearn.linear_model import Ridge  # Ridge 就是带 L2 的线性回归
model = Ridge(alpha=1.0)

总结一句话

L2 正则化 = 惩罚权重平方,压缩但保留全部参数,提升模型泛化能力。

Dropout (丢弃法)#

一句话定义

Dropout 是一种随机屏蔽神经元的正则化方法
它让神经网络在训练时更 “健壮”,防止过拟合。


背后的动机

深度神经网络容易过拟合,尤其当:

  • 层数深

  • 训练数据小

  • 参数多,模型复杂

原因是:

模型会学会 “依赖某些神经元组合” 来记住训练数据 → 泛化能力变差。

Dropout 就是打破这种依赖 ——
训练时,随机屏蔽(置 0)一部分神经元,强迫网络不能只靠一小撮神经元合作,而是必须具备冗余能力


怎么操作的?

训练时:

对某一隐层输出向量 h=(h1,,hn)\mathbf h = (h_1,\dots,h_n)
训练期应用:

h~=mph,miBernoulli(p)\tilde{\mathbf h}= \frac{\mathbf m}{p}\odot \mathbf h,\qquad m_i \sim \text{Bernoulli}(p)

保留概率 $p$ 由你设定;通常 0.5–0.9。

  • m\mathbf m:随机掩码,决定是否 “保留” 第 ii 个单元。

  • \odot:逐元素乘。

  • 1/p1/pinverted dropout 常用的重标定因子,使 E[h~i]=hi\mathbb E[\tilde h_i] = h_i,保证训练 / 推断期激活尺度一致。

所以从数学角度看,它是一种 乘性二元噪声注入,并非真的把神经元物理地删掉。

随机掩码(random mask)= 一张用 0/1 取值填充的张量,决定在本轮前向 / 反向传播里哪些单元 “暂时关灯”,哪些 “正常工作”。
在 Dropout(或其它噪声正则)中,它是把乘性噪声注入网络的最小 “开关矩阵”。

元素值

mijBernoulli(p){1(保留)0(丢弃)m_{ij} \sim \text{Bernoulli}(p)\quad \bigl\{ \begin{array}{l} 1\quad(\text{保留})\\ 0\quad(\text{丢弃}) \end{array}

测试时:

不 Drop,全部激活,但输出不缩放。


使用位置:
在全连接层(Dense Layer / Linear Layer)和其后的激活函数(如 ReLU, Sigmoid, Tanh 等)之间或之后。

  • 更常见的是放在激活函数之后: Dense -> Activation -> Dropout
  • 这样做是因为 Dropout 的目的是随机 “关闭” 神经元的输出。激活函数的输出代表了神经元的最终输出信号,对其进行 Dropout 更直接地模拟了神经元的随机失活。
  • 少数情况下也可能放在激活函数之前: Dense -> Dropout -> Activation
    虽然不那么主流,但也有研究和实践表明这样做有时也能取得效果。其逻辑是先对权重计算的线性组合结果进行 Dropout,然后再通过激活函数。

通常应用于一个或多个隐藏层 (Hidden Layers)

  • 对于较深的网络,可以在多个隐藏层之后都使用 Dropout。
    是否在所有隐藏层都使用,以及使用多大的 Dropout 率 (dropout rate/probability),通常是需要通过实验调整的超参数。

一般不建议在输出层 (Output Layer) 使用 Dropout。

  • 输出层负责产生最终的预测结果。如果在输出层使用 Dropout,可能会干扰模型最终的预测输出,特别是对于分类任务,可能会随机丢弃掉某些类别的预测信号,这通常是不希望看到的。

PyTorch 实现:

import torch.nn as nn

net = nn.Sequential(
    nn.Linear(256, 128),
    nn.ReLU(),
    nn.Dropout(p=0.5),   # Dropout 层:训练时屏蔽 50% 神经元
    nn.Linear(128, 10)
)

Dropout 的优势:

优点描述
抑制过拟合强制网络不能依赖某些特征
增强泛化能力每次训练像在训练不同 “子网络”
易用一行代码即可加入

⚠️ 注意事项:

  • Dropout 只在训练阶段起作用,测试阶段必须关闭 Dropout

  • 如果模型已经很小或者数据量足够,Dropout 有时反而会伤害性能(欠拟合)。


总结一句话:

Dropout 是一种 “训练时随机丢点,测试时全开” 的策略,增强模型鲁棒性,防止过拟合。

Early Stopping (早停法)#

一句话定义

Early Stopping 是通过监控验证集表现,在模型开始过拟合前停止训练的一种方法。


🧠 为什么需要 Early Stopping?

我们在训练一个模型时,经常会看到这样的现象:

轮数训练集准确率验证集准确率
160%58%
1095%88% ✅
3099% ✅70% ❌

训练集越来越好,但验证集越来越差。这说明:

模型正在 “死记硬背” 训练数据 → 过拟合开始了

这时候继续训练反而是浪费时间、甚至破坏模型。


✅** Early Stopping 的核心思路 **

很简单:

观察验证集的表现,一旦它开始下降,就立刻停止训练,保留效果最好的模型。

这样:

  • 模型不会过拟合

  • 训练速度更快

  • 一般不需要复杂的正则项

👉 所以 Early Stopping 是一种训练级别的正则方法,而不是结构级别的。


总结一句话

Early Stopping 是最朴素但极有效的正则化策略:当验证集不再变好,立刻停。

13、权重初始化#

为了避免 “信号爆炸或消失”,我们希望

网络里每一层的激活(正向)和梯度(反向)的均值 = 0,方差 = 常数

具体地它把每层的输出 hith_i^t 和梯度 hit\frac{\partial \ell}{\partial h_i^t} 当作随机变量:

方向均值方差
正向E[hit]=0\mathbb E[h_i^t]=0Var[hit]=a\mathrm{Var}[h_i^t]=a
反向E ⁣[hit]=0\mathbb E\!\left[\dfrac{\partial \ell}{\partial h_i^t}\right]=0Var ⁣[hit]=b\mathrm{Var}\!\left[\dfrac{\partial \ell}{\partial h_i^t}\right]=b

其中 a,ba,b 是两个你自己定的常数(一般取 1 或 2),且 对所有层 tt 和所有通道 ii 都一样

推导一层的 “方差守恒” 条件(全连接层为例)

hit=j=1ninWijtxjt1,xjt1 (上层激活)h_i^t=\sum_{j=1}^{n_{\text{in}}} W_{ij}^t\,x_j^{t-1},\qquad x_j^{t-1}~\text{(上层激活)}

常见假设

  1. E[xjt1]=0,  Var[xjt1]=a\mathbb E[x_j^{t-1}]=0,\; \mathrm{Var}[x_j^{t-1}]=a

  2. E[Wijt]=0,  Var[Wijt]=σw2\mathbb E[W_{ij}^t]=0,\; \mathrm{Var}[W_{ij}^t]=\sigma_w^2

  3. xxWW 独立、元素之间近似独立

于是

Var[hit]=ninσw2a\mathrm{Var}[h_i^t] = n_{\text{in}}\,\sigma_w^2\,a

要求 输出方差继续等于 aa

ninσw2a=a    σw2=1nin.n_{\text{in}}\,\sigma_w^2\,a = a \;\Longrightarrow\; \sigma_w^2 = \frac{1}{n_{\text{in}}}.

反向同理(梯度一路乘 WW^\top 传播),要求

σw2=1nout.\sigma_w^2 = \frac{1}{n_{\text{out}}}.

两端都顾及 → 折中方案

σw2=2nin+nout\sigma_w^2 = \frac{2}{n_{\text{in}}+n_{\text{out}}}

这就是 Glorot/Xavier 初始化。随机初始化

Xavier 初始化(Glorot 初始化)#

一句话:它是一种设置网络权重初值的策略,通过让正向激活反向梯度在每一层都保持方差相近,缓解深度网络里的梯度消失 / 爆炸问题。提出者是 Xavier Glorot 与 Yoshua Bengio(2010)。

具体公式

采样分布建议方差实际采样区间 / 标准差
均匀 U (−r, r)σw2=2nin+nout\sigma_w^2 = \dfrac{2}{n_\text{in}+n_\text{out}}r=6nin+noutr = \sqrt{\dfrac{6}{n_\text{in}+n_\text{out}}}
正态 𝒩(0, σ²)同上σ=2nin+nout\sigma = \sqrt{\dfrac{2}{n_\text{in}+n_\text{out}}}
  • n_in: 本层每个神经元接收的输入维度

  • n_out: 本层神经元个数

卷积层
nin=kernelh×kernelw×in_channelsn_\text{in}= \text{kernel}_h \times \text{kernel}_w \times \text{in\_channels}


与 He 初始化的区别

名称建议方差适用激活
Xavier/Glorot2nin+nout\dfrac{2}{n_\text{in}+n_\text{out}}Sigmoid、tanh、soft-sign 等双侧激活
He/Kaiming2nin\dfrac{2}{n_\text{in}}ReLU、Leaky-ReLU、GELU(单侧激活会丢掉 1/2 能量,需更大方差)

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。