跳到主要内容

机器学习入门

动手学深度学习 d2l-ai/d2l-zh: 《动手学深度学习》:github 仓库 PyTorch 教程 | 菜鸟教程 Embedding projector - visualization of high-dimensional data

耗费巨量时间翻译!全网最佳学习体验的吴恩达2025机器学习深度学习课程中英双语字幕版本,酣畅淋漓的学习体验!-神经网络/Pytorch/卷积神经网络 代码部分我都用了Pytorch 简介 · PyTorch 实用教程(第二版)


基础概念

深度学习计算概念与数据操作

张量操作

  • Python 数组一样:第一个元素的索引是 0,最后一个元素索引是-1;可以指定范围以包含第一个元素和最后一个之前的元素
  • 张量的维数指轴的个数,向量(一条轴)的维数指长度。axis(轴),dim(维)
  • 对于大张量,要注意其复制,id 可以确定唯一的内存(类似指针)
  • 范数是向量元素平方和的平方根,推广到矩阵,也是所有元素的平方和的平方根。按轴求和,会压缩维度(是否 keep dims)
  • 亚导数:对于左导数和右导数区间都可
  • 梯度指向变化最大的方向,和等高线正交。分子布局法:求导结果的维度以分子为主。关键是要掌握输入输出形状的变化

<img src="https://hanphone.top/gh/HanphoneJan/public_pictures/ml/01-梯度与等高线关系.webp" alt="梯度与等高线关系示意图" style="zoom:45%;" />

广播机制 不同形状的张量(n 维数组)进行运算,会自动扩充形状并补全元素

自动求导/微分 计算函数在一个指定值上的导数,有别于符号求导和数值求导。依赖于计算图。

  • 首先将代码分解成操作子,将计算表示成无环图
  • 系统会构建一个计算图(computational graph),来跟踪计算是哪些数据通过哪些操作组合起来产生输出
  • 自动微分使系统能够随后反向传播梯度,跟踪整个计算图,填充关于每个参数的偏导数

计算图 计算图的核心目标都是支持自动微分

  • 显式构造:要求用户预先完整定义计算图的结构,所有操作和依赖关系在运行前确定,典型的框架是 TensorFlow 1.x 的静态图模式
  • 隐式构造(又称动态图):在运行时动态构建计算图,操作按代码执行顺序即时生成。典型框架是 PyTorchTensorFlow 2.x 的 Eager Execution 模式

计算图可视化 在PyTorch中可以使用torchviz库可视化计算图

# 安装
pip install torchviz
# Graphviz需要单独安装:https://graphviz.org/download/

Numpy & Matplotlib

  • 查询教程使用相应函数即可
  • 数据预处理:csv 文件,pandas 包。处理缺失数据:用插值或者删除。插值:对于数值,可以用平均值填充;非数值的话,有两种方法:一是对每个值(包括缺失)都视作一个特征

机器学习三大范式

监督学习 Supervised Learning

监督学习是机器学习三大核心范式(监督、无监督、强化学习)中应用最广、技术最成熟的一种。其核心思想是"从标注数据中学习规律",就像学生在老师的指导下学习 —— 数据中的"标注"就是"老师给出的答案",模型通过学习"输入数据"与"标注答案"的对应关系。主要用于回归和分类

本质是学习一个从"输入空间"到"输出空间"的映射函数

监督学习的实现依赖三个关键要素:标注数据集(Labeled Dataset),模型,损失函数和优化算法。

无监督学习 Unsupervised Learning

关键在于数据无标注,即没有y_train,让算法自行挖掘,核心价值是"从混乱的数据中提取有用信息"。

聚类 Clustering:根据数据的"相似性",将无标签样本自动划分为多个互不重叠的"簇",使得同一簇内的样本高度相似,不同簇的样本差异显著。

降维 Dimensionality Reduction:在损失少量信息的前提下,将高维数据映射到低维空间,既简化数据结构,又保留数据的核心特征。

强化学习 Reinforcement Learning

强化学习目前在模拟世界、游戏等领域中表现好,但在真实机器人领域还不太行。

  • 关键是激励函数Reward Function —— 通过奖励/惩罚信号引导智能体学习
  • 四个要素:状态(智能体感知的环境信息)、动作(智能体可执行的操作)、奖励(执行动作后的即时反馈)、下一个状态(执行动作后环境的新状态)
  • discount factor折扣因子:衡量未来奖励的当前价值(0<γ<1),γ越小越关注即时奖励,γ越大越重视长期收益

监督学习

损失函数

Loss Function,又称为误差函数,是衡量算法拟合数据好坏程度的重要工具。它用于评价模型的预测值与真实值之间的不一致程度,是一个非负实值函数。

  • L1 Loss:平均绝对值误差(MAE)
  • L2 Loss:均方误差损失函数(MSE),算的是预测值与真实值之间差的平方的平均值
  • 交叉熵损失:用来衡量两个概率的区别,其梯度是真实概率和预测概率的区别

损失函数 vs 代价函数

  • 损失函数是对单个样本而言的
  • 对于包含 n 个样本的数据集,总损失为所有样本损失的平均值,也就是代价/成本函数 CostFunction
  • 在计算时应该将损失函数视作参数w,b的函数

回归模型

线性回归 Linear Regression

线性回归是对 n 维输入的加权(外加偏差),可以看做是单层神经网络,有显示解,使用平方损失函数。拟合问题。

损失函数

$$ J(\mathbf{w},b) = \frac{1}{2m} \sum_{i=0}^{m-1} \left( f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)} \right)^2 $$

优化算法 -- 梯度下降 Gradient Descent

用梯度下降法最小化损失函数,找到函数的全局最小点(这要求损失函数为凸函数,因为梯度下降只能确保找到局部最小点)。

梯度就是对于当前点下降速率最快的方向

