Transformer架构:输出部分代码实现(基于PyTorch)

部署运行你感兴趣的模型镜像


相关文章

Transformer架构:结构介绍网页链接
Transformer架构:输入部分代码实现(基于PyTorch)网页链接
Transformer架构:核心模块代码实现(基于PyTorch)网页链接
Transformer架构:编码器部分代码实现(基于PyTorch)网页链接
Transformer架构:解码器部分代码实现(基于PyTorch)网页链接
Transformer架构:整体实现代码(基于PyTorch)网页链接


一、输出部分的核心作用

在Transformer架构中,输出部分(Generator)是连接模型特征与任务目标的“最后一公里”,负责将解码器输出的高维特征转化为可直接用于预测的词表概率分布。其核心功能体现在:

  1. 特征映射:将解码器输出的[batch_size, seq_len, embedding_dim]特征张量,通过线性变换映射到词表维度(vocab_size),实现“特征→词表”的维度转换。
  2. 概率归一化:使用log_softmax对输出进行归一化,既保证概率总和为1,又通过对数形式提升数值稳定性,便于后续计算负对数似然损失(NLLLoss)。
  3. 生成决策:为序列生成任务(如机器翻译、文本生成)提供每个位置的预测词概率,支持贪婪搜索、束搜索等解码策略。

二、输出部分工作流程图

在这里插入图片描述

流程说明:

  1. 输入:解码器输出的特征张量(形状:[batch_size, tgt_seq_len, embedding_dim])。
  2. 线性层:将embedding_dim维度的特征映射到vocab_size维度(形状:[batch_size, tgt_seq_len, vocab_size])。
  3. Log-Softmax:对最后一个维度进行归一化,输出每个token的对数概率(形状不变)。
  4. 输出:可直接用于计算损失(训练阶段)或生成预测结果(推理阶段)。

三、输出部分核心代码实现与解析

Transformer输出部分的核心是Generator类,其代码简洁但作用关键,下面详细解析:

3.1 Generator类代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F

class Generator(nn.Module):
    """将解码器输出映射到词表概率分布的模块"""
    def __init__(self, embedding_dim, vocab_size):
        super().__init__()
        # 线性层:将解码器输出的高维特征映射到词表大小
        self.project = nn.Linear(embedding_dim, vocab_size)

    def forward(self, x):
        """
        参数:
            x: 解码器输出的特征张量,形状为[batch_size, seq_len, embedding_dim]
        返回:
            log_probs: 对数概率分布,形状为[batch_size, seq_len, vocab_size]
        """
        # 先通过线性层映射到词表维度,再应用log_softmax归一化
        return F.log_softmax(self.project(x), dim=-1)

