G7 - Semi-Supervised GAN 理论与实战

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

目录

  • 理论知识
  • 模型实现
    • 引用、配置参数
    • 初始化权重
    • 定义算法模型
    • 模型配置
    • 模型训练
    • 训练模型
  • 模型效果
  • 总结与心得体会


理论知识

在条件GAN中,判别器只用来判断图像的真和假,到了条件GAN中,图像本身其实是有标签的,这时候我们可能会想,为什么不直接让判别器输出图像的标签呢?本节要探究的SGAN就实现了这样一个GAN网络。

SGAN将GAN拓展到半监督学习,通过强制判别器D来输出类别标签来实现。

SGAN在一个数据集上训练一个生成器G和一个判别器D,输入是N类中的一个,在训练的时候,判别器D也被用于预测输入是属于N+1类中的哪一个,这个N+1是对应了生成器G的输出,这里的判别器D同时也充当起了分类器C的效果。

经过实验发现,这种方法可以用于训练效果更好的判别器D,并且可以比普通的GAN产生更加高质量的样本。

Semi-Supervised GAN有如下成果:

  • 作者对GANs做了一个新的扩展,允许它同时学习一个生成模型和一个分类器,我们把这个拓展称为半监督GAN或者SGAN
  • 实验结果表明,SGAN在有限数据集上比没有生成部分的基准分类器提升了分类性能
  • 实验结果表明,SGAN可以显著地提升生成样本的质量并降低生成器的训练时间
    模型判别器工作示意
    效果对比
    对比生成效果发现,SGAN比普通的DCGAN算法的结果更好。

模型实现

引用、配置参数

import argparse
import os
import numpy as np
import mathfrom torchvision import datasets, transforms
from torchvision.utils import save_imagefrom torch.utils.data import DataLoader
from torch.autograd import Variableimport torch.nn as nn
import torch.nn.functional as F
import torch# 创建结果输出目录,没有就新增,有就跳过
os.makedirs('images', exist_ok=True)# 参数
n_epochs = 50 # 训练轮数
batch_size = 64 # 每个批次的样本数量
lr = 0.0002 # 学习率
b1 = 0.5 # Adam优化器的第一个动量衰减参数
b2 = 0.999 # Adam 优化器的第二个动量衰减参数
n_cpu = 8 # 用于批次生成的CPU线程数
latent_dim = 100 # 潜在空间的维度
num_classes = 10 # 数据集的类别数
img_size = 32 # 每个图像的尺寸(高度和宽度相等)
channels = 1 # 图像的通道数(灰度图像通道数为1)
sample_interval = 400 # 图像采样间隔# 全局设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

初始化权重

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('BatchNorm') != -1:torch.nn.init.normal_(m.weight.data, 1.0, 0.02)torch.nn.init.normal_(m.bias.data, 0.0)

定义算法模型

# 生成器
class Generator(nn.Module):def __init__(self):super().__init__()# 创建一个标签嵌入层,用于将条件标签映射到潜在空间self.label_emb = nn.Embedding(num_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):out = self.l1(noise)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, num_classes + 1), 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().to(device)
# 交叉熵损失,用于辅助分类
auxiliary_loss = nn.CrossEntropyLoss().to(device)# 初始化生成器和鉴别器
generator = Generator().to(device)
discriminator = Discriminator().to(device)# 初始化模型权重
generator.apply(weights_init_normal)
discriminator.apply(weights_init_normal)# 配置数据加载器
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)# 创建优化器
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(opt._epochs):for i, (imgs, labels) in enumerate(dataloader):batch_size = imgs.shape[0]# 生成对抗训练的标签valid = Variable(FloatTensor(batch_size, 1).fill_(1.0), requires_grad=Falsefake = Variable(FloatTensor(batch_size, 2).fill_(0,0)fake_aux_gt = Variable(LongTensor(batch_size).fill_(opt.num_classes, requires_grad)

