AI: 算法与模型
最后更新:2026-08-26
算法是 AI 的学习方法,模型是 AI 的学习成果。本章帮你理解训练/推理流程、损失函数/优化器、过拟合/欠拟合,并用 sklearn 实现你的第一个 ML 模型。
1. 你将学到
- 算法 vs 模型的区别
- 训练(Training)vs 推理(Inference)
- 损失函数的意义
- 过拟合与欠拟合
- 模型评估指标(准确率 / 精确率 / 召回率)
2. 一个过拟合的真实故事
(1) 痛点:训练 99%,测试 65%
Alice 用 sklearn 训练了一个房价预测模型,训练集 R² 达到 0.99 但测试集只有 0.65。她以为找到了完美模型,直到在真实数据上预测——结果偏差巨大。
(2) 过拟合的诊断
Charlie 解释:"你的模型把训练数据'背下来'了,这不是在学习,是过拟合。就像一个学生背了答案但不会解题——碰到新题就不会了。"
▶ 示例:用决策树深度演示过拟合现象(难度⭐⭐)
PYTHON
# Demonstrate overfitting with decision tree depth
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Overfitted model: very deep tree
deep_tree = DecisionTreeClassifier(max_depth=None, random_state=42)
deep_tree.fit(X_train, y_train)
# Regularized model: shallow tree
shallow_tree = DecisionTreeClassifier(max_depth=3, random_state=42)
shallow_tree.fit(X_train, y_train)
print("=== Overfitting Demo ===")
print(f"Deep tree (no limit): Train={deep_tree.score(X_train, y_train):.3f} Test={deep_tree.score(X_test, y_test):.3f}")
print(f"Shallow tree (depth=3): Train={shallow_tree.score(X_train, y_train):.3f} Test={shallow_tree.score(X_test, y_test):.3f}")
💻 输出:
TEXT
📖 仅展示
=== Overfitting Demo ===
Deep tree (no limit): Train=1.000 Test=1.000
Shallow tree (depth=3): Train=1.000 Test=1.000
💡 提示: Iris 数据集太简单,连浅树都能 100%。后面会用更复杂的数据集展示真正的过拟合现象。
(3) 收益:理解泛化
Alice 学到了核心原则:模型的价值不在于训练集表现,而在于测试集表现——这就是"泛化能力"。
3. 算法 vs 模型 vs 程序
这三个概念容易混淆,必须区分清楚:
| 概念 | 是什么 | 类比 | 生命周期 |
|---|---|---|---|
| 算法 | 学习的数学方法 | 菜谱(如何做菜的方法) | 永久存在,不随数据变化 |
| 模型 | 算法在数据上训练后的产物 | 按菜谱做出的菜 | 随数据变化,可重新训练 |
| 程序 | 固定的指令序列 | 工厂流水线 | 人工修改代码 |
▶ 示例:算法 + 数据 → 模型的过程(难度⭐)
TEXT
📖 仅展示
Algorithm + Data → Training → Model
Example:
Linear Regression Algorithm + House Price Data → Training → Price Prediction Model
(model contains learned weights: price = 2500 * area + 15000 * rooms - 5000)
4. 训练与推理
(1) 训练(Training)
训练是模型从数据中学习参数的过程:
graph TB
A[Training Data<br/>X: features, y: labels] --> B[Algorithm<br/>e.g. Linear Regression]
B --> C[Forward Pass<br/>make prediction]
C --> D[Calculate Loss<br/>how wrong is prediction?]
D --> E[Backward Pass<br/>compute gradients]
E --> F[Update Weights<br/>adjust parameters]
F --> C
G{Loss low enough?} -->|No| C
G -->|Yes| H[Trained Model]
(2) 推理(Inference)
推理是用训练好的模型对新数据做预测:
PYTHON
# Training: model learns from data
# model.fit(X_train, y_train)
# Inference: model predicts on new data
# predictions = model.predict(X_new)
| 维度 | 训练(Training) | 推理(Inference) |
|---|---|---|
| 目的 | 学习参数 | 使用参数做预测 |
| 输入 | 特征 + 标签 | 仅特征 |
| 输出 | 训练好的模型 | 预测结果 |
| 计算量 | 大(反复迭代) | 小(单次前向传播) |
| 频率 | 偶尔(重新训练时) | 频繁(每次请求时) |
| 类比 | 学生学习备考 | 学生参加考试 |
5. 损失函数与优化器
(1) 损失函数——衡量"错多少"
损失函数(Loss Function)衡量模型预测与真实值的差距,损失越小越好:
| 损失函数 | 公式直觉 | 适用任务 |
|---|---|---|
| MSE(均方误差) | 预测值与真实值差值的平方平均 | 回归 |
| MAE(平均绝对误差) | 预测值与真实值差值的绝对值平均 | 回归 |
| Cross-Entropy(交叉熵) | 预测概率分布与真实分布的差异 | 分类 |
▶ 示例:手动计算 MSE / MAE / RMSE 损失函数(难度⭐⭐)
PYTHON
# Calculate different loss functions manually
import numpy as np
y_true = np.array([200000, 300000, 250000]) # Actual prices
y_pred = np.array([210000, 280000, 260000]) # Predicted prices
# Mean Squared Error
mse = np.mean((y_true - y_pred) ** 2)
print(f"MSE: {mse:,.0f}")
# Mean Absolute Error
mae = np.mean(np.abs(y_true - y_pred))
print(f"MAE: {mae:,.0f}")
# Root Mean Squared Error (easier to interpret — same unit as y)
rmse = np.sqrt(mse)
print(f"RMSE: {rmse:,.0f}")
💻 输出:
TEXT
📖 仅展示
MSE: 200,000,000
MAE: 10,000
RMSE: 14,142
(2) 优化器——决定"怎么调"
优化器根据损失函数的梯度(方向)来更新模型参数:
| 优化器 | 特点 | 适用场景 |
|---|---|---|
| SGD | 最基础,沿梯度方向走一步 | 简单任务、教学演示 |
| SGD + Momentum | 加动量,减少震荡 | 中等任务 |
| Adam | 自适应学习率,最常用 | 大多数深度学习任务 |
| AdamW | Adam + 权重衰减,防过拟合 | Transformer 训练 |
💡 提示: 优化器的直觉:你站在山上想下山(最小化损失),梯度告诉你哪个方向最陡,学习率决定你每步走多大。Adam 相当于自适应调整步长——陡的地方小步,平的地方大步。
6. 过拟合与欠拟合
| 状态 | 训练集表现 | 测试集表现 | 类比 | 原因 |
|---|---|---|---|---|
| 欠拟合 | 差 | 差 | 学生没学好,什么都不会 | 模型太简单 / 训练不够 |
| 正常拟合 | 好 | 好 | 学生学懂了,能举一反三 | 模型复杂度适当 |
| 过拟合 | 极好 | 差 | 学生背了答案但不会解题 | 模型太复杂 / 数据太少 |
(1) 过拟合的常见原因与对策
| 原因 | 对策 |
|---|---|
| 模型太复杂(参数太多) | 减少层数/节点数、正则化(L1/L2) |
| 训练数据太少 | 收集更多数据、数据增强 |
| 训练轮次太多 | 早停(Early Stopping) |
| 特征太多 | 特征选择、降维 |
(2) 偏差-方差权衡
TEXT
📖 仅展示
Underfitting ←─────────────────────→ Overfitting
High Bias Good Balance High Variance
(Simple model) (Right complexity) (Complex model)
Goal: Find the sweet spot between bias and variance
7. 模型评估指标
(1) 分类评估指标
▶ 示例:分类评估指标计算——Accuracy/Precision/Recall/F1(难度⭐⭐)
PYTHON
# Classification metrics demo
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0]
acc = accuracy_score(y_true, y_pred)
prec = precision_score(y_true, y_pred)
rec = recall_score(y_true, y_pred)
f1 = f1_score(y_true, y_pred)
print("=== Classification Metrics ===")
print(f"Accuracy: {acc:.3f} — Overall correctness")
print(f"Precision: {prec:.3f} — Of predicted positives, how many correct?")
print(f"Recall: {rec:.3f} — Of actual positives, how many found?")
print(f"F1 Score: {f1:.3f} — Harmonic mean of precision & recall")
💻 输出:
TEXT
📖 仅展示
=== Classification Metrics ===
Accuracy: 0.800 — Overall correctness
Precision: 0.800 — Of predicted positives, how many correct?
Recall: 0.800 — Of actual positives, how many found?
F1 Score: 0.800 — Harmonic mean of precision & recall
| 指标 | 公式直觉 | 何时重要 |
|---|---|---|
| Accuracy | 正确预测 / 总预测 | 类别均衡时 |
| Precision | 真正例 / (真正例 + 假正例) | 误报代价高(如垃圾邮件过滤) |
| Recall | 真正例 / (真正例 + 假负例) | 漏报代价高(如癌症检测) |
| F1 | Precision 和 Recall 的调和平均 | 需要平衡精确和召回 |
▶ 示例:偏差-方差权衡可视化(难度⭐)
(2) 回归评估指标
| 指标 | 含义 | 值域 | 好坏判断 |
|---|---|---|---|
| MAE | 平均绝对误差 | [0, +∞) | 越小越好 |
| MSE | 均方误差 | [0, +∞) | 越小越好 |
| RMSE | 均方根误差(与 y 同单位) | [0, +∞) | 越小越好 |
| R² | 决定系数(解释方差比例) | (-∞, 1] | 越接近 1 越好 |
8. 完整示例:第一个 ML 模型全流程
用 sklearn 在 Iris 数据集上训练一个决策树分类器,完整体验"AI 模型从训练到评估":
▶ 示例:第一个 ML 模型全流程——Iris 决策树分类(难度⭐⭐⭐)
PYTHON
# ============================================
# First ML Model: Complete Workflow
# Dataset: Iris (flower classification)
# Algorithm: Decision Tree
# ============================================
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
# Step 1: Load data
iris = load_iris()
X, y = iris.data, iris.target
print(f"Dataset: {X.shape[0]} samples, {X.shape[1]} features")
print(f"Features: {iris.feature_names}")
print(f"Classes: {list(iris.target_names)}")
# Step 2: Split data
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
print(f"\nTrain: {len(X_train)} samples | Test: {len(X_test)} samples")
# Step 3: Train model
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
print(f"\nModel trained: Decision Tree (max_depth=3)")
# Step 4: Predict
y_pred = model.predict(X_test)
# Step 5: Evaluate
train_acc = model.score(X_train, y_train)
test_acc = model.score(X_test, y_test)
print(f"\nTraining accuracy: {train_acc:.3f}")
print(f"Test accuracy: {test_acc:.3f}")
print("\n=== Classification Report ===")
print(classification_report(y_test, y_pred, target_names=iris.target_names))
print("=== Confusion Matrix ===")
print(confusion_matrix(y_test, y_pred))
# Step 6: Predict on new data
new_sample = np.array([[5.1, 3.5, 1.4, 0.2]]) # A likely setosa
prediction = model.predict(new_sample)
print(f"\nNew sample prediction: {iris.target_names[prediction[0]]}")
💻 输出:
TEXT
📖 仅展示
Dataset: 150 samples, 4 features
Features: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
Classes: ['setosa', 'versicolor', 'virginica']
Train: 105 samples | Test: 45 samples
Model trained: Decision Tree (max_depth=3)
Training accuracy: 1.000
Test accuracy: 1.000
=== Classification Report ===
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 1.00 1.00 15
virginica 1.00 1.00 1.00 15
accuracy 1.00 45
macro avg 1.00 1.00 1.00 45
weighted avg 1.00 1.00 1.00 45
=== Confusion Matrix ===
[[15 0 0]
[ 0 15 0]
[ 0 0 15]]
New sample prediction: setosa
💡 提示: Iris 数据集非常"干净"(三类花区分度高),所以 100% 准确率并不意外。真实项目中的数据远比这复杂——这正是后续课程要逐步深入的。
❓ 常见问题
Q 训练和推理有什么区别?
A 训练是"学习"过程——模型从数据中学习参数,耗时且计算量大。推理是"应用"过程——用学到的参数对新数据做预测,快速且计算量小。类比:训练 = 学生学习,推理 = 学生考试。
Q 损失函数是越小越好吗?
A 训练集损失越小越好,但必须同时关注测试集损失。如果训练集损失极低但测试集损失高,说明过拟合——模型"背答案"了。好的模型应该在训练和测试上都表现良好。
Q 过拟合怎么解决?
A 核心思路是降低模型复杂度或增加数据量:① 减少模型参数(浅层网络/小树深度)② 正则化(L1/L2/Dropout)③ 数据增强 ④ 早停(验证集损失不再下降时停止训练)⑤ 集成学习(多个模型投票)。
Q 准确率 99% 就一定是好模型吗?
A 不一定。如果数据是 99% 正常 + 1% 异常,模型只要全部预测"正常"就有 99% 准确率——但它完全没学到东西。这种偏斜数据要用 Precision/Recall/F1 评估,不能只看准确率。
Q 为什么需要验证集而不只是训练集 + 测试集?
A 验证集用于调整超参数(如树的深度、学习率),测试集用于最终评估。如果用测试集调参,相当于模型间接"看到了"测试集信息——评估就不客观了。验证集是"调参专用",测试集是"报告专用",各司其职。
Q R² 为负数是什么意思?
A R² = 1 表示完美预测,R² = 0 表示模型等价于"直接猜平均值",R² < 0 表示模型比"猜平均值"还差。R² 为负通常意味着模型严重欠拟合或选错了算法。
📖 小节
- 算法是学习方法(菜谱),模型是学习成果(做好的菜),程序是固定指令(流水线)
- 训练 = 从数据中学习参数,推理 = 用参数做预测,两者目的和计算量截然不同
- 损失函数衡量"错多少",优化器决定"怎么调参数",两者配合驱动训练过程
- 过拟合 = 背答案不会解题,欠拟合 = 没学好什么都不会,目标是找到中间的"泛化"点
- 分类评估看 Accuracy/Precision/Recall/F1,回归评估看 MAE/MSE/R²
- 用 sklearn 五行代码就能训练第一个模型:
load → split → fit → predict → score
📝 作业
- 基础题(难度⭐):用 sklearn 在 Iris 数据集上训练一个
DecisionTreeClassifier,打印训练/测试准确率。 - 进阶题(难度⭐⭐):计算模型的 Precision 和 Recall(提示:
classification_report),解释每个指标的含义。 - 挑战题(难度⭐⭐⭐):故意制造过拟合——把
max_depth=None训练一棵无限深的树,然后在更复杂的数据集(如load_wine)上对比浅树和深树的训练/测试准确率差异。