☰
DCGAN图像修复实战:本科生可复现的毕设级PyTorch项目
2026/10/7 13:37:35 网站建设 项目流程

简介:本资源是一套基于Python实现的深度生成对抗网络(GAN)图像修复模型完整项目,专为计算机相关专业本科生毕业设计、期末大作业及AI实战学习者打造。项目聚焦图像破损区域智能重建任务,涵盖DCGAN架构搭建、生成器与判别器训练、数据预处理及效果可视化等核心环节,难度适中且经过助教审定,适合初涉生成式AI的学生快速上手与二次开发。压缩包共7个文件,含6个Python源码(如model.py定义网络结构、train-dcgan.py实现训练流程、complete.py提供推理接口)和1份Markdown文档(README.md含环境配置、运行说明与结果示例),总大小仅12KB,轻量易部署。目前已有164人学习下载,所有代码均经本地编译验证可直接运行,附带清晰模块划分与关键注释,显著降低调试门槛,助力高效完成课程实践与项目交付。

1. 这不是玩具GAN:一个能跑通、能改、能交差的图像修复实战项目,专治毕设卡在“训练不收敛”和“eval报错no module”

你是不是也试过从GitHub clone一个标着“GAN图像修复”的项目,pip install完依赖,一跑train-dcgan.py就卡在RuntimeError: Expected 4-dimensional input, but got 3-dimensional input?或者训了200轮,生成图全是灰色噪点,loss曲线像心电图一样乱跳?别急——这个基于Python实现的深度生成对抗网络(GAN)图像修复模型,不是那种“README写得天花乱坠、代码里藏着三处硬编码路径”的半成品。它是一份经导师签字确认、评审98分、本地实测可复现的完整交付物:从数据预处理(complete.py)、DCGAN核心结构(model.py)、梯度操作封装(ops.py)到训练主循环(train-dcgan.py),全部模块化、参数可调、日志可查。它不追求SOTA指标,但严格遵循课程设计边界——用PyTorch+NumPy实现,不依赖TensorFlow或Keras,所有tensor shape都显式校验,batch_size、lr、noise_dim等关键参数全在train-dcgan.py顶部集中配置。适合计算机/人工智能方向本科生做毕业设计、期末大作业,也适合想亲手拆解GAN训练黑匣子的初学者。你不需要懂Wasserstein距离,但得会看loss下降趋势;你不用重写判别器,但能快速替换为ResNet骨干;你甚至可以只跑simple-distributions.py验证高斯噪声生成逻辑——它就是那种“打开就能跑、跑完能讲清、答辩能答住”的务实型源码包。


2. 从零启动:环境准备、目录结构解析与核心模块职责拆解

2.1 环境搭建:避开CUDA版本陷阱的Python依赖清单

这个项目对环境要求明确且克制:Python 3.7–3.9(不兼容3.10+,因ops.py中部分torch.nn.functional调用在新版有行为变更),PyTorch 1.8.1+cu111(必须带CUDA支持,CPU版训DCGAN极慢且易OOM)。我建议用conda新建隔离环境:

conda create -n gan-repair python=3.8 conda activate gan-repair pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html pip install numpy opencv-python tqdm matplotlib scikit-image

提示:不要用pip install torch自动匹配最新版!项目中model.py的nn.ConvTranspose2dstride设置依赖1.8.1的padding计算逻辑,新版会引发output size mismatch。若你只有CPU,需手动修改train-dcgan.py第32行:device = torch.device("cpu"),并把batch_size从64降到16,否则simple-distributions.py里的torch.randn(64, 100, 1, 1)会爆内存。

2.2 目录结构即设计蓝图:每个文件解决什么问题?

整个source.zip解压后是扁平结构,但模块职责清晰,绝非脚本堆砌:

文件名核心职责关键技术点是否可独立运行
utils.py数据加载与增强:读取图像、裁剪为64×64、归一化到[-1,1]、添加随机mask(模拟破损)使用cv2.resize双线性插值 +np.random.rand生成mask概率图✅ 可单独测试load_data()输出shape
model.pyDCGAN生成器G与判别器D定义:G用5层ConvTranspose2d上采样,D用5层Conv2d下采样,均含BatchNorm和LeakyReLU所有卷积层stride=2保证尺寸翻倍/减半,padding=1避免边缘失真✅python model.py会打印G/D结构
ops.py训练原子操作封装:gradient_penalty(WGAN-GP用)、get_optimizer(Adam with betas=(0.5,0.999))、save_checkpoint(保存G/D state_dict+epoch+loss)torch.autograd.grad手动求二阶导,torch.save含torch.version.cuda校验❌ 依赖model.py,但函数可单元测试
train-dcgan.py主训练循环:加载数据、初始化G/D、交替训练(1步D,1步G)、每10轮保存checkpoint、每50轮生成sample图torch.no_grad()包裹G生成、torch.set_grad_enabled(True)控制D梯度✅ 设置--epochs 10即可快速验证流程
simple-distributions.py验证生成器基础能力:用标准正态分布z生成fake image,不接判别器,纯看G能否把噪声映射成结构化图像torch.randn(64,100,1,1)→ G →torch.sigmoid→cv2.imwrite✅ 首推运行此文件,5秒出图,确认G无bug

2.3 模块间数据流:一张图看懂tensor如何穿越GAN

训练时tensor流动严格遵循DCGAN范式:

  1. utils.py输出(64,3,64,64)张量(batch=64,RGB,64×64)
  2. model.py中G接收(64,100,1,1)噪声向量,输出(64,3,64,64)fake_img
  3. D接收real_img或fake_img,输出(64,1)logits(未sigmoid)
  4. ops.py中get_optimizer为G/D分别创建Adam实例,gradient_penalty仅在D更新时注入(WGAN-GP约束)

关键细节:train-dcgan.py第87行fake_img = G(noise).detach()中的.detach()切断G梯度,确保D训练时不更新G参数——这是GAN训练稳定性的基石。若此处漏掉,D loss会异常震荡,这是新手最常踩的坑之一。


3. 训练全流程实操:从数据准备到loss可视化,每一步命令都附参数说明

3.1 数据准备:三类输入路径适配与mask生成逻辑

项目默认读取./data/下的图像,但utils.py支持三种模式:

  • 模式1:单图修复(调试用)
    将一张test.jpg放入./data/,load_data()自动resize为64×64,mask生成逻辑在add_mask()函数:

    def add_mask(img): # img shape: (3,64,64) mask = np.random.rand(64,64) > 0.7 # 30%像素置0 masked_img = img * mask[None,:,:] # 广播到3通道 return masked_img, mask

    参数说明:0.7是mask保留率,值越小破损越严重;mask[None,:,:]增加channel维度适配RGB。

  • 模式2:批量修复(毕设正式用)
    在train-dcgan.py第25行修改:data_path = "./data/train/",要求该目录下全是.jpg/.png,数量≥200张(太少会导致D过拟合)。

  • 模式3:自定义mask(进阶需求)
    若你有特定破损模板(如划痕、文字遮挡),可替换add_mask()为:

    mask = cv2.imread("./masks/scratch.png", cv2.IMREAD_GRAYSCALE) # 64x64 binary masked_img = img * (mask > 128)[None,:,:]

3.2 启动训练:命令行参数详解与典型配置组合

train-dcgan.py支持以下关键参数(全部有默认值,但建议显式指定):

参数默认值推荐值作用说明
--epochs200100训练总轮数,毕设100轮足够观察收敛趋势
--batch_size6432显存不足时必调,32对应约4GB显存
--lr0.00020.0001G/D学习率,过大导致loss爆炸,过小收敛慢
--beta10.50.5Adam beta1,保持0.5是DCGAN标准实践
--nz100100噪声向量维度,改小会降低生成多样性
--ngf6464G中base channel数,增大提升容量但易过拟合

典型启动命令(显存8GB场景):

python train-dcgan.py --epochs 100 --batch_size 32 --lr 0.0001 --save_dir ./checkpoints/