训练模型

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)fake_aux_gt= torch.ones((batch_size), dtype=torch.int64, device=device, requires_grad=False)*num_classes# 配置输入数据real_imgs = imgs.to(device)labels = labels.to(device)# ** 训练生成器 **optimizer_G.zero_grad()# 采样噪声和类别标签作为生成器的输入z = torch.rand([batch_size, latent_dim], device=device)# 生成一批图像gen_imgs = generator(z)# 计算生成器的损失衡量生成器欺骗鉴别器的能力validity, _ = discriminator(gen_imgs)g_loss = adversarial_loss(validity, valid)g_loss.backward()optimizer_G.step()# ** 训练鉴别器 **optimizer_D.zero_grad()# 真实图像的损失real_pred, real_aux = discriminator(real_imgs)d_real_loss = (adversarial_loss(real_pred, valid) + auxiliary_loss(real_aux, labels)) / 2# 生成图像的损失fake_pred, fake_aux = discriminator(gen_imgs.detach())d_fake_loss = (adversarial_loss(fake_pred, fake) + auxiliary_loss(fake_aux, fake_aux_gt)) /2# 总的鉴别器损失d_loss = (d_real_loss + d_fake_loss) / 2# 计算鉴别器准确率pred = np.concatenate([real_aux.data.cpu().numpy(), fake_aux.data.cpu().numpy()], axis=0)gt = np.concatenate([labels.data.cpu().numpy(), fake_aux_gt.data.cpu().numpy()], axis=0)d_acc = np.mean(np.argmax(pred, axis=1) == gt)d_loss.backward()optimizer_D.step()batches_done = epoch*len(dataloader) + iif batches_done % sample_interval == 0:save_image(gen_imgs.data[:25], 'images/%d.png' % batches_done, nrow=5, normalize=True)print('[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()))

训练过程

