深度学习的一切始于最简单的模型——感知机和线性回归。本课将从数学原理出发,理解这些基础模型如何学习,并通过PyTorch实机验证。
1957年,Frank Rosenblatt提出感知机——第一个可以学习的人工神经网络模型。它是现代神经网络的鼻祖,虽然简单,却蕴含了深度学习最核心的思想:通过数据自动学习参数。
感知机的数学表达式:
f(x) = σ(w₁x₁ + w₂x₂ + ... + wₙxₙ + b) = σ(wᵀx + b)
其中:
• x = (x₁, x₂, ..., xₙ) 是输入向量
• w = (w₁, w₂, ..., wₙ) 是权重向量
• b 是偏置项
• σ 是激活函数(感知机中使用阶跃函数)
在二维空间中,感知机画出一条直线 w₁x₁ + w₂x₂ + b = 0,将平面分成两个区域。权重向量 w 决定了直线的方向,偏置 b 决定了直线离原点的距离。
对于AND逻辑门,真值表为:
| x₁ | x₂ | AND |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
AND门是线性可分的——存在一条直线可以完美分开正例和负例,所以感知机可以学会。
import torch
import torch.nn as nn
# 感知机实现
class Perceptron(nn.Module):
def __init__(self, input_dim):
super().__init__()
self.linear = nn.Linear(input_dim, 1)
self.activation = nn.Sigmoid()
def forward(self, x):
return self.activation(self.linear(x))
# AND 门训练
X = torch.tensor([[0,0],[0,1],[1,0],[1,1]], dtype=torch.float32)
y = torch.tensor([[0],[0],[0],[1]], dtype=torch.float32)
model = Perceptron(2)
criterion = nn.BCELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.5)
losses = []
for epoch in range(1000):
optimizer.zero_grad()
output = model(X)
loss = criterion(output, y)
loss.backward()
optimizer.step()
if epoch % 200 == 0:
losses.append(f"Epoch {epoch}: loss={loss.item():.6f}")
# 测试
with torch.no_grad():
pred = model(X)
results = (pred > 0.5).float()
accuracy = (results == y).float().mean()
print("=== AND 门训练结果 ===")
for l in losses:
print(l)
print(f"\n预测输出: {pred.squeeze().tolist()}")
print(f"四舍五入: {results.squeeze().tolist()}")
print(f"准确率: {accuracy.item():.2%}")
# 权重分析
w = model.linear.weight.data.squeeze()
b = model.linear.bias.data.item()
print(f"\n权重: w1={w[0]:.4f}, w2={w[1]:.4f}")
print(f"偏置: b={b:.4f}")
print(f"决策边界: {w[0]:.4f}*x1 + {w[1]:.4f}*x2 + {b:.4f} = 0")
线性回归是机器学习最基本的模型,目标是找到最优的线性关系:
ŷ = wx + b
目标:最小化均方误差(MSE):
L(w,b) = (1/N) Σᵢ(yᵢ - ŷᵢ)² = (1/N) Σᵢ(yᵢ - wxᵢ - b)²
线性回归有解析解(闭式解),但在深度学习中,我们用梯度下降来优化。因为:
对w求偏导:∂L/∂w = (2/N) Σᵢ -xᵢ(yᵢ - wxᵢ - b)
对b求偏导:∂L/∂b = (2/N) Σᵢ -(yᵢ - wxᵢ - b)
梯度更新:w ← w - η · ∂L/∂w,b ← b - η · ∂L/∂b
其中 η 是学习率(learning rate)
import torch
import torch.nn as nn
import numpy as np
# 线性回归:y = 3x + 2 + noise
torch.manual_seed(42)
X = torch.linspace(0, 10, 100).reshape(-1, 1)
y = 3 * X + 2 + torch.randn(X.shape) * 1.5
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
loss_history = []
for epoch in range(500):
optimizer.zero_grad()
pred = model(X)
loss = criterion(pred, y)
loss.backward()
optimizer.step()
if epoch % 100 == 0:
loss_history.append(loss.item())
print(f"Epoch {epoch}: loss={loss.item():.4f}")
w = model.weight.item()
b = model.bias.item()
print(f"\n学习到的参数: w={w:.4f}, b={b:.4f}")
print(f"真实参数: w=3.0000, b=2.0000")
print(f"误差: w_err={abs(w-3):.4f}, b_err={abs(b-2):.4f}")
# 训练曲线数据
print("\n=== 训练曲线 ===")
for i, l in enumerate(loss_history):
bar = "█" * int(l / max(loss_history) * 30)
print(f"Epoch {i*100:4d}: {l:8.4f} {bar}")
感知机和线性回归本质上都是线性模型,区别在于:
| 特性 | 线性回归 | 感知机 |
|---|---|---|
| 输出 | 连续值 | 离散类别(0/1) |
| 损失函数 | MSE | 0-1损失/交叉熵 |
| 激活函数 | 恒等函数 | 阶跃/Sigmoid |
| 任务类型 | 回归 | 分类 |
学习率 η 是训练最重要的超参数之一:
单层感知机只能解决线性可分问题。但如果把多个感知机层叠起来,就能解决XOR等非线性问题。
MLP: y = σ₂(W₂·σ₁(W₁x + b₁) + b₂)
第一层:学习中间表示 h = σ₁(W₁x + b₁)
第二层:在新的特征空间上做线性分类 y = σ₂(W₂h + b₂)
XOR问题的解决:第一层将输入映射到新的空间,使得原来线性不可分的数据变得可分。
1989年,Cybenko证明:具有单个隐藏层的前馈网络,只要隐藏层足够宽,可以近似任意连续函数到任意精度。但实践中,深度比宽度更高效——更深的网络可以用指数级更少的神经元表达同样的函数。
| 假设 | 含义 | 违反时怎么办 |
|---|---|---|
| 线性关系 | y与x线性相关 | 特征变换/非线性模型 |
| 独立同分布 | 样本独立采样 | 时间序列模型 |
| 同方差性 | 误差方差恒定 | 加权回归 |
| 无多重共线性 | 特征间不高度相关 | 正则化/降维 |
💡 推荐资源:
修改上面的AND门代码,训练一个OR门感知机。OR门的真值表是什么?它是线性可分的吗?
尝试用单层感知机训练XOR门,观察结果。思考:为什么无法收敛?如何用两层感知机解决?
用学习率 0.001、0.01、0.1、1.0 分别训练线性回归,观察收敛速度和稳定性。
⚠️ 当模型不收敛时,按以下顺序检查:
虽然线性回归看起来简单,但它是理解深度学习的基石:
完成本课学习,你已经理解了深度学习最基础的构建块——感知机和线性回归。
这是从单细胞生物到神经网络的第一步!