让两层 MLP 过拟合四个样本
目标与命题
验证:带非线性的两层 MLP 能表示 XOR;去掉非线性后,即使写成两层也仍是线性模型。单 batch 过拟合是实现检查,不是泛化证据。
环境与固定输入
- Python 3.10+、PyTorch 2.x;CPU 即可;预计低于 1 分钟;
torch.manual_seed(7);四个 XOR 样本;隐藏维 4;全批次训练。
python
import torch
torch.manual_seed(7)
X = torch.tensor([[0.,0.],[0.,1.],[1.,0.],[1.,1.]])
y = torch.tensor([[0.],[1.],[1.],[0.]])
model = torch.nn.Sequential(
torch.nn.Linear(2, 4), torch.nn.Tanh(), torch.nn.Linear(4, 1)
)
opt = torch.optim.Adam(model.parameters(), lr=0.05)
loss_fn = torch.nn.BCEWithLogitsLoss()
for step in range(1000):
opt.zero_grad()
logits = model(X)
loss = loss_fn(logits, y)
loss.backward()
assert all(p.grad is not None for p in model.parameters())
opt.step()
pred = (model(X).sigmoid() > 0.5).float()
assert torch.equal(pred, y)
print(float(loss), pred.squeeze().tolist())消融与判断条件
- 原版最终预测应与
y完全相同。 - 删除
Tanh,保持两个 Linear。运行多个固定种子,记录是否无法稳定达到四个全对。 - 每 100 步记录 loss;若长期不降,检查梯度是否存在、学习率和目标 shape。
实际结果怎样解释
原版通过只支持“该实现能优化并表示这四点”。删除非线性失败支持“线性复合不足以表示 XOR”。它不支持网络能泛化到现实分类任务,也不比较不同优化器的普遍优劣。
常见失败与清理
- 输出使用 logits 时应搭配
BCEWithLogitsLoss,不要先 sigmoid 再重复使用该损失。 y的 shape 应与 logits 一致,避免无意广播。- 过大学习率可能振荡;先记录曲线再调整。
- 无文件输出,无需清理;复现时记录 PyTorch 版本、种子和本地代码变化。
完成后做第 2 章复习。