[Epoch 0/50] [Batch 937/938] [D loss: 1.361139, acc: 50%] [G loss: 0.692496]
[Epoch 1/50] [Batch 937/938] [D loss: 1.339481, acc: 50%] [G loss: 0.743710]
[Epoch 2/50] [Batch 937/938] [D loss: 1.324114, acc: 50%] [G loss: 0.876165]
[Epoch 3/50] [Batch 937/938] [D loss: 1.163164, acc: 50%] [G loss: 1.803553]
[Epoch 4/50] [Batch 937/938] [D loss: 1.115438, acc: 50%] [G loss: 3.103937]
[Epoch 5/50] [Batch 937/938] [D loss: 1.045782, acc: 50%] [G loss: 4.149418]
[Epoch 6/50] [Batch 937/938] [D loss: 0.996207, acc: 56%] [G loss: 5.366407]
[Epoch 7/50] [Batch 937/938] [D loss: 0.944309, acc: 67%] [G loss: 5.629416]
[Epoch 8/50] [Batch 937/938] [D loss: 0.923516, acc: 71%] [G loss: 5.145832]
[Epoch 9/50] [Batch 937/938] [D loss: 0.941332, acc: 78%] [G loss: 3.469946]
[Epoch 10/50] [Batch 937/938] [D loss: 0.945412, acc: 75%] [G loss: 3.282685]
[Epoch 11/50] [Batch 937/938] [D loss: 0.862699, acc: 84%] [G loss: 3.509322]
[Epoch 12/50] [Batch 937/938] [D loss: 0.880701, acc: 87%] [G loss: 2.907838]
[Epoch 13/50] [Batch 937/938] [D loss: 0.853650, acc: 92%] [G loss: 4.008491]
[Epoch 14/50] [Batch 937/938] [D loss: 0.814380, acc: 93%] [G loss: 4.354833]
[Epoch 15/50] [Batch 937/938] [D loss: 0.907486, acc: 89%] [G loss: 4.128651]
[Epoch 16/50] [Batch 937/938] [D loss: 0.839670, acc: 87%] [G loss: 3.847980]
[Epoch 17/50] [Batch 937/938] [D loss: 1.118082, acc: 75%] [G loss: 3.573672]
[Epoch 18/50] [Batch 937/938] [D loss: 0.877845, acc: 87%] [G loss: 3.234770]
[Epoch 19/50] [Batch 937/938] [D loss: 1.176042, acc: 75%] [G loss: 4.499653]
[Epoch 20/50] [Batch 937/938] [D loss: 0.942495, acc: 84%] [G loss: 4.823555]
[Epoch 21/50] [Batch 937/938] [D loss: 0.874024, acc: 93%] [G loss: 3.880158]
[Epoch 22/50] [Batch 937/938] [D loss: 0.887224, acc: 90%] [G loss: 3.924105]
[Epoch 23/50] [Batch 937/938] [D loss: 0.876955, acc: 89%] [G loss: 4.332885]
[Epoch 24/50] [Batch 937/938] [D loss: 1.164700, acc: 79%] [G loss: 5.855463]
[Epoch 25/50] [Batch 937/938] [D loss: 0.824182, acc: 100%] [G loss: 3.745309]
[Epoch 26/50] [Batch 937/938] [D loss: 0.991236, acc: 87%] [G loss: 4.963309]
[Epoch 27/50] [Batch 937/938] [D loss: 0.906700, acc: 92%] [G loss: 5.675440]
[Epoch 28/50] [Batch 937/938] [D loss: 0.864558, acc: 93%] [G loss: 5.964598]
[Epoch 29/50] [Batch 937/938] [D loss: 0.788707, acc: 96%] [G loss: 7.074716]
[Epoch 30/50] [Batch 937/938] [D loss: 1.044333, acc: 84%] [G loss: 4.304685]
[Epoch 31/50] [Batch 937/938] [D loss: 0.797054, acc: 100%] [G loss: 5.197765]
[Epoch 32/50] [Batch 937/938] [D loss: 0.824380, acc: 100%] [G loss: 5.913801]
[Epoch 33/50] [Batch 937/938] [D loss: 0.978360, acc: 87%] [G loss: 3.314190]
[Epoch 34/50] [Batch 937/938] [D loss: 1.014248, acc: 78%] [G loss: 8.149563]
[Epoch 35/50] [Batch 937/938] [D loss: 1.352330, acc: 68%] [G loss: 8.068608]
[Epoch 36/50] [Batch 937/938] [D loss: 0.906131, acc: 89%] [G loss: 7.385222]
[Epoch 37/50] [Batch 937/938] [D loss: 0.813954, acc: 98%] [G loss: 5.816649]
[Epoch 38/50] [Batch 937/938] [D loss: 0.840815, acc: 98%] [G loss: 6.768866]
[Epoch 39/50] [Batch 937/938] [D loss: 0.864865, acc: 90%] [G loss: 2.277655]
[Epoch 40/50] [Batch 937/938] [D loss: 0.810660, acc: 93%] [G loss: 6.076533]
[Epoch 41/50] [Batch 937/938] [D loss: 1.189352, acc: 78%] [G loss: 4.746247]
[Epoch 42/50] [Batch 937/938] [D loss: 0.823831, acc: 90%] [G loss: 9.117917]
[Epoch 43/50] [Batch 937/938] [D loss: 0.975088, acc: 85%] [G loss: 2.690667]
[Epoch 44/50] [Batch 937/938] [D loss: 0.911645, acc: 89%] [G loss: 6.431296]
[Epoch 45/50] [Batch 937/938] [D loss: 1.214794, acc: 65%] [G loss: 5.860756]
[Epoch 46/50] [Batch 937/938] [D loss: 0.849733, acc: 98%] [G loss: 4.305855]
[Epoch 47/50] [Batch 937/938] [D loss: 0.910819, acc: 90%] [G loss: 6.148373]
[Epoch 48/50] [Batch 937/938] [D loss: 0.828892, acc: 96%] [G loss: 9.507065]
[Epoch 49/50] [Batch 937/938] [D loss: 1.086049, acc: 84%] [G loss: 5.026798]