执行后会在./checkpoints/生成:

  • G_epoch_50.pth/D_epoch_50.pth(每50轮保存)
  • loss_log.txt(三列:epoch, D_loss, G_loss)
  • samples/目录(每10轮生成fake_epoch_XX.png,64张图拼成8×8网格)

3.3 Loss监控与收敛判断:拒绝“看图玄学”,用数据说话

不要只盯着samples/fake_epoch_XX.png是否“像图”,先看loss_log.txt:

  • 健康信号:D_loss在前20轮快速下降至1.5~2.5,G_loss同步缓慢上升至1.0~1.8,50轮后两者在±0.3内小幅震荡
  • 危险信号:D_loss < 0.3且持续下降 → D过强,G无法学习(需调小D lr或增D训练步数)
  • 翻车信号:G_loss突然飙升至>5.0 → G梯度爆炸(检查model.py中nn.LeakyReLU(0.2)是否误写为nn.ReLU())

我一般用pandas快速绘图:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("./checkpoints/loss_log.txt", sep=",", names=["epoch","D_loss","G_loss"]) plt.plot(df["epoch"], df["D_loss"], label="D Loss") plt.plot(df["epoch"], df["G_loss"], label="G Loss") plt.legend(); plt.xlabel("Epoch"); plt.ylabel("Loss"); plt.grid() plt.savefig("./checkpoints/loss_curve.png")

注意:loss_log.txt是追加写入,若中断重训,需手动清空该文件,否则曲线错乱。


4. 避坑指南:98分项目背后的5个血泪经验,省下你3天debug时间

4.1 现象:train-dcgan.py报错ModuleNotFoundError: No module named 'torchvision'

原因:项目依赖torchvision.transforms做图像增强,但pip install torch不自动安装torchvision,且版本必须严格匹配(PyTorch 1.8.1 → torchvision 0.9.1)
解决:执行pip install torchvision==0.9.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html,务必带+cu111后缀,否则CPU版torchvision会与CUDA版PyTorch冲突。

4.2 现象:训练初期D_loss=0.000,G_loss=inf,生成图全黑

原因:model.py中判别器最后一层nn.Linear(512,1)输出未经过nn.Sigmoid(),而BCELoss要求输入在[0,1]区间。原项目用nn.BCEWithLogitsLoss()(自动sigmoid+log),但若误换成nn.BCELoss()就会崩溃。
解决:检查train-dcgan.py第112行损失函数定义,确认是criterion = nn.BCEWithLogitsLoss()。若需改用BCELoss,则在D输出后加scores = torch.sigmoid(scores)。

4.3 现象:simple-distributions.py生成图是纯色块,无纹理

原因:生成器G的权重未正确初始化。model.py第42行nn.init.normal_(m.weight.data, 0.0, 0.02)被注释或删除,导致ConvTranspose2d权重全零。
解决:打开model.py,找到def weights_init(m):函数,确保if isinstance(m, nn.ConvTranspose2d):分支内的nn.init.normal_未被注释,且0.02标准差未被改为0。

4.4 现象:utils.py加载图像时报cv2.error: OpenCV(4.5.5) ... invalid value in function cv::resize

原因:输入图像存在损坏(如EXIF旋转标记未处理)或尺寸小于64×64,cv2.resize无法缩放。
解决:在load_data()函数中cv2.resize前加校验:

if img.shape[0] < 64 or img.shape[1] < 64: img = cv2.resize(img, (128,128), interpolation=cv2.INTER_CUBIC) # 先放大再裁 img = cv2.resize(img, (64,64))

4.5 现象:训练到50轮后loss突变,生成图出现大量条纹伪影

原因:ops.py中gradient_penalty计算时,eps插值系数固定为0.1,但在高分辨率或大batch下,该值导致梯度惩罚过强。
解决:修改ops.py第68行eps = torch.rand(real_img.size(0), 1, 1, 1)为eps = torch.rand(real_img.size(0), 1, 1, 1, device=device),补上device参数,否则混合精度训练时eps在CPU而real_img在GPU,触发隐式拷贝错误。


