在前三篇文章中,我们依次验证了:
- CNN 对平移等空间扰动具有天然优势
- 在低维灰度图(Fashion-MNIST)上,CNN 与 MLP 差距有限
- 在中等复杂度数据集(CIFAR-10)上,差距迅速拉大
到这里,一个重要问题浮现:
CNN 的优势到底来自“更大的数据集”还是来自“图像的空间结构”?
换句话说:是否即便不换更大的数据集,只要破坏空间结构,MLP 就会更吃亏?
本篇将从这一关键视角展开实验。
一、实验目标
本篇希望进一步回答:
🧪 1. 如果我们“破坏图像的局部结构”,MLP 与 CNN 谁更稳健?
🧪 2. 当图像遭遇“局部遮挡”“随机噪声”“随机擦除”等扰动,CNN 是否仍能保持较强泛化能力?
🧪 3. 既然 MLP 完全依赖全局平铺输入,空间破坏是否会对 MLP 造成毁灭性影响?
二、实验策略(不再更换数据集,而是更换扰动方式)
我们继续使用 CIFAR-10 —— 数据集本身不变。
但重点修改“输入图像”,通过注入不同类别的空间扰动,让模型面临真正的对抗性挑战。
本文采用一类典型扰动:
🔶 1. Random Erasing(随机擦除局部区域)
模拟遮挡:
- 随机挖掉图片中的一小块(如 16×16)
- 广泛用于训练 CNN 的增强策略
CNN 可通过周边区域补偿
MLP 因完全 flatten,会失去空间结构 → 特征被破坏
三、实验步骤
- 使用 CIFAR-10
- 训练 MLP 与 CNN(结构与上一章一致)
- 每种扰动分别训练 10 epoch,记录:
- 训练集精度
- 验证集精度
- 收敛速度
- 使用折线图展示 MLP vs CNN 的精度差异
四、核心实验代码(加入图像扰动增强)
以下为结构化 Demo,方便直接复现实验。
# -*- coding: utf-8 -*-
# 卷积神经网络的引入4 —— 空间扰动下的 MLP 与 CNN 鲁棒性对比实验
# Author: zhchoice
# Date: 2025-11-XXimport torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import randomdevice = 'mps' if torch.backends.mps.is_available() else 'cpu'# =============================
# 1️⃣ 扰动类型选择(重点)
# =============================
# 可选: none / erasing / gaussian / cutout
AUG_TYPE = 'erasing'print(f"===> 使用扰动方式:{AUG_TYPE}")# =============================
# 2️⃣ 定义扰动函数(核心部分)
# =============================def add_gaussian_noise(img, mean=0.0, std=0.1):noise = torch.randn_like(img) * std + meanreturn torch.clamp(img + noise, -1, 1)def cutout(img, size=16):_, h, w = img.size()y = random.randint(size, h - size)x = random.randint(size, w - size)img[:, y-size:y+size, x-size:x+size] = 0return imgclass CutoutTransform:"""可在 transforms 中使用的 cutout 封装"""def __call__(self, img):return cutout(img)class GaussianNoiseTransform:"""高斯噪声封装"""def __call__(self, img):return add_gaussian_noise(img)# =============================
# 3️⃣ 图像增强 pipeline 设置
# =============================
train_transforms = [transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),
]if AUG_TYPE == 'erasing':train_transforms.append(transforms.RandomErasing(p=1.0, scale=(0.1,0.2)))
elif AUG_TYPE == 'gaussian':train_transforms.append(GaussianNoiseTransform())
elif AUG_TYPE == 'cutout':train_transforms.append(CutoutTransform())train_transform = transforms.Compose(train_transforms)test_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])# =============================
# 4️⃣ CIFAR10 数据加载
# =============================
trainset = datasets.CIFAR10('./data', train=True, download=True, transform=train_transform)
testset = datasets.CIFAR10('./data', train=False, download=True, transform=test_transform)train_loader = DataLoader(trainset, batch_size=64, shuffle=True)
test_loader = DataLoader(testset, batch_size=256)# =============================
# 5️⃣ 定义模型(沿用上一章)
# =============================
class MLP(nn.Module):def __init__(self, input_dim=32*32*3, hidden=1024):super().__init__()self.net = nn.Sequential(nn.Flatten(),nn.Linear(input_dim, hidden),nn.ReLU(),nn.Linear(hidden, 10))def forward(self, x):return self.net(x)class CNN(nn.Module):def __init__(self, in_ch=3):super().__init__()self.net = nn.Sequential(nn.Conv2d(in_ch, 32, 3, padding=1),nn.BatchNorm2d(32),nn.ReLU(),nn.MaxPool2d(2),nn.Conv2d(32, 64, 3, padding=1),nn.BatchNorm2d(64),nn.ReLU(),nn.MaxPool2d(2),nn.Conv2d(64, 128, 3, padding=1),nn.ReLU(),nn.AdaptiveAvgPool2d(1),nn.Flatten(),nn.Linear(128, 10))def forward(self, x):return self.net(x)# =============================
# 6️⃣ 训练 & 验证
# =============================
loss_fn = nn.CrossEntropyLoss()def train_one_epoch(model, loader, opt):model.train()tot_loss, tot_correct = 0, 0for x, y in loader:x, y = x.to(device), y.to(device)out = model(x)loss = loss_fn(out, y)opt.zero_grad()loss.backward()opt.step()tot_loss += loss.item()tot_correct += (out.argmax(1) == y).sum().item()return tot_loss / len(loader), tot_correct / len(loader.dataset)def evaluate(model, loader):model.eval()tot_correct = 0with torch.no_grad():for x, y in loader:x, y = x.to(device), y.to(device)tot_correct += (model(x).argmax(1) == y).sum().item()return tot_correct / len(loader.dataset)# =============================
# 7️⃣ 实验执行
# =============================
mlp = MLP().to(device)
cnn = CNN().to(device)opt_mlp = torch.optim.Adam(mlp.parameters(), lr=1e-3)
opt_cnn = torch.optim.Adam(cnn.parameters(), lr=1e-3)epochs = 10mlp_train, mlp_test = [], []
cnn_train, cnn_test = [], []for ep in range(epochs):_, acc_m = train_one_epoch(mlp, train_loader, opt_mlp)_, acc_c = train_one_epoch(cnn, train_loader, opt_cnn)val_m = evaluate(mlp, test_loader)val_c = evaluate(cnn, test_loader)mlp_train.append(acc_m)cnn_train.append(acc_c)mlp_test.append(val_m)cnn_test.append(val_c)print(f"[{ep+1}/{epochs}] MLP val={val_m:.3f} | CNN val={val_c:.3f}")# =============================
# 8️⃣ 画精度曲线
# =============================
plt.figure(figsize=(10,6))
plt.plot(range(1,epochs+1), mlp_train, 'r--o', label='MLP Train')
plt.plot(range(1,epochs+1), mlp_test, 'r-', label='MLP Val')
plt.plot(range(1,epochs+1), cnn_train, 'b--o', label='CNN Train')
plt.plot(range(1,epochs+1), cnn_test, 'b-', label='CNN Val')plt.title(f"Accuracy Curve under Perturbation: {AUG_TYPE}")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
五、训练结果表现

