Post

机器学习基础

机器学习基础

Machine Learning : “Field of study that gives computers the ability to learn without being explicitly programmed.” (Samuel 1959)

传统编程 = 人写规则 → 程序处理数据 → 输出结果

机器学习 = 人提供数据+结果 → 程序自己发现规则

本质上,就是让机器具备寻找函数的能力

主流机器学习分为监督学习(supervised learning)和无监督学习(unsupervised learning)

【补:推荐系统(recommender systems)和强化学习(reinforcement learning)】

机器怎么寻找一个函数

Step 1:Function with Unknown

选一个有参数的函数族(hypothesis class),例如线性模型:

\[\hat{y} = wx + b\]
  • 已知的$x$叫feature,$w, b$ 是 unknown的(weight, bias),是我们要找的
  • 函数族的选择本身就是一个设计决策(bias-variance tradeoff 的起点)

image-20260409121751741

Step 2:Define Loss from Training Data

为什么需要 Loss? 我们不能直接比较两个函数的好坏,但可以比较它们在已知数据上的”错误程度”。Loss 就是把”函数好不好”量化成一个标量,让优化成为可能。

常见选择:

Loss 函数适用场景直觉
MSE: $\frac{1}{N}\sum(\hat{y}-y)^2$回归惩罚大误差更重
MAE: \(\frac{1}{N}\sum\lvert\hat{y}-y\rvert\)回归(鲁棒)对离群点不敏感
Cross-Entropy分类基于概率的惩罚

关键洞察:Loss 是定义在训练集上的。这是泛化问题的根源——我们优化的目标和真正关心的目标(在未见数据上表现好)不完全一致。

Step 3:Optimization — Gradient Descent

\[w^*, b^* = \arg\min_{w,b} L\]

问题:$L$ 对 $w, b$ 是一个高维曲面,如何找最低点? — 用局部信息(梯度)指导方向。

Gradient Descent 机制:模型怎么学习

问题:怎么找最小的w和b

最naive的想法:把所有可能的 w 和 b 都试一遍,找最小的。

为什么不行?

  • w 是连续实数,有无穷多个取值
  • 多个参数组合爆炸:100个参数 → 无穷∞次尝试
  • 暴力搜索在数学上不可行

先看单参数情形(固定 $b$,只优化 $w$):

Update rule

\[w_{t+1} = w_t - \eta \cdot \frac{\partial L}{\partial w}\bigg|_{w_t}\]

逐项拆解

符号含义角色
$\eta$Learning rate超参数,自己设定
$\frac{\partial L}{\partial w}$斜率(梯度)告诉方向和陡峭程度
负号往下走梯度指向上升最快,取负则下降

为什么步长 = $\eta \times$ 斜率,而不只是固定步长?

  • 斜率大 → 离最优还远,可以走大步
  • 斜率小 → 接近最优,自动小步,防止越过

⚠️ Learning rate 不等于步长。步长 = \(\eta \times \lvert\frac{\partial L}{\partial w}\rvert\),两者共同决定。

扩展到两个参数

固定 $b$ 只是为了讲清楚直觉。实际中 $w$ 和 $b$ 同时更新

\[w \leftarrow w - \eta \cdot \frac{\partial L}{\partial w}\] \[b \leftarrow b - \eta \cdot \frac{\partial L}{\partial b}\]

两个偏导数各自负责自己参数的方向——这就是偏微分!

减号:因为要往下坡走,坡度是正的就减小w,坡度是负的就增大w。

$\eta$ 叫学习率(Learning Rate),控制每步走多远。

Learning Rate 的工程意义

$\eta$ 取值结果
太小收敛极慢,训练成本高
太大在最优附近震荡甚至发散
动态调整Learning Rate Schedule(如 warmup + decay)——实际系统中的标准操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
α 太小:
Loss │*
     │ *
     │  *
     │   *
     │    *          ← 收敛极慢,要走几万步
     └──────── 迭代次数

