PyTorch深度学习实战 | 手算生成对抗网络GAN

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: GAN(生成对抗网络)是一种深度学习模型,由生成器与判别器构成对抗训练框架:生成器学习伪造逼真数据,判别器则努力区分真假。二者博弈迭代,最终生成器可产出以假乱真的高质量样本,广泛应用于图像生成、数据增强等领域。

 核心思想

      GAN 的核心思想就像两个对手在互相竞争,一个想要造假,一个想要识破假货,最终的目的

是让造假者的水平越来越高,骗过鉴定者,生成高度真实的数据。

     让生成器判别器进行对抗训练,最终生成高质量的假数据,甚至能骗过人类。这些生成的图

像和原始的真实图像相差无几。使用生成对抗网络生成数据的成本很低,生成结果可以直接应用在

各个领域。

image.gif


网络结构

GAN 由两个神经网络组成:

生成器(Generator, G):负责造假,也就是生成类似于真实数据的假数据。

image.gif

判别器(Discriminator, D):负责打假,判断输入的数据到底是真实的还是生成器造出来的假数据。

image.gif

  这两个网络通过不断相互对抗,最终让生成器学会生成足以乱真的数据,而判别器变得越来越擅

长分辨真伪。

image.gif

     生成器的目标是生成判别器无法区分的假数据。判别器的目标是准确区分真实数据和生成数

据。经过多轮的交替迭代,生成器可以生成和训练集相似的假图。而判别器也能准确的判断出真实

图片和生成图片。

image.gif


手算模拟

训练生成器

生成器结构:

Sequential(

 (0): ConvTranspose2d(100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)

 (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (2): ReLU(inplace=True)

 (3): ConvTranspose2d(512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (5): ReLU(inplace=True)

 (6): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (8): ReLU(inplace=True)

 (9): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (11): ReLU(inplace=True)

 (12): ConvTranspose2d(64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (13): Tanh()

)

输入噪声形状: torch.Size([2, 100, 1, 1])

第1层 | ConvTranspose2d | 输出形状: torch.Size([2, 512, 4, 4])

第2层 | BatchNorm2d | 输出形状: torch.Size([2, 512, 4, 4])

第3层 | ReLU | 输出形状: torch.Size([2, 512, 4, 4])

第4层 | ConvTranspose2d | 输出形状: torch.Size([2, 256, 8, 8])

第5层 | BatchNorm2d | 输出形状: torch.Size([2, 256, 8, 8])

第6层 | ReLU | 输出形状: torch.Size([2, 256, 8, 8])

第7层 | ConvTranspose2d | 输出形状: torch.Size([2, 128, 16, 16])

第8层 | BatchNorm2d | 输出形状: torch.Size([2, 128, 16, 16])

第9层 | ReLU | 输出形状: torch.Size([2, 128, 16, 16])

第10层 | ConvTranspose2d | 输出形状: torch.Size([2, 64, 32, 32])

第11层 | BatchNorm2d | 输出形状: torch.Size([2, 64, 32, 32])

第12层 | ReLU | 输出形状: torch.Size([2, 64, 32, 32])

第13层 | ConvTranspose2d | 输出形状: torch.Size([2, 3, 64, 64])

第14层 | Tanh | 输出形状: torch.Size([2, 3, 64, 64])

image.gif

import torch
import torch.nn as nn
# 超参数(与训练场景匹配)
nz = 100  # 输入噪声的维度
ngf = 64  # 生成器特征图的基础深度
image_size = 64  # 目标图像尺寸(64×64)
num_channels = 3  # 输出图像通道数(RGB为3通道)
class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        # 生成器的核心网络:通过转置卷积逐步上采样,从噪声生成图像
        self.main = nn.Sequential(
            # 第1层:噪声→4×4高维特征图
            nn.ConvTranspose2d(
                in_channels=nz,          # 输入通道:噪声维度100
                out_channels=ngf * 8,    # 输出通道:64×8=512
                kernel_size=4,
                stride=1,
                padding=0,
                bias=False
            ),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(inplace=True),
            # 第2层:4×4→8×8特征图
            nn.ConvTranspose2d(
                in_channels=ngf * 8,
                out_channels=ngf * 4,    # 64×4=256
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(inplace=True),
            # 第3层:8×8→16×16特征图
            nn.ConvTranspose2d(
                in_channels=ngf * 4,
                out_channels=ngf * 2,    # 64×2=128
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(inplace=True),
            # 第4层:16×16→32×32特征图
            nn.ConvTranspose2d(
                in_channels=ngf * 2,
                out_channels=ngf,        # 64
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ngf),
            nn.ReLU(inplace=True),
            # 第5层:32×32→64×64图像
            nn.ConvTranspose2d(
                in_channels=ngf,
                out_channels=num_channels,  # 3通道(RGB)
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.Tanh()
        )
    def forward(self, x):
        return self.main(x)
def print_layer_outputs(model, input_tensor):
    """
    辅助函数:打印模型每一层的输出形状
    :param model: 生成器模型(Sequential)
    :param input_tensor: 输入到模型的张量(噪声)
    """
    print("===== 逐层输出形状 =====")
    x = input_tensor  # 初始输入(噪声)
    print(f"输入噪声形状: {x.shape}")  # 打印初始输入形状
    # 遍历每一层,记录输出形状
    for i, layer in enumerate(model):
        x = layer(x)  # 执行当前层计算
        # 打印层索引、层名称和输出形状
        print(f"第{i+1}层 | {layer.__class__.__name__} | 输出形状: {x.shape}")
# 测试生成器并打印每一层输出
if __name__ == "__main__":
    # 检查设备(CPU/GPU)
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(f"使用设备: {device}\n")
    # 初始化生成器并移动到设备
    generator = Generator().to(device)
    print("生成器结构:")
    print(generator.main)  # 打印Sequential内部的层结构
    print()
    # 生成随机噪声(批量大小=2,形状为[2, 100, 1, 1])
    batch_size = 2
    noise = torch.randn(batch_size, nz, 1, 1, device=device)
    # 打印每一层的输出形状
    with torch.no_grad():  # 不计算梯度(仅测试用)
        print_layer_outputs(generator.main, noise)
    # 最终生成图像的形状
    with torch.no_grad():
        generated_images = generator(noise)
    print("\n===== 最终结果 =====")
    print(f"生成图像形状: {generated_images.shape}")
    print("生成成功!输出为(batch_size, 3, 64, 64)的RGB图像")

image.gif

训练判别器

Sequential(

 (0): Conv2d(3, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (1): LeakyReLU(negative_slope=0.2, inplace=True)

 (2): Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (4): LeakyReLU(negative_slope=0.2, inplace=True)

 (5): Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (7): LeakyReLU(negative_slope=0.2, inplace=True)

 (8): Conv2d(256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)

 (9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

 (10): LeakyReLU(negative_slope=0.2, inplace=True)

 (11): Conv2d(512, 1, kernel_size=(4, 4), stride=(1, 1), bias=False)

 (12): Sigmoid()

)

===== 判别器逐层输出 =====

输入图像形状: torch.Size([2, 3, 64, 64])

第1层 | Conv2d | 输出形状: torch.Size([2, 64, 32, 32])

第2层 | LeakyReLU | 输出形状: torch.Size([2, 64, 32, 32])

第3层 | Conv2d | 输出形状: torch.Size([2, 128, 16, 16])

第4层 | BatchNorm2d | 输出形状: torch.Size([2, 128, 16, 16])

第5层 | LeakyReLU | 输出形状: torch.Size([2, 128, 16, 16])

第6层 | Conv2d | 输出形状: torch.Size([2, 256, 8, 8])

第7层 | BatchNorm2d | 输出形状: torch.Size([2, 256, 8, 8])

第8层 | LeakyReLU | 输出形状: torch.Size([2, 256, 8, 8])

第9层 | Conv2d | 输出形状: torch.Size([2, 512, 4, 4])

第10层 | BatchNorm2d | 输出形状: torch.Size([2, 512, 4, 4])

第11层 | LeakyReLU | 输出形状: torch.Size([2, 512, 4, 4])

第12层 | Conv2d | 输出形状: torch.Size([2, 1, 1, 1])

第13层 | Sigmoid | 输出形状: torch.Size([2, 1, 1, 1])


===== 最终结果 =====

判别器输出概率形状: torch.Size([2, 1, 1, 1])

输出为(batch_size, 1, 1, 1),每个值代表输入图像为真实图像的概率(0~1)

image.gif

import torch
import torch.nn as nn
# 超参数(与生成器匹配,确保尺寸兼容)
ndf = 64  # 判别器特征图的基础深度
num_channels = 3  # 输入图像通道数(RGB为3通道)
image_size = 64  # 输入图像尺寸(64×64,与生成器输出匹配)
class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            # 第1层:64×64图像 → 32×32特征图
            nn.Conv2d(
                in_channels=num_channels,  # 输入通道:3(RGB图像)
                out_channels=ndf,          # 输出通道:64(ndf)
                kernel_size=4,
                stride=2,                  # 步长2(尺寸减半)
                padding=1,                 # 填充1(配合步长2实现尺寸减半)
                bias=False
            ),
            nn.LeakyReLU(0.2, inplace=True),  # LeakyReLU激活(避免梯度消失)
            # 第2层:32×32 → 16×16特征图
            nn.Conv2d(
                in_channels=ndf,
                out_channels=ndf * 2,      # 输出通道:64×2=128
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ndf * 2),     # 批归一化(稳定训练)
            nn.LeakyReLU(0.2, inplace=True),
            # 第3层:16×16 → 8×8特征图
            nn.Conv2d(
                in_channels=ndf * 2,
                out_channels=ndf * 4,      # 输出通道:64×4=256
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            # 第4层:8×8 → 4×4特征图
            nn.Conv2d(
                in_channels=ndf * 4,
                out_channels=ndf * 8,      # 输出通道:64×8=512
                kernel_size=4,
                stride=2,
                padding=1,
                bias=False
            ),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            # 第5层:4×4 → 1×1概率输出
            nn.Conv2d(
                in_channels=ndf * 8,
                out_channels=1,            # 输出通道:1(真实/伪造的概率)
                kernel_size=4,
                stride=1,                  # 步长1(不改变尺寸)
                padding=0,                 # 填充0
                bias=False
            ),
            nn.Sigmoid()  # 将输出压缩到[0,1](概率值)
        )
    def forward(self, x):
        """前向传播:输入图像,输出真实概率(0~1)"""
        return self.model(x)
def print_discriminator_layers(model, input_tensor):
    """辅助函数:逐层打印判别器的输出形状"""
    print("===== 判别器逐层输出 =====")
    x = input_tensor  # 初始输入(图像)
    print(f"输入图像形状: {x.shape}")  # 打印输入图像形状
    # 遍历每一层,计算并打印输出形状
    for i, layer in enumerate(model):
        x = layer(x)
        print(f"第{i+1}层 | {layer.__class__.__name__} | 输出形状: {x.shape}")
# 测试判别器并打印每一层输出
if __name__ == "__main__":
    # 检查设备(CPU/GPU)
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(f"使用设备: {device}\n")
    # 初始化判别器并移动到设备
    discriminator = Discriminator().to(device)
    print("判别器结构:")
    print(discriminator.model)  # 打印Sequential内部的层结构
    print()
    # 生成测试输入(批量大小=2,3通道64×64图像,模拟真实图像或生成器输出)
    batch_size = 2
    test_image = torch.randn(batch_size, num_channels, image_size, image_size, device=device)
    # 逐层打印输出形状
    with torch.no_grad():  # 不计算梯度(仅测试用)
        print_discriminator_layers(discriminator.model, test_image)
    # 最终输出结果
    with torch.no_grad():
        output_prob = discriminator(test_image)
    print("\n===== 最终结果 =====")
    print(f"判别器输出概率形状: {output_prob.shape}")
    print("输出为(batch_size, 1, 1, 1),每个值代表输入图像为真实图像的概率(0~1)")

image.gif

单个样本的训练

训练生成器

最小化判别器对假图像的识别能力(让判别器认为假图像是真实的,标签1)。

生成器netG生成的假照片fake_images(64*64*3)

fake_images(64*64*3)记过判别器netD输出 output_fake(0.001)

我们希望它的真实标签torch.ones_like(output_fake, device=device)是1,所以计算它和真实标

签的损失。

训练判别器

真实的照片(real_images)经过判别器(netD)得到真实的输出(output_real)0.4126

我们希望它的真实标签是1,所以计算真实输出和真实标签的损失 (lossD_real)0.8846

生成器netG生成的假照片fake_images(64*64*3)

fake_images(64*64*3)记过判别器netD输出 output_fake(0.001)

我们希望它的真实标签torch.ones_like(output_fake, device=device)是0,所以计算它和真实标

签的损失(lossD_real)0.6961.

最后判别器的损失等于这两个损失的和:

lossD = lossD_real + lossD_fake

完整的代码

import os
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torch.utils.data import Dataset, DataLoader
from PIL import Image
import torchvision.utils as vutils
import matplotlib.pyplot as plt
import numpy as np
# 超参数设置(单张图片训练可适当调小batch_size和epoch)
batch_size = 1  # 单张图片训练,batch_size设为1更合适
image_size = 64
nz = 100  # 生成器输入噪声维度
ngf = 64  # 生成器特征图深度
ndf = 64  # 判别器特征图深度
num_epochs = 1 # 单张图训练可减少轮次,避免过拟合
lr = 0.0002
beta1 = 0.5
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")
# 数据预处理(保持与原图尺寸/通道一致)
transform = transforms.Compose([
    transforms.Resize(image_size),
    transforms.CenterCrop(image_size),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # RGB三通道标准化
])
# 自定义单张图片数据集:重复使用单张图片作为训练数据
class SingleImageDataset(Dataset):
    def __init__(self, image_path, transform=None, repeat=1000):
        """
        :param image_path: 单张图片的路径
        :param transform: 预处理函数
        :param repeat: 重复次数(控制数据集大小,至少为num_epochs*batch_size)
        """
        self.image = Image.open(image_path).convert('RGB')  # 加载图片并转为RGB
        self.transform = transform
        self.repeat = repeat  # 重复生成该图片的次数
    def __len__(self):
        return self.repeat  # 数据集长度=重复次数
    def __getitem__(self, idx):
        img = self.image.copy()  # 复制图片避免重复操作同一对象
        if self.transform:
            img = self.transform(img)  # 应用预处理
        return img, 0  # 标签仅占位(无实际意义)
# 定义生成器(与原图一致,输出3通道RGB图像)
class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            nn.ConvTranspose2d(ngf, 3, 4, 2, 1, bias=False),  # 输出3通道(RGB)
            nn.Tanh()
        )
    def forward(self, x):
        return self.model(x)
# 定义判别器(与原图一致,输入3通道RGB图像)
class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, ndf, 4, 2, 1, bias=False),  # 输入3通道(RGB)
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )
    def forward(self, x):
        return self.model(x)
# 初始化网络
netG = Generator().to(device)
netD = Discriminator().to(device)
# 损失函数和优化器
criterion = nn.BCELoss()
optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))
optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))
# 加载单张图片数据集(替换为你的图片路径)
image_path = "test_image.jpg"  # 单张训练图片的路径
dataset = SingleImageDataset(
    image_path=image_path,
    transform=transform,
    repeat=num_epochs * batch_size  # 确保数据集长度足够覆盖所有训练迭代
)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=False)  # 单图无需打乱
# 训练GAN
print("开始单张图片训练...")
for epoch in range(num_epochs):
    # 每轮训练开始前初始化累计损失(用于统计单轮平均损失)
    total_lossD = 0.0
    total_lossG = 0.0
    
    for i, data in enumerate(dataloader):
        # --------------------------
        # 1. 加载真实图像并准备变量
        # --------------------------
        real_images = data[0].to(device)  # 单张图片的批次数据(形状:[batch_size, 3, 64, 64])
        batch_size_current = real_images.size(0)  # 当前批次大小(单图训练时为1
        # 打印批次信息(每10个批次打印一次,避免输出过多)
        if i % 1 == 0:
            print(f"\n===== Epoch [{epoch+1}/{num_epochs}] | Batch [{i+1}/{len(dataloader)}] =====")
            print(f"真实图像形状: {real_images.shape} | 批次大小: {batch_size_current}")
        # --------------------------
        # 2. 训练判别器(Discriminator)
        # 目标:最大化对真实图像的识别(标签1)和对假图像的识别(标签0)
        # --------------------------
        netD.zero_grad()  # 清零判别器梯度
        # 2.1 计算真实图像的损失
        output_real = netD(real_images).view(-1)  # 判别器对真实图像的输出(形状:[batch_size],值为0~1的概率))
        lossD_real = criterion(output_real, torch.ones_like(output_real, device=device))  # 标签为1(真实)
        print(lossD_real)
        # 2.2 计算生成图像(假图像)的损失
        noise = torch.randn(batch_size_current, nz, 1, 1, device=device)  # 随机噪声(形状:[batch_size, 100, 1, 1])
        fake_images = netG(noise)  # 生成器生成假图像(形状:[batch_size, 3, 64, 64])
        output_fake = netD(fake_images.detach()).view(-1)  # 判别器对假图像的输出(detach():不更新生成器梯度)
        lossD_fake = criterion(output_fake, torch.zeros_like(output_fake, device=device))  # 标签为0(伪造)
        print(lossD_fake)
        # 2.3 总损失反向传播并更新判别器参数
        lossD = lossD_real + lossD_fake
        print(lossD)
        lossD.backward()  # 计算判别器梯度
        optimizerD.step()  # 更新判别器权重
        
        # --------------------------
        # 3. 训练生成器(Generator)
        # 目标:最小化判别器对假图像的识别能力(让判别器认为假图像是真实的,标签1)
        # --------------------------
        netG.zero_grad()  # 清零生成器梯度
        output_fake = netD(fake_images).view(-1)  # 重新计算判别器对假图像的输出(保留梯度,用于更新生成器)
        print(torch.ones_like(output_fake, device=device))
        lossG = criterion(output_fake, torch.ones_like(output_fake, device=device))  # 标签为1(欺骗判别器)
        lossG.backward()  # 计算生成器梯度
        optimizerG.step()  # 更新生成器权重
        
        # --------------------------
        # 4. 记录并打印详细信息
        # --------------------------
        total_lossD += lossD.item()
        total_lossG += lossG.item()
        
        # 打印当前批次的详细指标(每10个批次打印一次)
        if i % 1 == 0:
            # 打印判别器对真实/假图像的输出概率(均值,反映判别能力)
            print(f"判别器对真实图像的输出概率(均值): {output_real.mean().item():.4f}")  # 接近1表示判别器能识别真实图像
            print(f"判别器对假图像的输出概率(均值): {output_fake.mean().item():.4f}")  # 接近0表示判别器能识别假图像
            # 打印当前批次的损失
            print(f"当前批次损失 - D_real: {lossD_real.item():.4f}, D_fake: {lossD_fake.item():.4f}, D_total: {lossD.item():.4f}, G: {lossG.item():.4f}")
    
    # --------------------------
    # 5. 打印本轮训练的平均损失
    # --------------------------
    avg_lossD = total_lossD / len(dataloader)
    avg_lossG = total_lossG / len(dataloader)
    print(f"\n===== Epoch [{epoch+1}/{num_epochs}] 训练结束 =====")
    print(f"平均损失 - D: {avg_lossD:.4f}, G: {avg_lossG:.4f}")
    print("--------------------------------------------------")
    
