43这周打卡——生成手势图像 (可控制生成)

目录

前言

1.导入数据及数据可视化

2.构建模型

3.训练模型

4.模型分析并生成指定图像

总结


前言

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

1.导入数据及数据可视化

from torchvision       import datasets, transforms
from torch.autograd    import Variable
from torchvision.utils import save_image, make_grid
from torchsummary      import summary
import matplotlib.pyplot as plt
import numpy             as np
import torch.nn          as nn
import torch.optim       as optim
import torchdevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
devicebatch_size = 128train_transform = transforms.Compose([transforms.Resize(128),transforms.ToTensor(),transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5])])train_dataset = datasets.ImageFolder(root='data/data/rps/', transform=train_transform)train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True,num_workers=6)# 可视化第一个 batch 的数据
def show_images(dl):for images, _ in dl:fig, ax = plt.subplots(figsize=(10, 10))ax.set_xticks([]); ax.set_yticks([])ax.imshow(make_grid(images.detach(), nrow=16).permute(1, 2, 0))breakshow_images(train_loader)


2.构建模型

latent_dim    = 100
n_classes     = 3
embedding_dim = 100# 自定义权重初始化函数,用于初始化生成器和判别器的权重
def weights_init(m):# 获取当前层的类名classname = m.__class__.__name__# 如果当前层是卷积层(类名中包含 'Conv' )if classname.find('Conv') != -1:# 使用正态分布随机初始化权重,均值为0,标准差为0.02torch.nn.init.normal_(m.weight, 0.0, 0.02)# 如果当前层是批归一化层(类名中包含 'BatchNorm' )elif classname.find('BatchNorm') != -1:# 使用正态分布随机初始化权重,均值为1,标准差为0.02torch.nn.init.normal_(m.weight, 1.0, 0.02)# 将偏置项初始化为全零torch.nn.init.zeros_(m.bias)class Generator(nn.Module):def __init__(self):super(Generator, self).__init__()# 定义条件标签的生成器部分,用于将标签映射到嵌入空间中# n_classes:条件标签的总数# embedding_dim:嵌入空间的维度self.label_conditioned_generator = nn.Sequential(nn.Embedding(n_classes, embedding_dim),  # 使用Embedding层将条件标签映射为稠密向量nn.Linear(embedding_dim, 16)             # 使用线性层将稠密向量转换为更高维度)# 定义潜在向量的生成器部分,用于将噪声向量映射到图像空间中# latent_dim:潜在向量的维度self.latent = nn.Sequential(nn.Linear(latent_dim, 4*4*512),  # 使用线性层将潜在向量转换为更高维度nn.LeakyReLU(0.2, inplace=True)  # 使用LeakyReLU激活函数进行非线性映射)# 定义生成器的主要结构,将条件标签和潜在向量合并成生成的图像self.model = nn.Sequential(# 反卷积层1:将合并后的向量映射为64x8x8的特征图nn.ConvTranspose2d(513, 64*8, 4, 2, 1, bias=False),nn.BatchNorm2d(64*8, momentum=0.1, eps=0.8),  # 批标准化nn.ReLU(True),  # ReLU激活函数# 反卷积层2:将64x8x8的特征图映射为64x4x4的特征图nn.ConvTranspose2d(64*8, 64*4, 4, 2, 1, bias=False),nn.BatchNorm2d(64*4, momentum=0.1, eps=0.8),nn.ReLU(True),# 反卷积层3:将64x4x4的特征图映射为64x2x2的特征图nn.ConvTranspose2d(64*4, 64*2, 4, 2, 1, bias=False),nn.BatchNorm2d(64*2, momentum=0.1, eps=0.8),nn.ReLU(True),# 反卷积层4:将64x2x2的特征图映射为64x1x1的特征图nn.ConvTranspose2d(64*2, 64*1, 4, 2, 1, bias=False),nn.BatchNorm2d(64*1, momentum=0.1, eps=0.8),nn.ReLU(True),# 反卷积层5:将64x1x1的特征图映射为3x64x64的RGB图像nn.ConvTranspose2d(64*1, 3, 4, 2, 1, bias=False),nn.Tanh()  # 使用Tanh激活函数将生成的图像像素值映射到[-1, 1]范围内)def forward(self, inputs):noise_vector, label = inputs# 通过条件标签生成器将标签映射为嵌入向量label_output = self.label_conditioned_generator(label)# 将嵌入向量的形状变为(batch_size, 1, 4, 4),以便与潜在向量进行合并label_output = label_output.view(-1, 1, 4, 4)# 通过潜在向量生成器将噪声向量映射为潜在向量latent_output = self.latent(noise_vector)# 将潜在向量的形状变为(batch_size, 512, 4, 4),以便与条件标签进行合并latent_output = latent_output.view(-1, 512, 4, 4)# 将条件标签和潜在向量在通道维度上进行合并,得到合并后的特征图concat = torch.cat((latent_output, label_output), dim=1)# 通过生成器的主要结构将合并后的特征图生成为RGB图像image = self.model(concat)return image
generator = Generator().to(device)
generator.apply(weights_init)
print(generator)from torchinfo import summarysummary(generator)a = torch.ones(100)
b = torch.ones(1)
b = b.long()
a = a.to(device)
b = b.to(device)import torch
import torch.nn as nnclass Discriminator(nn.Module):def __init__(self):super(Discriminator, self).__init__()# 定义一个条件标签的嵌入层,用于将类别标签转换为特征向量self.label_condition_disc = nn.Sequential(nn.Embedding(n_classes, embedding_dim),     # 嵌入层将类别标签编码为固定长度的向量nn.Linear(embedding_dim, 3*128*128)         # 线性层将嵌入的向量转换为与图像尺寸相匹配的特征张量)# 定义主要的鉴别器模型self.model = nn.Sequential(nn.Conv2d(6, 64, 4, 2, 1, bias=False),       # 输入通道为6(包含图像和标签的通道数),输出通道为64,4x4的卷积核,步长为2,padding为1nn.LeakyReLU(0.2, inplace=True),             # LeakyReLU激活函数,带有负斜率,增加模型对输入中的负值的感知能力nn.Conv2d(64, 64*2, 4, 3, 2, bias=False),    # 输入通道为64,输出通道为64*2,4x4的卷积核,步长为3,padding为2nn.BatchNorm2d(64*2, momentum=0.1, eps=0.8),  # 批量归一化层,有利于训练稳定性和收敛速度nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(64*2, 64*4, 4, 3, 2, bias=False),  # 输入通道为64*2,输出通道为64*4,4x4的卷积核,步长为3,padding为2nn.BatchNorm2d(64*4, momentum=0.1, eps=0.8),nn.LeakyReLU(0.2, inplace=True),nn.Conv2d(64*4, 64*8, 4, 3, 2, bias=False),  # 输入通道为64*4,输出通道为64*8,4x4的卷积核,步长为3,padding为2nn.BatchNorm2d(64*8, momentum=0.1, eps=0.8),nn.LeakyReLU(0.2, inplace=True),nn.Flatten(),                               # 将特征图展平为一维向量,用于后续全连接层处理nn.Dropout(0.4),                            # 随机失活层,用于减少过拟合风险nn.Linear(4608, 1),                         # 全连接层,将特征向量映射到输出维度为1的向量nn.Sigmoid()                                # Sigmoid激活函数,用于输出范围限制在0到1之间的概率值)def forward(self, inputs):img, label = inputs# 将类别标签转换为特征向量label_output = self.label_condition_disc(label)# 重塑特征向量为与图像尺寸相匹配的特征张量label_output = label_output.view(-1, 3, 128, 128)# 将图像特征和标签特征拼接在一起作为鉴别器的输入concat = torch.cat((img, label_output), dim=1)# 将拼接后的输入通过鉴别器模型进行前向传播,得到输出结果output = self.model(concat)return outputdiscriminator = Discriminator().to(device)
discriminator.apply(weights_init)
print(discriminator)summary(discriminator)a = torch.ones(2,3,128,128)
b = torch.ones(2,1)
b = b.long()
a = a.to(device)
b = b.to(device)c = discriminator((a,b))
c.size()


