G9 - ACGAN理论与实战

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

目录

  • 环境
  • 步骤
    • 环境设置
    • 数据准备
    • 工具方法
    • 模型设计
    • 模型训练
    • 模型效果展示
  • 总结与心得体会


上周已经简单的了解了ACGAN的原理,并且不经实践的编写了部分代码,这周复现一下真正的ACGAN

环境

Pytorch: 2.3.1+cu121
Nvidia GTX 4090

步骤

环境设置

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from torchvision.utils import save_image

from torch.utils.data import DataLoader
from torch.autograd import Variable
import numpy as np

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 全局参数
n_epochs = 200
batch_size = 64
lr = 0.0002
b1 = 0.5
b2 = 0.999
n_cpu = 8
latent_dim = 100
n_classes = 10
img_size = 32
channels = 1
sample_interval = 400

数据准备

# 创建中间采样图片的文件夹
import os
os.makedirs('images', exist_ok=True)
# 配置数据集
os.makedirs('data/mnist', exist_ok=True)
dataloader = DataLoader(
    datasets.MNIST(
        'data/mnist',
        train=True,
        download=True,
        transform=transforms.Compose([
            transforms.Resize(img_size),
            transforms.ToTensor(),
            transforms.Normalize([0.5], [0.5])
        ]),
    ),
    batch_size=batch_size,
    shuffle=True,
)

工具方法

# 权重初始化函数
def weights_init_normal(m):
    classname = m.__class__.__name__
    if classname.find('Conv') != -1:
        torch.nn.init.normal_(m.weight.data, 0.0, 0.02)
    elif classname.find('BatchNorm2d') != -1:
        torch.nn.init.normal_(m.weight.data, 1.0, 0.02)
        torch.nn.init.constant_(m.bias.data, 0.0)

# 日志函数 因为使用了jupyter notebook环境,长时间的任务日志无法直接查看,于是需要打印到文件
import logging
import sys
import datetime

def init_logger(filename, logger_name):
    '''
    @brief:
        initialize logger that redirect info to a file just in case we lost connection to the notebook
    @params:
        filename: to which file should we log all the info
        logger_name: an alias to the logger
    '''

    # get current timestamp
    timestamp = datetime.datetime.utcnow().strftime('%Y%m%d_%H-%M-%S')
    
    logging.basicConfig(
        level=logging.INFO, 
        format='[%(asctime)s] %(name)s {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(filename=filename),
            logging.StreamHandler(sys.stdout)
        ]
    )

    # Test
    logger = logging.getLogger(logger_name)
    logger.info('### Init. Logger {} ###'.format(logger_name))
    return logger

# Initialize
my_logger = init_logger("./ml_notebook.log", "ml_logger")

# 生成函数的结果保存
def sample_image(n_row, batches_done):
    """保存从0到n_classes的生成数字的图像风格"""
    # 采样噪声
    z = torch.randn((n_row**2, latent_dim), device=device)
    # 为n行生成标签从0到n_classes
    labels = torch.tensor([num for _ in range(n_row) for num in range(n_row)], device=device)
    gen_imgs = generator(z, labels)
    save_image(gen_imgs.data.cpu(), 'images/%d.png' % batches_done, nrow=n_row, normalize=True)

模型设计