模型效果

第一次输出的图像
第一次输出图像
25轮输出的图像
25轮输出的图像
最后输出的图像
最后输出的图像
通过图像可以发现,不同类型的数字间有很大区别,SGAN可以生成的很好

总结与心得体会

SGAN对于GAN的改进,更像是一个拥有着部分共同权重的一组小模型,可以让每个分类的图像生成的更加精确,避免生成的图像同时拥有着几种手势的特点,有点不伦不类。
目前的判别器中,无法对生成的图像打上准确的标签,这样应该会影响生成的精度,如果可以结合CGAN,直接让生成器也学习不同分类的特点,然后让判别器精确的区分,应该可以得到一个更精确的条件生成网络。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Reddit、Discord等社媒网站抓取总结:如何更高效实现网页抓取?

有效的网络抓取需要采取战略方法来克服挑战并确保最佳数据提取。让我们深入研究一些关键实践,这些实践将使您能够掌握复杂的网络抓取。 一、了解 Web 抓取检测 在深入探讨最佳实践之前,让我们先了解一下网站如何识别和抵御网络爬虫。了解您在这一过程中…

隐藏element的DateTimePicker组件自带的清空按钮

管理台页面使用到el-date-picker,type datetimerange 但是组件自带了清空按钮,实际上这个控件业务上代表开始时间和结束时间是一个必填选项,所有想要把清空按钮隐藏掉。 查看了文档https://element.eleme.io/#/zh-CN/component/datetime-p…

如何使用k8s安装nexus3呢

百度云盘地址 链接:https://pan.baidu.com/s/1YN1qc2RvzTU3Ba6L_zCTdg?pwd5z1i 提取码:5z1i 下载后上传到本地服务器 docker load -i nexus3 创建 nexus-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:name: nexus3-deployment spec…

visualbox搭建linux环境双网卡配置

文章目录 1. 双网卡模式简介2. 网络模式配置2.1 virtualBox说明2.2 host-only网络模式配置2.3 NAT网络模式配置 3. 虚拟主机网络设置3.1 网卡一设置3.2 网卡二设置 4. 网卡配置5. ssh访问 本篇的目的是为了搭建本地的linux测试环境用。 1. 双网卡模式简介 双网卡网络模式简介 …

数据仓库 基础教程

数据仓库 基础教程 1. 数据仓库概述 数据仓库(Data Warehouse,简称DW或者DWH)是通过集成来自多个异构数据源的数据来构建的。它支持分析报告、结构化和/或特别查询和决策制定。本教程采用循序渐进的方法来解释数据仓库的所有必要概念。 “数据仓库”一词最早是由Bill Inmon在1…

JDBC之API(DriverManager)详解

之前在 JDBC 的快速入门写代码的时候,遇到了很多的API。这篇博客主要学习一些API。 目录 一、API(介绍) 二、JDBC之API——DriverManager (1)DriverManager (获取 Connection 的连接对象) 1、…

路由器的Wi-Fi性能是否限制了你的网速?这里有你想要的答案

​你的无线网络速度阻碍了你吗?信不信由你,升级到超快的互联网计划可能不值得。以下是如何判断路由器的Wi-Fi速度是否阻碍了你,以及你能做些什么。 如何测试你的Wi-Fi速度 比较你的有线速度和无线速度可以表明你的路由器是否阻碍了你。虽然很多人认为“Wi-Fi”和“互联网”…

rknn转换后精度差异很大,失真算子自纠

