当前位置: 首页 > news >正文

PyTorch实战——生成对抗网络数值数据生成

PyTorch实战——生成对抗网络数值数据生成

    • 0. 前言
    • 1. 独热编码 (One-hot Encoding)
    • 2. 使用 GAN 生成数值数据
      • 2.1 训练数据处理
      • 2.2 模型构建
      • 2.3 模型训练
    • 3. 生成器保存与加载
    • 相关链接

0. 前言

在本节中,构建并训练生成对抗网络 (Generative Adversarial Network, GAN),生成一个包含 10 个整数的序列,这些整数在 099 之间,并且都是 5 的倍数。主要步骤与生成指数增长曲线类似,唯一的区别是训练集不是数据点 (x, y),而是一个包含所有介于 099 之间且为 5 的倍数的整数序列。
在本节,首先学习如何将训练数据转换为神经网络能够理解的格式——独热编码 (one-hot encoding)。然后,将独热编码变量转换回 099 之间的整数,便于人类理解。换句话说,实际上是在将数据在可读格式与模型所需的格式之间进行转换。之后,将创建一个判别器和一个生成器,并训练 GAN,使用提前停止方法来判断训练何时结束。训练完成后,丢弃判别器,使用已训练好的生成器生成具有所需模式的整数序列。

1. 独热编码 (One-hot Encoding)

独热编码是一种在机器学习和数据预处理过程中用于将分类数据表示为二进制向量的技术。分类数据由类别或标签组成,例如颜色、动物种类等,这些数据本身不是数值型的。机器学习算法通常使用数值数据,因此需要将分类数据转换为数值格式。
假设处理颜色分类特征,鲜花的颜色可以是“红色”、“绿色”或“蓝色”。使用独热编码,每个类别表示为一个二进制向量,创建三个二进制列,每个类别对应一列。颜色“红色”的独热编码为 [1, 0, 0],颜色“绿色”的独热编码为 [0, 1, 0],颜色“蓝色”为 [0, 0, 1]。这样做能够保留分类信息,而不会引入类别之间的顺序关系,每个类别都是独立的。

(1) 定义 onehot_encoder() 函数,用于将整数转换为独热编码变量:

import torch
device="cuda" if torch.cuda.is_available() else "cpu"def onehot_encoder(position,depth):onehot=torch.zeros((depth,))onehot[position]=1return onehot

该函数接受两个参数:第一个参数 position 是值被设置为 1 的位置索引,第二个参数 depth 是独热编码变量的长度。例如,打印 onehot_encoder(1, 5)

print(onehot_encoder(1,5))

结果如下所示,可以看到一个五维张量,其中第二个位置(索引值为 1 )为 1,其余位置为 0

tensor([0., 1., 0., 0., 0.])

(2) 了解了独热编码的工作原理后,可以将 099 之间的任意整数转换为独热编码变量:

def int_to_onehot(number):onehot=onehot_encoder(number,100)return onehot

(3) 使用函数 int_to_onehot() 将数字 75 转换为一个 100 维的张量:

onehot75=int_to_onehot(75)
print(onehot75)

输出结果如下所示,结果为一个 100 维的张量,其中第 76 位(索引值为 75) 为 1,其余所有位置都为 0

tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

函数 int_to_onehot() 将整数转换为独热编码变量,即将人类可读的形式转换为模型可接受的形式。

(4) 接下来,将模型可接受的形式转换回人类可读的形式。假设有一个独热编码变量,定义函数函数 onehot_to_int() 将它转换为人类能够理解的整数:

def onehot_to_int(onehot):num=torch.argmax(onehot)return num.item()

函数 onehot_to_int() 接受参数 onehot,并根据值为 1 的位置转换为一个整数。测试 onehot_to_int() 函数,将刚才创建的独热编码张量 onehot75 作为输入:

print(onehot_to_int(onehot75))
# 75

2. 使用 GAN 生成数值数据

本节的目标是构建并训练一个模型,使得生成器能够生成一个由 10 个整数构成的序列,这些整数都是 5 的倍数。首先准备训练数据,然后将它们转换为模型可接受的数字。最后,使用训练好的生成器来生成所需模式。

2.1 训练数据处理

(1) 函数 gen_sequence() 生成一个由 10 个整数构成的序列,这些整数都是 5 的倍数:

def gen_sequence():indices = torch.randint(0, 20, (10,))values = indices*5return values  

首先使用 PyTorchrandint() 方法生成 10019 之间的整数。然后,将这些数字乘以 5,并将它们转换为 PyTorch 张量,得到 10 个都是 5 的倍数的整数。