$$ w_j = w_j - \alpha \frac{\partial J(w, b)}{\partial w_j} = w_j - \alpha \frac{1}{n} \sum_{i=1}^{n} (\hat{y}i - y_i) x{i,j}, \alpha 为学习率 $$

$$ b = b - \alpha \frac{\partial J(w, b)}{\partial b} = b - \alpha \frac{1}{n} \sum_{i=1}^{n} (\hat{y}_i - y_i) $$

image.webp

学习率:步长的超参数,要适中。太小会导致收敛太慢,太大可能会导致震荡无法收敛。

小批量随机梯度下降:在整个训练集上算梯度太贵,随机采 b 个样本降低成本,是深度学习默认求解算法。

矢量化加速:而不是使用 for 循环

# 无向量化时效率低
f=0
for i in range(n):
f = f + w[i]*x[i]
f=f+b
# numpy中的函数能充分利用硬件的并行能力,运行效率高
np.dot(w,x)+b

多项式回归 Polynomial Regression

使用多项式代替线性公式。若原始特征是 [x1, x2],则生成 [x1, x2, x1², x1x2, x2²](二次多项式)等组合特征。生成的多项式特征可以让线性回归模型(本质是对特征做线性组合)拟合出非线性的关系。

正则化线性回归

$$ J(\mathbf{w},b) = \frac{1}{2m} \sum_{i=0}^{m-1} \left( f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)} \right)^2 + \frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2 $$

$$ w_j = w_j · (1 - α·λ/m) - α·(1/m)·Σ(f_{w,b}(x^{(i)}) - y^{(i)})·x_j^{(i)} $$


分类模型

逻辑回归 Logistic Regression

线性回归不适合分类问题:线性回归的目标是最小化"预测值与真实值的误差"(如均方误差 MSE),输出的是连续数值;而分类问题的目标是最大化"类别判断的准确率",输出的是离散类别。逻辑回归是 Softmax 回归在二分类情况下的特例。

Sigmoid S 形函数

引入 sigmoid 函数,能将任意实数映射到(0,1)区间,且趋势合理。

$$ p=\sigma(z) = \frac{1}{1 + e^{-z}},z=wX+b $$

逻辑回归通过 sigmoid 函数将线性决策边界转化为概率输出,既保留了线性模型的可解释性,又满足了分类任务的需求。

训练目标是找到最优的权重 w 和偏置 b,使模型对训练数据的预测概率尽可能接近真实标签。

交叉熵损失

逻辑回归不使用线性回归中的均方误差(MSE),而是采用交叉熵损失(Cross-Entropy Loss),原因是 MSE 对于 sigmoid 函数来说是非凸的(存在多个局部最小值,难以找到全局最优)。

$$ H(p, q) = \sum_{x} p(x) \log \frac{1}{q(x)} $$

$$ L(f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)}), y^{(i)}) = \begin{cases} -\log\left(f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)})\right) & \text{if } y^{(i)} = 1 \ -\log\left(1 - f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)})\right) & \text{if } y^{(i)} = 0 \end{cases} $$

$$ L(f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)}), y^{(i)}) = -y^{(i)}\log\left(f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)})\right) - (1 - y^{(i)})\log\left(1 - f_{\overrightarrow{w},b}(\overrightarrow{x}^{(i)})\right) $$

# 对损失函数用链式法则求导,X.T是特征矩阵的转置,点乘后得到每个特征的梯度总和,除以样本数得到平均值
dw = (1/n_samples) · X.T · (ŷ - y)
# 偏置可以看作是一个恒为 1 的特征的权重,所有预测误差的平均值
db = (1/n_samples) · Σ(ŷ - y)

可视化决策边界

在数据散点图中绘制类别的分界线,满足 "预测概率 = 0.5" 的点集。

正则化逻辑回归

$$ J(\mathbf{w},b) = \frac{1}{m} \sum_{i=0}^{m-1} \left[ -y^{(i)} \log\left(f_{\mathbf{w},b}\left( \mathbf{x}^{(i)} \right) \right) - \left( 1 - y^{(i)}\right) \log \left( 1 - f_{\mathbf{w},b}\left( \mathbf{x}^{(i)} \right) \right) \right] + \frac{\lambda}{2m} \sum_{j=0}^{n-1} w_j^2 $$

$$ w_j = w_j - α · [ (1/m) · Σ( f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)} ) · x_j^{(i)} + (λ/m) · w_j ] $$

Softmax 回归

多类分类模型。使用 softmax 操作子得到每个类的预测置信度,使用交叉熵来衡量损失。

Softmax 函数的核心是将任意实数输入映射为 0-1 之间的概率值,且所有输出概率之和为 1。

对于一个输入向量 $\boldsymbol{x} \in \mathbb{R}^d$,Softmax 回归首先计算每个类别的得分(logits):

$$ \boldsymbol{z} = \boldsymbol{W}\boldsymbol{x} + \boldsymbol{b} $$

其中 $\boldsymbol{W} \in \mathbb{R}^{k \times d}$ 是权重矩阵,$\boldsymbol{b} \in \mathbb{R}^k$ 是偏置向量,$k$ 是类别数量。

然后在输出层通过 Softmax 函数将得分转换为概率分布:

$$ \hat{y}_i = \text{softmax}(\boldsymbol{z})i = \frac{e^{z_i}}{\sum{j=1}^k e^{z_j}} \quad \text{for } i = 1, 2, \ldots, k $$

其中 $\hat{y}i$ 表示预测为第 $i$ 类的概率,且满足 $\sum{i=1}^k \hat{y}_i = 1$ 和 $0 \leq \hat{y}_i \leq 1$。

使用交叉熵损失函数:

$$ L(\boldsymbol{y}, \hat{\boldsymbol{y}}) = -\sum_{i=1}^k y_i \log(\hat{y}_i) $$

其中 $\boldsymbol{y}$ 是真实标签的独热编码表示($y_i = 1$ 表示样本属于第 $i$ 类,否则为 0)。