# 生成器
class Generator(nn.Module):
    def __init__(self):
        super().__init__()
        # 标签嵌入
        self.label_emb = nn.Embedding(n_classes, latent_dim)

        # 计算上采样前的初始大小
        self.init_size = img_size // 4

        # 第一层线性层
        self.l1 = nn.Sequential(
            nn.Linear(latent_dim, 128*self.init_size**2)
        )
        # 卷积层
        self.conv_blocks = nn.Sequential(
            nn.BatchNorm2d(128),
            nn.Upsample(scale_factor=2),
            nn.Conv2d(128, 128, 3, stride=1, padding=1),
            nn.BatchNorm2d(128, 0.8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Upsample(scale_factor=2),
            nn.Conv2d(128, 64, 3, stride=1, padding=1),
            nn.BatchNorm2d(64, 0.8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(64, channels, 3, stride=1, padding=1),
            nn.Tanh(),
        )
    def forward(self, noise, labels):
        # 标签嵌入到噪声中
        gen_input = torch.mul(self.label_emb(labels), noise)

        # 通过第一层线性层
        out = self.l1(gen_input)

        # 整形
        out = out.view(out.shape[0], 128, self.init_size, self.init_size)

        # 卷积生成图像
        img = self.conv_blocks(out)
        return img
# 判别器
class Discriminator(nn.Module):
    def __init__(self):
        super().__init__()

        # 判别器块生成函数
        def discriminator_block(in_filters, out_filters, bn=True):
            """返回每个判别器层"""
            block = [nn.Conv2d(in_filters, out_filters, 3, 2, 1), nn.LeakyReLU(0.2, inplace=True), nn.Dropout2d(0.25)]
            if bn:
                block.append(nn.BatchNorm2d(out_filters, 0.8))
            return block
        
        # 卷积层
        self.conv_blocks = nn.Sequential(
            *discriminator_block(channels, 16, bn=False),
            *discriminator_block(16, 32),
            *discriminator_block(32, 64),
            *discriminator_block(64, 128),
        )
        
        # 下采样后,图像的宽高
        ds_size = img_size // 2 ** 4

        # 输出层
        self.adv_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, 1), nn.Sigmoid())
        self.aux_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, n_classes), nn.Softmax())

    def forward(self, img):
        out = self.conv_blocks(img)
        out = out.view(out.shape[0], -1)
        validity = self.adv_layer(out)
        label = self.aux_layer(out)
        return validity, label

# 模型初始化

# 损失函数
adversarial_loss = nn.BCELoss()
auxiliary_loss = nn.CrossEntropyLoss()

# 初始化生成器和判别器
generator = Generator().to(device)
discriminator = Discriminator().to(device)

# 初始化权重
generator.apply(weights_init_normal)
discriminator.apply(weights_init_normal)

模型训练

# 训练

# 优化器
optimizer_G = torch.optim.Adam(generator.parameters(), lr=lr, betas=(b1, b2))
optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=lr, betas=(b1, b2))



for epoch in range(n_epochs):
    for i, (imgs, labels) in enumerate(dataloader):
        batch_size = imgs.shape[0]

        # 图像是 真实的 标签
        valid = torch.ones((batch_size, 1), requires_grad=False, device=device)
        # 图像是 生成的 标签
        fake = torch.zeros((batch_size, 1), requires_grad=False, device=device)

        real_imgs = imgs.to(device)
        labels = labels.to(device)

        # 训练生成器
        optimizer_G.zero_grad()
        # 采样噪声和标签作为生成器的输入
        z = torch.randn((batch_size, latent_dim), device=device)
        gen_labels = torch.randint(0, 1, (batch_size,), device=device)
        # 生成一批图像
        gen_imgs = generator(z, gen_labels)

        # 损失度量 生成器欺骗判别器的能力
        validity, pred_label = discriminator(gen_imgs)
        g_loss = 0.5 * (adversarial_loss(validity, valid) + auxiliary_loss(pred_label, gen_labels))

        g_loss.backward()
        optimizer_G.step()

        # 训练判别器
        optimizer_D.zero_grad()
        # 真实图像的损失
        real_pred, real_aux = discriminator(real_imgs)
        d_real_loss = 0.5 * (adversarial_loss(real_pred, valid) + auxiliary_loss(real_aux, labels))
        # 生成图像的损失
        fake_pred, fake_aux = discriminator(gen_imgs.detach())
        d_fake_loss = 0.5 * (adversarial_loss(fake_pred, fake) + auxiliary_loss(fake_aux, gen_labels))
        # 判别器的总损失
        d_loss = 0.5 * (d_real_loss + d_fake_loss)

        # 计算判别器的准确率
        pred = np.concatenate([real_aux.data.cpu().numpy(), fake_aux.data.cpu().numpy()], axis=0)
        gt = np.concatenate([labels.data.cpu().numpy(), gen_labels.data.cpu().numpy()], axis=0)
        d_acc = np.mean(np.argmax(pred, axis=1) == gt)

        d_loss.backward()
        optimizer_D.step()

        if i % 100 == 0:
            my_logger.info("[Epoch %d/%d] [Batch %d/%d] [D loss: %f, acc: %d%%] [G loss: %f]" % (epoch, n_epochs, i, len(dataloader), d_loss.item(), 100 * d_acc, g_loss.item()))
        batches_done = epoch * len(dataloader) + i
        if batches_done % sample_interval == 0:
            sample_image(n_row=10, batches_done=batches_done)