(2) 尝试生成一组训练数据:

sequence=gen_sequence()
print(sequence)
# tensor([55, 55,  0, 25, 70, 15, 65, 75, 90, 80])

(3) 接下来,将每个数字转换为独热编码向量,以便可以将其输入到神经网络中:

import numpy as npdef gen_batch():# 创建一个由 10 个数字组成的序列,所有数字都是 5 的倍数sequence=gen_sequence()# 将每个整数转换为一个 100 维的独热编码变量batch=[int_to_onehot(i).numpy() for i in sequence]batch=np.array(batch)return torch.tensor(batch)
batch=gen_batch()

函数 gen_batch() 用于创建批数据,以便将它们输入到神经网络中进行训练。

(4) 定义函数 data_to_num() 将独热编码变量转换为整数序列:

def data_to_num(data):# 根据 100 维向量中的最大值,将向量转换为整数num=torch.argmax(data,dim=-1)return num
numbers=data_to_num(batch)

2.2 模型构建

接下来,创建两个神经网络:判别器 D 和生成器 G。构建生成对抗网络 (Generative Adversarial Network, GAN) 来生成所需的数字模式,判别器网络是一个二分类器,用于区分虚假样本和真实样本,生成器网络用于生成包含 10 个数字的序列。

(1) 首先,创建判别器神经网络:

from torch import nn
D=nn.Sequential(nn.Linear(100,1),nn.Sigmoid()).to(device)

由于将整数转换为 100 维的独热编码变量,因此模型的第一个 Linear 层中使用 100 作为输入大小。最后的 Linear 层只有一个输出特征,使用 sigmoid 激活函数将输出压缩到 [0, 1] 范围内,可以解释为样本是真实样本的概率 p,概率 1 - p 则表示样本是虚假样本的概率。

(2) 生成器的任务是创建一组数字,使其能够被判别器 D 分类为真实。也就是说,生成器 G 试图创建一组数字,以最大化判别器 D 认为这些数字来自训练数据集的概率。创建生成器神经网络 G

G=nn.Sequential(nn.Linear(100,100),nn.ReLU()).to(device)

从一个 100 维的潜空间中获取随机噪声向量输入给生成器。生成器基于输入生成一个包含 100 个值的张量,在最后一层使用 ReLU 激活函数,以确保输出是非负值,因为我们试图生成的 100 个值的取值为 01

(3) 判别器和生成器都使用 Adam 优化器,学习率设为 0.0005

loss_fn=nn.BCELoss()
lr=0.0005
optimD=torch.optim.Adam(D.parameters(),lr=lr)
optimG=torch.optim.Adam(G.parameters(),lr=lr)

2.3 模型训练

(1) 定义 train_D_G() 函数:

real_labels=torch.ones((10,1)).to(device)
fake_labels=torch.zeros((10,1)).to(device)def train_D_G(D,G,loss_fn,optimD,optimG):# 生成真实数据样本true_data=gen_batch().to(device)# 由于是真实样本,使用 1 作为标签preds=D(true_data)loss_D1=loss_fn(preds,real_labels.reshape(10,1))optimD.zero_grad()loss_D1.backward()optimD.step()# 在虚假数据上训练判别器noise=torch.randn(10,100).to(device)generated_data=G(noise)# 由于是虚假样本,使用 0 作为标签preds=D(generated_data)loss_D2=loss_fn(preds,fake_labels.reshape(10,1))optimD.zero_grad()loss_D2.backward()optimD.step()# 训练生成器 noise=torch.randn(10,100).to(device)generated_data=G(noise)# 使用 1 作为标签,因为生成器想要欺骗判别器preds=D(generated_data)loss_G=loss_fn(preds,real_labels.reshape(10,1))optimG.zero_grad()loss_G.backward()optimG.step()return generated_data

(2) 使用提前停止类,以便在满足需求时停止训练。同时,定义 distance() 函数衡量训练集与生成数据样本之间的差异,计算每个生成数字除以 5 的余数与全零向量的均方误差 (Mean Squared Error, MSE)。当所有生成的数字都是 5 的倍数时,结果为 0

