本文是邱锡鹏老师《神经网络与深度学习》第二章的超详细读书笔记。每个概念都用大白话+生活例子+代码来解释,适合零基础同学。


一、什么是机器学习?

1.1 一句话解释

机器学习 = 让计算机从数据中自动找规律,然后用这个规律去预测新数据。

举个例子:

  • 你教小孩认猫:给他看 100 张猫的照片,告诉他"这是猫"。看了 100 张之后,小孩看到一张新的猫照片,也能认出来。
  • 机器学习也是一样:给计算机看 100 张猫的照片(训练数据),让它自己学会"什么是猫"(找到规律),然后给它一张新照片,它也能判断是不是猫。

1.2 用买芒果理解所有核心概念

假设你完全不会挑芒果,想让计算机帮你挑。

第一步:收集数据

你去市场买了 100 个芒果,每个都记录:

颜色大小形状产地好不好吃?
黄色海南好吃 ✅
青色广西不好吃 ❌
红色海南好吃 ✅

第二步:理解术语

术语大白话芒果例子
样本(Sample)一条数据一个芒果
特征(Feature)描述样本的属性颜色、大小、形状、产地
特征向量所有特征放在一起[黄色, 大, 圆, 海南]
标签(Label)你要预测的东西“好吃"或"不好吃”
数据集(Data Set)所有样本的集合100 个芒果的数据
训练集用来教计算机的数据80 个芒果
测试集用来考试的数据20 个芒果

第三步:让计算机学习

计算机从 80 个训练芒果中找到规律:

  • “颜色偏黄 + 形状圆 + 产地海南 → 大概率好吃”
  • “颜色偏青 + 形状长 → 大概率不好吃”

第四步:用规律预测

你去市场看到一个新芒果:黄色、大、圆、海南产。
计算机根据学到的规律告诉你:这个芒果大概率好吃!

这就是机器学习的全部过程。


二、机器学习的三要素

机器学习 = 模型 + 学习准则 + 优化算法

用大白话说:

  • 模型 = 你选择用什么"公式"来算(比如用一条直线来分,还是用一个圆来分)
  • 学习准则 = 你用什么"标准"来判断模型好不好(比如"算错了几次")
  • 优化算法 = 你用什么"方法"来让模型变好(比如"每次都往错少的方向调")

2.1 模型:选择什么样的函数

模型就是一个函数,输入是特征,输出是预测结果。

# 线性模型:最简单,就是一条直线
# f(x) = w * x + b
# w 是权重(斜率),b 是偏置(截距)

# 举个例子:预测芒果好不好吃
# 特征 x = [颜色值, 大小值, 形状值]
# f(x) = w1*颜色 + w2*大小 + w3*形状 + b

# 如果算出来的 f(x) > 0 → 好吃
# 如果算出来的 f(x) < 0 → 不好吃

模型分为两种:

  • 线性模型:用直线/平面来分(简单,但能力有限)
  • 非线性模型:用曲线/曲面来分(复杂,能力更强,神经网络就是非线性模型)

2.2 学习准则:怎么判断模型好不好

你有了一个模型,怎么知道它好不好?需要一个评分标准

损失函数:算"错了多少"

损失函数就是衡量"模型预测值"和"真实值"之间差多少的函数。差得越多,损失越大,说明模型越差。

(1)0-1 损失:最简单,对就 0 分,错就 1 分
def zero_one_loss(y_true, y_pred):
    if y_true == y_pred:
        return 0  # 预测对了,损失为 0
    else:
        return 1  # 预测错了,损失为 1

问题: 不连续,没法求导,没法用梯度下降优化。

(2)平方损失:算"差了多少的平方"
def quadratic_loss(y_true, y_pred):
    return 0.5 * (y_true - y_pred) ** 2

适用于: 回归问题(预测连续值,比如房价、温度)

例子:

  • 真实房价 = 100 万,模型预测 = 90 万
  • 损失 = 0.5 × (100 - 90)² = 50
  • 预测越准,损失越小
(3)交叉熵损失:分类问题最常用
import numpy as np

def cross_entropy_loss(y_true_one_hot, y_pred_prob):
    """
    y_true_one_hot: 真实标签的 one-hot 编码,比如 [0, 0, 1] 表示第 3 类
    y_pred_prob: 模型预测的概率,比如 [0.1, 0.2, 0.7]
    """
    return -np.sum(y_true_one_hot * np.log(y_pred_prob))