5. 模型部署与效果增强:三步让修复结果从“能看”到“可用”

5.1 修复单张图像:脱离训练框架的轻量推理脚本

毕设答辩常被问“能修我这张图吗?”,此时需一个独立推理脚本。新建inference.py:

import torch import cv2 import numpy as np from model import Generator # 1. 加载训练好的生成器 G = Generator(nz=100, ngf=64, nc=3) G.load_state_dict(torch.load("./checkpoints/G_epoch_100.pth")) G.eval() # 关闭dropout/batchnorm # 2. 读取待修复图并预处理 img = cv2.imread("./input/test.jpg")[:, :, ::-1] # BGR→RGB img = cv2.resize(img, (64,64)) / 255.0 * 2 - 1 # 归一化到[-1,1] img = torch.from_numpy(img.transpose(2,0,1)).float().unsqueeze(0) # (1,3,64,64) # 3. 生成修复图 with torch.no_grad(): noise = torch.randn(1, 100, 1, 1) fake = G(noise).squeeze(0).cpu().numpy() # (3,64,64) fake = ((fake + 1) / 2 * 255).astype(np.uint8).transpose(1,2,0) # [-1,1]→[0,255] cv2.imwrite("./output/repaired.jpg", fake[:, :, ::-1]) # RGB→BGR保存

关键点:G.eval()必不可少,否则BatchNorm统计量会污染;unsqueeze(0)补batch维度;squeeze(0)移除batch维度以便后续处理。

5.2 效果增强:后处理三板斧提升视觉可信度

GAN生成图常有颜色偏移、边缘锯齿、局部模糊,用OpenCV做低成本增强:

增强类型OpenCV代码作用参数建议
白平衡cv2.cvtColor(fake, cv2.COLOR_RGB2LAB)→lab[:,:,0] = cv2.equalizeHist(lab[:,:,0])→cv2.cvtColor(lab, cv2.COLOR_LAB2RGB)校正整体色调必做,尤其修复老照片
边缘锐化kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])→sharpened = cv2.filter2D(fake, -1, kernel)强化破损边缘结构kernel可微调,5→6增强强度
去马赛克fake = cv2.resize(fake, (256,256), interpolation=cv2.INTER_CUBIC)→fake = cv2.resize(fake, (64,64), interpolation=cv2.INTER_AREA)抑制高频噪声仅当生成图有明显块效应时启用

将三者串联,修复图质感提升显著,答辩时老师会直观感受到“这不像GAN乱画的”。

5.3 毕设加分项:可视化中间特征,证明你真懂GAN在学什么

评审最爱看“为什么有效”。在model.py的Generator中插入hook:

# 在Generator.__init__末尾添加 self.feature_maps = {} def hook_fn(module, input, output): self.feature_maps[module._get_name()] = output.detach().cpu().numpy() self.main[0].register_forward_hook(hook_fn) # 第一层ConvTranspose2d

然后在inference.py生成fake后,打印G.feature_maps['ConvTranspose2d'].shape(应为(1,1024,4,4)),再用matplotlib显示前4个通道:

import matplotlib.pyplot as plt feats = G.feature_maps['ConvTranspose2d'][0] # (1024,4,4) fig, axes = plt.subplots(2,2) for i, ax in enumerate(axes.flat): ax.imshow(feats[i], cmap='viridis') plt.savefig("./output/features.png")

这张图能说明:G第一层已学会提取低频结构(如轮廓、大块色块),而非随机噪声——这就是你答辩时说“生成器在早期层捕获全局结构”的证据。

从那以后我每次交毕设代码,都强制走一遍simple-distributions.py → train-dcgan.py(10轮)→ inference.py → features.py四步验证链,确保从噪声生成、训练收敛、单图推理到原理可视化全部闭环。这比单纯调参重要十倍——因为答辩时老师问的从来不是“loss多少”,而是“你观察到了什么现象?怎么解释它?”。希望帮到你。

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

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

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

立即咨询