ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vision Transformer图像去雾实战:Python源码+数据集+项目说明

Vision Transformer图像去雾实战:Python源码+数据集+项目说明 简介本资源面向计算机视觉方向的研究者与深度学习实践者提供一套基于Vision Transformer的图像去雾算法完整实现方案可用于复现实验、课程设计或二次开发。压缩包共340个文件约156.35MB以204个Python源码为核心辅以39张png与4张jpg结果图、16份yaml配置、12份csv实验记录、9份ipynb笔记本及8份md说明文档另含gif演示、txt日志与sh脚本等覆盖训练、推理与评估全流程。内容预览中可见cifar10、cifar100等数据集在ResNet、AlexNet与ViT-Ti等模型上的损失景观与损坏实验记录便于对比不同骨干网络的去雾表现。目前已有97人学习下载适合希望深入理解Transformer在底层视觉任务中应用的读者可据此掌握数据组织、模型搭建与实验分析思路。1. 从一张灰蒙蒙的照片说起Vision Transformer 图像去雾到底在做什么你手里有一张在雾天拍的街景远处楼宇的轮廓糊成一团近处的车牌也像蒙了层灰纱。传统做法是上暗通道先验调几个参数能出效果但一到浓雾、天空区域或者大面积白墙就容易翻车出现光晕和色偏。这几年 Vision TransformerViT被搬进图像去雾任务后情况有了变化它靠自注意力机制建模长距离依赖能把「远处那栋楼该是什么颜色」和「近处路面反射的光」关联起来去雾结果在细节和色彩上更稳。这个标题讲的就是用 Vision Transformer 做图像去雾的完整落地Python 源码、配套数据集、项目说明打包在一起。它解决的是「我有一堆雾图想训一个能实际用的去雾模型」这件事。适合两类人一是刚入门深度学习、想找一个端到端项目练手的同学二是做过 CNN 去雾、想对比 Transformer 方案到底强在哪的工程师。下面我按「先立住原理、再跑通代码、最后避坑」的顺序把这条路走一遍。2. 为什么去雾要从 CNN 换到 Vision Transformer原理与选型2.1 去雾任务的本质是一个像素级回归问题图像去雾在数学上通常写成大气散射模型I(x) J(x)·t(x) A·(1 - t(x))。I 是观测到的雾图J 是待恢复的清晰图t 是透射率A 是大气光。传统方法分两步走先估 A 和 t再反解 J。深度学习的方法干脆跳过显式建模直接让网络学 I 到 J 的映射把去雾当成端到端的图像到图像回归。CNN 方案比如 DehazeNet、AOD-Net、FFA-Net靠卷积核的局部感受野逐层堆叠来扩大视野。问题是卷积的感受野增长是线性的要覆盖整张图的全局信息得堆很深参数量和显存都吃不消。雾的分布恰恰是全局相关的一片浓雾会同时影响画面里相距很远的区域局部卷积很难把这种关联学到位。2.2 自注意力为什么适合去雾Vision Transformer 把图像切成固定大小的 patch常见 16×16 或 8×8每个 patch 展平后加位置编码送进多层 Transformer Encoder。核心是自注意力每个 patch 都能直接和图上任意其他 patch 计算相关性权重。这意味着处理左上角一块浓雾时网络可以同时参考右下角相对清晰的区域来推断全局大气光这在 CNN 里要靠很深的网络才能勉强做到。代价也很直接自注意力的计算量随 patch 数量平方增长。一张 256×256 的图切成 16×16 的 patch 是 256 个 token还能接受切成 8×8 就是 1024 个 token显存立刻吃紧。所以实际项目里常见两种折中一是用 Swin Transformer 这类窗口注意力把全局注意力限制在滑动窗口内兼顾效率和感受野二是用混合结构浅层用卷积提局部细节深层用 Transformer 建模全局。标题里的方案通常属于后者或 Swin 变体这也是当前去雾领域比较主流的做法。2.3 选型对比CNN、纯 ViT、混合结构怎么选方案全局建模显存占用训练难度适合场景纯 CNNFFA-Net 等弱低低数据少、算力有限纯 ViT强高高大数据集、充足算力CNNViT 混合较强中中大多数实际项目Swin Transformer强中高中追求 SOTA 效果我一般会建议如果你手上雾图数据不到几千张优先混合结构或 Swin纯 ViT 很容易过拟合如果数据上万张且有 A100 级别的卡可以试纯 ViT 冲效果。这个判断比盲目追新架构重要得多。3. 把项目跑起来环境、数据、训练三步走3.1 环境搭建与依赖安装项目是 Python 写的主流框架是 PyTorch。先确认显卡驱动和 CUDA 版本匹配这一步不对后面全是玄学报错。我习惯用 conda 建独立环境避免和系统里的包打架。# 创建独立环境python 版本按项目说明选一般 3.8 或 3.9 稳妥 conda create -n dehaze_vit python3.9 -y conda activate dehaze_vit # 安装 PyTorchCUDA 版本按自己显卡驱动来这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装项目其余依赖通常包含 numpy、opencv、tqdm、tensorboard 等 pip install numpy opencv-python tqdm tensorboard pillow scikit-image逻辑说明先隔离环境再装框架是为了让 CUDA 版本和 PyTorch 编译版本严格对应。参数上python3.9是兼容性最好的选择3.10 以上偶尔会遇到某些依赖没预编译轮子。装完务必跑一句python -c import torch; print(torch.cuda.is_available())返回 True 才算环境通了。返回 False 就是驱动或 CUDA 版本不匹配别急着往下走。3.2 数据集组织与预处理去雾数据集常见两类合成数据集如 RESIDE 的 ITS、OTS用清晰图加雾生成配对数据和真实数据集如 NH-HAZE、Dense-Haze真实雾天拍摄。项目一般用配对数据训练即每张雾图对应一张清晰图。目录结构通常长这样dataset/ ├── train/ │ ├── hazy/ # 雾图 │ └── clear/ # 对应清晰图文件名一一对应 ├── test/ │ ├── hazy/ │ └── clear/预处理的关键是配对不能错位。我见过太多人因为文件名排序不一致导致雾图和清晰图对不上训练 loss 死活降不下去排查半天。下面这段代码做的是读取配对、归一化、转 tensorimport os import cv2 import torch from torch.utils.data import Dataset class DehazeDataset(Dataset): def __init__(self, root, modetrain, size256): self.hazy_dir os.path.join(root, mode, hazy) self.clear_dir os.path.join(root, mode, clear) self.size size # 按文件名排序保证雾图和清晰图严格对应 self.names sorted(os.listdir(self.hazy_dir)) def __len__(self): return len(self.names) def __getitem__(self, idx): name self.names[idx] hazy cv2.imread(os.path.join(self.hazy_dir, name)) clear cv2.imread(os.path.join(self.clear_dir, name)) # BGR 转 RGB缩放到统一尺寸 hazy cv2.cvtColor(hazy, cv2.COLOR_BGR2RGB) clear cv2.cvtColor(clear, cv2.COLOR_BGR2RGB) hazy cv2.resize(hazy, (self.size, self.size)) clear cv2.resize(clear, (self.size, self.size)) # 归一化到 [0,1]转成 CHW 格式 hazy torch.from_numpy(hazy).permute(2, 0, 1).float() / 255.0 clear torch.from_numpy(clear).permute(2, 0, 1).float() / 255.0 return hazy, clear逻辑说明sorted保证两个目录读取顺序一致这是配对数据最容易翻车的地方。size256是去雾任务的常用输入尺寸太大显存扛不住太小细节丢失。归一化到 [0,1] 而不是 [-1,1]是因为多数去雾损失函数L1、MSE在 [0,1] 区间数值更稳定。如果你的数据分辨率很高建议先离线裁剪成 patch 再训练而不是在__getitem__里随机裁后者会拖慢数据加载。3.3 训练脚本与关键参数训练循环本身不复杂难的是损失函数和超参。去雾常用 L1 损失打底再加感知损失perceptual loss或 SSIM 损失提升视觉质量。下面是一个精简的训练骨架import torch from torch.utils.data import DataLoader from model import DehazeViT # 项目里的模型定义 device torch.device(cuda if torch.cuda.is_available() else cpu) model DehazeViT().to(device) dataset DehazeDataset(dataset, modetrain, size256) loader DataLoader(dataset, batch_size8, shuffleTrue, num_workers4) # 去雾常用组合L1 主损失 感知损失 optimizer torch.optim.AdamW(model.parameters(), lr2e-4, weight_decay1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max100) for epoch in range(100): model.train() for hazy, clear in loader: hazy, clear hazy.to(device), clear.to(device) pred model(hazy) loss torch.nn.functional.l1_loss(pred, clear) optimizer.zero_grad() loss.backward() optimizer.step() scheduler.step() print(fepoch {epoch}, loss {loss.item():.4f})逻辑说明batch_size8是 256 分辨率下 12G 显存的稳妥值显存够可以往上加但要注意学习率同步调整。AdamW比 Adam 多了正确的权重衰减Transformer 类模型基本都用它。lr2e-4是 ViT 微调的常见起点太大容易震荡太小收敛慢。CosineAnnealingLR让学习率余弦下降后期更稳。损失函数先用 L1 跑通确认能降下来再叠加感知损失一上来就堆复杂损失出问题你都不知道是哪一项的锅。4. 训练不收敛、结果发灰去雾项目避坑清单4.1 现象loss 降到某个值就不动了原因多半是学习率过大导致在局部极小值附近震荡或者数据归一化不一致雾图归一化了清晰图没归一化。解决先把学习率降到 1e-4 试同时检查数据加载里两张图的处理流程是否完全一致。我习惯在训练前打印一个 batch 的像素范围确认都在 [0,1]。4.2 现象去雾结果整体发灰、对比度低原因L1 损失倾向于输出所有可能值的中间值导致结果偏保守、发灰。解决叠加 SSIM 损失或对抗损失或者在推理后做一次简单的对比度拉伸。另一个常见原因是训练数据里清晰图本身偏暗模型学到了这个偏差。4.3 现象显存溢出CUDA out of memory原因patch 切得太小导致 token 数量爆炸或者 batch_size 设太大。解决把 patch 从 8×8 改成 16×16token 数直接降到四分之一或者用梯度累积模拟大 batch。混合精度训练amp也能省不少显存但要注意某些损失函数在 fp16 下会溢出。4.4 现象测试集效果好真实雾图一塌糊涂原因合成数据集和真实雾的分布差异大模型过拟合了合成雾的统计特征。解决训练时加入真实雾数据做微调或者用域适应方法。这是去雾领域最经典的坑别指望一个合成数据训出来的模型能直接上真实场景。4.5 现象推理速度慢到没法用原因纯 ViT 的注意力计算量大或者推理时没关掉梯度。解决推理时加torch.no_grad()用 ONNX 或 TensorRT 导出加速或者换 Swin 这类效率更高的结构。如果只是做演示可以先把输入分辨率降到 128 再放大。5. 让去雾结果更耐看验证方法与一个实用技巧训练完不能只看 loss 曲线得用客观指标加主观观察双重验证。客观指标常用 PSNR 和 SSIM但这两个指标和人类视觉感受并不总是一致PSNR 高的图有时看着反而更糊。我的习惯是先跑 PSNR/SSIM 筛掉明显崩掉的模型再挑几张典型图含天空、白墙、远景肉眼对比。import torch from skimage.metrics import peak_signal_noise_ratio as psnr from skimage.metrics import structural_similarity as ssim model.eval() with torch.no_grad(): for hazy, clear in test_loader: hazy, clear hazy.to(device), clear.to(device) pred model(hazy).clamp(0, 1) # 推理结果裁剪到合法范围 # 转成 numpy 算指标注意转成 HWC 格式 pred_np pred[0].permute(1, 2, 0).cpu().numpy() clear_np clear[0].permute(1, 2, 0).cpu().numpy() print(PSNR:, psnr(clear_np, pred_np, data_range1.0)) print(SSIM:, ssim(clear_np, pred_np, channel_axis2, data_range1.0))逻辑说明clamp(0,1)很重要模型输出可能超出合法范围不裁剪会让 PSNR 计算失真。channel_axis2是 skimage 新版本的参数名老版本用multichannelTrue版本不对会直接报错这也是个常见坑。一个实用技巧推理时对同一张图做水平翻转两次结果取平均。这个 TTA测试时增强操作几乎零成本通常能把 PSNR 提 0.1 到 0.3 dB对边缘细节尤其有效。别小看这点提升在去雾这种像素级任务里0.2 dB 往往就是肉眼可感的差别。最后说个我自己的教训我早期做去雾时一门心思调网络结构换了三四个注意力变体效果提升都不明显。后来发现问题出在数据上——训练集的清晰图有几张本身就有轻微雾感模型学了个「去一半雾」的中间态。把这几张脏数据清掉重训效果立刻上了一个台阶。做这类项目数据质量永远比结构花哨更重要先把数据洗干净再谈模型。希望帮到你。本文还有配套的精品资源点击获取
返回列表