例子:

  • 一个三分类问题,真实标签是第 3 类 → y_true = [0, 0, 1]
  • 模型预测概率 → y_pred = [0.1, 0.2, 0.7]
  • 损失 = -(0×log(0.1) + 0×log(0.2) + 1×log(0.7)) = -log(0.7) ≈ 0.357

如果模型预测得很准(概率接近 1),损失就很小;如果预测得很差(概率接近 0),损失就很大。

(4)Hinge 损失:SVM 用的
def hinge_loss(y_true, y_pred):
    # y_true 是 +1 或 -1
    return max(0, 1 - y_true * y_pred)

适用于: 二分类问题,SVM(支持向量机)

经验风险:在训练集上"平均错了多少"

有了损失函数,就可以算经验风险——在所有训练样本上的平均损失:

def empirical_risk(model, X_train, y_train, loss_fn):
    total_loss = 0
    for x, y in zip(X_train, y_train):
        y_pred = model.predict(x)
        total_loss += loss_fn(y, y_pred)
    return total_loss / len(X_train)

经验风险最小化(ERM): 找到一组参数,让经验风险最小。

# 就是找到最好的模型参数
best_params = argmin(empirical_risk)
过拟合:在训练集上表现太好,反而不好

过拟合就像一个学生把所有练习题都背下来了,练习题全对,但考试题一换就不会了。

训练集表现:99% 正确 → 看起来很好
测试集表现:60% 正确 → 实际很差
→ 这就是过拟合

为什么会过拟合?

  • 训练数据太少
  • 模型太复杂(参数太多)
  • 数据有噪声

怎么解决?正则化!

结构风险最小化:加一个"惩罚项"

在经验风险的基础上,加一个正则化项,惩罚模型太复杂:

# 结构风险 = 经验风险 + 正则化项
def structural_risk(model, X_train, y_train, loss_fn, lambda_reg):
    emp_risk = empirical_risk(model, X_train, y_train, loss_fn)
    reg_term = lambda_reg * np.sum(model.params ** 2)  # L2 正则化
    return emp_risk + reg_term

通俗理解:

  • 经验风险说:“你把训练题做对就行”
  • 正则化说:“但你不能太复杂,公式不能太长”
  • 两者平衡 → 模型既能在训练集上表现好,又不会太复杂,能泛化到新数据

L₁ 正则化 vs L₂ 正则化:

L₁ 正则化L₂ 正则化
公式λ Σ|wᵢ|λ Σ wᵢ²
效果使参数稀疏(很多变成 0)使参数变小(但不为 0)
用途特征选择防止过拟合

2.3 优化算法:怎么找到最好的参数

有了模型和学习准则,接下来就是怎么找到最好的参数

梯度下降法:像下山一样找最低点

想象你在一个山上,想走到山谷最低点(损失最小的地方)。

1. 看看脚下哪个方向最陡(计算梯度)
2. 往最陡的方向走一步(更新参数)
3. 重复,直到走到最低点
def gradient_descent(params, gradient_fn, learning_rate, num_iterations):
    for i in range(num_iterations):
        gradient = gradient_fn(params)  # 计算梯度(哪个方向最陡)
        params = params - learning_rate * gradient  # 往梯度方向走一步
    return params

学习率(Learning Rate): 每一步走多远。

  • 学习率太大 → 走过头,来回震荡
  • 学习率太小 → 走得太慢,训练时间太长
三种梯度下降法
# 批量梯度下降(BGD):每次用所有数据算梯度
# → 稳定,但慢
for epoch in range(num_epochs):
    gradient = compute_gradient(all_data)  # 用全部数据
    params -= learning_rate * gradient

# 随机梯度下降(SGD):每次只用 1 个数据算梯度
# → 快,但不稳定
for epoch in range(num_epochs):
    for x, y in shuffle(data):  # 随机打乱
        gradient = compute_gradient(x, y)  # 只用 1 个数据
        params -= learning_rate * gradient