3.训练模型

adversarial_loss = nn.BCELoss() def generator_loss(fake_output, label):gen_loss = adversarial_loss(fake_output, label)return gen_lossdef discriminator_loss(output, label):disc_loss = adversarial_loss(output, label)return disc_losslearning_rate = 0.0002G_optimizer = optim.Adam(generator.parameters(),     lr = learning_rate, betas=(0.5, 0.999))
D_optimizer = optim.Adam(discriminator.parameters(), lr = learning_rate, betas=(0.5, 0.999))# 设置训练的总轮数
num_epochs = 300
# 初始化用于存储每轮训练中判别器和生成器损失的列表
D_loss_plot, G_loss_plot = [], []# 循环进行训练
for epoch in range(1, num_epochs + 1):# 初始化每轮训练中判别器和生成器损失的临时列表D_loss_list, G_loss_list = [], []# 遍历训练数据加载器中的数据for index, (real_images, labels) in enumerate(train_loader):# 清空判别器的梯度缓存D_optimizer.zero_grad()# 将真实图像数据和标签转移到GPU(如果可用)real_images = real_images.to(device)labels      = labels.to(device)# 将标签的形状从一维向量转换为二维张量(用于后续计算)labels = labels.unsqueeze(1).long()# 创建真实目标和虚假目标的张量(用于判别器损失函数)real_target = Variable(torch.ones(real_images.size(0), 1).to(device))fake_target = Variable(torch.zeros(real_images.size(0), 1).to(device))# 计算判别器对真实图像的损失D_real_loss = discriminator_loss(discriminator((real_images, labels)), real_target)# 从噪声向量中生成假图像(生成器的输入)noise_vector = torch.randn(real_images.size(0), latent_dim, device=device)noise_vector = noise_vector.to(device)generated_image = generator((noise_vector, labels))# 计算判别器对假图像的损失(注意detach()函数用于分离生成器梯度计算图)output = discriminator((generated_image.detach(), labels))D_fake_loss = discriminator_loss(output, fake_target)# 计算判别器总体损失(真实图像损失和假图像损失的平均值)D_total_loss = (D_real_loss + D_fake_loss) / 2D_loss_list.append(D_total_loss.item())# 反向传播更新判别器的参数D_total_loss.backward()D_optimizer.step()# 清空生成器的梯度缓存G_optimizer.zero_grad()# 计算生成器的损失G_loss = generator_loss(discriminator((generated_image, labels)), real_target)G_loss_list.append(G_loss.item())# 反向传播更新生成器的参数G_loss.backward()G_optimizer.step()# 打印当前轮次的判别器和生成器的平均损失print('Epoch: [%d/%d]: D_loss: %.3f, G_loss: %.3f' % ((epoch), num_epochs, torch.mean(torch.FloatTensor(D_loss_list)), torch.mean(torch.FloatTensor(G_loss_list))))# 将当前轮次的判别器和生成器的平均损失保存到列表中D_loss_plot.append(torch.mean(torch.FloatTensor(D_loss_list)))G_loss_plot.append(torch.mean(torch.FloatTensor(G_loss_list)))if epoch%10 == 0:# 将生成的假图像保存为图片文件save_image(generated_image.data[:50], './images/sample_%d' % epoch + '.png', nrow=5, normalize=True)# 将当前轮次的生成器和判别器的权重保存到文件torch.save(generator.state_dict(), './training_weights/generator_epoch_%d.pth' % (epoch))torch.save(discriminator.state_dict(), './training_weights/discriminator_epoch_%d.pth' % (epoch))

