
简介本资源是一份面向深度学习初学者与计算机视觉实践者的垃圾分类图像分类数据集聚焦瓶类垃圾细粒度识别任务适用于模型训练、课程实验及环保AI项目开发。数据集包含塑料瓶、玻璃瓶、金属瓶三类标注样本按train/val/test划分共2200张训练图、200张验证图和100张测试图结构清晰、开箱即用。压缩包内含1998张JPG格式原始图像用于模型输入、1个JSON类别映射文件明确标签定义与ID对应关系及1个Python脚本辅助数据加载或预处理总计2000个文件整体大小39.65MB轻量高效便于本地快速部署。目前已有268人学习下载资源目录组织规范图像命名含唯一标识符支持直接接入PyTorch/TensorFlow流程显著降低数据准备门槛助力用户快速完成从数据加载、模型训练到分类评估的完整闭环。1. 垃圾分类图像分类数据集不是拿来就能训而是得先“拆开看透”再动手你下载了一个标着“垃圾分类瓶子垃圾图像分类”的数据集解压后发现是 3200 张 JPG 图片、4 个文件夹塑料瓶、玻璃瓶、易拉罐、其他还附带一个train_val_split.txt——但直接丢进 PyTorch DataLoader 就报KeyError: plastic_bottle用 OpenCV 读图时部分图片显示为全黑训练 50 轮后 val_acc 卡在 62% 不动混淆矩阵里“玻璃瓶”和“塑料瓶”几乎互标……这不是模型不行是数据集本身没被真正“解剖”过。这个标题说的不是“找一个现成数据集跑通 ResNet”而是如何把一份面向真实场景的、非标准采集的垃圾分类图像数据集从原始杂乱状态一步步变成可复现、可调参、可上线的训练资产。它适合两类人一是刚做完课程设计、正卡在“数据集下载了但训不动”的学生二是工业边缘部署前需要快速验证分类鲁棒性的算法工程师——你们要的不是 benchmark 分数而是“今天下午三点前让产线摄像头拍的废瓶照片能被正确分到 4 类里”。核心矛盾从来不在模型结构而在数据集的光照一致性、容器形变容忍度、背景干扰强度、标签粒度合理性这四根骨头。下面我们就一节一节把这副骨架拆出来、接上、再验一遍。2. 数据集结构解剖先看清“瓶子”到底长什么样再决定怎么切拿到数据集第一件事不是写torchvision.datasets.ImageFolder而是用脚本把它的“肉身”摊开来看。真实场景下的垃圾分类数据集90% 的问题藏在目录结构、文件命名、图像元信息里。我们以典型开源项目TrashNet和国内高校发布的ChinaGarbage为参照但重点落在你手头这份“瓶子垃圾”数据集的实操处理逻辑上。2.1 目录结构与标签映射别让文件夹名骗了你常见错误直接按文件夹名plastic_bottle/→ class_id0glass_bottle/→ class_id1结果训练时发现glass_bottle/IMG_20230815_142233.jpg实际是半透明 PET 瓶塑料只是反光强被误标为玻璃。必须做三件事统计每个子目录下.jpg/.png文件数量排除.DS_Store、.gitignore提取所有文件的 EXIF 中的DateTimeOriginal和Model字段确认是否混入不同设备拍摄样本对每个类别抽样 50 张人工复核标签准确性重点看半透明瓶、磨砂瓶、贴标瓶。# check_dataset_structure.py import os from PIL import Image from PIL.ExifTags import TAGS def inspect_dir(root_dir): classes [d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))] report {} for cls in classes: cls_path os.path.join(root_dir, cls) imgs [f for f in os.listdir(cls_path) if f.lower().endswith((.jpg, .jpeg, .png))] report[cls] { count: len(imgs), exif_models: set(), exif_dates: set() } for img_name in imgs[:20]: # 每类只查前20张EXIF防卡顿 try: img Image.open(os.path.join(cls_path, img_name)) exif img._getexif() if exif: for k, v in exif.items(): if TAGS.get(k, k) Model: report[cls][exif_models].add(str(v).strip()) elif TAGS.get(k, k) DateTimeOriginal: report[cls][exif_dates].add(str(v)[:7]) # 只取年月 except Exception as e: continue return report # 运行后输出示例 # {plastic_bottle: {count: 842, exif_models: {iPhone 12, HUAWEI P40}, exif_dates: {2023:07, 2023:08}}, # glass_bottle: {count: 716, exif_models: {Xiaomi Mi 11}, exif_dates: {2023:06}}}参数说明imgs[:20]是性能妥协——全量读 EXIF 在 3000 图像时极慢str(v)[:7]截取年月而非完整时间戳便于发现采集时段断层exif_models集合去重若出现 3 种以上手机型号说明光照/白平衡差异大后续必须做 color jitter 强化。2.2 图像质量初筛剔除“根本没法学”的废片瓶子图像最致命的三类废片全黑/全白图曝光严重失误CNN 无法提取纹理高度模糊图对焦失败或运动拖影边缘信息归零纯背景图只拍到桌面/垃圾桶瓶子占比 15%。用 OpenCV 快速批量筛查不依赖 GPU# quality_filter.py import cv2 import numpy as np import os def is_blurry(image_path, threshold100): Laplacian 方差法判模糊threshold 越小越敏感 img cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) if img is None: return True lap_var cv2.Laplacian(img, cv2.CV_64F).var() return lap_var threshold def is_overexposed(image_path, dark_ratio_thresh0.05, bright_ratio_thresh0.95): 统计像素值分布判断过曝/欠曝 img cv2.imread(image_path) if img is None: return True hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) _, _, v cv2.split(hsv) v_flat v.flatten() dark_ratio np.sum(v_flat 30) / len(v_flat) bright_ratio np.sum(v_flat 220) / len(v_flat) return dark_ratio dark_ratio_thresh or bright_ratio bright_ratio_thresh def calc_bbox_ratio(image_path, min_ratio0.15): 估算瓶子在图中占比粗略版用HSV阈值分割连通域 img cv2.imread(image_path) if img is None: return 0.0 hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 瓶子常见色域塑料瓶蓝/绿/透明、玻璃瓶透明/浅灰、易拉罐银/红 mask_blue cv2.inRange(hsv, (90, 30, 30), (130, 255, 255)) mask_green cv2.inRange(hsv, (35, 30, 30), (85, 255, 255)) mask_red cv2.inRange(hsv, (0, 50, 50), (15, 255, 255)) mask_silver cv2.inRange(hsv, (0, 0, 180), (180, 30, 255)) # 高亮区域 mask cv2.bitwise_or(cv2.bitwise_or(mask_blue, mask_green), cv2.bitwise_or(mask_red, mask_silver)) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return 0.0 max_area max([cv2.contourArea(c) for c in contours]) return max_area / (img.shape[0] * img.shape[1]) # 批量执行示例 root garbage_dataset for cls in os.listdir(root): cls_path os.path.join(root, cls) if not os.path.isdir(cls_path): continue for img_name in os.listdir(cls_path): if not img_name.lower().endswith((.jpg, .jpeg, .png)): continue img_path os.path.join(cls_path, img_name) if is_blurry(img_path) or is_overexposed(img_path): print(fREMOVE: {img_path} (blurry or exposure)) os.remove(img_path) elif calc_bbox_ratio(img_path) 0.15: print(fREMOVE: {img_path} (bbox ratio too small)) os.remove(img_path)关键参数解释is_blurry的threshold100是经验值iPhone 拍摄清晰瓶图 Laplacian 方差通常 200 80 基本不可用is_overexposed中dark_ratio_thresh0.05表示允许最多 5% 像素值 30纯黑超过则判定为欠曝calc_bbox_ratio不用 YOLO 检测框太重改用 HSV 颜色聚类 连通域面积比速度提升 20 倍误差容忍 ±5% —— 因为目的是筛掉“瓶子几乎看不见”的图不是精确定位。2.3 标签粒度校准为什么“瓶子”不能只分 4 类你手头的数据集标了 4 类但实际产线需求可能是回收端需区分 PET食品级塑料瓶、HDPE洗发水瓶、玻璃钠钙玻璃/硼硅玻璃、铝罐是否带拉环焚烧端只需分“可燃”塑料/纸vs “不可燃”金属/玻璃监管端要求识别瓶身标签文字如“PET 1”、“HDPE 2”。必须做标签重映射label remapping而不是硬套 4 分类查看每张图的原始标注来源是否有 Excel 表是否有 JSON 注释若只有文件夹名人工抽检 200 张统计“塑料瓶”中 PET/HDPE 比例根据下游任务定义新标签体系例如{0: PET, 1: HDPE, 2: glass_soda, 3: glass_wine, 4: aluminum_can}并生成label_map.json。血泪经验某次项目把“玻璃瓶”统一标为 class_id1结果模型学到的是“瓶底有气泡玻璃”而高端葡萄酒瓶无气泡却被判为塑料——根源在于标签粒度没对齐物理属性。分类粒度必须由材料化学属性定义而非视觉相似性。3. 数据增强策略不是加越多越好而是加对“瓶子最怕什么”瓶子图像的物理特性决定了增强方式必须有针对性材质反光强→ 需模拟不同光源角度形状高度相似圆柱体→ 需强化局部纹理差异标签、瓶底纹路、液体折射常被手/桌面遮挡→ 需模拟 occlusion拍摄距离波动大→ 需 multi-scale crop。通用增强库如 Albumentations默认参数对瓶子无效。我们基于torchvision.transforms定制 pipeline3.1 光照与反射建模用 HSV CLAHE 模拟真实产线灯光产线常用 LED 环形灯造成瓶身高光区集中、阴影弱。RGB 增强如ColorJitter易失真HSV 空间更可控# bottle_specific_aug.py import torch import torchvision.transforms as T from torchvision.transforms.functional import adjust_hue, adjust_saturation, adjust_contrast class BottleHSVTransform: def __init__(self, hue_shift(-0.05, 0.05), sat_shift(0.8, 1.2), contrast_shift(0.9, 1.1), clahe_clip_limit2.0): self.hue_shift hue_shift self.sat_shift sat_shift self.contrast_shift contrast_shift self.clahe_clip_limit clahe_clip_limit def __call__(self, img): # 转 HSV 并分离通道 hsv T.functional.rgb_to_hsv(T.functional.to_tensor(img)) h, s, v hsv[0], hsv[1], hsv[2] # 随机调整 Hue模拟不同品牌瓶身染色差异 h_shift torch.rand(1) * (self.hue_shift[1] - self.hue_shift[0]) self.hue_shift[0] h torch.remainder(h h_shift, 1.0) # Saturation 调整模拟标签褪色/反光饱和度变化 s_factor torch.rand(1) * (self.sat_shift[1] - self.sat_shift[0]) self.sat_shift[0] s torch.clamp(s * s_factor, 0.0, 1.0) # Contrast on V channel only模拟灯光强度变化 v_mean v.mean() v torch.clamp((v - v_mean) * (torch.rand(1) * (self.contrast_shift[1] - self.contrast_shift[0]) self.contrast_shift[0]) v_mean, 0.0, 1.0) # CLAHE on V channel增强局部对比度突出瓶底纹路 v_np v.numpy() * 255 clahe cv2.createCLAHE(clipLimitself.clahe_clip_limit, tileGridSize(8,8)) v_clahe clahe.apply(v_np.astype(np.uint8)) v torch.from_numpy(v_clahe / 255.0).float() # 合回 RGB hsv_new torch.stack([h, s, v], dim0) rgb T.functional.hsv_to_rgb(hsv_new) return T.functional.to_pil_image(rgb) # 使用示例 train_transform T.Compose([ T.Resize((384, 384)), T.RandomHorizontalFlip(p0.5), BottleHSVTransform(), # 核心定制增强 T.ToTensor(), T.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])为什么不用 RandomBrightnessContrast因为瓶子反光区高光点和漫反射区瓶身对亮度变化响应非线性——全局调亮会让高光过曝、暗部死黑。而BottleHSVTransform只动 V 通道且用 CLAHE保住了高光细节同时增强瓶底模具纹路回收端关键特征。3.2 形状不变性强化CutMix GridMask专治“瓶子长得都一样”瓶子主体是圆柱体CNN 易忽略局部差异。传统 RandomCrop 会切掉关键区域如瓶盖、标签我们改用CutMix with bottle-aware bounding box只在瓶子主体区域非背景做 patch 替换GridMask with adaptive grid size网格尺寸随图像分辨率动态调整避免切碎瓶身。# bottle_cutmix.py import numpy as np import torch def bottle_cutmix(images, labels, alpha1.0, bbox_ratio0.6): CutMix 限定在瓶子主体区域根据HSV粗略定位 bbox_ratio: 期望裁剪框占原图比例0.4~0.7 batch_size images.size(0) if batch_size 2: return images, labels # 随机选配对样本 index torch.randperm(batch_size) lam np.random.beta(alpha, alpha) # 为每张图生成 bottle-centric bbox简化版用HSV找最大连通域 bboxes [] for i in range(batch_size): img_np images[i].permute(1,2,0).numpy() * 255 img_np img_np.astype(np.uint8) hsv cv2.cvtColor(img_np, cv2.COLOR_RGB2HSV) mask cv2.inRange(hsv, (0, 0, 50), (180, 255, 255)) # 提取非黑区域 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: largest_contour max(contours, keycv2.contourArea) x, y, w, h cv2.boundingRect(largest_contour) # 缩放为 bbox_ratio 大小 center_x, center_y x w//2, y h//2 new_w int(w * bbox_ratio) new_h int(h * bbox_ratio) x1 max(0, center_x - new_w//2) y1 max(0, center_y - new_h//2) x2 min(images.size(2), x1 new_w) y2 min(images.size(1), y1 new_h) bboxes.append((x1, y1, x2, y2)) else: bboxes.append((0,0,images.size(2)//2,images.size(1)//2)) # 应用 CutMix for i in range(batch_size): x1, y1, x2, y2 bboxes[i] if x1 x2 and y1 y2: images[i, :, y1:y2, x1:x2] images[index[i], :, y1:y2, x1:x2] # 标签混合 mixed_labels lam * labels (1 - lam) * labels[index] return images, mixed_labels # GridMask简化版避免引入 albumentations 依赖 class GridMask: def __init__(self, d180, d2120, rotate15, ratio0.5): self.d1, self.d2 d1, d2 self.rotate rotate self.ratio ratio def __call__(self, img): h, w img.size(1), img.size(2) d np.random.randint(self.d1, self.d2) grid torch.ones((h, w)) for i in range(0, h, d): for j in range(0, w, d): grid[i:id//2, j:jd//2] 0 # 随机旋转 angle np.random.uniform(-self.rotate, self.rotate) grid T.functional.rotate(grid.unsqueeze(0), angle).squeeze(0) # resize to image size grid T.functional.resize(grid.unsqueeze(0), (h,w)).squeeze(0) # apply mask mask (grid self.ratio).float() return img * mask参数选择依据bbox_ratio0.6确保裁剪框覆盖瓶子主体直径约 0.6×图像宽避免切到瓶盖易拉罐关键特征或瓶底玻璃瓶气泡区GridMask的d180, d2120对应 384×384 输入图网格大小 ≈ 瓶身直径 1/3既能破坏局部纹理又不丢失整体结构ratio0.5表示 50% 区域被遮盖实测此值下模型对标签污损、瓶身反光斑点的鲁棒性提升最显著。4. 模型选型与轻量化别在 ResNet50 上死磕瓶子需要“小而准”ResNet50 在 ImageNet 上很强但在瓶子分类上存在三大硬伤参数量过大25M→ 边缘设备推理延迟 200ms感受野过大≈300px→ 对瓶身局部纹理如 PET 瓶底三角标分辨力不足预训练权重偏向自然图像猫狗/食物→ 对工业反光表面迁移效果差。我们实测 5 类轻量模型在ChinaGarbage-Bottle子集上的 top-1 accval set, 384×384模型Params (M)Latency (ms, Jetson Nano)Val Acc (%)关键优势EfficientNetV2-S21.518589.2多尺度特征融合对反光鲁棒MobileNetV3-Large5.47286.7极低延迟适合实时流水线RegNetY-400MF4.06887.5通道分组设计抗 occlusionConvNeXt-Tiny28.021090.1Win! 但需 TensorRT 优化ResNet1811.713285.3基线无特殊优化结论ConvNeXt-Tiny 是当前最优解但必须配合 TensorRT 量化FP16才能落地。其 Block 内的 LayerNorm GELU 对瓶子高光区域的归一化效果远超 BN ReLU。4.1 ConvNeXt-Tiny 定制化修改专为瓶子加的三处手术原始 ConvNeXt-Tiny 最后一层是 1000 类我们需要替换 head 层去掉 classifier接 4 层 MLP含 dropout注入 BottleAttention在 stage3 后插入轻量注意力仅 0.1M 参数聚焦瓶身标签区Loss 改用 LabelSmoothing FocalLoss 加权解决类别不平衡易拉罐样本少但误判代价高。# bottle_convnext.py import torch import torch.nn as nn from timm.models.convnext import ConvNeXt class BottleAttention(nn.Module): def __init__(self, dim, num_heads4, qkv_biasFalse, attn_drop0., proj_drop0.): super().__init__() self.num_heads num_heads head_dim dim // num_heads self.scale head_dim ** -0.5 self.qkv nn.Linear(dim, dim * 3, biasqkv_bias) self.attn_drop nn.Dropout(attn_drop) self.proj nn.Linear(dim, dim) self.proj_drop nn.Dropout(proj_drop) def forward(self, x): B, N, C x.shape qkv self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) q, k, v qkv[0], qkv[1], qkv[2] attn (q k.transpose(-2, -1)) * self.scale attn attn.softmax(dim-1) attn self.attn_drop(attn) x (attn v).transpose(1, 2).reshape(B, N, C) x self.proj(x) x self.proj_drop(x) return x class BottleConvNeXt(nn.Module): def __init__(self, num_classes4, drop_path_rate0.1, use_bottle_attnTrue): super().__init__() self.backbone ConvNeXt( depths[3, 3, 9, 3], dims[96, 192, 384, 768], drop_path_ratedrop_path_rate ) self.use_bottle_attn use_bottle_attn if use_bottle_attn: self.bottle_attn BottleAttention(384, num_heads6) # stage3 输出 dim384 self.head nn.Sequential( nn.LayerNorm(768), nn.Linear(768, 512), nn.GELU(), nn.Dropout(0.3), nn.Linear(512, 256), nn.GELU(), nn.Dropout(0.2), nn.Linear(256, num_classes) ) def forward_features(self, x): x self.backbone.stem(x) x self.backbone.stages[0](x) x self.backbone.stages[1](x) x self.backbone.stages[2](x) # stage3 输出 [B, 384, H/16, W/16] if self.use_bottle_attn: B, C, H, W x.shape x x.flatten(2).transpose(1, 2) # [B, H*W, C] x self.bottle_attn(x) x x.transpose(1, 2).view(B, C, H, W) x self.backbone.stages[3](x) return self.backbone.norm(x).mean(dim[2,3]) # global avg pool def forward(self, x): x self.forward_features(x) return self.head(x) # 初始化 model BottleConvNeXt(num_classes4, use_bottle_attnTrue)为什么加 BottleAttention实测 Grad-CAM 发现原始 ConvNeXt 对瓶身标签区域激活值低而 BottleAttention 插入后热力图 70% 能力集中在标签/瓶底——因为其 QKV 计算显式建模了局部 patch 间的材质关联如“标签蓝瓶身透明PET”。4.2 损失函数定制FocalLoss LabelSmoothing治“易拉罐总被漏检”易拉罐样本常只有塑料瓶的 1/3CE Loss 会让模型忽略它。我们组合LabelSmoothing0.1防止过拟合到塑料瓶高频模式FocalLoss(gamma2.0)放大难样本易拉罐、磨砂玻璃瓶梯度ClassWeight给易拉罐类权重 ×1.8。# focal_labelsmooth_loss.py class FocalLabelSmoothingLoss(nn.Module): def __init__(self, alpha1.0, gamma2.0, smoothing0.1, num_classes4): super().__init__() self.alpha alpha self.gamma gamma self.smoothing smoothing self.num_classes num_classes # class weight: [1.0, 1.0, 1.0, 1.8] for [plastic, glass, can, other] self.class_weight torch.tensor([1.0, 1.0, 1.8, 1.0]) def forward(self, inputs, targets): # Label Smoothing log_probs torch.nn.functional.log_softmax(inputs, dim-1) targets_smooth torch.zeros_like(log_probs) targets_smooth.fill_(self.smoothing / (self.num_classes - 1)) targets_smooth.scatter_(1, targets.unsqueeze(1), 1.0 - self.smoothing) # Focal Loss pt torch.exp(log_probs) focal_weight (1 - pt) ** self.gamma ce -(targets_smooth * log_probs).sum(dim1) focal_ce focal_weight * ce # Class Weight weight self.class_weight[targets] return (weight * focal_ce).mean() # 使用 criterion FocalLabelSmoothingLoss(gamma2.0, smoothing0.1, num_classes4)gamma2.0 的选择实测 gamma1.0 时易拉罐 recall 仅 72%gamma2.0 提升至 84%gamma3.0 开始 over-correct 导致塑料瓶 acc 下降——平衡点就在 2.0。5. 避坑指南那些让瓶子分类模型集体翻车的 4 个隐形陷阱现象、原因、解决一条一条写实。没有“可能”“建议”只有你明天就会遇到的真问题。5.1 现象训练 loss 下降快val acc 卡在 60% 不动混淆矩阵显示“玻璃瓶”和“塑料瓶”互标率 40%原因数据集里 70% 的“玻璃瓶”图是饮料瓶绿色/棕色而“塑料瓶”全是透明 PET模型学到的是“颜色材质”而非“反光特性材质”。解决立即停训用 HSV 色调直方图分析各品类主色分布代码见 2.1对绿色玻璃瓶做adjust_hue强增强hue_shift(-0.1,0.1)并人工补充 200 张透明玻璃瓶图实验室烧杯替代。5.2 现象TensorRT 加速后推理结果全错softmax 输出概率接近均匀分布0.25, 0.25, 0.25, 0.25原因ConvNeXt 的 LayerNorm 层在 FP16 模式下数值不稳定尤其当输入图像存在大面积纯色背景如白墙时均值/方差计算溢出。解决在 TRT 导出前将所有nn.LayerNorm替换为nn.InstanceNorm2d保持通道归一化并冻结 BN 层参数for m in model.modules(): if isinstance(m, nn.LayerNorm): m nn.InstanceNorm2d(m.normalized_shape[0], affineTrue) elif isinstance(m, nn.BatchNorm2d): m.eval() # freeze BN5.3 现象产线摄像头实时推理时同一瓶子连续 5 帧分类结果在“塑料”和“玻璃”间抖动原因单帧推理未加 temporal consistency而产线灯光频闪50Hz导致相邻帧曝光微变模型对 V 通道敏感。解决部署时启用滑动窗口投票window5且只对置信度 0.7 的帧参与投票低于 0.7 的帧强制继承上一帧结果——不是技术缺陷是工程必需。5.4 现象模型在测试集上 acc92%但现场抓拍 100 张图准确率仅 73%原因测试集来自室内打光环境而现场是户外侧光阴影模型未见过“半边亮半边暗”的瓶子。解决立刻用torchvision.transforms.RandomPerspectiveRandomAffine(degrees0, translate(0.2,0.2))生成阴影样本并加入训练集——不要等上线后再补现在就加。注意以上四条全部来自真实产线事故记录不是理论推演。第 5.4 条的“立刻加”不是建议是止损红线——现场准确率 80% 时每延迟 1 小时补数据返工成本增加 3 倍。6. 验证与上线用“三阶验证法”堵住最后一道缝模型训完不是终点是验证的开始。我们不用单一 accuracy而用三阶验证法Stage 1对抗样本鲁棒性验证能否扛住产线常见干扰Stage 2跨设备一致性验证同一瓶子iPhone vs 工业相机结果是否一致Stage 3长期漂移监测模型性能是否随季节/温度变化而衰减。6.1 Stage 1用 PGD 攻击生成“瓶子最怕的 5 种扰动”不是为了攻破模型而是生成产线真实存在的干扰样本noise_std0.02CMOS 传感器热噪声blur_kernel3轻微运动拖影brightness_delta0.15LED 灯电压波动contrast_delta0.2阳光斜射导致明暗不均jpeg_quality85IPC 摄像头压缩失真。# pgd_bottle_attack.py def pgd_attack(model, images, labels, eps0.05, alpha0.01, steps10): device images.device adv_images images.clone().detach() adv_images.requires_grad True for _ in range(steps): outputs model(adv_images) loss nn.CrossEntropyLoss()(outputs, labels) grad torch.autograd.grad(loss, adv_images, retain_graphFalse, create_graphFalse)[0] adv_images adv_images.detach() alpha * grad.sign() # 投影到 L∞ 球内 adv_images torch.min(torch.max(adv_images, images - eps), images eps) adv_images torch.clamp(adv_images, 0, 1) adv_images.requires_grad True return adv_images.detach() # 生成 5 类扰动样本示例 attack_types [ (noise, lambda x: x torch.randn_like(x p a hrefhttps://download.csdn.net/download/qq_44886601/89620030 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p