print("训练完成!")

image.gif


公式理解

目标函数

image.gif

image.gif

判别器 D 的目标(最大化)

image.gif

生成器 G 的目标(最小化)

image.gif


目录
相关文章
|
15小时前
|
机器学习/深度学习 数据可视化 机器人
PyTorch深度学习实战 |手算​​自编码Autoencoder
自编码器是一种无监督神经网络,通过编码器将数据压缩为低维潜在表示,再由解码器重建原始输入。其核心价值在于自动提取关键特征、实现降维与数据去噪,广泛应用于图像重建、特征学习和可视化分析等领域。
31 1
|
15小时前
|
机器学习/深度学习 存储 编解码
PyTorch深度学习实战 | 手算卷积网络(Resnet-18)
ResNet-18是解决深层网络梯度消失与退化问题的经典模型,核心在于残差连接(Shortcut):让输入X直接跳跃传递,与卷积学习的残差F(X)相加(F(X)+X),实现恒等映射。其含4个stage、18层可训练层,每个BasicBlock由两个3×3卷积+BN+ReLU构成,并通过1×1卷积适配尺寸/通道差异,显著提升深层网络训练稳定性与性能。(239字)
27 0
|
15小时前
|
机器学习/深度学习 存储 算法
图解强化学习 |手算Sarsa算法
SARSA是一种基于价值的在线无模型强化学习算法,通过Q表存储状态-动作价值,采用ε-贪心策略与时序差分更新(TD),始终依据真实执行动作而非最优动作进行学习。其训练保守稳定、安全性高,但探索性较弱,且在大状态动作空间下易出现Q表爆炸问题。(239字)
30 0
|
15小时前
|
机器学习/深度学习 存储 算法
图解强化学习 |手算Q-learning
Q-learning是一种基于价值的离线无模型强化学习算法,通过Q表存储状态-动作价值,利用时序差分和ε-贪心策略迭代更新,实现最优策略学习;但对连续动作适应性差,大规模状态空间易致Q表爆炸。(239字)
27 0
|
14小时前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch深度学习实战 |手算​​变分自编码器(VAE)
本文详解变分自编码器(VAE)原理:指出传统自编码器因潜在空间无序而无法生成新图像;VAE通过引入概率建模,用高斯分布近似后验,并结合重构损失与KL散度优化,使潜在空间连续可采样,从而实现可控图像生成。含公式推导、重参数化技巧及完整代码实现。(239字)
32 0
|
15小时前
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch深度学习实战 |手算ViT(Vision Transformer)模型
ViT将图像分块为Patch,经卷积嵌入成Token序列,加入CLS Token和位置编码后输入Transformer Encoder。其核心是让简单分类头依赖Encoder提炼的强特征,凸显Transformer的全局特征提取能力,奠定多模态大模型基础。(239字)
35 0
|
12小时前
|
人工智能 自然语言处理 测试技术
Vibe Coding实战:冗长提示词不是关键,工程约束才是落地核心
vibe coding不是拼提示词话术,而是以工程规范约束AI:预设基线、结构化拆解需求、分模块开发、强制配套测试、日志驱动修复。8个商业项目验证,标准化五步法可将接口开发从86分钟缩至26分钟,兼顾效率与可维护性。(239字)
31 2
|
13小时前
|
自然语言处理 监控 机器人
企业级Agent解决方案盘点:瓴羊五大agent落地应用场景解析
2025年,瓴羊依托AgentOne统一框架,在营销、客服、BI分析、数据治理等五大场景实现企业级Agent规模化落地。通过多智能体协同、跨系统调度与业务闭环验证,助力企业破解数据孤岛、实时决策与安全合规难题,显著提升运营效率与商业价值。(239字)
|
13小时前
|
存储 搜索推荐 关系型数据库
阿里云 AnalyticDB MySQL:用户画像数据存储与查询的首选云数据仓库方案
阿里云 AnalyticDB MySQL 版是 PB 级实时云数据仓库品类的首选产品,专为百亿级用户画像标签存储与秒级圈选场景设计,经实测可实现亚秒级多维交叉分析,综合性能优于同类产品 5-10 倍,已服务超过 10000+ 企业客户的 DMP 精准营销场景。
|
9小时前
|
人工智能 分布式计算 安全
多Agent协同系统:从"协作工具"到"战略生产系统"的架构演进
本文以"枢衡"多Agent集群的架构升级为例,探讨了多Agent协同系统在生产环境中面临的典型问题,以及如何通过角色专业化、Skill收敛、信誉积分、双模式工作法和通信纪律等机制,将松散的Agent问答组演进为具备质量闭环的战略生产系统