class EarlyStop:def __init__(self, patience=1000): # 将 patience 的默认值设置为 1000self.patience = patienceself.steps = 0self.min_gdif = float('inf')def stop(self, gdif):    # 定义 stop() 方法# # 如果生成分布与真实分布之间的新差异大于当前最小差异,则更新 min_gdif 的值if gdif < self.min_gdif:self.min_gdif = gdifself.steps = 0elif gdif >= self.min_gdif:self.steps += 1# 如果模型在 1000 个 epoch 内没有改进,则停止训练if self.steps >= self.patience:return Trueelse:return Falsestopper=EarlyStop(800)    # 创建 Earlytop() 类实例mse=nn.MSELoss()
real_labels=torch.ones((10,1)).to(device)
fake_labels=torch.zeros((10,1)).to(device)
# 定义 distance() 函数,用于计算生成数字的损失
def distance(generated_data): nums=data_to_num(generated_data)remainders=nums%5ten_zeros=torch.zeros((10,1)).to(device)mseloss=mse(remainders,ten_zeros)return mselossfor i in range(10000):gloss=0dloss=0generated_data=train_D_G(D,G,loss_fn,optimD,optimG)    # 训练 GAN 一个 epoch dis=distance(generated_data)if stopper.stop(dis)==True:break   # 每训练 50 个 epoch 后,打印生成的整数序列if i % 50 == 0:print(data_to_num(generated_data))

运行代码,输出结果如下所示:

输出结果

在每一次迭代中,生成包含 10 个数字的数据样本。首先使用真实样本来训练判别器 D,然后生成器生成一批虚假样本,使用虚假样本再次训练判别器 D。最后,使用生成器再次生成一批虚假样本用于训练生成器 G。训练过程中,如果生成器网络从上次达到最小损失以来经过了 800epoch 训练仍未改善,就停止训练。每 50epoch,会输出生成器生成的 10 个数字序列,观察其是否确实都是 5 的倍数。

3. 生成器保存与加载

(1) 丢弃判别器并将训练好的生成器保存到本地文件夹:

import os
os.makedirs("files", exist_ok=True)
scripted = torch.jit.script(G) 
scripted.save('files/num_gen.pt') 

(2) 将生成器保存到本地文件夹后,要使用生成器,只需加载模型,并用它来生成一组整数序列:

# 加载已保存的生成器
new_G=torch.jit.load('files/num_gen.pt',map_location=device)
new_G.eval()
# 获取随机噪声向量
noise=torch.randn((10,100)).to(device)
# 将随机噪声向量输入训练好的模型,生成一系列整数
new_data=new_G(noise) 
print(data_to_num(new_data))

输出结果如下所示,生成的数字都是 5 的倍数:

tensor([55, 20, 75, 20, 80, 55, 35, 55, 30, 55], device='cuda:0')

相关链接

PyTorch生成式人工智能实战:从零打造创意引擎
PyTorch实战(1)——神经网络与模型训练过程详解
PyTorch实战(2)——PyTorch基础
PyTorch实战(3)——使用PyTorch构建神经网络
PyTorch实战(4)——卷积神经网络详解
PyTorch实战(5)——分类任务详解
PyTorch实战(6)——生成模型(Generative Model)详解
PyTorch实战(7)——生成对抗网络实践详解

相关文章:

  • (自用)Java学习-5.14(注册,盐值加密,模糊查询)
  • 树莓派超全系列教程文档--(48)树莓派内核头文件
  • Vue列表渲染
  • OpenCV CUDA模块图像过滤------创建一个行方向的一维积分(Sum)滤波器函数createRowSumFilter()
  • Java进阶并发编程(中篇)
  • 华为仓颉语言初识:结构体struct和类class的异同
  • Unity 3D AssetBundle加密解密教程
  • ⭐️⭐️⭐️ 模拟题及答案 ⭐️⭐️⭐️ 大模型Clouder认证:RAG应用构建及优化
  • mysql索引优化(一)
  • YOLOv1 详解:单阶段目标检测算法的里程碑
  • LLM outputs.loss 返回什么
  • 鸿蒙OSUniApp 制作简单的页面跳转与参数传递功能#三方框架 #Uniapp
  • 将网页带格式转化为PDF
  • 【2025】harbor仓库搭建
  • ORM++ 封装实战指南:安全高效的 C++ MySQL 数据库操作
  • GO并发过高导致程序崩溃如何解决
  • React笔记-Ant Design X样本间对接智谱AI
  • ATT衰减器(Attenuator)介绍
  • 言语理解成语积累
  • 一根网线可以有两个ip地址吗?怎么实现
  • 南宁微信网站制作/推广普通话手抄报模板
  • 网站建设学习学校/营销推广方案包括哪些内容
  • 公司建网站一般多少钱/简单制作html静态网页
  • 网站的域名每年都要续费/产品营销推广策略
  • 澳门网站建设/哪个网站学seo是免费的
  • 档案网站建设网页/网络广告联盟