α 太大:
Loss │*       *
     │  *   *
     │    *          ← 在山谷两侧反复横跳,永远到不了底部
     └──────── 迭代次数

α 合适:
Loss │*
     │ *
     │  **
     │    ***        ← 稳定下降,合理收敛
     └──────── 迭代次数

学习率不是模型从数据中学到的,是手动设置的。 这类参数叫超参数(Hyperparameter)

总结:完整算法
1
2
3
4
5
6
7
8
9
10
11
12
13
输入:训练数据 (x, y),学习率 eta,迭代次数 N

初始化:w = 0, b = 0(或随机值)

重复 N 次:
    1. 计算预测值:  ŷ = w·x + b
    2. 计算误差:    error = ŷ - y
    3. 计算梯度:    grad_w = mean(error · x)
                    grad_b = mean(error)
    4. 更新参数:    w = w - eta · grad_w
                    b = b - eta · grad_b

输出:最终的 w, b

局限性

  • 局部最优:GD 只保证收敛到局部最小值。深度学习的 loss 曲面极其复杂,但实践发现许多局部最优”足够好”。

  • 线性回归:没有这个问题,损失函数是碗形,只有一个最低点

    神经网络:有这个问题,但实践中比理论担心的要好处理

  • 鞍点问题:梯度为 0 但不是最优——SGD 的噪声反而能帮助逃离。

  • 计算代价:每次更新都算全部训练数据的梯度(Batch GD)——太慢,引出 Stochastic GD / Mini-batch GD
1
2
3
4
5
6
Gradient Descent
    ├── SGD(随机梯度下降)— 用单个样本估计梯度
    ├── Mini-batch GD — 实际最常用
    ├── Momentum — 引入"惯性"加速收敛
    ├── Adam — 自适应 learning rate(工程首选)
    └── 二阶方法(Newton)— 用曲率信息,理论更优但计算贵

在 PyTorch/TensorFlow 里调用 optimizer.step(),本质上就是执行上面的 update rule——只是框架帮你自动计算了 $\frac{\partial L}{\partial w}$

为什么引入sigmoid函数?

线性模型 $ y = b + wx_1$ 的本质是: 在所有可能的函数里,我们只在“直线”这个极小的子集里搜索

如果真实的输入输出关系是非线性的,无论怎么调 $w, b$,直线永远拟合不了。这就是 Model Bias(模型偏差):函数族本身太受限,最优解根本不在搜索空间里。

朴素想法:用折线逼近任意曲线

先看这个核心思想:任意一条连续曲线,都可以用足够多的“阶梯函数”之和来无限逼近。Sigmoid 的引入,本质上就是把这个思路变得可微分、可优化。

Sigmoid 解决了两个问题

问题 1:非线性(Model Bias) 线性模型只能表达直线。引入非线性激活函数,模型才能弯曲,才能拟合复杂的输入输出关系。

问题 2:可微分性(让 GD 能工作) 最直觉的非线性函数是”硬阶梯”(Heaviside step function)——值要么 0 要么 1,跳跃处梯度不存在。Sigmoid 是它的光滑近似,处处可微,梯度下降才能工作。

一句话:Sigmoid = “软化版的阶梯函数”,既带来非线性,又保持可微性。

如:$ y = b + wx_1$可以变成:

\[y = b + \sum_i c_i \, \text{sigmoid}(b_i + w_i x_1)\]

在 $c_i \cdot \text{sigmoid}(b_i + w_i x) $ 中:

截屏2026-04-09 14.47.57

通过叠加足够多的 sigmoid,可以组合出任意形状的折线——这就是Universal Approximation Theorem 的直觉:只要隐层神经元足够多,单隐层网络可以逼近任意连续函数

拓展到多个输入,$y = b+\sum_j\ w_j x_j$可以变成:

\[y = b + \sum_i c_i \, \text{sigmoid}(b_i + \sum_jw_{ij} x_j)\]