训练过程

模型效果展示

刚开始训练
训练到最后

总结与心得体会

通过对模型的复现,发现我之前对判别器的理解有偏差,如果在判别器的输入中插入分类信息,等于是将答案直接给了判别器,生成的结果反而不会太好。还有一个和我预想的不一样的地方,在生成器中,将标签嵌入到特征向量使用了矩阵乘法,而没有直接使用concatenate操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/775112.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot集成jacoco实现单元测试覆盖统计

1.什么是jacoco? JaCoCo,即 Java Code Coverage,是一款开源的 Java 代码覆盖率统计工具。支持 Ant 、Maven、Gradle 等构建工具,支持 Jenkins、Sonar 等持续集成工具,支持 Java Agent 技术远程监控 Java 程序运行情况…

便携式气象站:预测天气的得力助手

在户外探险、农业种植、环境监测等领域,气象信息的准确性对于决策至关重要。 一、便携式气象站的工作原理 便携式气象站是一种集成了多种气象传感器的设备,能够实时监测和记录环境中的温度、湿度、气压、风速、风向、降雨量等气象参数。 二、便携式气象站…

模板初阶和string容器

目录 1.模板 函数模板 函数模板的调用规则: 类模板 容器与迭代器 string的简单介绍 iterator(迭代器) begin()与end() rbegin()和rend() Capacity(容量) shrink…

Alibaba Cloud Toolkit前端使用proxy代理配置