# 小批量梯度下降(Mini-Batch):每次用一小批数据算梯度
# → 兼顾速度和稳定(实际最常用)
for epoch in range(num_epochs):
    for batch in get_batches(data, batch_size=32):  # 每次 32 个
        gradient = compute_gradient(batch)
        params -= learning_rate * gradient
提前停止:防止训练过度
每个 epoch 结束后,在验证集上测试一下:
- 验证集表现还在变好 → 继续训练
- 验证集表现不再变好(甚至变差)→ 停止训练

为什么要这样做?

  • 训练集表现一直变好,不代表模型真的在变好
  • 可能只是在"背答案"(过拟合)
  • 验证集表现才是真正的"考试成绩"
参数 vs 超参数
参数超参数
是什么模型内部的参数,通过学习得到模型外部的参数,人工设定
怎么确定优化算法自动学习人工调参或搜索
例子权重 w、偏置 b学习率、正则化系数 λ、网络层数、batch size

三、线性回归:机器学习的"Hello World"

3.1 什么是线性回归?

线性回归 = 用一条直线来拟合数据。

比如:根据房屋面积预测房价。

面积(平方米)  房价(万元)
50              150
80              240
100             300
120             360

画出来就是一些点,线性回归就是找到一条直线,尽可能穿过这些点。

房价 = w × 面积 + b

比如:房价 = 3 × 面积 + 0
面积 50 → 预测 150 万
面积 100 → 预测 300 万

3.2 怎么找到最好的直线?

目标: 找到 w 和 b,让预测值和真实值的差距最小。

损失函数(均方误差):

def mse_loss(y_true, y_pred):
    return np.mean((y_true - y_pred) ** 2)

最小二乘法: 令损失函数的导数为 0,直接算出最优解。

# 矩阵形式的闭式解
# w* = (X Xᵀ)⁻¹ X y

import numpy as np

# X 是特征矩阵,y 是标签向量
X = np.array([[50, 1], [80, 1], [100, 1], [120, 1]])  # 加了偏置列
y = np.array([150, 240, 300, 360])

# 计算最优参数
w = np.linalg.inv(X.T @ X) @ X.T @ y
print(f"权重: {w}")  # [3.0, 0.0] → 房价 = 3 × 面积

3.3 四种参数估计方法

线性回归有四种方式来求参数,它们之间有深刻联系:

(1)经验风险最小化 → 最小二乘法
思路:让训练集上的平均损失最小
公式:w* = (XXᵀ)⁻¹Xy
(2)结构风险最小化 → 岭回归
思路:在最小二乘法基础上加正则化
公式:w* = (XXᵀ + λI)⁻¹Xy

为什么要加正则化?

  • 当特征之间有相关性时,XXᵀ 可能不可逆
  • 加一个 λI 使其一定可逆
  • 还能防止过拟合
(3)最大似然估计(MLE)
思路:找到一组参数,使得观测到的数据出现的概率最大

通俗理解:

  • 假设数据是由某个分布生成的(比如高斯分布)
  • 找到一组参数,使得"这组数据出现的可能性"最大
  • 对于线性回归 + 高斯噪声,MLE 的解 = 最小二乘法的解
(4)最大后验估计(MAP)
思路:在 MLE 基础上加先验知识
公式:w* = (XXᵀ + (σ²/τ²)I)⁻¹Xy

通俗理解:

  • MLE 只看数据,不加任何先验
  • MAP 在看数据之前,先假设"参数应该长什么样"(先验分布)
  • MAP 的解 = 岭回归的解
四种方法的关系图
┌─────────────────────────────────────────────────────────┐
│                                                         │
│   经验风险最小化(ERM)                                    │
│        ↓                                                │
│   最小二乘法(LSM)←──────────→ 最大似然估计(MLE)          │
│        │                         │                      │
│        │ 加正则化                  │ 加先验                │
│        ↓                         ↓                      │
│   岭回归(Ridge)  ←──────────→ 最大后验估计(MAP)          │
│                                                         │
│   频率学派:参数是固定常数    贝叶斯学派:参数是随机变量       │
│                                                         │
└─────────────────────────────────────────────────────────┘

四、偏差-方差分解:为什么模型会出错?

4.1 用打靶理解偏差和方差

想象你在打靶:

情况 1:子弹都打在靶心附近,很集中
→ 偏差低(瞄得准),方差低(很稳定)→ ✅ 最好