内层的 $\sum_j w_{ij} x_j $ 是对所有输入特征的加权求和——本质是把多维输入先做线性投影,再过 sigmoid。每个 $i$ 对应一个“神经元”,负责检测输入空间里某个特定的线性组合是否超过阈值。【$i$是自己决定的,也就是说sigmoid函数的个数是自己决定的】

这正是全连接层(fully connected layer)+ 激活函数的完整结构。

我们假设i、j的取值都是1,2,3,那么就有:

\[r_1 = b_1 + w_{11}x_1 + w_{12}x_2 + w_{13}x_3\] \[r_2 = b_2 + w_{21}x_1 + w_{22}x_2 + w_{23}x_3\] \[r_3 = b_3 + w_{31}x_1 + w_{32}x_2 + w_{33}x_3\] \[\begin{bmatrix} r_1 \\ r_2 \\ r_3 \end{bmatrix} = \begin{bmatrix} b_1 \\ b_2 \\ b_3 \end{bmatrix} + \begin{bmatrix} W_{11} & W_{12} & W_{13} \\ W_{21} & W_{22} & W_{23} \\ W_{31} & W_{32} & W_{33} \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \\ x_3 \end{bmatrix}\]

对于$i = 1,2,3$ ,都有:

\[a_i = \text{sigmoid}(r_i) = \frac{1}{1 + e^{-r_i}}\]

这样,就获得了一个sigmoid函数,接着:

\[y = b + c^T a\]

而这和我们上面的式子一模一样

当我们有多个输入的时候,Loss和Optimization没有任何区别:

Loss
\[Loss = \frac{1}{N} \sum_n e_n\]
Optimization
\[\space\space\theta^* = \arg \min_{\theta} L\]

其中$\theta$是包含所有未知数的向量

梯度计算公式:

\[gradient=\begin{bmatrix} \frac{\partial L}{\partial \theta_1} \bigg|_{\theta = \theta^0} \\ \frac{\partial L}{\partial \theta_2} \bigg|_{\theta = \theta^0} \\ \vdots \end{bmatrix}\]

简写为: \(g = \nabla L(\theta^0)\)

Gradient Descent:

\[\begin{bmatrix} \theta_1^{1} \\ \theta_2^{1} \\ \vdots \end{bmatrix} \leftarrow \begin{bmatrix} \theta_1^{0} \\ \theta_2^{0} \\ \vdots \end{bmatrix} - \begin{bmatrix} \eta \frac{\partial L}{\partial \theta_1} \bigg|_{\theta = \theta^0} \\ \eta \frac{\partial L}{\partial \theta_2} \bigg|_{\theta = \theta^0} \\ \vdots \end{bmatrix}\]

简写为: \(\theta^1 \leftarrow \theta^0 - \eta g\)

在实际操作中,可以把N个资料随机分成一组一组的batch,假设每个batch有B个资料,现在我们只拿出B个data拿出来算loss(假设叫$L_1$),根据$L_1$算出Gradinent,用这个Gradient来更新参数;接着再选一个batch算出$L_2$,再更新参数……当我们把所有的batch看过一次,这就叫一个Epoch,每次更新参数就叫一次Update

局限

Sigmoid 并不是现在深度学习的首选,原因是:

  • 梯度消失(Vanishing Gradient):sigmoid 在输入很大或很小时,导数趋近于 0。深层网络里,多层梯度连乘后几乎为 0,前面的层几乎学不到东西。
  • 输出不以 0 为中心(范围是 0~1),会影响训练稳定性。

这就是为什么现代网络主要用 ReLU($\max(0, x) $)及其变体——同样是非线性,但梯度消失问题轻得多。Sigmoid 更多出现在输出层(二分类概率输出)。

ReLU

image-20260409153952394

梯度消失不是“梯度变小”,而是指数级衰减。Sigmoid 导数最大值只有 0.25,链式法则连乘之后,10 层网络前面的层几乎收不到任何信号。这是促使 ReLU 诞生的直接动机。

