🧪 三代方法实战对照:用 MNIST 看透 AI 进化

同一个任务——识别手写数字——用规则方法几乎不可能,用传统 ML 勉强能打,用 DL 像开挂。这个进化过程比任何理论都更能说明"为什么深度学习是革命"。

📋 问题定义

MNIST:60000 张 28×28 的手写数字灰度图,判断每张是 0-9 中的哪个数字。AI 界的 "Hello World"。

方法 A:规则方法 — 几乎不可能

符号 AI
def recognize_digit(image):
    if has_horizontal_top_line(image) and has_diagonal_line(image):
        return 7
    if has_two_loops(image):
        return 8
    if has_vertical_line_only(image):
        return 1
    # ... 需要写几百条规则,且每个人写法不同
    return "?"

# ❌ 准确率:<20%

手写变体无穷、旋转倾斜、每个人字迹不同——规则方法完全不可行。

方法 B:传统 ML — HOG 特征 + SVM

传统 ML

思路:人工提取 HOG(方向梯度直方图)特征 → SVM 学习分类边界。

import numpy as np
from sklearn import svm, metrics
from sklearn.preprocessing import StandardScaler
from skimage.feature import hog
from tensorflow.keras.datasets import mnist

# 1. 加载数据
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 2. 特征工程:提取 HOG 特征
def extract_hog_features(images):
    features = []
    for img in images:
        hog_feat = hog(img, orientations=9,
                       pixels_per_cell=(4, 4),
                       cells_per_block=(2, 2))
        features.append(hog_feat)
    return np.array(features)

X_train_hog = extract_hog_features(x_train)  # (60000, 324)
X_test_hog = extract_hog_features(x_test)

# 3. 标准化
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train_hog)
X_test_s = scaler.transform(X_test_hog)

# 4. 训练 SVM
clf = svm.SVC(kernel='rbf', C=5, gamma=0.05)
clf.fit(X_train_s, y_train)

# 5. 评估
y_pred = clf.predict(X_test_s)
print(f"准确率: {metrics.accuracy_score(y_test, y_pred):.2%}")
# 典型结果:~98.5%

✅ 准确率不错 · ❌ 特征工程依赖人 · ❌ HOG 丢掉笔顺等信息 · ❌ 换任务要重设计特征

方法 C:深度学习 — CNN 端到端

深度学习

思路:原始像素直接丢 CNN,网络自己学会边缘→纹理→形状→数字。零手工特征。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from tensorflow.keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train_t = torch.tensor(x_train, dtype=torch.float32).unsqueeze(1) / 255.0
y_train_t = torch.tensor(y_train, dtype=torch.long)
x_test_t = torch.tensor(x_test, dtype=torch.float32).unsqueeze(1) / 255.0
y_test_t = torch.tensor(y_test, dtype=torch.long)

train_loader = DataLoader(
    TensorDataset(x_train_t, y_train_t),
    batch_size=64, shuffle=True)

# 经典 LeNet 风格 CNN
class SimpleCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3)    # 1→32 通道
        self.conv2 = nn.Conv2d(32, 64, 3)   # 32→64
        self.pool = nn.MaxPool2d(2)
        self.dropout = nn.Dropout(0.25)
        self.fc1 = nn.Linear(64 * 5 * 5, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.pool(torch.relu(self.conv1(x)))
        x = self.pool(torch.relu(self.conv2(x)))
        x = x.view(-1, 64 * 5 * 5)
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)
        return self.fc2(x)

model = SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练 5 epochs
for epoch in range(5):
    for batch_x, batch_y in train_loader:
        optimizer.zero_grad()
        loss = criterion(model(batch_x), batch_y)
        loss.backward()
        optimizer.step()

# 评估
model.eval()
with torch.no_grad():
    pred = model(x_test_t).argmax(dim=1)
    acc = (pred == y_test_t).float().mean()
    print(f"准确率: {acc:.2%}")
    # 典型结果:~99.2%

✅ 准确率最高 · ✅ 零手工特征 · ✅ 换任务只改数据 · ❌ 模型是黑箱

📊 三种方法全面对比

维度规则方法HOG + SVMCNN
准确率<20%~98.5%~99.2%
代码量巨量规则~30 行~50 行
人工设计量极重中等(HOG)几乎零
需要的知识手写规则逻辑CV 特征工程神经网络基础
可扩展性换任务重写换任务重设计特征换数据就行
可解释性清晰HOG 可视化黑箱

📖 核心教训

从规则到学习:范式的上升

规则方法:人把知识写成规则 → 机器执行
    ↓
传统 ML:人设计特征模板 → 机器学分类边界
    ↓
深度学习:机器自己学特征 + 分类边界
    ↓
未来?:机器自己提问、设计实验、自己学
💡 98.5% vs 99.2% 没差多少?
对 MNIST 如此,但换成 ImageNet(1000 类物体):
传统 ML(SIFT + SVM):~60%
CNN:~90%+
任务越难,DL 的优势越碾压。

💭 我的理解

跑完这三套代码的最大感受:DL 真正把 AI 开发从"设计智能"变成了"设计学习机制"

写规则 = 假设我知道答案
设计特征 = 假设我知道什么信息重要
训练网络 = 我不知道,让数据来告诉我

这个谦逊的转变,反而带来了更强大的结果。

📚 参考

🧠 返回中枢 ← 深度学习的奥秘 🎯 ML vs DL 决策 → 路线图总览