☰
NAFNet图像去模糊实战:Python环境搭建、推理与训练避坑指南
2026/10/1 3:54:21 网站建设 项目流程

简介:这份资源是面向图像处理与深度学习方向的开发者、学生及研究者的NAFNet图像去模糊实战项目,基于Python实现,适合具备一定深度学习基础、希望上手图像复原任务的中高级学习者。压缩包共20个文件,约11.98MB,以png、jpg图像样本和xml配置为主,辅以2个Python脚本、md说明文档及IDE工程文件,覆盖模型运行所需的代码、数据与配置。项目围绕NAFNet的卷积层、残差块与注意力机制展开,提供4k_pic_restoration.py与normal_pic_restoration.py两套脚本,分别对应高清与普通分辨率图像的去模糊处理,并附带inputs、outputs目录便于直接观察输入输出效果。已有763人学习下载,读者可借此理解模型定义、训练与测试流程,掌握数据预处理、PSNR与SSIM指标评估及超参数调整思路,快速搭建可复用的图像去模糊实验环境。

1. 从一张糊掉的夜景照片说起:NAFNet 图像去模糊到底解决什么问题

夜里拍的路牌,灯光边缘一圈毛刺,车牌数字糊成一团,这种图丢给传统锐化只会把噪点一起放大。NAFNet(Nonlinear Activation Free Network)是图像复原领域一个很实用的基线:它把注意力机制里常见的非线性激活(GELU、ReLU、Sigmoid)几乎全部拿掉,用乘法和门控代替,在去模糊、去噪、超分这几类任务上都能用较小的显存跑出接近 SOTA 的效果。这个标题对应的就是一套 Python 实现的 NAFNet 去模糊工程,拿到手后你要做的事很明确:配好 Python 环境、装依赖、准备成对的模糊/清晰图、跑推理或训练、把结果图导出来。适合两类人:一类是手里有模糊照片想批量修复的工程同学,一类是想拿 NAFNet 当 backbone 做二次开发的研究向开发者。下面按「环境怎么搭 → 数据怎么组织 → 模型怎么跑 → 坑在哪 → 怎么调优」的顺序讲透。

2. 环境搭建与依赖安装:把 Python 侧的坑先填平

2.1 为什么 NAFNet 对 Python 环境比一般脚本敏感

NAFNet 依赖 PyTorch、torchvision、以及可选的 basicsr / timm 等库,这些库对 CUDA 版本、Python 版本、编译器版本都有耦合。很多人pip install一把梭之后报undefined symbol或者CUDA error: no kernel image is available,本质是 PyTorch 的 CUDA 版本和本机驱动不匹配。我的习惯是先固定 Python 3.9 或 3.10,再按显卡驱动去 PyTorch 官网选对应 CUDA 版本的安装命令,而不是直接pip install torch。如果你只是推理,CPU 也能跑,只是单张 1080p 图可能要十几秒,批量处理会很难受。

2.2 用 conda 建一个干净环境并装依赖

# 创建独立环境,避免污染系统 Python conda create -n nafnet python=3.10 -y conda activate nafnet # 按本机 CUDA 版本装 PyTorch,这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 常用辅助库 pip install opencv-python pillow numpy tqdm scikit-image

逻辑说明:conda create保证环境隔离,避免和系统里已有的 numpy、opencv 冲突;PyTorch 用官方 index 安装能自动匹配 CUDA runtime,比手动编译省事。参数上,python=3.10是兼容性最好的版本区间,3.12 目前部分视觉库轮子还不全。装完用下面这段验证:

import torch print("torch:", torch.__version__) print("cuda available:", torch.cuda.is_available()) print("device:", torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU")

如果cuda available是 False,先别急着改代码,去查驱动版本nvidia-smi和 PyTorch 要求的 CUDA 版本是否对得上。这一步是后面所有操作的前提,翻车大多翻在这里。

2.3 目录结构与权重放置

拿到工程后,常见目录是models/、options/、data/、results/。权重文件(.pth)一般放在experiments/或weights/下,具体路径以工程里的配置为准。我一般会先跑一次python -c "import models"之类的导入测试,确认没有缺模块,再动数据。如果工程里带requirements.txt,优先用它,但要注意里面可能锁死了旧版本 torch,和你的 CUDA 冲突时以能跑起来为准,不要死磕版本号。

3. 数据准备与推理跑通:从单张图到批量去模糊

3.1 输入数据的组织方式

NAFNet 去模糊训练需要成对数据:模糊图(input)和清晰图(target),文件名一一对应。推理阶段只需要模糊图。常见做法是建两个文件夹:

datasets/ train/ input/ # 模糊图 target/ # 清晰图 val/ input/ target/

文件名保持一致,比如0001.png对0001.png。格式上 PNG 无损,适合做训练;JPG 会有压缩伪影,去模糊任务里会干扰模型。分辨率不要求统一,但训练时会被裁剪成 patch,常见是 256×256。如果你的图特别大(4K 以上),推理时显存吃紧,需要分块处理,这个后面讲。

3.2 单张图推理的最小命令

python inference_nafnet.py \ --input ./datasets/val/input/0001.png \ --output ./results/0001_out.png \ --weights ./weights/nafnet_deblur.pth \ --device cuda

逻辑说明:--input指向待处理图,--output是结果路径,--weights是训练好的权重,--device选 cuda 或 cpu。参数上,如果工程用的是配置文件驱动(options/*.yml),那命令会变成python inference.py -opt options/deblur.yml,此时改路径要去 yml 里改,不要硬改脚本。跑完先肉眼对比输入输出,如果输出和输入几乎一样,多半是权重没加载成功或者模型处于 eval 之外的状态。

3.3 批量推理脚本

import os, cv2, torch from models.NAFNet import NAFNet # 路径以实际工程为准 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = NAFNet(width=32, enc_blk_nums=[2,2,4,8], middle_blk_num=12, dec_blk_nums=[2,2,2,2]).to(device) model.load_state_dict(torch.load("./weights/nafnet_deblur.pth", map_location=device)["params"]) model.eval() in_dir, out_dir = "./datasets/val/input", "./results" os.makedirs(out_dir, exist_ok=True) with torch.no_grad(): for name in os.listdir(in_dir): img = cv2.imread(os.path.join(in_dir, name)) # BGR, HWC img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype("float32") / 255.0 tensor = torch.from_numpy(img).permute(2,0,1).unsqueeze(0).to(device) out = model(tensor).clamp(0, 1) # 输出限制到 [0,1] out = out.squeeze(0).permute(1,2,0).cpu().numpy() * 255 cv2.imwrite(os.path.join(out_dir, name), cv2.cvtColor(out.astype("uint8"), cv2.COLOR_RGB2BGR))

逻辑说明:load_state_dict里取["params"]是因为很多 NAFNet 权重保存成 dict 包了一层,直接 load 会报 key 不匹配;clamp(0,1)防止输出溢出导致保存出花屏;颜色通道 BGR→RGB→BGR 的来回转换是最容易写错的地方,写反了结果会偏色。参数上width=32是通道基数,越大越准也越吃显存,enc_blk_nums等要和权重训练时的结构完全一致,结构对不上会直接报 size mismatch。

4. 训练自己的去模糊模型:参数怎么设、显存怎么省

4.1 训练配置的关键参数

参数常见取值作用与调整建议
batch_size4~16显存不够先降这个,再考虑降 patch
patch_size256太小模型学不到全局模糊,太大显存爆
lr1e-4 ~ 2e-4配合 cosine 衰减,太大直接发散
iters20w~40w去模糊收敛慢,几万步看不出效果
lossL1 + FFT纯 L1 偏平滑,加频域损失锐度更好

4.2 启动训练

python train.py -opt options/train_deblur.yml

逻辑说明:配置文件里改dataroot、batch_size_per_gpu、total_iter。如果单卡显存 8G,batch 设 4、patch 256 一般能跑;12G 可以上 8。训练日志里重点看 L1 loss 是否稳定下降,如果前几千步就震荡,先降 lr。验证集 PSNR 涨得慢是正常的,去模糊任务前期提升很缓,别急着换模型。

4.3 显存不够时的三个手段

第一,开混合精度,torch.cuda.amp能省 30% 左右显存;第二,梯度累积,把 batch 拆成多次前向再统一 backward;第三,patch 从 256 降到 192 或 128,但要注意降太多会损失大范围模糊的建模能力。这三招按顺序试,不要一上来就砍 patch。

5. 避坑与排查:NAFNet 去模糊最常见的 5 个翻车点

5.1 输出全黑或全白

现象:推理结果是一张纯色图。原因:权重没加载成功,或者输入归一化方式不对(有的工程用 [0,1],有的用 [-1,1])。解决:打印模型第一层输出确认非零,检查预处理是否和训练时一致,/255.0还是/127.5 - 1要对齐。

5.2 结果偏色、发绿或发紫

现象:去模糊后颜色明显不对。原因:BGR/RGB 通道顺序在读写时搞反了,cv2 读进来是 BGR,送模型前要转 RGB,保存前再转回 BGR。解决:统一在送模型前转 RGB,保存时转回,中间不要重复转。

5.3 CUDA out of memory

现象:跑到一半报显存不足。原因:图太大或 batch 太大。解决:推理时对大图做分块(tile),每块带 overlap 再拼接;训练时降 batch 或开 amp。分块拼接要注意边缘融合,否则会有明显接缝。

5.4 PSNR 很高但肉眼很糊

现象:指标好看,实际观感差。原因:L1/L2 损失偏向平均值,模型学会了「保守输出」。解决:加感知损失或频域损失,或者用 GAN 框架微调,但要注意 GAN 容易引入伪影,调参成本高。

5.5 训练 loss 不降

现象:跑了几万步 loss 几乎不动。原因:学习率太大导致发散,或者数据对没对齐(input 和 target 不是同一场景)。解决:先降 lr 到 1e-5 试几百步,再检查数据配对,随机抽几对图叠一起看是否对齐。

6. 进阶技巧:分块推理与结果验证怎么做才靠谱

大图去模糊最实际的问题是显存。我的做法是把图切成带 overlap 的 tile,比如 512×512、overlap 64,逐块推理后按权重融合边缘。融合权重可以用简单的余弦窗,中间权重高、边缘低,这样接缝几乎看不出来。代码上就是在每个 tile 输出上乘一个窗函数,累加到 canvas,最后除以权重和。

验证方面,别只看 PSNR。去模糊任务里 PSNR 高不代表观感好,我一般会同时看三样:一是局部放大对比(文字、边缘),二是频域能量分布是否更接近清晰图,三是找几张训练集里没有的场景做泛化测试。如果模型只在训练分布上好,换个场景就崩,说明过拟合了,需要加数据增强或者正则。

还有一个容易忽略的点:推理时的 padding。NAFNet 里有下采样,输入尺寸不是 2 的幂次时,边缘会出现伪影。稳妥做法是把输入 pad 到 32 的倍数,推理完再裁回去。这个细节不写进代码里,跑小图看不出来,跑大图边缘就会翻车。

我自己踩过最深的一次坑,是拿一个去噪权重直接去做去模糊,结果输出全是涂抹感,后来才明白任务不匹配的权重再像也不能混用。所以每次换权重,先跑一张已知结果的图验证,再上批量。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询