基于扩散模型的图像恢复:从原理到实践的全流程指南

发布时间:2026/9/4 3:45:11
基于扩散模型的图像恢复:从原理到实践的全流程指南 简介本资源是一套基于扩散模型Diffusion Model实现图像恢复任务的完整可运行代码面向深度学习初学者与图像处理研究者解决去雨、去雾、去雪等真实场景下的图像退化复原问题。压缩包共30个文件含13个核心Python源码如train_diffusion.py、eval_diffusion.py、unet.py、ddm.py等、5个XML配置与IDE配置文件、1个YML超参配置、1个README说明及PSNR/SSIM指标计算脚本总大小仅29KB轻量易部署。已有14934人学习下载体现其在实际科研与工程落地中的广泛参考价值。用户只需修改数据集路径即可快速启动训练与测试配套详细实验流程说明、参数调整指引及关键模块注释并提供博客链接供原理延伸学习代码结构清晰涵盖数据加载、模型定义、采样优化、指标评估全流程具备强复用性与低门槛适配能力。1. 项目缘起为什么用扩散模型做图像恢复最近在整理一些老照片和修复一些低质量的网络图片时我遇到了一个经典难题传统的图像恢复方法比如基于卷积神经网络CNN的超分辨率或去噪算法效果虽然不错但总感觉“匠气”太重。它们倾向于生成过度平滑、缺乏真实纹理细节的图像尤其是在处理严重退化如大面积遮挡、极端噪声时结果往往显得模糊或不自然。这让我开始寻找一种能“理解”图像内容、并能生成更逼真细节的新方法。扩散模型Diffusion Model在这时进入了我的视野。你可能更熟悉它在文生图如Stable Diffusion领域的惊艳表现但它本质上是一种强大的生成模型。它的核心思想不是直接预测干净的图像而是学习一个从纯噪声逐步“去噪”恢复出清晰图像的过程。这个“逐步去噪”的特性让它特别适合图像恢复任务——我们可以把一张受损的图片如模糊、有噪点、有划痕的图片看作是“某个中间状态”的噪声图然后让扩散模型从这个状态开始逆向去噪最终恢复出高质量的图像。这个过程更像是一个“想象力补全”模型会根据学到的海量图像先验知识智能地填充缺失的、合理的细节而不是简单地做插值或滤波。因此我决定动手实现一个基于扩散模型的图像恢复项目。我的目标很明确提供一个从零开始、完整可运行的代码库并附上详细的实验操作流程让无论是研究者还是开发者都能快速上手理解扩散模型在图像恢复上的应用并能在自己的数据上复现效果。本文将围绕这个目标拆解每一个技术环节分享我踩过的坑和最终调优的经验。2. 核心原理拆解扩散模型如何“逆向修复”图像在深入代码之前我们必须先搞懂扩散模型运作的基本原理。很多人觉得扩散模型数学复杂但其实它的直觉非常直观。我们可以把它想象成一个“逐步去噪”的艺术家。整个流程分为两个阶段前向扩散过程和反向生成过程。2.1 前向扩散过程将图像逐步“加噪”这个过程是确定的、无需学习的。它模拟了将一张清晰的图片比如你的一张高清照片一步步变成纯粹高斯噪声的过程。起点我们有一张干净的原始图像x0。每一步我们在当前图像x_{t-1}上添加一小部分来自标准高斯分布均值为0方差为1的噪声ε。同时保留一部分上一时刻的图像信息。数学表达这个过程可以用一个重参数化技巧的公式简洁表示x_t √(α_t) * x_{t-1} √(1 - α_t) * ε其中α_t是一个介于0和1之间的值称为噪声调度系数noise schedule它随着步数t增大而减小。√(α_t)决定了保留多少原图信息√(1 - α_t)决定了加入多少噪声。ε是从标准正态分布中采样的噪声。终点当t足够大比如1000步时α_t趋近于0x_T就几乎完全变成了一个纯粹的噪声图像看不出任何原始信息。注意这个前向过程的关键在于我们可以通过一个巧妙的推导直接从原始图像x0计算出任意中间时刻t的加噪图像x_t而无需一步步迭代。公式是x_t √(γ_t) * x_0 √(1 - γ_t) * ε其中γ_t是α_1到α_t的连乘积。这大大提高了训练和采样的效率。2.2 反向生成过程从噪声中“去噪”重建这才是模型需要学习的核心。我们的目标是训练一个神经网络通常是一个U-Net让它学会“猜出”前向过程中加入的噪声。核心任务在训练时我们随机采样一个时间步t对一张干净图片x0加噪得到x_t同时我们知道加入的真实噪声ε。然后我们让神经网络ε_θ(x_t, t)根据加噪图片x_t和时间步t去预测这个噪声ε。损失函数最常用的损失是均方误差MSE即最小化预测噪声和真实噪声的差距L E[||ε - ε_θ(x_t, t)||^2]。网络ε_θ学习的就是这个去噪函数。图像恢复的适配对于图像恢复任务我们的输入不是纯噪声而是一张退化图像y例如模糊图。我们需要告诉模型从这个“起点”开始去噪。一种经典方法是条件扩散模型。我们在反向过程的每一步都将退化图像y作为额外条件输入到网络中即网络变为ε_θ(x_t, t, y)。这样模型在去噪时会同时参考当前的噪声状态x_t、时间步t以及我们提供的退化条件y从而生成一个既清晰去噪目标又与y内容一致条件约束的图像。2.3 采样生成/恢复过程训练好模型后我们就可以用它来恢复图像了。采样是一个迭代过程从退化图像y出发我们可以将其视为在某个中间噪声状态通常不是纯噪声。一种简单有效的做法是直接从y添加少量噪声作为起始点x_ss是一个较大的时间步或者使用更复杂的后验采样技术。循环迭代对于从t s到t 1的每一步 a. 用训练好的网络预测噪声ε_pred ε_θ(x_t, t, y)。 b. 根据预测的噪声计算出去除一部分噪声后的图像x_{t-1}。这里会用到不同的求解器Sampler如DDPM、DDIM等它们本质上是上述反向过程公式的不同离散化近似。 c. 将x_{t-1}作为下一步的输入。终点当t0时得到的x_0就是模型恢复出的高清图像。这个过程就像一位修复大师看着一张破损的油画y结合自己对完整世界训练数据的理解一笔一笔一步一去噪地将缺失的部分合理、逼真地描绘出来。3. 环境准备与代码结构解析理解了原理我们开始动手。首先你需要准备好Python环境。我强烈建议使用Anaconda来管理环境避免包冲突。3.1 创建并激活Conda环境conda create -n diffusion_restoration python3.9 conda activate diffusion_restoration3.2 安装核心依赖库我们将使用PyTorch作为深度学习框架。请根据你的CUDA版本前往 PyTorch官网 获取安装命令。例如对于CUDA 11.8pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118然后安装其他必要的库pip install numpy opencv-python pillow matplotlib tqdm scikit-image einops # 为了简化网络构建可以安装timm和pytorch-lightning可选但推荐 pip install timm pytorch-lightning3.3 项目代码结构一个清晰的项目结构是高效实验的基石。我的项目目录组织如下diffusion_image_restoration/ ├── configs/ # 配置文件 │ └── train_config.yaml # 训练超参数配置 ├── data/ # 数据目录 │ ├── train/ # 训练集 (高清原图) │ ├── val/ # 验证集 │ └── test/ # 测试集 (可放退化图像) ├── models/ # 模型定义 │ ├── unet.py # U-Net网络结构 │ └── diffusion.py # 扩散过程的前向、反向、采样逻辑 ├── utils/ # 工具函数 │ ├── dataset.py # 数据加载与退化模拟 │ ├── losses.py # 损失函数 │ ├── metrics.py # 评估指标 (PSNR, SSIM) │ └── visualization.py # 可视化工具 ├── scripts/ # 脚本文件 │ ├── train.py # 模型训练脚本 │ └── inference.py # 模型推理/恢复脚本 ├── outputs/ # 输出目录 │ ├── checkpoints/ # 保存的模型权重 │ ├── logs/ # 训练日志 │ └── results/ # 推理结果图像 └── README.md # 项目说明这个结构将数据、模型、训练逻辑、工具函数清晰地分离方便管理和迭代。接下来我们深入最核心的models部分。4. 核心模块实现U-Net与扩散调度器4.1 构建条件U-Net网络扩散模型的核心是一个去噪网络U-Net因其强大的特征提取和融合能力成为首选。我们的U-Net需要能接收时间步嵌入和条件图像。时间步嵌入网络需要知道当前是在去噪的哪一步。我们将时间步t一个标量通过正弦位置编码转换为一个高维向量然后通过MLP映射后以类似AdaIN的方式注入到U-Net的每个残差块中。条件注入对于图像恢复条件就是退化图像y。我们采用**拼接Concatenation**的方式。在U-Net的输入层直接将退化图像y与当前噪声图x_t在通道维度上进行拼接。例如如果x_t是3通道RGB图y也是3通道那么输入就是6通道。这样网络在第一层就能直接“看到”退化条件。以下是unet.py中关键部分的简化代码import torch import torch.nn as nn import torch.nn.functional as F from einops import rearrange class ResidualBlock(nn.Module): def __init__(self, in_channels, out_channels, time_emb_dim): super().__init__() self.time_mlp nn.Linear(time_emb_dim, out_channels) self.conv1 nn.Conv2d(in_channels, out_channels, 3, padding1) self.conv2 nn.Conv2d(out_channels, out_channels, 3, padding1) self.shortcut nn.Conv2d(in_channels, out_channels, 1) if in_channels ! out_channels else nn.Identity() def forward(self, x, t_emb): h F.silu(self.conv1(x)) # 注入时间步信息 t_emb self.time_mlp(F.silu(t_emb)) h h t_emb[:, :, None, None] # 广播相加 h F.silu(self.conv2(h)) return h self.shortcut(x) class ConditionalUNet(nn.Module): def __init__(self, in_channels6, # x_t (3) condition y (3) model_channels128, out_channels3): super().__init__() self.time_embed nn.Sequential( nn.Linear(model_channels, model_channels*4), nn.SiLU(), nn.Linear(model_channels*4, model_channels*4), ) # 定义下采样和上采样路径... # 输入层直接接收拼接后的[x_t, y] self.input_conv nn.Conv2d(in_channels, model_channels, 3, padding1) def forward(self, x, t, condition): # x: 当前噪声图 [B, 3, H, W] # condition: 退化条件图 [B, 3, H, W] # 拼接条件 x torch.cat([x, condition], dim1) # [B, 6, H, W] # 时间步嵌入 t_emb sinusoidal_embedding(t, self.model_channels) t_emb self.time_embed(t_emb) # 网络前向传播... return predicted_noise实操心得条件拼接是最简单有效的方式。也有研究使用交叉注意力Cross-Attention将条件作为Key/Value但实现更复杂在纯图像恢复任务中拼接通常已足够。确保condition和x的空间尺寸一致必要时进行resize。4.2 实现扩散调度与采样器在diffusion.py中我们需要实现噪声调度和采样算法。这里我选择了DDPM和DDIM两种经典算法。噪声调度我们使用余弦调度它在训练初期和后期加噪更平缓通常能取得更好的效果。def cosine_beta_schedule(timesteps, s0.008): steps timesteps 1 x torch.linspace(0, timesteps, steps) alphas_cumprod torch.cos(((x / timesteps) s) / (1 s) * math.pi * 0.5) ** 2 alphas_cumprod alphas_cumprod / alphas_cumprod[0] betas 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1]) return torch.clip(betas, 0, 0.999)采样器以DDIM为例DDIM是一种确定性采样器可以用更少的步数如50步获得与DDPM 1000步相当的质量极大加速推理。class DDIMSampler: def __init__(self, model, schedulecosine, timesteps1000, ddim_timesteps50): self.model model self.timesteps timesteps self.ddim_timesteps ddim_timesteps # 计算并存储所有alpha, beta等参数... self.ddim_timestep_seq np.linspace(0, timesteps-1, ddim_timesteps).astype(int) torch.no_grad() def sample(self, condition, shape, start_stepNone): batch_size shape[0] device condition.device # 初始化噪声或从退化图加噪开始 if start_step is None: img torch.randn(shape, devicedevice) start_step self.timesteps else: # 对于图像恢复可以从退化图加噪开始 noise torch.randn(shape, devicedevice) img self.q_sample(condition, start_step, noise) # 模拟前向到第start_step步 for i in range(self.ddim_timesteps-1, -1, -1): t torch.full((batch_size,), self.ddim_timestep_seq[i], devicedevice, dtypetorch.long) pred_noise self.model(img, t, condition) # DDIM更新公式 img self.ddim_step(img, pred_noise, t, i) return img注意start_step是图像恢复的关键超参数。它控制了我们将退化图像y视为加噪了多少步。值越大模型“想象力”发挥的空间越大但可能偏离原图内容值越小则更忠实于y但修复能力可能减弱。这需要在验证集上调试。5. 数据准备与退化模拟高质量的图像恢复模型需要成对的训练数据高清原图GT和对应的退化图Degraded。对于真实场景获取精确配对的GT和退化图很难。因此我们通常采用合成退化的方法来构建数据集。5.1 构建数据加载器在utils/dataset.py中我们创建一个PairedImageDataset。它从文件夹中读取高清原图并在运行时动态生成各种退化图像。import cv2 from torch.utils.data import Dataset from PIL import Image import numpy as np class DegradationSimulator: 模拟多种图像退化 staticmethod def add_gaussian_noise(img, sigma_range(5, 50)): sigma np.random.uniform(*sigma_range) noise np.random.randn(*img.shape) * sigma noisy_img img noise return np.clip(noisy_img, 0, 255).astype(np.uint8) staticmethod def apply_blur(img, ksize_range(3, 11)): ksize np.random.choice(range(ksize_range[0], ksize_range[1]1, 2)) return cv2.GaussianBlur(img, (ksize, ksize), 0) staticmethod def apply_jpeg_compression(img, quality_range(10, 70)): quality np.random.randint(*quality_range) encode_param [int(cv2.IMWRITE_JPEG_QUALITY), quality] _, encimg cv2.imencode(.jpg, img, encode_param) decimg cv2.imdecode(encimg, 1) return decimg class PairedImageDataset(Dataset): def __init__(self, gt_dir, transformNone, degradation_modecomplex): self.gt_paths [os.path.join(gt_dir, f) for f in os.listdir(gt_dir) if f.endswith((.png, .jpg))] self.transform transform self.degrader DegradationSimulator() self.mode degradation_mode # noise, blur, jpeg, complex def __getitem__(self, idx): gt_img Image.open(self.gt_paths[idx]).convert(RGB) gt_array np.array(gt_img) # 模拟退化 if self.mode complex: # 随机组合多种退化更贴近真实场景 if np.random.rand() 0.5: gt_array self.degrader.apply_blur(gt_array) if np.random.rand() 0.5: gt_array self.degrader.add_gaussian_noise(gt_array) if np.random.rand() 0.5: gt_array self.degrader.apply_jpeg_compression(gt_array) elif self.mode noise: gt_array self.degrader.add_gaussian_noise(gt_array) # ... 其他模式 degraded_img Image.fromarray(gt_array) if self.transform: gt_img self.transform(gt_img) degraded_img self.transform(degraded_img) return degraded_img, gt_img # 返回 (退化图 原图)实操心得退化模拟的强度如噪声sigma、模糊核大小、JPEG质量需要仔细调整以匹配你目标应用的真实退化水平。太弱则模型学不到东西太强则任务不可能完成。建议先用一个小的验证集人工检查生成的退化-原图对是否合理。5.2 数据增强与预处理使用torchvision.transforms进行标准的图像预处理from torchvision import transforms train_transform transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.RandomCrop(256), # 根据你的GPU内存调整裁剪尺寸 transforms.ToTensor(), transforms.Normalize(mean[0.5, 0.5, 0.5], std[0.5, 0.5, 0.5]) # 归一化到[-1, 1] ])扩散模型的输入输出通常归一化到[-1, 1]这与噪声分布的范围一致。6. 模型训练全流程与调优技巧有了数据和模型我们就可以开始训练了。训练扩散模型相对稳定但也有一些需要特别注意的地方。6.1 训练脚本核心逻辑scripts/train.py的主要流程如下# 初始化 model ConditionalUNet(...).to(device) diffusion GaussianDiffusion(...) # 封装了前向加噪和损失计算 optimizer torch.optim.AdamW(model.parameters(), lr1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_maxtotal_epochs) dataloader DataLoader(..., batch_size16, shuffleTrue) for epoch in range(total_epochs): model.train() for batch in dataloader: clean_imgs, degraded_imgs batch clean_imgs clean_imgs.to(device) degraded_imgs degraded_imgs.to(device) optimizer.zero_grad() # 扩散模型的核心训练步骤 loss diffusion.training_losses(model, clean_imgs, degraded_imgs) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) # 梯度裁剪防止爆炸 optimizer.step() # 验证与保存 if epoch % val_interval 0: model.eval() with torch.no_grad(): # 在验证集上采样生成图像计算PSNR/SSIM psnr, ssim evaluate(model, diffusion, val_loader, device) if psnr best_psnr: best_psnr psnr torch.save(model.state_dict(), fbest_model.pth) scheduler.step()6.2 关键超参数与调优经验学习率与优化器AdamW优化器配合Cosine退火调度器是黄金组合。初始学习率1e-4是个不错的起点。如果训练损失震荡可以尝试降低到5e-5。批大小Batch Size在显存允许的情况下尽可能使用大的批大小如16、32。扩散模型训练需要大量的噪声样本大批大小能使梯度估计更稳定。时间步数Timesteps训练时通常使用1000步。这定义了加噪的离散程度。更多的步数理论上能学习更精细的去噪过程但也会增加计算开销。1000是一个经验上的平衡点。损失函数简单的噪声预测MSE损失L2损失通常效果就很好。也有人尝试L1损失或混合损失但MSE的稳定性和效果在大多数情况下是足够的。梯度裁剪强烈建议加上梯度裁剪。扩散模型的训练有时会出现梯度尖峰裁剪能有效防止训练崩溃。范数阈值设为1.0或0.5。EMA指数移动平均使用模型权重的EMA版本进行验证和推理往往能获得更稳定、质量更好的结果。这几乎成了扩散模型训练的标准操作。6.3 训练监控与问题排查观察损失曲线正常的训练损失应该平滑下降并逐渐趋于平缓。如果损失剧烈震荡或突然上升检查学习率是否过高、梯度裁剪是否生效、数据是否有问题。定期可视化每训练几个epoch就在验证集上运行一次采样保存生成的图像。直观对比退化图、生成图和真实原图是判断模型是否在正确学习的最直接方法。如果生成图全是灰色或无意义的纹理说明模型可能坍塌了。验证集指标PSNR和SSIM是客观指标但不要完全依赖它们。有时PSNR不高但人眼视觉质量更好扩散模型生成的结果往往如此。应以人眼主观评价为主指标为辅。7. 推理部署与效果展示模型训练完成后我们就可以用它来恢复图像了。scripts/inference.py脚本负责加载模型并对单张或批量图像进行恢复。7.1 推理脚本详解import argparse from PIL import Image import torch from models.diffusion import DDIMSampler from utils.visualization import save_grid def restore_image(model, sampler, degraded_img_path, output_path, start_step250): 恢复单张图像 # 1. 加载并预处理退化图像 degraded_img Image.open(degraded_img_path).convert(RGB) transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) degraded_tensor transform(degraded_img).unsqueeze(0).to(device) # [1, C, H, W] # 2. 设置采样参数 sampler.ddim_timesteps 50 # 使用50步DDIM加速采样 shape degraded_tensor.shape # 3. 执行采样恢复 with torch.no_grad(): restored_tensor sampler.sample( conditiondegraded_tensor, shapeshape, start_stepstart_step # 关键参数 ) # 4. 后处理并保存 restored_img tensor_to_image(restored_tensor) # 反归一化转回PIL Image restored_img.save(output_path) print(fRestored image saved to {output_path}) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--input, typestr, requiredTrue, helpPath to degraded image) parser.add_argument(--output, typestr, default./restored.png, helpOutput path) parser.add_argument(--model_path, typestr, requiredTrue, helpPath to trained model checkpoint) parser.add_argument(--start_step, typeint, default250, helpDDIM start step (controls restoration strength)) args parser.parse_args() # 加载模型和采样器 model ConditionalUNet(...).to(device) model.load_state_dict(torch.load(args.model_path, map_locationdevice)) model.eval() sampler DDIMSampler(model) restore_image(model, sampler, args.input, args.output, args.start_step)7.2 关键参数start_step的调试start_step是推理阶段最重要的超参数没有之一。它定义了我们将输入退化图像视为扩散过程中第几步的加噪结果。start_step较大如400-600模型认为输入图像噪声很大因此会进行更“激进”的去噪和重建。这适合处理严重退化如极度模糊、大块遮挡的图像因为模型有更大的空间发挥其生成先验来“创造”细节。但风险是可能引入幻觉或改变原图内容。start_step较小如50-150模型认为输入图像比较清晰只进行轻微的“精修”。这适合处理轻度退化如轻微噪声、小划痕的图像能保持对原图的最大忠实度但修复能力有限。如何选择没有固定值。必须针对你的具体任务和退化类型进行调试。建议准备一组有代表性的测试图对每个图尝试不同的start_step例如50, 150, 250, 400用人眼观察选择效果最好的值。通常对于中等退化start_step250是一个不错的起点。7.3 效果对比与案例分析为了直观展示效果我使用在DIV2K数据集800张高清训练图上训练的模型对几种典型退化进行了测试。所有测试均使用DDIM50步采样。退化类型退化图像描述最佳start_step恢复效果主观评价关键观察高斯噪声(σ30)图像布满颗粒状噪点200噪点被有效去除纹理恢复自然无明显平滑感。扩散模型去噪能保留边缘锐利度优于传统BM3D等算法产生的“塑料感”。运动模糊(核大小15)图像有拖影细节丢失300拖影大幅减轻部分高频细节如文字边缘被重建。对于线性运动模糊恢复效果显著。但对于复杂模糊重建的细节可能存在少许伪影。JPEG压缩伪影(质量10)出现明显的分块效应和振铃150分块边界被平滑振铃效应减轻图像整体更干净。模型有效学习了自然图像的平滑先验但过度压缩丢失的高频信息无法完全找回。中值遮挡(随机遮挡20%区域)图像部分区域被灰色块覆盖400遮挡区域被合理的内容填充与周围纹理连贯性较好。这是扩散模型的强项展示了强大的“inpainting”能力。填充内容是否符合语义取决于训练数据是否相关。踩坑实录在一次测试中我对一张人脸模糊图使用start_step500结果恢复出的人脸五官位置发生了轻微偏移。这是因为过大的start_step给了模型太多“自由发挥”空间而人脸结构是高度敏感的。对于具有固定结构如人脸、文字的图像建议使用较小的start_step或采用更高级的条件控制方法如引入结构先验。8. 进阶探索与项目扩展完成基础版本后你可以从这个项目出发进行多方向的深入探索使其更强大、更高效或更专用。8.1 加速采样算法DDIM 50步已经比原始DDPM 1000步快了很多但还能更快。可以研究并实现PLMS (Pseudo Linear Multi-step)一种更高效的采样器。DPM-Solver专为扩散模型设计的高阶求解器可能只需10-20步就能达到很好效果。知识蒸馏训练一个更小的学生网络来模仿大模型多步采样的行为实现单步或几步生成。8.2 引入更强大的条件控制基础的拼接条件有时不够。可以尝试多尺度条件将退化图像下采样到不同尺度分别输入到U-Net的不同层级提供多尺度信息。潜在扩散模型 (LDM)在潜在空间而非像素空间进行扩散大幅降低计算量。这是Stable Diffusion的核心。你可以将图像通过一个VAE编码器压缩到潜在空间在潜在空间训练扩散模型进行恢复最后再用解码器还原到像素空间。ControlNet结构如果你想引入额外的控制条件如边缘图、深度图、语义分割图可以集成ControlNet。它将条件图像通过一个可训练的编码器网络将其输出以零卷积的方式注入到主U-Net中实现精准控制。8.3 面向真实世界的改进合成退化与真实退化存在差距。为了提升实用价值盲恢复训练一个模型来处理未知类型和强度的退化。这需要构建更复杂、更多样的退化模拟数据集。两阶段训练/微调先在大型合成数据集上预训练然后在少量真实退化-清晰图像对上进行微调使模型适应真实退化分布。感知损失与对抗损失在MSE损失之外加入基于VGG的特征感知损失Perceptual Loss或引入一个判别器使用对抗损失GAN Loss可以进一步提升恢复图像的视觉真实感。但要注意这可能会降低PSNR指标因为模型会倾向于生成更真实但可能与原图像素不完全一致的纹理。这个项目提供了一个完整的扩散模型图像恢复框架。从原理到代码从训练到推理我希望这份详细的指南能帮助你顺利跑通第一个实验并为你后续的探索打下坚实的基础。图像生成与修复的世界正在被扩散模型深刻改变亲手实现它是理解其魅力的最佳方式。本文还有配套的精品资源点击获取