下面是添加了详细注释的优化代码: import cv2 import numpy as np import onnx import onnxruntime as rt from onnx import helper, shape_inferencedef get_all_node_names(model):"""获取模型中所有节点的名称。参数:model (onnx.ModelProto): O…

现代易货交易:重塑物品交换的新纪元

在数字时代的浪潮中,交易模式正在经历一场革命。其中,现代易货交易模式以其独特的魅力,逐渐在市场中崭露头角。这种交易模式不仅是对古老“以物换物”的复兴,更是对物品价值和交换方式的全新定义。 现代易货:物品交换的…

openppp2 命令行接口详解

openppp2 是一个工作在 OSI/3 Layer 网络通信层的虚拟以太网工具链的开源软件,在查阅本文之前,人们可以查阅以下资料。 开源仓库: liulilittle/openppp2: PPP PRIVATE NETWORK™ 2 VPN Next Generation Reliable and Secure Virtual Etherne…

LeetCode 19.删除链表的倒数第N个结点

链接 https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/ 题目: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5…

电动汽车厂商Rivian将全新设计元素融入由虚幻引擎驱动的车机界面

Rivian Automotive(简称:“Rivian”),是美国一家电动汽车厂商,该品牌创办于2009年,总部位于加州埃尔文,专注于生产电动皮卡车Rivian R1T和电动SUV Rivian R1S。 Rivian的车主们正追寻这样一条道…

Qt坐标系统

目录 概述 渲染 逻辑表示 锯齿绘制 坐标转换 模拟时钟示例 Window-Viewport转换 概述 坐标系统由QPainter类控制。与QPaintDevice和QPaintEngine类一起,QPainter构成了Qt绘画系统的基础。QPainter用于执行绘制操作,QPaintDevice是一个二维空间的抽…

番外篇 | YOLOv8算法解析和实战应用:车辆检测 + 车辆追踪 + 行驶速度计算

前言:Hello大家好,我是小哥谈。YOLOv8是ultralytics公司在2023年1月10号开源的,是YOLOv5的下一个重大更新版本,目前支持图像分类、物体检测和实例分割任务,在还没有开源时就收到了用户的广泛关注。它是一个SOTA模型,建立在以前YOLO版本的成功基础上,并引入了新的功能和改…

开发中遇到的错误 - @SpringBootTest 注解爆红

我在使用 SpringBootTest 注解的时候爆红了&#xff0c;ait 回车也导不了包&#xff0c;后面发现是因为没有加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>…

【shell脚本速成】函数

文章目录 一、函数1.1、函数介绍1.2、函数定义1.3、函数调用 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xf…

网络虚拟化考题

vrrp讲过吗&#xff1f;&#xff1f;&#xff1f; d 每一层都是什么设备啊 abcd 为啥流量不可控不可视 c是啥意思 讲过吗 abc aNET网络虚拟化是啥啊 为啥&#xff1f;&#xff1f; 啥是CDN&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;

Java数据类型与运算符

1. 变量和类型 变量指的是程序运行时可变的量&#xff0c;相当于开辟一块空间来保存一些数据。 类型则是对变量的种类进行了划分&#xff0c;不同类型的变量具有不同的特性。 1.1 整型变量&#xff08;重点&#xff09; 基本语法格式&#xff1a; int 变量名 初始值;代码示…

舔狗日记Puls微信小程序源码

源码介绍&#xff1a; 这是一款舔狗日记Puls微信小程序源码&#xff0c;提供每日一舔的功能&#xff0c;让你舔到最后&#xff0c;什么都有&#xff01; 源码通过API获取一些舔狗日记&#xff0c;内置了100多句舔狗日记&#xff0c;让你摆脱上班摸鱼的无聊时光&#xff0c; …

TIM: A Time Interval Machine for Audio-Visual Action Recognition

标题&#xff1a;TIM&#xff1a;一种用于视听动作识别的时间间隔机器 源文链接&#xff1a;openaccess.thecvf.com/content/CVPR2024/papers/Chalk_TIM_A_Time_Interval_Machine_for_Audio-Visual_Action_Recognition_CVPR_2024_paper.pdfhttps://openaccess.thecvf.com/cont…