softmax 回归是一个线性模型(linear model)

多输出分类 Multi-label Classification


神经网络基础

常见的层

按训练过程分:输入层、输出层、隐藏层

全连接层 Fully Connected Layer / 密集层 Dense Layer

全连接层,也称为密集层,是神经网络中最基础的层结构之一。

在密集层中,每个神经元会与前一层的所有神经元建立连接(即"全连接"),其计算过程为:对前一层的输出进行线性变换(权重矩阵相乘 + 偏置),再通过激活函数生成当前层的输出。

这种层结构的核心特点是参数密集(每个连接对应一个权重参数),能学习输入特征间的复杂关联,是提取高阶特征的基础组件,广泛用于神经网络的各个部分。

import numpy as np

def dense(a_in, w, b, g):
units = w.shape[1]
a_out = np.zeros(units)
for j in range(units):
w_j = w[:, j]
z = np.dot(w_j, a_in) + b[j]
a_out[j] = g(z)
return a_out

def sequential(x):
a1 = dense(x, W1, b1)
a2 = dense(a1, W2, b2)
a3 = dense(a2, W3, b3)
a4 = dense(a3, W4, b4)
f_x = a4
return f_x

卷积层 Convolutional Neural Layer


激活函数 Activate Function

为什么要使用激活函数:多层神经网络直接退化为一个线性函数

  • 二分类问题:sigmoid
  • 预测值可正可负:linear(no activation)
  • 预测值只能是正值或 0:ReLU
  • 隐藏层默认使用 ReLU

使用 ReLU 函数会比使用 Sigmoid 更快一些,因为 Sigmoid 过于平滑导致梯度下降较慢。

image.webp

多层感知机 MLP

MLP由输入层、隐层、输出层组成(其中隐层可以是有多层的),都是全连接层,各层则由神经元构成

感知机是二分类线性分类模型,线性回归和 softmax 也属于感知机。

线性意味着单调假设:任何特征的增大都会导致模型输出的增大。因此增加隐藏层,对每个隐藏单元应用非线性的激活函数,使多层感知机不可能退化成线性模型,每一层都要记录一个权重矩阵和一个偏置向量。多层感知机的训练过程与 softmax 回归的训练过程完全相同。


训练过程

前向传播 Forward Propagation

前向传播指的是从输入数据开始,按照网络层的连接顺序(从输入层 → 隐藏层 → 输出层),依次计算每一层的输出,最终得到网络预测结果的过程。

具体来说,输入数据通过与各层权重矩阵相乘、加上偏置项,再经过激活函数处理后,得到该层的输出;这个输出作为下一层的输入,重复上述计算,直到通过最后一层输出最终结果。

本质是通过网络的参数(权重和偏置)对输入数据进行一系列线性变换和非线性映射,实现从输入空间到输出空间的特征转换。

image.webp

步骤

  1. 输入数据 x。 x 是向量,分量是特征
  2. 计算隐藏层的输入 z。z=x*隐藏层权重矩阵 w
  3. 通过激活函数得到隐藏层的输出 h
  4. 计算输出层的输入 o。 o=h*隐藏层权重矩阵 w
  5. 计算损失 L。 用输出 o 和真实的标签 y 来计算损失函数 L
  6. 计算正则化损失 J(目标函数)= L + s(由 L2 正则化公式给定)

计算图前向传播

反向传播 Backward Propagation

基于链式法则,反向传播更有利于计算导数。

前向:执行计算图,存储中间结果。反向:从相反方向执行图,去除不需要的枝。

反向传播(backward propagation)指的是计算神经网络参数梯度的方法。该方法根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络。该算法存储了计算某些参数梯度时所需的任何中间变量(偏导数)。

推理 Inference/Prediction

训练 Training


深度学习计算

层和块

什么是"层"和"块"?

  • 层(Layer):神经网络的基本单元,比如"全连接层"(Dense)。它能接收输入、生成输出,还有可调的参数(比如权重和偏置)
  • 块(Block):比层更灵活的"组件",可以是单个层、多个层的组合,甚至是整个模型。比如"多层感知机"就是一个块,里面包含多个层

如何用块搭建模型?

  • 顺序块(Sequential Block):最简单的块,按顺序连接多个层或块。比如用 nn.Sequential把"全连接层 + 激活函数 + 全连接层"按顺序串起来
  • 自定义块:如果需要更灵活的逻辑(比如加入循环、条件判断),可以自己定义块

块的优势

  • 模块化:每个块可以独立设计、复用
  • 递归组合:块里可以包含块,层层嵌套,形成复杂网络
  • 自动处理参数和梯度:只要按规则定义块(比如在 PyTorch 中继承 nn.Module),框架会自动处理参数初始化、梯度反向传播等底层细节

参数管理

1.参数访问:找到模型里的"零件"