4.模型分析并生成指定图像

G_loss_list = [i.item() for i in G_loss_plot]
D_loss_list = [i.item() for i in D_loss_plot]import matplotlib.pyplot as plt
#隐藏警告
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        #分辨率plt.figure(figsize=(8,4))
plt.title("Generator and Discriminator Loss During Training")
plt.plot(G_loss_list,label="G")
plt.plot(D_loss_list,label="D")
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()# 导入所需的库
from numpy.random import randint, randn
from numpy        import linspace
from matplotlib   import pyplot, gridspec# 导入生成器模型
generator.load_state_dict(torch.load('./training_weights/generator_epoch_300.pth'), strict=False)
generator.eval()   interpolated = randn(100)  # 生成两个潜在空间的点
# 将数据转换为torch张量并将其移至GPU(假设device已正确声明为GPU)
interpolated = torch.tensor(interpolated).to(device).type(torch.float32)label  = 0  # 手势标签,可在0,1,2之间选择
labels = torch.ones(1) * label
labels = labels.to(device).unsqueeze(1).long()# 使用生成器生成插值结果
predictions = generator((interpolated, labels))
predictions = predictions.permute(0,2,3,1).detach().cpu()#隐藏警告
import warnings
warnings.filterwarnings("ignore")               #忽略警告信息
plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号
plt.rcParams['figure.dpi']         = 100        #分辨率plt.figure(figsize=(8, 3))pred = (predictions[0, :, :, :] + 1 ) * 127.5
pred = np.array(pred)
plt.imshow(pred.astype(np.uint8))
plt.show()