定义

\[\text{ReLU}(x) = \max(0, x) = \begin{cases} x & x > 0 \\ 0 & x \leq 0 \end{cases}\]

ReLU 的本质:一个二选一的”开关”:

x > 0 → 激活,梯度 = 1,信号完整通过,不衰减;

x ≤ 0 → 沉默,梯度 = 0,该神经元本次不参与学习

把一个sigmoid改写成ReLU(两个ReLU才能合成一个hard sigmoid):

\[y = b + \sum_{2i} c_i \, \text{max} \left( 0, b_i + \sum_j w_{ij} x_j \right)\]

ReLU 解决了什么,引入了什么

解决的问题:

  • 梯度消失:正区间导数恒为 1,链式法则连乘不衰减,深层网络终于可以训练
  • 计算极廉价:只是一个 max 操作,比 sigmoid 的 exp 快得多
  • 稀疏激活:网络里通常约 50% 的神经元输出为 0,形成稀疏表示,有正则化效果

引入的新问题——Dying ReLU:

当某个神经元的输入在训练过程中始终 $\leq 0 $(比如被一个大的负梯度“打死”),该神经元输出恒为 0,梯度也恒为 0,永远无法再更新。这个神经元就“死了”。

一旦死亡,无法自愈——因为梯度为 0,参数不再移动。

为解决负区间难以处理的问题,产生了许多变体:

image-20260409154311608

ReLU 还是非线性的吗?

ReLU 在正区间斜率是 1,是线性的。那它为什么还有用?

因为线性性是分段的。对于不同的输入,不同神经元的激活状态不同,网络有效地选择了不同的线性区域组合。整体看,网络是一个分段线性函数(piecewise linear function),拐点由激活边界决定。

本质上:ReLU 网络 = 对输入空间做分区,每个区域内是线性函数,区域之间非线性拼接。

这也是 ReLU 能保持强表达能力的原因——$n $ 个 ReLU 神经元最多能创造 $O(2^n) $ 个不同的线性区域。

 SigmoidReLU
导数范围(0, 0.25]{0, 1}
梯度消失严重正区间无
计算速度慢(含 exp)极快(max)
死亡风险有(负区间永久沉默)
输出范围(0, 1)[0, +∞)
常用场景输出层(概率)隐藏层(默认)

注意:我们可以令 $a^t$表示第 t 轮的输出,则第 t+1 轮的输入为$a^t$,并计算$a^{t+1}=σ(a^t)$,进行多轮训练,如图:

截屏2026-04-09 16.26.01

这些sigmoid或者ReLU就叫Neuron,整合起来就叫Neural Network;每一层叫一个hidden layer,许多hidden layer组合起来,就叫deep learning

🫠 但是想一想,只需要一层sigmoid或者ReLU,是不是也可以逼近任意的function,那deep learning的意义在哪呢?为什么不用“fat learning”呢?——暂且按下不表!

Overfitting:在训练过的资料上变好,但是在没看过的资料上没有变好

机器学习任务攻略

\[\text{Training data: } \{(x^1, \hat{y}^1), (x^2, \hat{y}^2), \dots, (x^N, \hat{y}^N)\}\] \[\text{Testing data: } \{x^{N+1}, x^{N+2}, \dots, x^{N+M}\}\]

Pipeline

截屏2026-04-09 20.57.40

loss on training data:large

在训练资料上没有学好 — 为什么

截屏2026-04-09 20.01.45

原因1:model bias

模型过于简单,在所有可能的function set里会存在一个让loss相对最小的,但是loss小只是相对的,更好的function根本不在set里!

“函数族本身太受限,最优解根本不在搜索空间里”

解决方案:重新设计model,给model更大的弹性,如给model更多的feature

原因2:optimization issue

由于Gradient Descent找到的只是局部最优解,可能更好的function确实存在于这个set里,但是由于GD本身的原因没找出来