情况 2:子弹都打在同一个位置,但偏离靶心
→ 偏差高(瞄不准),方差低(很稳定)→ ⚠️ 欠拟合

情况 3:子弹分散在靶心周围,但平均来看在靶心
→ 偏差低(瞄得准),方差高(不稳定)→ ⚠️ 过拟合

情况 4:子弹分散,而且偏离靶心
→ 偏差高(瞄不准),方差高(不稳定)→ ❌ 最差

4.2 数学定义

期望错误 = 偏差² + 方差 + 噪声

其中:
- 偏差² = (平均预测 - 最优预测)²  → 模型的"系统性误差"
- 方差 = 不同训练集上预测的差异 → 模型的"不稳定性"
- 噪声 = 数据本身的噪声 → 无法消除

4.3 偏差-方差与模型复杂度

模型简单(比如直线):
  → 偏差高(拟合能力不够)→ 欠拟合
  → 方差低(不同训练集得到的直线差不多)

模型复杂(比如高次多项式):
  → 偏差低(拟合能力强)
  → 方差高(不同训练集得到的曲线差别很大)→ 过拟合

这就是"偏差-方差权衡":

  • 想要偏差低 → 模型要复杂
  • 想要方差低 → 模型要简单
  • 两者矛盾,需要找平衡点

4.4 实际操作指南

训练集错误率高 → 偏差高 → 欠拟合
  解决方案:
  - 增加特征(让模型看到更多信息)
  - 提高模型复杂度(用更复杂的模型)
  - 减小正则化系数

训练集错误率低,但验证集错误率高 → 方差高 → 过拟合
  解决方案:
  - 增加训练数据(让模型看到更多样本)
  - 降低模型复杂度(用更简单的模型)
  - 加大正则化系数
  - 使用 Dropout(深度学习中常用)

五、机器学习的三大类型

5.1 监督学习:有老师教

特点: 每个训练样本都有标签(正确答案)。

# 监督学习的训练数据
training_data = [
    (特征1, 标签1),  # 比如:(猫的图片, "猫")
    (特征2, 标签2),  # 比如:(狗的图片, "狗")
    ...
]

常见任务:

任务标签类型例子
分类离散类别垃圾邮件检测(是/否)、手写数字识别(0-9)
回归连续值房价预测、温度预测
结构化学习结构化对象机器翻译(输入句子→输出句子)

5.2 无监督学习:没有老师,自己学

特点: 训练数据没有标签,让计算机自己发现数据中的规律。

# 无监督学习的训练数据
training_data = [
    特征1,  # 没有标签!
    特征2,
    ...
]

常见任务:

任务目标例子
聚类把相似的数据分到一组用户分群(把用户分成不同类型)
降维减少特征数量,保留主要信息PCA 把 100 维数据降到 2 维可视化
密度估计估计数据的概率分布异常检测

5.3 强化学习:在试错中学习

特点: 智能体通过和环境交互来学习,根据奖励调整策略。

智能体 → 做一个动作 → 环境给一个奖励 → 智能体调整策略 → 重复

例子:

  • 训练 AI 下围棋:赢了给正奖励,输了给负奖励
  • 训练机器人走路:走得好给奖励,摔倒给惩罚

5.4 三种学习的对比

监督学习无监督学习强化学习
训练数据有标签无标签环境交互
学习方式从"答案"中学从"规律"中发现从"试错"中学习
典型应用图像分类、语音识别聚类、降维游戏 AI、机器人
数据成本高(需要人工标注)低(不需要标注)中等

六、数据的特征表示

6.1 为什么要关心特征?

特征的好坏直接决定了模型的上限。 再好的模型,如果特征不行,也做不出好结果。

传统机器学习中,80% 的时间花在特征工程上

6.2 图像特征

最简单:把图片的所有像素值拉成一个向量。

# 一张 28×28 的灰度图片
# 像素值范围:0-255
# 特征向量:28×28 = 784 维

import numpy as np
image = np.random.randint(0, 256, (28, 28))
feature_vector = image.flatten()  # 拉成 784 维向量

问题: 原始像素特征维度高、冗余大、对光照/旋转敏感。

改进: 加入直方图、边缘特征、纹理特征等。

6.3 文本特征——词袋模型