总结

在本次实验中,我们完成了数据准备、模型构建、训练与结果分析的完整流程。

数据准备方面,采用 torchvision.datasets.ImageFolder 从自定义文件夹中加载图像数据,并依次进行缩放、张量化和归一化等预处理操作。为了直观了解输入情况,利用 show_images 函数展示了训练集中首个批次的图像,这有助于确认数据管道是否正常。

模型设计部分包括生成器和判别器两个核心模块。生成器接收潜在向量与类别标签作为输入,其中类别标签先经过嵌入层映射为特征向量,再与潜在向量结合,经由多层反卷积逐步生成目标图像。判别器则接收图像和类别标签作为输入,将标签转化为特征图并与图像拼接,随后通过多层卷积进行特征提取,最终输出一个标量用于判别真伪。此外,使用自定义的 weights_init 方法对模型参数进行初始化,保证了训练的稳定性。

训练过程中,损失函数选择了二元交叉熵(BCELoss),优化器采用 Adam,对生成器与判别器分别进行参数更新。具体流程为:在每个 epoch 内,判别器和生成器交替更新;对于每个 batch,先更新判别器,使其更好地区分真实与伪造图像,再更新生成器,使其生成的结果更具迷惑性。训练过程中,每隔 10 个 epoch 保存生成样本和模型权重,方便后续分析与复现。

结果分析环节,通过记录生成器和判别器的损失曲线,可以直观反映训练进展和收敛趋势。随着对抗博弈的进行,生成器不断提高欺骗判别器的能力,而判别器也在努力提升辨别水平,二者的竞争推动了模型整体性能的提升。

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

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

相关文章

TDengine 时间函数 TIMEDIFF() 用户手册

TDengine TIMEDIFF() 函数详细使用手册 目录 功能概述函数语法参数说明返回值说明版本变更说明技术特性使用场景及示例时间单位处理数据类型兼容性注意事项常见问题最佳实践 功能概述 TIMEDIFF() 函数用于计算两个时间戳的差值,返回 expr1 - expr2 的结果。结果…

【2025ICCV-持续学习方向】一种用于提示持续学习(Prompt-based Continual Learning, PCL)的新方法

1. 背景与问题 (Background & Problem):​​ ​持续学习 (CL):​​ 目标是在不遗忘旧任务知识的情况下,让模型持续学习一系列新任务。主要挑战是灾难性遗忘。 ​基于提示的持续学习 (PCL):​​ 利用预训练视觉Transformer (ViT),冻结其权重,通过微调称为“提示”(prompt…

2025 年 08 月 GitHub 十大热门项目排行榜

欢迎来到 2025 年 8 月 GitHub 热门开源项目排行榜!本月榜单集中展示了来自智能体平台、AI 编程助手、多模态角色系统、本地化部署工具到可视化白板与企业协同平台的多元创新。从构建 AI 助手中枢的 Archon,到终端 AI 编码拍档 Crush,再到虚拟…

LeetCode每日一题,2025-9-4

多数元素 投票法 让你找到序列中出现超过二分之一的元素,一定要记住这个规则。 记录两个值val和cnt,刚开始val为任意数,cnt0。 如果cnt是0,就把当前val num。接下来判断,ifnum val,则cnt ,e…

第7章 安全配置

7.1 安全概述 Jenkins安全威胁 常见安全风险: 访问控制风险: - 未授权访问Jenkins实例 - 权限提升攻击 - 横向移动攻击 - 敏感信息泄露代码执行风险: - 恶意脚本注入 - 构建脚本篡改 - 插件漏洞利用 - 远程代码执行数据安全风险: …

腾讯混元世界模型Voyager开源:单图生成3D世界的“核弹级”突破,游戏、VR、自动驾驶迎来新变量

当AI绘画、视频生成技术逐渐从“新鲜感”走向“实用化”,3D内容生成却始终卡在“效率低、成本高、门槛高”的瓶颈里。传统3D建模需要专业软件、大量人工调整,甚至依赖昂贵的硬件设备,让中小团队和个人创作者望而却步。 但腾讯AI实验室最近开…

数据库(基础操作)

SQL 结构化的查询语句 我们现在需要写SQL语句 --- 这个玩意儿就是数据库的操作语句我们的数据库就类似于一个excl表格它有n列,每一列为一个大类,数据以行存在,一行代表一个条目数据如:我现在想建立一个数据库保存学生的信息你需要…

linux ubi文件系统

1,UBI(Unsorted Block Images)是 Linux 内核中为原始 Flash 设备提供的一种抽象层,位于 MTD(Memory Technology Device)和文件系统(如 UBIFS)之间。它负责坏块管理、磨损均衡、逻辑卷…

深度厚金板PCB与厚铜PCB的区别

厚金板PCB和厚铜PCB在电子制造领域都有重要应用,它们有着不同的特点和适用场景。下面为你详细介绍二者的区别。厚金PCB是什么厚金PCB是在印制电路板表面镀上较厚金层的电路板。这层厚金能提升电路板的导电性、抗氧化性和耐磨性。在一些对信号传输要求极高、使用环境…

一阶低通滤波器应用示例(演示)

1. 代码 这段代码实现了一个一阶低通滤波器(也称为指数加权移动平均滤波器)。它适用于需要平滑数据、减少噪声的场合。以下是一些常见的应用场景: 传感器数据平滑:在嵌入式系统或物联网设备中,传感器(如温度…

RT-Thread源码分析字节实现socket源码

无论是客户端还是服务器程序,发送的底层都是发送AT指令:1)发送命令到串口;2)阻塞等待返回结果接收的底层都是1)阻塞等待;2)被唤醒后拷贝处理数据两者均由后台任务唤醒,后…