从本次 “Random Erasing(随机擦除)” 的实验结果中,我们能够观察到以下几个清晰结论:
- CNN 在局部遮挡下的鲁棒性显著优于 MLP
从第 1 个 epoch 起:
CNN 验证集精度:0.426
MLP 验证集精度:0.437
两者相差不大。但随着训练继续进行,CNN 的表现开始快速提升:
最终 CNN val ≈ 0.660
而 MLP val ≈ 0.505
CNN 的验证精度始终保持 10%~15% 的稳定优势,并且在整个训练过程中曲线平滑、稳步上升。
结论:CNN 对于随机擦除造成的局部结构破坏具有天然抗性,而 MLP 曲线提升缓慢且上限更低。
- 随机擦除对 MLP 的影响远大于对 CNN 的影响
从曲线可以看到:
MLP 的训练曲线与验证曲线始终存在明显 gap
且验证集精度增长缓慢,后期几乎进入停滞
随机擦除破坏了 MLP flatten 后的全局向量,使模型难以恢复有效特征
而 CNN:
即便被遮挡一部分区域
仍能通过局部卷积核从未被遮挡的区域提取足够信息
验证曲线平滑且稳定上升
这表明:MLP 缺乏空间补偿机制,一旦局部像素被破坏,整体特征都会被扰乱;而 CNN 则具备“局部容错”能力。
- CNN 的收敛速度明显快于 MLP
观察前 3 个 epoch:
CNN val:从 0.426 → 0.562 → 0.590
MLP val:从 0.437 → 0.465 → 0.475
CNN 的增长速度更快,曲线也更陡峭。
CNN 在早期就掌握了稳健的局部纹理特征,而 MLP 则需要更长时间才开始学习到有效结构。
- 随机擦除反而进一步凸显了 CNN 的优势
与上一章(无扰动)相比:
CNN 在 erasing 下精度略降,但仍维持高稳定性与高上限
MLP 在 erasing 下损失明显加剧,最终验证精度也更低
这说明:
扰动越强,MLP 越脆弱;
扰动越强,CNN 越体现其辨识局部结构的能力。
🎯 最终总结(卷4核心结论)
基于本次实验数据可以明确得出:
CNN 的优势不依赖于更大的数据集,而是来源于“空间结构敏感性 + 局部特征补偿能力”。
随机擦除本质上破坏了:
局部纹理
部分语义区域
MLP 由于 flatten 特性:
完全没有空间意识
局部损坏会扰乱整个输入向量
因此验证精度严重受损
CNN 则可以:
靠周边特征补偿缺失的信息
保持稳定学习
在遮挡环境下仍能正确分类
因此:
在任何涉及图像“遮挡、噪声、局部损坏”的任务中,CNN 都显著优于 MLP。