CGAN原理讲解与源码

1.CGAN原理

生成器,输入的是c和z,z是随机噪声,c是条件,对应MNIST数据集,要求规定生成数字是几。
输出是生成的虚假图片。
在这里插入图片描述

判别器的输入是
1.生成器输出的虚假图片x;
2.对应图片的标签c

在这里插入图片描述
来自真实数据集,且标签是对的,就是1
如果是生成器生成的虚假照片就直接是1,都不需要看是否与标签对应

上面第二张图的意思就是,当图片是来自真实数据集,再来看是否与标签对应

2.CGAN损失函数

在这里插入图片描述
上面这个值,生成器越小越好,即判别器认为真实图片是真实图片的概率越低越好,认为虚假图片是真实图片的概率越高越好
判别器越大越好,即判别器认为真实图片是真实图片的概率越大越好,认为虚假图片是真实图片的概率越小越好

criterion(output, label)

在判别器中,
1)output是预测来自真实数据集的图片和标签是否是真实且符合标签的概率,label是1
2)output是预测虚假图片是否是虚假图片的概率,label是0
在生成器中,
output是判别器预测虚假图片是否是真实图片的概率,label是1
以上三种,都是交叉熵越小越好

3.生成器和判别器的源码

class Generator(nn.Module):def __init__(self, num_channel=1, nz=100, nc=10, ngf=64):super(Generator, self).__init__()self.main = nn.Sequential(# 输入维度 110 x 1 x 1nn.ConvTranspose2d(nz + nc, ngf * 8, 4, 1, 0, bias=False),nn.BatchNorm2d(ngf * 8),nn.ReLU(True),# 特征维度 (ngf*8) x 4 x 4nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 4),nn.ReLU(True),# 特征维度 (ngf*4) x 8 x 8nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf * 2),nn.ReLU(True),# 特征维度 (ngf*2) x 16 x 16nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),nn.BatchNorm2d(ngf),nn.ReLU(True),# 特征维度 (ngf) x 32 x 32nn.ConvTranspose2d(ngf, num_channel, 4, 2, 1, bias=False),nn.Tanh()# 特征维度. (num_channel) x 64 x 64)self.apply(weights_init)def forward(self, input_z, onehot_label):input_ = torch.cat((input_z, onehot_label), dim=1)n, c = input_.size()input_ = input_.view(n, c, 1, 1)return self.main(input_)class Discriminator(nn.Module):def __init__(self, num_channel=1, nc=10, ndf=64):super(Discriminator, self).__init__()self.main = nn.Sequential(# 输入维度 (num_c3# channel+nc) x 64 x 64  1*64*64的图像和10维的类别   10维类别先转换成10*64*64    然后合并就是11*64*64# 输入通道  输出通道   卷积核的大小   步长  填充#原始输入张量:b 11 64  64nn.Conv2d(num_channel + nc, ndf, 4, 2, 1, bias=False),   #b  64  32  32nn.LeakyReLU(0.2, inplace=True),# 特征维度 (ndf) x 32 x 32nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),  #b   64*2   16  16nn.BatchNorm2d(ndf * 2),nn.LeakyReLU(0.2, inplace=True),# 特征维度 (ndf*2) x 16 x 16nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),    #b   64*4   8    8nn.BatchNorm2d(ndf * 4),nn.LeakyReLU(0.2, inplace=True),# 特征维度 (ndf*4) x 8 x 8nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),    #b   64*8    4    4nn.BatchNorm2d(ndf * 8),nn.LeakyReLU(0.2, inplace=True),# 特征维度 (ndf*8) x 4 x 4nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),        #b   1    1    1      其实就是一个数值,区间在正无穷到负无穷之间nn.Sigmoid())self.apply(weights_init)def forward(self, images, onehot_label):device = 'cuda' if torch.cuda.is_available() else 'cpu'h, w = images.shape[2:]n, nc = onehot_label.shape[:2]label = onehot_label.view(n, nc, 1, 1) * torch.ones([n, nc, h, w]).to(device)input_ = torch.cat([images, label], 1)return self.main(input_)

4.训练过程

MODEL_G_PATH = "./"
LOG_G_PATH = "Log_G.txt"
LOG_D_PATH = "Log_D.txt"
IMAGE_SIZE = 64
BATCH_SIZE = 128
WORKER = 1
LR = 0.0002
NZ = 100
NUM_CLASS = 10
EPOCH = 10data_loader = loadMNIST(img_size=IMAGE_SIZE, batch_size=BATCH_SIZE)  #原始图片宽高是28*28的,给改变成64*64
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
netG = Generator().to(device)
netD = Discriminator().to(device)
criterion = nn.BCELoss()
real_label = 1.
fake_label = 0.
optimizerD = optim.Adam(netD.parameters(), lr=LR, betas=(0.5, 0.999))
optimizerG = optim.Adam(netG.parameters(), lr=LR, betas=(0.5, 0.999))g_writer = LossWriter(save_path=LOG_G_PATH)
d_writer = LossWriter(save_path=LOG_D_PATH)fix_noise = torch.randn(BATCH_SIZE, NZ, device=device)
fix_input_c = (torch.rand(BATCH_SIZE, 1) * NUM_CLASS).type(torch.LongTensor).squeeze().to(device)
fix_input_c = onehot(fix_input_c, NUM_CLASS)img_list = []
G_losses = []
D_losses = []
iters = 0print("开始训练>>>")
for epoch in range(EPOCH):print("正在保存网络并评估...")save_network(MODEL_G_PATH, netG, epoch)with torch.no_grad():fake_imgs = netG(fix_noise, fix_input_c).detach().cpu()images = recover_image(fake_imgs)full_image = np.full((5 * 64, 5 * 64, 3), 0, dtype="uint8")for i in range(25):row = i // 5col = i % 5full_image[row * 64:(row + 1) * 64, col * 64:(col + 1) * 64, :] = images[i]plt.imshow(full_image)#plt.show()plt.imsave("{}.png".format(epoch), full_image)for data in data_loader:##################################################判别器交叉熵越小越好# 1. 更新判别器D: 最大化 log(D(x)) + log(1 - D(G(z)))# 等同于最小化 - log(D(x)) - log(1 - D(G(z)))#################################################netD.zero_grad()real_imgs, input_c = data   #这里的input_c其实就是数据集每一批中的每个图片对应的标签input_c = input_c.to(device)input_c = onehot(input_c, NUM_CLASS).to(device)# 1.1 来自数据集的样本#这里这一步就是想训练判别器,能够识别出是否真实图片,以及图片与对应的标签是否对应real_imgs = real_imgs.to(device)b_size = real_imgs.size(0)label = torch.full((b_size,), real_label, dtype=torch.float, device=device)#上面的torch.full是生成一维的 b_size这么多的,填充值为1.的张量# real_label = 1.# fake_label = 0.# 使用鉴别器对数据集样本做判断output = netD(real_imgs, input_c).view(-1)   #view() 方法被用来将模型输出的张量进行扁平化操作,即将张量中的所有元素都展开成一个一维向量# 计算交叉熵损失 -log(D(x))errD_real = criterion(output, label)# 对判别器进行梯度回传errD_real.backward()D_x = output.mean().item()    #对同一批预测结果的交叉熵取平均值## 1.2 生成随机向量   这一步想要训练判别器是否能够识别出是虚假图片noise = torch.randn(b_size, NZ, device=device)# 生成随机标签input_c = (torch.rand(b_size, 1) * NUM_CLASS).type(torch.LongTensor).squeeze().to(device)input_c = onehot(input_c, NUM_CLASS)#fix_noise = torch.randn(BATCH_SIZE, NZ, device=device)#fix_input_c = (torch.rand(BATCH_SIZE, 1) * NUM_CLASS).type(torch.LongTensor).squeeze().to(device)#fix_input_c = onehot(fix_input_c, NUM_CLASS)# 来自生成器生成的样本fake = netG(noise, input_c)label.fill_(fake_label)# real_label = 1.# fake_label = 0.# 使用鉴别器对生成器生成样本做判断output = netD(fake.detach(), input_c).view(-1)   #view() 方法被用来将模型输出的张量进行扁平化操作,即将张量中的所有元素都展开成一个一维向量# 计算交叉熵损失 -log(1 - D(G(z)))errD_fake = criterion(output, label)# 对判别器进行梯度回传errD_fake.backward()D_G_z1 = output.mean().item()# 对判别器计算总梯度,-log(D(x))-log(1 - D(G(z)))errD = errD_real + errD_fake# 更新判别器optimizerD.step()################################################## 2. 更新生成器G: 最小化 log(D(x)) + log(1 - D(G(z))),# 等同于最小化log(1 - D(G(z))),即最小化-log(D(G(z)))# 也就等同于最小化-(log(D(G(z)))*1+log(1-D(G(z)))*0)# 令生成器样本标签值为1,上式就满足了交叉熵的定义#################################################netG.zero_grad()# 对于生成器训练,令生成器生成的样本为真,label.fill_(real_label)# real_label = 1.# fake_label = 0.output = netD(fake, input_c).view(-1)# 对生成器计算损失errG = criterion(output, label)# 因为这里判别器的角度label真实应该是0,但是站在生成器的角度,label真实应该是1,即生成器希望生成的虚假图片让判别器识别的时候,会误以为1才比较好,即误以为是真实的图片# 所以生成器交叉熵也是越小越好# 对生成器进行梯度回传errG.backward()D_G_z2 = output.mean().item()# 更新生成器optimizerG.step()# 输出损失状态if iters % 5 == 0:print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'% (epoch, EPOCH, iters % len(data_loader), len(data_loader),errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))d_writer.add(loss=errD.item(), i=iters)g_writer.add(loss=errG.item(), i=iters)# 保存损失记录G_losses.append(errG.item())D_losses.append(errD.item())iters += 1

5.关于交叉熵

熵代表确定性,熵越小越好,说明确定性越好
在这里,因为参照的是真实标签,它的熵是0
而交叉熵-熵=相对熵
故相对熵在预测情况相对真实情况的时候,相对熵=交叉熵,相对熵越小,说明预测情况越接近真实情况;
同理,交叉熵越小,说明预测情况越接近真实情况。

在二分类0,1任务中,经过卷积、正则化、激活函数ReLU等操作之后,假如生成了一个(B,1,1,1)的张量,每个值在(无穷小,无穷大)之间,经过sigmoid函数,会变成一个(B,1,1,1)的张量,数值h在(0,1)之间,如果这个h>0.5说明模型预测的是1,如果h<0.5说明模型预测的是0,但是这是模型预测的标签值y*,而还有个真实标签值y。假如现在h=0.6,那么说明模型预测的标签y*是1,真实标签却是0,

交叉熵= -y(lgh) -(1-y)(lg(1-h))
即当y=1时,交叉熵是-lgh 这个情况下,h越大越好
当y=0时,交叉熵是-(lg(1-h)) 这个情况下,h越小越好

6.训练过程运行结果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

7.测试结果

在这里插入图片描述

测试代码


NZ = 100
NUM_CLASS = 10
BATCH_SIZE = 10
DEVICE = "cpu"# fix_input_c = (torch.rand(BATCH_SIZE, 1) * NUM_CLASS).type(torch.LongTensor).squeeze().to(DEVICE)netG = Generator()
netG = restore_network("./", "49", netG)
fix_noise = torch.randn(BATCH_SIZE, NZ, device=DEVICE)
fix_input_c = torch.tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
device = "cuda" if torch.cuda.is_available() else "cpu"
fix_input_c = onehot(fix_input_c, NUM_CLASS)
fix_input_c = fix_input_c.to(device)
fix_noise = fix_noise.to(device)
netG = netG.to(device)
#fake_imgs = netG(fix_noise, fix_input_c).detach().cpu()# images = recover_image(fake_imgs)
# full_image = np.full((1 * 64, 10 * 64, 3), 0, dtype="uint8")
# for i in range(10):
#     row = i // 10
#     col = i % 10
#     full_image[row * 64:(row + 1) * 64, col * 64:(col + 1) * 64, :] = images[i]#fix_noise = torch.randn(BATCH_SIZE, NZ, device=DEVICE)
full_image = np.full((10 * 64, 10 * 64, 3), 0, dtype="uint8")
for num in range(10):input_c = torch.tensor(np.ones(10, dtype="int64") * num)input_c = onehot(input_c, NUM_CLASS)fix_noise = fix_noise.to(device)input_c = input_c.to(device)fake_imgs = netG(fix_noise, input_c).detach().cpu()images = recover_image(fake_imgs)for i in range(10):row = numcol = i % 10full_image[row * 64:(row + 1) * 64, col * 64:(col + 1) * 64, :] = images[i]plt.imshow(full_image)
plt.show()
plt.imsave("hah.png", full_image)

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

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

相关文章

什么是高性能计算岗位

最近有小伙伴咨询什么是高性能计算岗位。 1、什么是高性能计算 高性能计算&#xff0c;在很多招聘信息中也会被标注为 HPC&#xff0c;是 High Performance Computing 的缩写。 目前很多 AI 公司或者从事 AI 的部门招聘都有这个岗位需求&#xff0c;我从某聘上截取了几个有代…

Shopee买家号想要多开怎么解决?

拥有多个Shopee买家号有很多优势。多账号可以帮助卖家获得更多流量、还能帮助提供关键词排名、提高销量等。 但是要管理多个Shopee买家号并非易事。面对不同账号的登录、注销和切换&#xff0c;可能会花费大量的时间和精力。而且&#xff0c;Shopee平台对于使用同一IP地址同时登…

Android Termux SFTP如何实现远程文件传输

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…

微信api开发接口文档

简要描述&#xff1a; 搜索联系人 请求URL&#xff1a; http://域名地址/searchUser 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wI…

通俗易懂的spring Cloud;业务场景介绍 二、Spring Cloud核心组件:Eureka 、Feign、Ribbon、Hystrix、zuul

文章目录 通俗易懂的spring Cloud一、业务场景介绍二、Spring Cloud核心组件&#xff1a;Eureka三、Spring Cloud核心组件&#xff1a;Feign四、Spring Cloud核心组件&#xff1a;Ribbon五、Spring Cloud核心组件&#xff1a;Hystrix六、Spring Cloud核心组件&#xff1a;Zuul七…

redisserver一闪而过 redis闪退解决版本

1.进入Redis根目录 2.输入redis-server 或 redis-server.exe redis.windows.conf 启动redis命令&#xff0c;看是否成功。 执 一闪而过的问题 可能是因为已启动或者其他问题&#xff0c;需要重启 先输入redis-cli.exe再输入shutdown再输入redis-server.exe redis.windows.c…

智能优化算法应用:基于被囊群算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于被囊群算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于被囊群算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.被囊群算法4.实验参数设定5.算法结果6.参考文献7.…

交换技术-电路交换-报文交换-分组交换

交换技术是指主机之间、通信设备之间或主机与通信设备之间为交换信息所采用的数据格式和交换装置的方式。按交换技术可分为&#xff1a;电路交换、报文交换和分组交换。 电路交换 交换(switching)&#xff0c;就是按照某种方式动态地分配传输线路的资源。 电路交换是在源结点…

影响机器视觉测量精度的因素有哪些?

精度测量取决于分辨率 在机器视觉测量中提供高精度和低不确定度的决定性因素是获取的图像的分辨率。在这种情况下&#xff0c;术语分辨率 &#xff08;或图像分辨率&#xff09;意味着以实际单位的单个像素的大小。简而言之&#xff0c;如果一个摄像机传感器在水平方向上包含…

Python GUI 图形用户界面程序设计,Python自带 tkinter 库

文章目录 前言GUI介绍简单操作tkinter组件介绍向窗体中添加按钮控件使用文本框控件使用菜单控件使用标签控件使用单选按钮和复选按钮组件使用绘图组件关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集…

Redis深入理解-三次握手、槽位机制

Redis 节点之间的三次握手原理分析 比如多台 Redis 之间要建立集群&#xff0c;那么连接其中的一台 Redis 客户端&#xff0c;向其他 Redis 发送 meet 命令即可通知其他节点&#xff0c;那么发送 meet 命令给其他节点后&#xff0c;对方也会在内存中创建一个 ClusterNode 结构…

手摸手Element-ui路由VueRoute

后端WebAPI准备 https://router.vuejs.org/zh/guide/ https://v3.router.vuejs.org/zh/installation.html <template><el-table:data"tableData"style"width: 100%":row-class-name"tableRowClassName"><!-- <el-table-colum…