1、vscode 先安装插件 Alibaba Cloud Toolkit 2、前端代码: /personnel: {// target: http://xxx.xx.xxx.xx:9100, // 测试环境// target: http://xxx.xx.xxx.xx:9200, // 线上环境target: http://127.0.0.1:18002, // toolkit 代理changeOrigin: true

如何取消闪迪Micro SD卡的写保护?这个技巧很有效!

由于受写保护影响,无法格式化闪迪Micro SD卡?别担心!通过本文你可以学习如何解除闪迪Micro SD卡的写保护。 我的闪迪SD卡有写保护怎么办? “我打算格式化我的闪迪SD卡。但当我进行格式化时,提示我磁盘被写保护。我想用…

机器人具身智能Embodied AI

强调智能体(如机器人)通过物理身体在物理世界中的实时感知、交互和学习来执行任务。 通过物理交互来完成任务的智能系统。它由“本体”(即物理身体)和“智能体”(即智能核心)耦合而成,能够在复…

MaxKB开源知识库问答系统发布v1.3.0版本,新增强大的工作流引擎

2024年4月12日,1Panel开源项目组正式发布官方开源子项目——MaxKB开源知识库问答系统(github.com/1Panel-dev/MaxKB)。MaxKB开源项目发布后迅速获得了社区用户的认可,成功登顶GitHub Trending趋势榜主榜。 截至2024年7月4日&…

Git 安装

目录 Git 安装 Git 安装 在使用 Git 前我们需要先安装 Git。Git 目前支持 Linux/Unix、Solaris、Mac 和 Windows 平台上运行。Git 各平台安装包下载地址为:http://git-scm.com/downloads 在 Linux 平台上安装(包管理工具安装) 首先&#xff0…

基于Spring Boot框架的EAM系统设计与实现

摘 要:文章设计并实现一个基于Spring Boot框架的EAM系统,以应对传统人工管理模式存在的低效与信息管理难题。系统利用Java语言、JSP技术、MySQL数据库等技术栈,构建了一个B/S架构的高效管理平台,提升了资产管理的信息化水平。该系…

固态继电器的未来浅析

固态继电器(SSR)已成为传统机电继电器的可靠替代品,具有开关速度更快、使用寿命更长、电磁干扰更少等诸多优势。随着技术的不断进步,SSR的未来有望在设计和应用的各个方面实现更显著的改进和创新。 1.小型化和集成化: 固态继电器开发的主要趋…

当火热的Mamba遇到火热的YOLO,会发生怎么样的反应吗?

作者:浙江师范大学 论文地址:https://arxiv.org/pdf/2406.05835 代码地址:https://github.com/HZAI-ZJNU/Mamba-YOLO 目录 前言一、摘要二、介绍二、相关工作2.1 实时目标检测器2.2 端到端的目标检测器2.3 视觉状态空间模型 三 方法3.1 基础知…

服务器数据恢复—DS5300存储raid5阵列数据恢复案例

服务器存储数据恢复环境: 某单位一台某品牌DS5300存储,1个机头4个扩展柜,50块硬盘组建2组RAID5磁盘阵列(一组raid5阵列有27块成员盘,存放Oracle数据库文件;另外一组raid5阵列有23块成员盘)。存储…

OpenCV 车牌检测

OpenCV 车牌检测 级联分类器算法流程车牌检测相关链接 级联分类器 假设我们需要识别汽车图像中车牌的位置,利用深度学习目标检测技术可以采取基于锚框的模型,但这需要在大量图像上训练模型。 但是,级联分类器可以作为预训练文件直接使用&…

python通过COM Interface控制CANoe

python通过COM Interface控制CANoe 介绍打开示例工程python代码示例介绍 通过python可以控制CANoe的启动和停止等其他操作,在做高阶的自动化项目时可以用到。 打开示例工程 python代码示例 # --------------------------------------------------------------------------…

C++ 类和对象 构造函数

一 类的6个默认成员函数&#xff1a; 如果一个类中什么成员都没有&#xff0c;简称为空类。 例&#xff1a; #include <iostream> class Empty {// 空类&#xff0c;什么成员都没有 }; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&a…

ONNX Runtime入门示例:在C#中使用ResNet50v2进行图像识别

ONNX Runtime简介 ONNX Runtime 是一个跨平台的推理和训练机器学习加速器。ONNX 运行时推理可以实现更快的客户体验和更低的成本&#xff0c;支持来自深度学习框架&#xff08;如 PyTorch 和 TensorFlow/Keras&#xff09;以及经典机器学习库&#xff08;如 scikit-learn、Lig…

文件打开的系统错误分析流程

当用户出现“Open file failed”错误时&#xff0c;手动产生dump文件。 &#xff08;1&#xff09;打开资源管理器&#xff0c;选择AppNameXXX.exe进程&#xff0c;右击鼠标选择“创建转储文件” (2) 生成转储文件 3.获取用户转储文件 4.用Visual studio2015打开dump文件分析…

深入讲解C++基础知识(二)

目录 一、复合类型1.引用1.1 引用的定义和使用1.2 引用的注意事项 2. 指针2.1 指针的定义和使用2.2 指针的四种状态2.3 指针的注意事项2.4 其他指针操作2.5 void* 指针 3. 理解复合类型变量的声明4. const 限定符4.1 const 对象的注意事项4.2 const 和引用4.2.1 术语&#xff1…

绘唐科技聚星文社是同款一键生成工具

聚星文社是同款一键生成工具 工具下载 绘唐科技成立于2015年&#xff0c;是一家专注于虚拟现实&#xff08;VR&#xff09;技术和产品开发的高科技企业。绘唐科技的目标是利用虚拟现实技术为人们带来更加沉浸式的体验&#xff0c;推动虚拟现实在各个领域的应用和发展。 绘唐科…

【FFmpeg】avcodec_send_frame函数

目录 1.avcodec_send_frame1.1 将输入的frame存入内部buffer&#xff08;encode_send_frame_internal&#xff09;1.1.1 frame的引用函数&#xff08;av_frame_ref &#xff09;1.1.1.1 帧属性的拷贝&#xff08;frame_copy_props&#xff09;1.1.1.2 buffer的引用函数&#xf…