神经网络训练时需要调整的"参数",主要是各层的权重(weight)和偏置(bias)。

  1. 单层参数:比如一个两层的神经网络,想查看第二层的权重,就像从一个列表里按索引取元素(如 net[1].weight
  2. 所有参数:可以一次性获取整个模型的所有参数,比如用 net.collect_params()(MXNet)或 net.named_parameters()(PyTorch)
  3. 嵌套结构参数:如果模型是"块中套块",参数访问就像层层打开嵌套的盒子

2.参数初始化:给"零件"设定初始值

内置初始化

  • 正态分布:权重从均值 0、标准差 0.01 的正态分布中随机取值,偏置设为 0
  • 均匀分布:权重在某个范围内(如 [-0.07, 0.07])随机初始化
  • Xavier 初始化:根据层的输入输出维度自动调整分布,让梯度更稳定(常见于卷积神经网络)

自定义初始化

  • 让权重以 50% 的概率为 0,25% 的概率在 [5,10],25% 的概率在 [-10,-5]
  • 直接将所有权重设为常数(如 1),偏置设为 0
# 用PyTorch举例
net = nn.Sequential(
nn.Linear(4, 8), # 第一层:输入4维,输出8维
nn.ReLU(),
nn.Linear(8, 1) # 第二层:输入8维,输出1维
)

nn.init.normal_(net[0].weight, mean=0, std=0.1) # 第一层权重正态分布
nn.init.constant_(net[1].weight, 1) # 第二层权重全为1

3.参数绑定:让多个"零件"共用同一套设置

有时多个层需要共享参数(即使用相同的权重和偏置),比如在循环神经网络(RNN)中,同一层的参数在不同时间共享。具体做法:

  • 先定义一个层(如 shared = nn.Dense(8)),然后在多个位置引用它的参数。这样,修改其中一个层的参数,另一个层的参数也会同步变化
  • 好处:减少参数数量,避免重复计算,适合需要参数共享的架构

4.为什么参数管理很重要?

  1. 调试与诊断:访问参数可以查看模型是否正确初始化,训练中参数是否合理更新
  2. 性能影响:好的初始化能让模型更快收敛,避免梯度消失或爆炸
  3. 模型复用:保存和加载参数时,需要正确访问和操作参数

延后初始化

"延后初始化",简单说就是:模型在定义时不用提前知道输入数据的维度,框架会在数据第一次传入时自动确定各层的参数形状

1.什么是"延后初始化"?

平时搭神经网络时,每个层的输入维度(比如全连接层的输入神经元数量)通常需要明确指定。但有时候我们不想提前定死,比如输入数据的维度可能变化(如图像分辨率不固定),或者想让代码更灵活。这时候,深度学习框架会"延后"到数据第一次通过模型时,再动态推断每个层的输入输出维度。

2.具体怎么工作?

  1. 定义模型时不指定输入维度: 比如定义一个两层的全连接网络,第一层只说"输出 256 个神经元",不写输入维度;第二层说"输出 10 个神经元",也不写输入维度(框架用 -1 表示未知)。

    # MXNet示例
    net = nn.Sequential()
    net.add(nn.Dense(256, activation='relu')) # 输入维度未知(-1)
    net.add(nn.Dense(10)) # 输入维度未知(-1,依赖前一层输出)
  2. 首次调用模型前,参数未初始化: 这时候模型知道各层的输出维度(如 256、10),但输入维度未知,所以权重矩阵的形状也不确定,参数没有真正初始化。

  3. 数据第一次传入时,框架推断维度并初始化: 当输入一个具体数据(比如形状为 (2, 20) 的数据,表示 2 个样本,每个 20 维特征),框架会从输入开始逐层推导,确定各层的参数形状,并随机生成权重矩阵。

3.为什么需要延后初始化?

  1. 简化模型定义:不用手动计算每一层的输入维度
  2. 避免维度错误:框架自动推导,减少手动指定维度时可能出现的匹配错误
  3. 灵活修改模型:如果后续想调整输入维度,不需要修改模型定义

自定义层

不带参数的层(无训练参数)

这类层不需要学习参数,只对输入数据做固定操作,如数据预处理、激活函数层等。

例子:定义一个"中心化层",将输入数据减去均值,让数据分布以 0 为中心。

# 用PyTorch举例
class CenteredLayer(nn.Module):
def __init__(self):
super().__init__() # 继承基础层类

def forward(self, X): # 前向传播函数,定义数据如何被处理
return X - X.mean() # 输入减去均值

带参数的层(有训练参数)

这类层包含可学习的参数(如权重和偏置),需要通过训练调整参数。

例子:自定义全连接层(类似 PyTorch 的 nn.Linear),包含权重矩阵和偏置,并用 ReLU 激活函数。

# 用PyTorch举例
class MyLinear(nn.Module):
def __init__(self, in_units, units): # in_units=输入维度,units=输出维度
super().__init__()
# 定义权重参数(随机初始化)
self.weight = nn.Parameter(torch.randn(in_units, units))
# 定义偏置参数(随机初始化)
self.bias = nn.Parameter(torch.randn(units))

def forward(self, X): # 前向传播:矩阵乘法 + 偏置 + ReLU激活
return F.relu(torch.matmul(X, self.weight) + self.bias)

读写文件的作用

  1. 保存和加载"数据块"(张量)

    • 单个张量:比如一个向量 [0,1,2,3],可以用框架提供的函数(如 PyTorch 的 torch.save、TensorFlow 的 np.save)直接存成文件
    • 多个张量:可以把多个张量放在列表或字典里保存(比如 {'x': 向量1, 'y': 向量2}
  2. 保存和加载模型"参数"(训练好的权重和偏置)


模型训练思路

对于大型神经网络用小数据集训练,使用合适的正则化可以使其至少与小模型表现相当。一个神经网络,尤其是大型,通常是低偏差机器,适合拟合复杂函数。

学习曲线

学习曲线是以训练轮次、训练数据大小等等为横轴,模型的性能指标(如损失值、准确率)为纵轴的折线图解读Bias 和 Variance


模型训练技巧

特征缩放 Feature Scaling

使梯度下降更平滑稳定,防止反复

归一化 Mean Normalization

$$ x_i := \dfrac{x_i - \mu_i}{max - min} $$

Z-SCORE Normalization

独热编码

如果一个分类特征有k个取值,则将其拆分为k个分类特征。

模型选择、欠拟合、过拟合

将模型在训练数据上拟合的比在潜在分布中更接近的现象称为过拟合(overfitting),用于对抗过拟合的技术称为正则化(regularization)

高偏差 High Bias, Underfit 欠拟合,高方差 High Variance Overfit过拟合。

image.webp image.webp

解决办法

  1. 收集更多数据
  2. 选择只使用部分特征作为输入
  3. 正则化

数据集划分

  • 当数据量不是很大的时候(万级别以下)的时候将训练集、验证集以及测试集划分为 6:2:2
  • 若是数据很大,可以将训练集、验证集、测试集比例调整为 98:1:1

K 折交叉验证:原始训练数据被分成 K 个不重叠的子集。然后执行 K 次模型训练和验证,每次在 K−1 个子集上进行训练,并在剩余的一个子集上进行验证。

正则化技术

目标是限制参数的大小,一般只限制 w。在每次迭代的作用一般是让 w 乘以一个略小于 1 的$\lambda$(正则化系数)。参数的绝对值越大,平方和越大,正则化项对总损失的贡献就越大。

$\lambda$ 选择方法:选择不同的$\lambda$,训练,在验证集上计算损失然后比较。

权重衰减(L2 正则化)

L2 范数惩罚

暂退法 Dropout

在前向传播过程中,计算每一内部层的同时注入噪声。神经网络过拟合与每一层都依赖于前一层激活值相关,称这种情况为"共适应性",暂退法会破坏共适应性。每个中间活性值 h 以暂退概率p 由随机变量 h′替换,即 p 概率 h'=0,1-p 概率 h'=h/(1-p)。通常在测试时不用暂退法。

参数初始化

梯度消失和梯度爆炸

梯度消失是指在神经网络训练过程中,梯度变得非常小,导致模型的权重更新非常缓慢,甚至几乎不更新。这使得训练过程变得非常缓慢,甚至无法收敛。

原因: 在神经网络中,梯度是通过反向传播计算的。如果网络很深,梯度会从输出层一层一层地传回到输入层。如果每一层的权重或激活函数的导数小于 1,那么多次相乘后,梯度会变得非常小。假设每层的梯度是 0.5,经过 10 层后,梯度会变成 0.5^10=0.000976,非常接近于 0。

梯度爆炸也是梯度变得过大,导致无法收敛。

打破对称性

在神经网络中,如果所有神经元的初始权重完全相同,那么在训练过程中,这些神经元的行为也会完全相同。换句话说,它们会以相同的方式更新权重,最终学到的特征也完全一样。这种情况就叫做"对称性"。

如果权重初始化过大或过小,会导致梯度爆炸或梯度消失。

默认:随机初始化,能够打破对称性。Xavier 初始化:从一个默认的高斯分布中采样权重。暂退法也能打破对称性。

梯度下降优化

Adam算法

为每个参数单独计算专属的学习率,动态调整。对每个参数,算法会持续记录两样东西:一是梯度的"方向趋势"(一阶矩),二是梯度的"波动大小"(二阶矩)。对梯度小且稳定的参数,则增大学习率。对梯度大或波动大的参数,缩小有效学习率。

import torch.optim as optim # 导入PyTorch的优化器模块,包含各种优化算法
optimizer_multi = optim.Adam(
model_multi.parameters(), # 要优化的模型参数
lr=0.001, # 初始学习率
weight_decay=1e-4 # L2正则化系数,防止过拟合
)

模型测试

对于测试集,其损失函数不一定要用训练时的相同。比如可以直接使用未成功预测的比例。

交叉验证集 Cross Validation Set

即验证集,也称Dev Set。主要用于计算泛化误差,方便选择模型,同时防范过拟合和欠拟合。而测试集只用于最终评估。

错误分析

人类手动查看导致错误结果产生的原因,并针对性调整训练

增加数据

  • 增加数据、增加数据类型
  • 数据增强 Data Augmentation:通过扭曲原有数据来增加数据,比如增加背景噪声(尽量使用数据集)
  • 数据合成 Data Synthesis

迁移学习 Transfer Learning

迁移学习是把从一个任务中学到的知识,迁移到另一个相关但不同的任务中,因为不同任务间往往存在共性,比如识别猫和识别狗都需要先学习边缘、纹理等通用图像特征。有两种方式:

  • 特征提取:冻结预训练模型的大部分层(通常是卷积层),只替换最后几层分类器,用新任务数据训练分类器部分。这种方式适用于新任务数据少、与原任务相似度高的场景。
  • 微调(Fine-tuning):不冻结预训练模型,而是用新任务数据对整个模型或部分高层进行小幅训练。这种方式适用于新任务数据较多、与原任务有差异但相关的场景。

处理倾斜数据集

真实类别 \ 预测类别预测为正类(Positive)预测为负类(Negative)
真实为正类(Positive)TP(True Positive)<br><br>(真阳性)FN(False Negative)<br><br>(假阴性)
真实为负类(Negative)FP(False Positive)<br><br>(假阳性)TN(True Negative)<br><br>(真阴性)
  • 精确率 Precision = TP / (TP + FP),核心是降低误判(FP)
  • 召回率 Recall = TP / (TP + FN),核心是不遗漏正类(FN)

精确率和召回率是反向变化的,为达到平衡,使用F1 Score衡量。F1 Score 是精确率(Precision)和召回率(Recall)的调和平均数,调和平均对较小值更敏感,能强制精确率和召回率都达到较高水平,才会给出高 F1 值。

建立基准性能

常用人类表现水平作为基准性能,根据训练集、验证集损失与人类水平比较,确定学习效果。

环境与分布偏移

分布偏移的类型

  • 协变量偏移:指训练集与测试集的输入特征分布有变化,但标签和特征的条件分布不变,即特征变化不影响标签生成规则
  • 标签偏移:是训练集和测试集的标签分布变化,而特征与标签的条件分布不变,即标签出现频率变了,特征和标签的关系不变
  • 概念偏移:即训练集和测试集的标签定义或生成规则有变化,即便输入特征和标签分布看似未变,它们之间的关系也已改变

分布偏移纠正

  1. 加权经验风险最小化:给每个训练样本赋予一个权重,这些权重反映了样本在测试分布中的重要性
  2. 对数几率回归(Logistic Regression):用于协变量偏移纠正
  3. 标签偏移纠正:如果标签的分布发生变化,但特征和标签的关系保持不变

决策树模型

与深度学习算法同级的机器学习算法,看起来混乱复杂但工作得很好。用于分类或回归。一般只用于结构化数据,训练速度比神经网络更快,小型决策树人类可解释。

测量样本纯度

使用熵来衡量,熵越小越纯。

测量样本纯度

  • 如何分裂节点:选择具有最大信息增益的节点分裂方式
  • 如何决定何时停止:已经达到理想状态或者节点深度超过阈值或者分裂的信息增益小于某个阈值
  • 构建决策树在代码上使用递归算法实现

处理连续值特征

尝试不同的阈值,取某个阈值进行分割,比如体重、身高,将其从具体数值变为是否比某个值大或者小。

决策树回归

使用多个决策树

单个决策树对单一数据变化很敏感,办法是使用多个决策树同时进行预测最后投票。

随机森林算法 Random Forest

袋装决策树算法:使用有放回抽样构建随机替换采样的新训练集,然后训练出新的决策树。最后多个决策树集成。

随机森林算法由袋装决策树算法改进而来:在树的每个节点分裂时,不使用所有特征,而是随机选择部分特征(如总特征数的√n 或 1/2)作为候选分裂特征,从这些候选特征中选择最优分裂点。

通过限制每个节点的候选特征,进一步降低树之间的相关性(若所有树都依赖少数强特征,集成效果会下降),增强模型的多样性。

XGBoost (extreme gradient boosting)

boost:可以理解在选择特征时强迫选择了原本做的不那么好的,尝试训练。

梯度提升树算法:基于 boosting 框架,通过迭代方式逐步构建模型,每棵新树都专注于修正前序所有树的预测误差(残差),最终将多棵树的预测结果加权求和得到最终输出。

XGBoost 是梯度提升树的极致优化版本,核心改进包括:

  • 正则化优化:在目标函数中加入树结构复杂度的正则项(如叶子节点数量、叶子节点权重平方和),控制模型过拟合,增强泛化能力
  • 分裂点优化:采用近似算法高效寻找最优分裂点(分位数切割候选特征值),同时支持缺失值自动处理,提升计算效率
  • 并行化加速:在特征粒度上并行计算分裂增益,利用缓存优化数据存储,大幅提升训练速度
  • 梯度优化:使用二阶泰勒展开近似目标函数,相比传统梯度提升(一阶导数)能更精准地优化损失,加速模型收敛
from xgboost import XGBClassifier, XGBRegressor

# 初始化模型
model = XGBClassifier() # 分类
model = XGBRegressor() # 回归

# 训练模型
model.fit(X_train, y_train)

# 预测
y_pred = model.predict(X_test)

无监督学习

聚类 Clustering

聚类是无监督学习最经典的任务之一,目标是根据数据的"相似性",将无标签样本自动划分为多个互不重叠的"簇"(Cluster),使得同一簇内的样本高度相似,不同簇的样本差异显著。

应用场景:电商用户分群、新闻/内容聚类、生物分类

K-均值算法

实质是在最小化一个特定的代价函数:

$$ J(c^{(1)},\dots,c^{(m)},\mu_1,\dots,\mu_K) = \frac{1}{m}\sum_{i=1}^{m} |x^{(i)} - \mu_{c^{(i)}}|^2 $$

步骤

  1. 确定聚类数量 K(根据后续的目标选择,比如需要设计三个尺码的衣服)
  2. 初始化:从样本中随机选择 K 个点作为初始聚类中心(多次随机初始化可减少因初始中心选择不当导致的局部最优问题,最终选择代价函数最小的结果)
  3. 分配样本:计算每个样本到各聚类中心的距离,将样本划分到距离最近的中心所属聚类
  4. 更新中心:计算每个聚类中所有样本的均值,将其作为新的聚类中心
  5. 重复步骤 3 和 4,直到聚类中心位置不再显著变化(或达到预设迭代次数),此时算法收敛

降维 Dimensionality Reduction

现实中的数据往往具有"高维度"特征(如一张 100×100 像素的图片有 10000 个维度,一份用户行为数据可能包含数十个特征),高维度会导致"维度灾难"——数据稀疏、计算成本高、模型易过拟合。

降维的目标是在损失少量信息的前提下,将高维数据映射到低维空间,既简化数据结构,又保留数据的核心特征。

应用场景:高维数据可视化、图像/文本预处理、特征压缩

主成分分析 PCA

Principle component analysis,首先应该做特征归一化到均值 0(即中心化,使每个特征的均值为 0,消除量纲对协方差计算的影响)。

主成分:投影到某一个轴后,数据具有最大方差,则是主成分轴。每一个主成分轴都与其他主成分轴垂直。最大化投影分布等于最小化这些数据点到投影轴的距离

PCA 的核心逻辑是通过对数据协方差矩阵进行特征值分解,将特征值从大到小排序,其对应的特征向量即为按重要性排序的主成分。取前 k 个主成分可将高维数据投影到 k 维空间实现降维,保留数据中最具区分度的信息(方差越大,信息越重要)。

步骤示例: 假设有3个二维样本数据(已做均值归一化),构成矩阵X,数据分布在直线 y=x 附近

  1. 协方差矩阵:

    $$ X^T X = \begin{bmatrix} -1&0&1 \ -1&0&1 \end{bmatrix} \begin{bmatrix} -1&-1 \ 0&0 \ 1&1 \end{bmatrix} = \begin{bmatrix} 2 & 2 \ 2 & 2 \end{bmatrix} $$

    $$ \Sigma = \frac{1}{n-1} X^T X = \begin{bmatrix} 1 & 1 \ 1 & 1 \end{bmatrix} $$

  2. 特征值与主成分: 特征值 $\lambda_1 = 2$,$\lambda_2 = 0$;主成分矩阵为 $u_1 = \begin{bmatrix} 1/\sqrt{2} \ 1/\sqrt{2} \end{bmatrix}$

  3. 压缩到一维:

    $$ z = X \cdot u_1 = \begin{bmatrix} -1 & -1 \ 0 & 0 \ 1 & 1 \end{bmatrix} \begin{bmatrix} 1/\sqrt{2} \ 1/\sqrt{2} \end{bmatrix} = \begin{bmatrix} -\sqrt{2} \ 0 \ \sqrt{2} \end{bmatrix} $$

  4. 重构数据:

    $$ \hat{X} = z \cdot u_1^T = \begin{bmatrix} -\sqrt{2} \ 0 \ \sqrt{2} \end{bmatrix} \begin{bmatrix} 1/\sqrt{2} & 1/\sqrt{2} \end{bmatrix} = \begin{bmatrix} -1 & -1 \ 0 & 0 \ 1 & 1 \end{bmatrix} $$

异常检测 Anomaly Detection

异常检测(也称离群点检测)的目标是从大量正常数据中,自动识别出"不符合常规模式"的样本(异常样本),这些样本通常代表"异常事件",比如金融欺诈检测、工业设备故障预警、医疗异常诊断。

其核心逻辑是:正常样本会形成特定的分布或模式,异常样本会显著偏离该模式

密度检测 Density Estimation

通过估计数据的概率密度分布,将密度低于某一阈值的样本判定为异常。

常见的密度估计方法包括:

  • 参数化方法:如基于高斯正态分布的估计
  • 非参数化方法:如 K 近邻密度估计,通过计算样本周围一定范围内的邻居数量或距离来衡量该样本所在区域的密度,邻居越少、距离越远,密度越低,越可能是异常样本

高斯正态分布 Normal Distribution

对每一个特征都使用高斯分布拟合。因而关键在于调整参数$\varepsilon$,当数据点概率小于$\varepsilon$时,则为异常。

使用评估算法

划分出交叉验证集与测试集,标注异常数据,借此评估已经训练的算法效果。

那为什么不直接用监督学习呢?异常检测算法更适用于正样本(即异常数据)很少的时候,非常适合用于检测全新的异常。

选择特征

选择特征对于异常检测算法相比对于监督学习算法来说更重要。确保特征数据近似高斯分布。

# 快速绘制图像以调整特征数据分布
plt.hist(np.log(x), bins=50, color='b')

一般遇到的错误是 p(x)普遍偏大,通过改变特征来修正。

异常检测算法错误分析

推荐系统 Recommendation System

协同过滤算法 Collaborative Filtering

根据与你给出相似评分的用户的评分,向你推荐物品。将x也作为参数进行学习

协同过滤推荐系统的目标是生成两个向量:针对每个用户,生成一个"参数向量",用以体现该用户的电影偏好;针对每部电影,生成一个尺寸相同的特征向量,用以体现该电影的相关描述信息。两个向量的点积加上偏置项,应能得出用户可能给予该电影的评分估计。

协同过滤算法示例1.webp

数据矩阵定义

  • $Y$:评分矩阵,$Y[i,j]$表示用户$j$对电影$i$的评分(0.5~5分,0表示未评分)
  • $R$:指示矩阵,$R[i,j]=1$表示用户$j$对电影$i$有评分,用于筛选有效训练数据

向量学习逻辑

  • 电影特征向量$x^{movie}$需兼顾所有评价过该电影的用户偏好
  • 用户参数向量$w^{user}$需匹配该用户评价过的所有电影特征

代价函数

$$ \frac{1}{2} \sum_{(i,j): r(i,j)=1} \left( w^{(j)} \cdot x^{(i)} + b^{(j)} - y^{(i,j)} \right)^2 + \frac{\lambda}{2} \sum_{j=1}^{n_u} \sum_{k=1}^{n} \left( w_k^{(j)} \right)^2 + \frac{\lambda}{2} \sum_{i=1}^{n_m} \sum_{k=1}^{n} \left( x_k^{(i)} \right)^2 $$

梯度下降

  • $w_i^{(j)} = w_i^{(j)} - \alpha \frac{\partial}{\partial w_i^{(j)}} J(w, b, x)$
  • $b^{(j)} = b^{(j)} - \alpha \frac{\partial}{\partial b^{(j)}} J(w, b, x)$
  • $x_k^{(i)} = x_k^{(i)} - \alpha \frac{\partial}{\partial x_k^{(i)}} J(w, b, x)$

协同过滤不适用于冷启动问题(新物品、新用户)。

处理二进制标签
  • 单个样本的损失函数(交叉熵损失): $$ L\left(f_{(w,b,x)}(x), y^{(i,j)}\right) = -y^{(i,j)} \log\left(f_{(w,b,x)}(x)\right) - \left(1 - y^{(i,j)}\right) \log\left(1 - f_{(w,b,x)}(x)\right) $$
  • 整体代价函数: $$ J(w, b, x) = \sum_{(i,j): r(i,j)=1} L\left(f_{(w,b,x)}(x), y^{(i,j)}\right) $$
  • 均值归一化:
    • 对物品的数据归一化更有利于处理对全新用户的推荐
    • 对用户的数据归一化更有利于处理对全新物品的推荐
发现相关物品

基于物品特征向量的相似性检索方法:物品$i$的特征 $x^{(i)}$ 很难解释。要找到与之相关的其他物品,找到物品 $k$,其 $x^{(k)}$ 与 $x^{(i)}$ 相似,即(两者)距离最小,距离的计算式为 $\sum_{l=1}^{n} \left( x_l^{(k)} - x_l^{(i)} \right)^2$,也可表示为 $| x^{(k)} - x^{(i)} |^2$。

关联规则挖掘 Association Rule Mining

关联规则挖掘的目标是从大量数据中,发现"不同物品/事件之间的频繁关联关系"。

其核心是找到"频繁项集"(即同时出现频率高的物品组合),再基于频繁项集生成关联规则(如"购买 A → 很可能购买 B")。

应用场景:商品推荐、医疗诊断关联、网页浏览行为分析

基于内容的过滤算法 Content-base Filtering

根据用户和物品的特征来寻找良好匹配,从而向你推荐物品。相比协同过滤,冷启动更好。

大型目录推荐

  • 检索:根据规则给出项目候选列表(比如根据用户最近看过的十部电影给出十部最相似的)
  • 排序:将项目候选列表输入用户相关的神经网络,按预测评分排序

强化学习 Reinforcement Learning

强化学习目前在模拟世界、游戏等领域中表现好,但在真实机器人领域还不太行。

在某些领域使用监督学习效果不好,因为状态很多(如环境变量、自身姿态等组合爆炸),很难穷尽所有状态并给出精确动作示范,也难以定义"绝对正确"的动作(因环境动态变化)。强化学习的关键是激励函数Reward Function——通过奖励/惩罚信号引导智能体学习(类似巴普洛夫的狗通过奖惩形成条件反射)。

四个要素:状态(智能体感知的环境信息,如机器人当前位置)、动作(智能体可执行的操作,如移动、抓取)、奖励(执行动作后的即时反馈,如完成任务得正奖、碰撞得负奖)、下一个状态(执行动作后环境的新状态)

discount factor折扣因子:衡量未来奖励的当前价值(0<γ<1),γ越小越关注即时奖励,γ越大越重视长期收益。

回报 Return

从当前状态开始,所有未来状态奖励的加权和(含折扣因子),即奖励函数$R_s = r_{s+1} + \gamma r_{s+2} + \gamma^2 r_{s+3} + ...$,反映长期累积收益。

决策 Policy

智能体的行为策略函数,通常表示为$\pi(a|s)$,即给定状态s时选择动作a的概率分布(或确定性选择),目标是找到最大化长期回报 $R$ 的最优策略$\pi$

强化学习概念示例.webp

Markov Decision Process(MDP)

在马尔可夫决策过程中,未来只取决于当前状态和动作,与历史无关(无记忆性),可用状态转移概率$P(s'|s,a)$描述从状态s执行动作a后到s'的概率,是强化学习的核心数学模型。

State action value function 动作状态值函数即Q(s,a),表示在状态s下执行动作a后,遵循当前策略能获得的期望回报;最优Q值$Q^*(s,a)$则指遵循最优策略时的期望回报。

贝尔曼方程 Bellman Equation

将当前状态的价值与未来状态的价值关联的递归方程。公式表达为:

$$ Q(s,a) = R(s) + \gamma \max_{a'} Q(s',a') $$

通过分解即时奖励和未来最优价值,解决了价值函数的循环定义问题。

随机环境/处理错误

在随机环境中,动作执行和状态转移存在不确定性(如误步概率),因此计算奖励时需考虑奖励期望(即所有可能结果的概率加权平均),而非单一确定性结果。这要求价值函数(如 Q 值)的更新需基于"动作 - 状态转移的概率分布",通过贝尔曼方程的期望形式(引入状态转移概率 $P(s'|s,a)$)处理随机性,使策略在不确定环境中仍能学习到稳健的长期收益。

连续状态空间应用

连续状态空间中,状态通常是一个高维向量(包含环境的连续特征,如机器人的位置坐标、速度、传感器数据等),无法像离散状态那样枚举。此时需通过函数近似方法(如神经网络)对价值函数或策略进行建模,用参数化模型(如输入状态向量、输出 Q 值或动作概率的网络)拟合状态与价值 / 动作的映射关系。

对于离散型,可以用表格、有限状态机、决策树等建模。

DQN算法

深度Q算法,即使用深度学习来训练Q函数,对Q进行随机初始化在状态 $s$ 下,将 $s$ 输入神经网络,选择能使 $Q(s,a)$ 最大化的动作 $a$。

$\varepsilon$ -贪心策略

($\varepsilon = 0.05$)

  • 以0.95的概率,选择使 $Q(s,a)$ 最大化的动作 $a$。"贪心(Greedy)",即"利用(Exploitation)"
  • 以0.05的概率,随机选择一个动作 $a$。"探索(Exploration)"

初始时 $\varepsilon$ 设得较高(如 1.0),随着训练推进从 1.0 逐渐降低到 0.01 左右,平衡前期探索与后期利用。

小批量 mini-batch

训练时,从经验回放池中随机抽取一小批样本(如 32 或 64 个)进行梯度下降更新,减少样本间的相关性,提升训练稳定性。

小批量梯度下降与普通梯度下降对比图示例.webp

软更新 soft update

为了提升训练稳定性,会设置目标网络(用于计算目标Q值),解耦目标计算与参数更新的强耦合关系。软更新是指以很小的学习率(这里是0.01)将新网络的参数比如权重 $W_{new}$、偏置 $B_{new}$ 缓慢融合到目标网络的权重 $W$、偏置 $B$ 中,公式为 $W = 0.01W_{new} + 0.99W$、 $B = 0.01B_{new} + 0.99B$。

这种方式让目标网络的参数更新更平滑,减少训练过程中的波动,帮助模型更稳定地收敛。

库 gym/gymnasium

Gymnasium 文档 内置上百种实验环境,每个环境就代表着一类强化学习问题,用户通过设计和训练自己的智能体来解决这些强化学习问题。

旧版本库是gym,python版本建议选择3.10

pip install gym  # 基础安装
pip install gym[box2d] # 带box2d扩展安装
pip install gym[all] # 全量安装

安装swig: SWIG(Simplified Wrapper and Interface Generator)是一个开源工具,主要用于连接 C/C++ 代码与其他编程语言。安装swig网址

新版本gymnasium

pip install swig
pip install gymnasium[box2d]