news 2026/4/16 14:01:59

卷积神经网络的引入4 —— 局部扰动与空间结构破坏下的鲁棒性验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
卷积神经网络的引入4 —— 局部扰动与空间结构破坏下的鲁棒性验证

在中等复杂度数据集(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-XX

import 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 random

device = '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 + mean

return 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] = 0

return img

class 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, 0

for 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 = 0

with 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 = 10

mlp_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()

五、训练结果表现

image

从本次 “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 则可以:

靠周边特征补偿缺失的信息

保持稳定学习

在遮挡环境下仍能正确分类

因此:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 1:47:50

Jmeter性能综合实战——签到及批量签到

提取性能测试的三个方面:核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作: 签到线程组 n HTTP请求默认值 n HTTP cookie 管理器 n 首页访问请求 n 登录请求 n 查看结果树 n 调试取样器 l HTTP代理服务器 (1)创建线…

作者头像 李华
网站建设 2026/4/16 12:43:41

EdgeVLA: Efficient Vision-Language-Action Models

序号 属性值1论文名称EdgeVLA2发表时间/位置2025/硅谷创业公司 K-scale Labs3Codekscalelabs/evla: EdgeVLA: An open-source edge vision-language-action model for robotics.4创新点 1:模型“瘦身” 现有的 OpenVLA 基于 7B 模型(Llama-2)…

作者头像 李华
网站建设 2026/4/14 16:06:06

Android刷机终极指南:小米手机一键刷入LineageOS完整教程

Android刷机终极指南:小米手机一键刷入LineageOS完整教程 【免费下载链接】palera1n Jailbreak for arm64 devices on iOS 15.0 项目地址: https://gitcode.com/GitHub_Trending/pa/palera1n 🚀 想让你老旧的小米手机重获新生?厌倦了官…

作者头像 李华
网站建设 2026/4/13 17:38:00

JS(ES6+)基础

1. js基本数据类型(7种) string,number, boolean, null, undefined, Symbol, BigInt 2. ES6新增类型 Symbol 唯一不可变的原始类型BigInt 超大整数类型Map 键值对集合Set 无重复值的集合WeakMap/WeakSet 弱引用集合 WeakMap:键…

作者头像 李华
网站建设 2026/4/13 23:49:43

C++14 变量模板(Variable Templates)详解

C14 变量模板(Variable Templates)详解 变量模板是 C14 引入的核心特性之一,允许模板化的变量——即变量可以像函数/类模板一样被参数化,根据模板参数生成不同的变量实例。在此之前,C 仅支持函数模板、类模板和别名模板…

作者头像 李华