词袋模型(Bag-of-Words, BoW): 把文本看作词的集合,不考虑词序。

# 两个文本
text1 = "我 喜欢 读书"
text2 = "我 讨厌 读书"

# 词表:[我, 喜欢, 讨厌, 读书]
# 词袋表示:
x1 = [1, 1, 0, 1]  # "我"出现1次,"喜欢"出现1次,"讨厌"出现0次,"读书"出现1次
x2 = [1, 0, 1, 1]  # "我"出现1次,"喜欢"出现0次,"讨厌"出现1次,"读书"出现1次

问题: 丢失了词序信息。"我喜欢读书"和"读书喜欢我"的表示完全一样。

改进:N-gram 特征

# 二元特征(2-gram):每两个连续词组成一个特征
text1 = "我 喜欢 读书"
# 2-gram: ["我 喜欢", "喜欢 读书"]

text2 = "我 讨厌 读书"  
# 2-gram: ["我 讨厌", "讨厌 读书"]

# 现在 "我 喜欢" 和 "我 讨厌" 是不同的特征了!

6.4 传统特征学习方法

方法类型做什么例子
特征选择监督/无监督从原始特征中选有用的子集信息增益、L₁ 正则化
特征抽取(降维)无监督把高维特征映射到低维PCA、自编码器
特征抽取监督根据标签抽取有用的特征线性判别分析(LDA)

6.5 深度学习:自动学特征

传统方法:人工设计特征 → 训练模型(两步分开)

深度学习:自动学习特征 + 训练模型(端到端)

传统方法:
图片 → 人工提取边缘/纹理/颜色 → 分类器 → 结果
         ↑
    需要专家知识,费时费力

深度学习:
图片 → 神经网络自动学习特征 → 结果
         ↑
    自动学习,端到端

七、评价指标:怎么知道模型好不好?

7.1 准确率和错误率

# 最简单的指标
accuracy = 预测正确的样本数 / 总样本数
error_rate = 1 - accuracy

# 例子:100 个样本,85 个预测正确
accuracy = 85 / 100 = 85%
error_rate = 1 - 85% = 15%

问题: 当数据不均衡时,准确率会骗人。

例子:1000 个邮件,990 个正常,10 个垃圾邮件
如果模型把所有邮件都预测为"正常":
accuracy = 990 / 1000 = 99%!
但实际上 10 个垃圾邮件全都没检测出来!

7.2 混淆矩阵

混淆矩阵帮你更细致地看模型的表现:

                    预测为正    预测为负
实际为正(真正有病)    TP         FN
实际为负(真的没病)    FP         TN
术语全称含义
TPTrue Positive真正例:实际为正,预测也为正 ✅
FNFalse Negative假负例:实际为正,但预测为负 ❌(漏检)
FPFalse Positive假正例:实际为负,但预测为正 ❌(误报)
TNTrue Negative真负例:实际为负,预测也为负 ✅

7.3 精确率和召回率

精确率(Precision)= TP / (TP + FP)
→ "预测为正的里面,有多少是真的正?"
→ 关注"误报":预测为垃圾邮件的里面,有多少真的是垃圾邮件?

召回率(Recall)= TP / (TP + FN)
→ "真正为正的里面,有多少被找到了?"
→ 关注"漏检":所有垃圾邮件中,有多少被检测出来了?

精确率和召回率的矛盾:

想精确率高 → 宁可漏检,也不要误报 → 召回率可能低
想召回高 → 宁可误报,也不要漏检 → 精确率可能低

7.4 F1 值:精确率和召回率的平衡

F1 = 2 × Precision × Recall / (Precision + Recall)

F1 是精确率和召回率的调和平均,当精确率和召回率都高时,F1 才高。

7.5 宏平均 vs 微平均

# 宏平均(Macro Average):先算每一类的指标,再求平均
macro_precision = (precision_类1 + precision_类2 + precision_类3) / 3

# 微平均(Micro Average):先汇总所有类的 TP/FP/FN,再算指标
micro_precision = total_TP / (total_TP + total_FP)

什么时候用哪个?

  • 数据均衡 → 两者差不多
  • 数据不均衡 → 宏平均更关注小类别,更合理

7.6 交叉验证