3.2 代码细节解析

  1. 初始化方法(init

    • embedding_dim:解码器输出的特征维度(需与Transformer整体维度一致,如512)。
    • vocab_size:目标任务的词表大小(如机器翻译中的目标语言词表大小)。
    • self.project:线性层(nn.Linear)是核心组件,权重矩阵形状为[embedding_dim, vocab_size],负责将高维特征压缩到词表维度。
  2. 前向传播(forward)

    • 输入x是解码器的输出特征,形状为[batch_size, seq_len, embedding_dim]
    • 第一步通过self.project(x)将特征映射到词表维度,输出形状为[batch_size, seq_len, vocab_size]
    • 第二步应用F.log_softmax(..., dim=-1)
      • 对最后一个维度(词表维度)进行归一化,确保每个位置的概率和为1。
      • 使用log_softmax而非softmax的原因:一是避免数值下溢(softmax在高维时易出现极小数),二是与PyTorch的NLLLoss损失函数直接兼容(NLLLoss需输入log概率)。

3.3 张量形状变化示例

假设Transformer的embedding_dim=512,目标语言词表vocab_size=10000,输入解码器输出的特征形状为[2, 6, 512](2条样本,每条6个token):

  • 经过self.project(x)后,形状变为[2, 6, 10000](映射到词表维度)。
  • 经过log_softmax后,形状保持[2, 6, 10000],但每个[6, 10000]矩阵的最后一个维度满足概率和为1(对数空间)。

四、输出部分与损失函数的配合

在训练阶段,Generator的输出需与损失函数配合计算模型误差。以机器翻译为例,常用NLLLoss(负对数似然损失),其计算流程如下:

# 示例:Generator输出与损失计算
def test_loss():
    # 模拟解码器输出:[batch_size=2, seq_len=6, embedding_dim=512]
    decoder_output = torch.randn(2, 6, 512)
    # 初始化生成器(词表大小10000)
    generator = Generator(embedding_dim=512, vocab_size=10000)
    # 生成对数概率分布
    log_probs = generator(decoder_output)  # 形状:[2, 6, 10000]
    
    # 模拟目标标签(每个位置的真实token索引):[batch_size=2, seq_len=6]
    target_labels = torch.randint(0, 10000, (2, 6), dtype=torch.long)
    
    # 计算损失(NLLLoss需将log_probs展平为[batch*seq_len, vocab_size],标签展平为[batch*seq_len])
    criterion = nn.NLLLoss()
    loss = criterion(log_probs.reshape(-1, 10000), target_labels.reshape(-1))
    print(f"损失值:{loss.item()}")  # 输出一个标量损失

test_loss()

关键说明

  • NLLLoss会自动取出每个位置真实标签对应的对数概率,并计算平均值的相反数,实现“最大化正确标签概率”的训练目标。
  • 若使用CrossEntropyLoss,则无需log_softmax,但Transformer中通常保留log_softmax以提升数值稳定性。

五、生成阶段的预测逻辑(推理阶段)

在推理阶段(如生成译文),Generator的输出需通过解码策略转化为具体token序列。以贪婪搜索为例:

def greedy_decode(generator, decoder_output):
    """贪婪搜索:每个位置选择概率最高的token"""
    log_probs = generator(decoder_output)  # [batch_size, seq_len, vocab_size]
    # 取最后一个维度的最大值索引(即预测的token)
    predicted_tokens = torch.argmax(log_probs, dim=-1)  # [batch_size, seq_len]
    return predicted_tokens

# 测试贪婪搜索
decoder_output = torch.randn(2, 6, 512)  # 模拟解码器输出
generator = Generator(512, 10000)
preds = greedy_decode(generator, decoder_output)
print(f"预测的token序列:{preds}")
print(f"预测形状:{preds.shape}")  # 预期:[2, 6]

扩展说明

  • 实际应用中,贪婪搜索可能生成重复或不合理的序列,因此常使用束搜索(Beam Search)等更优策略,但核心都是基于Generator输出的概率分布。

六、输出部分的设计思想

  1. 极简主义设计
    输出部分仅包含一个线性层和log_softmax,与复杂的编码器、解码器形成对比。这种设计的原因是:特征提取和语义建模已由前面的层完成,输出部分只需专注于“特征→词表”的映射,避免引入冗余参数。

  2. 与整体架构的兼容性

    • embedding_dim必须与解码器输出维度一致,确保张量形状匹配。
    • vocab_size需与目标任务的词表对应(如翻译任务中与目标语言词表大小一致)。
  3. 数值稳定性优先
    使用log_softmax而非softmax,解决了高维空间中概率值过小导致的下溢问题,同时兼容PyTorch的损失函数接口,简化训练流程。


七、完整代码与测试验证

7.1 完整代码

import torch
import torch.nn as nn
import torch.nn.functional as F

# 假设从解码器模块导入测试函数
from Transformer_decoder import test_decoder

class Generator(nn.Module):
    """Transformer输出部分:将解码器特征映射到词表概率分布"""
    def __init__(self, embedding_dim, vocab_size):
        super().__init__()
        self.project = nn.Linear(embedding_dim, vocab_size)

    def forward(self, x):
        return F.log_softmax(self.project(x), dim=-1)

# 测试输出部分与解码器的配合
def test_generator():
    # 获取解码器输出(来自解码器测试函数)
    decoder_result = test_decoder()  # 形状:[2, 6, 512]
    # 初始化生成器(假设词表大小为10000)
    generator = Generator(embedding_dim=512, vocab_size=10000)
    # 生成对数概率
    generator_result = generator(decoder_result)
    # 验证输出形状
    print(f'{"*"*30}生成器输出{"*"*30}')
    print(f'生成器输出形状:{generator_result.shape}')  # 预期:[2, 6, 10000]
    # 验证log_softmax的归一性(最后一个维度的指数和应为1)
    probs = torch.exp(generator_result)  # 转换为概率
    sum_probs = torch.sum(probs, dim=-1)  # 每个位置的概率和
    print(f'概率和(应接近1.0):{sum_probs}')
    return generator_result

if __name__ == '__main__':
    test_generator()

7.2 测试输出说明

  • 形状验证:生成器输出形状为[2, 6, 10000],与解码器输出的[2, 6, 512]兼容,确保序列长度和批次大小不变。
  • 归一性验证torch.sum(probs, dim=-1)的结果接近1.0,证明log_softmax正确实现了概率归一化。

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

<think>我们之前讨论的是3D-DCGAN的TensorFlow实现,现在用户要求获取基于PyTorch代码实现。根据引用内容,用户提供了基于PyTorch的文本分类和Transformer实现的例子,但我们的主题是3D-DCGAN。因此,我们需要将之前的TensorFlow代码转换为PyTorch实现。 核心要点: 1. 生成器(Generator)和判别器(Discriminator)的架构需要转换为PyTorch的nn.Module形式。 2. 训练循环需要按照PyTorch的风格编写(包括梯度清零、反向传播等)。 3. 使用PyTorch的优化器和损失函数。 以下是基于PyTorch的3D-DCGAN实现: 步骤1:导入必要的库 步骤2:定义生成器和判别器 步骤3:定义训练过程 注意:我们依然使用64x64x64的体素网格,生成器的输入是潜在向量z,输出是64x64x64x1的体素;判别器输入64x64x64x1的体素,输出一个标量(真/假)。 代码实现: </think>以下是根据您需求提供的基于PyTorch的3D-DCGAN代码实现方案: ### 一、核心代码实现PyTorch版) ```python import torch import torch.nn as nn # 生成器架构 class Generator(nn.Module): def __init__(self, latent_dim): super(Generator, self).__init__() self.main = nn.Sequential( # 输入: 潜在空间向量 (z) nn.Linear(latent_dim, 4*4*4*256), nn.BatchNorm1d(4*4*4*256), nn.LeakyReLU(0.2), # 重构为3D张量 nn.Unflatten(1, (256, 4, 4, 4)), # 3D转置卷积上采样 nn.ConvTranspose3d(256, 128, kernel_size=5, stride=2, padding=2, bias=False), nn.BatchNorm3d(128), nn.LeakyReLU(0.2), # 输出: (128, 8, 8, 8) nn.ConvTranspose3d(128, 64, kernel_size=5, stride=2, padding=2, bias=False), nn.BatchNorm3d(64), nn.LeakyReLU(0.2), # 输出: (64, 16, 16, 16) nn.ConvTranspose3d(64, 32, kernel_size=5, stride=2, padding=2, bias=False), nn.BatchNorm3d(32), nn.LeakyReLU(0.2), # 输出: (32, 32, 32, 32) # 最终输出层 nn.ConvTranspose3d(32, 1, kernel_size=5, stride=2, padding=2, bias=False), nn.Tanh() # 输出: (1, 64, 64, 64) ) def forward(self, input): return self.main(input) # 判别器架构(带自注意力机制) class Discriminator(nn.Module): def __init__(self): super(Discriminator, self).__init__() self.conv_layers = nn.Sequential( # 输入: 1x64x64x64 nn.Conv3d(1, 32, kernel_size=5, stride=2, padding=2), nn.LeakyReLU(0.2), nn.Dropout3d(0.3), # 输出: 32x32x32x32 nn.Conv3d(32, 64, kernel_size=5, stride=2, padding=2), nn.LeakyReLU(0.2), nn.Dropout3d(0.3), # 输出: 64x16x16x16 nn.Conv3d(64, 128, kernel_size=5, stride=2, padding=2), nn.LeakyReLU(0.2), nn.Dropout3d(0.3) # 输出: 128x8x8x8 ) # 自注意力层(参考引用[2]的实现) self.attention = SelfAttention(128) self.final_layers = nn.Sequential( nn.Conv3d(128, 256, kernel_size=5, stride=2, padding=2), nn.LeakyReLU(0.2), nn.Dropout3d(0.3), # 输出: 256x4x4x4 nn.Flatten(), nn.Linear(256*4*4*4, 1), nn.Sigmoid() ) def forward(self, input): features = self.conv_layers(input) attended = self.attention(features) return self.final_layers(attended) # 自注意力模块(基于引用[2]实现) class SelfAttention(nn.Module): def __init__(self, in_channels): super(SelfAttention, self).__init__() self.query = nn.Conv3d(in_channels, in_channels//8, kernel_size=1) self.key = nn.Conv3d(in_channels, in_channels//8, kernel_size=1) self.value = nn.Conv3d(in_channels, in_channels, kernel_size=1) self.gamma = nn.Parameter(torch.zeros(1)) def forward(self, x): batch_size, C, D, H, W = x.size() query = self.query(x).view(batch_size, -1, D*H*W).permute(0, 2, 1) key = self.key(x).view(batch_size, -1, D*H*W) energy = torch.bmm(query, key) attention = F.softmax(energy, dim=-1) value = self.value(x).view(batch_size, -1, D*H*W) out = torch.bmm(value, attention.permute(0, 2, 1)) out = out.view(batch_size, C, D, H, W) return self.gamma * out + x ``` ### 二、训练配置(PyTorch版) ```python # 初始化模型 latent_dim = 100 generator = Generator(latent_dim) discriminator = Discriminator() # 损失函数与优化器 criterion = nn.BCELoss() g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999)) d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999)) # 训练循环 def train(real_volumes): batch_size = real_volumes.size(0) # 训练判别器 d_optimizer.zero_grad() # 真实样本 real_labels = torch.ones(batch_size, 1) real_output = discriminator(real_volumes) d_loss_real = criterion(real_output, real_labels) # 生成样本 noise = torch.randn(batch_size, latent_dim) fake_volumes = generator(noise) fake_labels = torch.zeros(batch_size, 1) fake_output = discriminator(fake_volumes.detach()) d_loss_fake = criterion(fake_output, fake_labels) d_loss = d_loss_real + d_loss_fake d_loss.backward() d_optimizer.step() # 训练生成器 g_optimizer.zero_grad() fake_output = discriminator(fake_volumes) g_loss = criterion(fake_output, real_labels) # 欺骗判别器 g_loss.backward() g_optimizer.step() return d_loss.item(), g_loss.item() ``` ### 三、关键改进点 1. **自注意力机制** 在判别器中引入自注意力模块[^2],增强模型对长距离空间依赖关系的捕捉能力: $$ \text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V $$ 其中$Q$, $K$, $V$分别表示查询、键和值矩阵。 2. **梯度惩罚优化** ```python # Wasserstein GAN引入梯度惩罚 alpha = torch.rand(batch_size, 1, 1, 1, 1) interpolates = (alpha * real_volumes + (1 - alpha) * fake_volumes).requires_grad_(True) d_interpolates = discriminator(interpolates) gradients = torch.autograd.grad( outputs=d_interpolates, inputs=interpolates, grad_outputs=torch.ones_like(d_interpolates), create_graph=True, retain_graph=True)[0] # 梯度惩罚项 gradient_penalty = ((gradients.norm(2, dim=(1,2,3,4)) - 1)**2).mean() * 10 d_loss += gradient_penalty ``` 3. **Transformer编码器增强**(参考引用[3]) ```python class TransformerEncoder(nn.Module): def __init__(self, embed_dim): super().__init__() self.encoder_layer = nn.TransformerEncoderLayer( d_model=embed_dim, nhead=8, dim_feedforward=2048) self.transformer_encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=6) def forward(self, x): # 将3D体素展开为序列 x = x.flatten(2).permute(2, 0, 1) return self.transformer_encoder(x) ``` ### 四、性能优化技巧 1. **混合精度训练** ```python from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() with autocast(): fake_volumes = generator(noise) # ... 后续计算 ... scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() ``` 2. **分布式训练** ```python # 初始化分布式训练 torch.distributed.init_process_group(backend='nccl') generator = nn.parallel.DistributedDataParallel(generator) discriminator = nn.parallel.DistributedDataParallel(discriminator) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值