keil 5 STM32工程介绍

目录 一、工程文件介绍 1.自动生成的文件 2.自建文件 (1)USER 文件夹 (2)FWLIB 文件夹 (3)CMSIS 文件夹 二、工程创建教程 1.下载固件库 2.创建工程 (1)创建不完善的工程 …

AI大模型如何重塑日常?从智能办公到生活服务的5个核心改变

AI大模型重塑日常:从智能办公到生活服务的5个核心改变一、引言• 简述AI大模型技术的快速发展背景,说明其已从技术领域逐步渗透到大众日常生活• 提出核心观点:AI大模型正从办公和生活服务两大场景,深度改变人们的行为模式与…

迈威通信从送快递角度教你分清网络二层和三层

还在为网络里的二层、三层概念头大?其实就像送快递那么简单!今天迈威通信用最接地气的方式给你讲明白~网络传输 送快递?没错!二层网络:本地送货员负责同小区的包裹配送(局域网传输),就像小区里的快递站(对应设备:交换机)&#…

【Linux】网络安全管理:SELinux 和 防火墙联合使用 | Redhat

本专栏文章持续更新,新增内容使用蓝色表示。 往期相关内容 【Linux】权限管理详解(三):SELinux安全性管理 | Redhat-CSDN博客 【Linux】网络安全管理:Netfilter、nftables 与 Firewalld | Redhat_linux netfilter-C…

微论-构建完整的智能环:具身智能系统的层级化架构探析

### **构建完整的智能环:具身智能系统的层级化架构探析**#### **引言:迈向与现实交互的智能**人工智能的发展正经历一场从“虚拟”走向“现实”的范式迁移。具身智能,作为这一浪潮的核心,强调智能体必须拥有“身体”,并…

Spring如何解决循环依赖:深入理解三级缓存机制

Spring如何解决循环依赖:深入理解三级缓存机制 引言 在我们之前的文章中,我们探讨了什么是循环依赖以及它带来的问题。作为Java生态系统中最重要的框架之一,Spring Framework在处理循环依赖方面有着独特而精妙的解决方案。今天,让…

HTML第六课:表格展示

HTML第六课&#xff1a;表格展示学生花名册学生花名册 效果示列 代码展示 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang"zh-CN"> <head><meta …

医疗行业API管理优化:使用QuickAPI提高数据安全与接口性能

背景与挑战在医疗行业&#xff0c;特别是医院信息系统&#xff08;HIS&#xff09;或其他相关部门&#xff08;如实验室信息系统LIS、药品管理系统等&#xff09;&#xff0c;数据安全和隐私保护一直是核心问题。然而&#xff0c;许多医疗机构仍然面临着以下问题&#xff1a;数…

docker 部署RustDesk服务

最近要用到远程桌面服务&#xff0c;网上的资料很丰富&#xff0c;但是和我的情况有点点区别&#xff0c;我是要搭一台局域网使用的远程桌面服务。 首先是源的问题&#xff1a; 很多都是不能用的&#xff0c;我用的docker桌面版&#xff0c; 其他的不重要&#xff0c;源地址&…