K 折交叉验证: 把数据分成 K 份,轮流用 K-1 份训练、1 份验证。

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
scores = cross_val_score(model, X, y, cv=5)  # 5 折交叉验证
print(f"平均准确率: {scores.mean():.2f} ± {scores.std():.2f}")

为什么要用交叉验证?

  • 如果只分一次训练集/测试集,结果可能受随机性影响
  • 交叉验证做了 K 次实验,结果更可靠

八、重要的理论定理

8.1 PAC 学习理论

PAC(Probably Approximately Correct)= 可能近似正确

核心思想: 我们不要求模型 100% 正确,只要求它"大概率"(Probably)“近似正确”(Approximately Correct)。

关键结论:

需要的样本数量 ≥ (1/2ε²)(log|H| + log(2/δ))

其中:
- ε:允许的误差(越小需要越多样本)
- δ:允许的失败概率(越小需要越多样本)
- |H|:假设空间大小(模型越复杂,需要越多样本)

通俗理解:

  • 想要模型越准确(ε 小)→ 需要更多训练数据
  • 想要模型越可靠(δ 小)→ 需要更多训练数据
  • 模型越复杂(|H| 大)→ 需要更多训练数据

8.2 没有免费午餐定理(NFL)

不存在一种机器学习算法适合于任何领域或任务。

通俗理解: 没有"万能"的算法。如果一个算法在某些问题上好,那它一定在另一些问题上差。

启示: 不要迷信某个算法,要"具体问题具体分析"。

8.3 奥卡姆剃刀原理

如无必要,勿增实体。

通俗理解: 如果有两个模型表现差不多,选简单的那个。

为什么?

  • 简单的模型泛化能力更好
  • 简单的模型更不容易过拟合
  • 简单的模型更容易理解和解释

8.4 丑小鸭定理

丑小鸭与白天鹅之间的区别和两只白天鹅之间的区别一样大。

通俗理解: 世界上不存在"客观"的相似性标准。什么是"相似",完全取决于你用什么特征来描述。

启示: 特征的选择非常重要!不同的特征会导致完全不同的"相似性"判断。

8.5 归纳偏置

归纳偏置 = 学习算法自带的"偏见"或"假设"。

算法归纳偏置
最近邻分类器假设"相似的样本属于同一类"
朴素贝叶斯假设"每个特征之间互相独立"
决策树假设"可以用特征的组合来分类"
线性模型假设"数据可以用一条直线分开"

每个算法都有归纳偏置,没有"无偏见"的算法。 选择算法就是选择一种"偏见"。


九、总结

全章脉络

机器学习 = 从数据中找规律

三要素:
├── 模型:用什么公式算(线性/非线性)
├── 学习准则:用什么标准评判(损失函数 + 风险最小化)
└── 优化算法:用什么方法找最优参数(梯度下降)

核心问题:
├── 过拟合:训练集好,测试集差
│   └── 解决:正则化、提前停止、增加数据
├── 偏差-方差权衡:简单模型偏差高,复杂模型方差高
│   └── 解决:找平衡点
└── 特征工程:好的特征 > 好的模型
    └── 解决:深度学习自动学特征

学习类型:
├── 监督学习:有标签(分类、回归)
├── 无监督学习:无标签(聚类、降维)
└── 强化学习:试错中学习(游戏 AI)

评价指标:
├── 准确率:整体对了多少
├── 精确率:预测为正的里面有多少是对的
├── 召回率:真正为正的有多少被找到了
└── F1:精确率和召回率的平衡

理论基础:
├── PAC 学习:需要多少数据才够
├── NFL:没有万能算法
├── 奥卡姆剃刀:简单即好
└── 归纳偏置:每个算法都有"偏见"

一句话总结

机器学习 = 选一个模型 + 定一个评判标准 + 用一个优化方法 + 在数据上训练 + 用指标评估。


参考资料

  • 邱锡鹏.《神经网络与深度学习》. 机械工业出版社, 2020. https://nndl.github.io/
  • 周志华.《机器学习》. 清华大学出版社, 2016.
  • Goodfellow I, Bengio Y, Courville A. Deep Learning. MIT Press, 2016.

如果觉得有帮助,点个 👍 收藏一下!下一章我们聊线性模型(Logistic 回归、Softmax 回归、感知器、SVM)。

更多推荐