怎么判断是哪个原因呢? — 可以通过比较不同的模型来看现在的模型够不够大

ref:Deep Residual Learning for Image Recognition

截屏2026-04-09 20.14.15

根据图1,就可以判断是optimization的问题,因为56层的network弹性更大,一定可以做到20层network可以做到的事,但结果并非如此,这不是overfitting,也不是model bias!

可以先跑一些比较浅的network,甚至一些不是deep learning的方法,如linear model、support vector machine,这些model一般不会有失败的问题,先有个概念,看看这些model可以得到什么样的loss;再换更深的model,如果深的model明明弹性比较大,但是弹性不能压得更低,那就说明optimization有问题 — 怎么办呢?我们暂且按下不表

loss on training data:small

Test Loss:Large — overfitting

考虑一个极端的例子

\[\text{Training data: } \{(x^1, \hat{y}^1), (x^2, \hat{y}^2), \dots, (x^N, \hat{y}^N)\}\] \[f(x) = \begin{cases} \hat{y}^i & \exists x^i=x \\ \text{random}& \text{otherwise} \end{cases}\]

这个一无是处的function的loss可是0啊!

截屏2026-04-09 20.54.34

为什么更有弹性的model更容易overfitting?

solution:

  1. 增加训练资料,如Data augmentation(数据增强) = 人工“造”更多训练数据,但不改变标签语义:如在图片识别里,将图片左右翻转、局部放大来获得更多的training data
  2. 不要让模型有这么大的弹性,去给模型一些限制 — 需要对研究的问题有较好的理解,一般有如下这些方法:
    • 给比较少的参数/神经元数目
    • 让model共用参数 — 详见CNN(fully-connected,弹性差)讲解部分
    • 用比较少的feature
    • early stopping
    • regularization
    • dropout

怎么选出一个好模型呢?

截屏2026-04-09 21.05.33

N-fold Cross Validation(N折交叉验证): 把数据分成 N 份,每次拿 1 份做测试(validation),其余做训练(train),重复 N 次,最后取平均

监督学习

\[\text{input} \xrightarrow{\text{mapping}} \text{output label}\]

intro:想象你是一个房产中介,脑子里积累了大量经验:

  • 100㎡的房子,卖了200万
  • 150㎡的房子,卖了280万
  • 80㎡的房子,卖了160万

现在来了一套120㎡的房子,你凭经验估价。

这个”凭经验估价”的过程,就是机器学习在做的事。

只不过机器没有”经验”,它只有数据。所以问题变成:

给定历史数据,如何找到一个数学规律,用来预测新数据?

这就是监督学习的本质。

定义

“监督”这个词来自:每条训练数据都有正确答案(标签);监督学习正是通过看到正确的输入X和期望的输出标签Y对来进行学习,算法最终期盼在仅有输入的情况下就输出准确的预测

1
2
3
4
5
6
7
输入 X          →    模型    →    预测 ŷ
(房屋面积120㎡)                  (预测价格?)

                                 ↕ 对比

                                真实答案 y
                             (实际成交价230万)

三个核心要素:

要素含义房价例子
特征 X输入数据面积、地段、房间数
标签 y正确答案实际售价
模型 f找到的规律f(X) ≈ y

目标:找到一个函数 f,使得 f(X) 尽可能接近真实的 y

分类

  • 回归(regression):从无限多个可能的数字中预测一个数字

  • 分类(classification):只有有限个、离散的输出(categories) — 继而可以尝试寻找边界

无监督学习

定义

无监督学习使用的训练数据没有标签,目标是让算法自己从数据中发现隐藏的结构、模式或规律,而不是学习从输入到输出的映射

如:无监督学习可能把结果分配到不同的组或者簇中 — clustering

  • Anomaly detection : find unusual data points
  • Dimensionalty reduction : compress data using fewer numbers
This post is licensed under CC BY 4.0 by the author.