You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于TorchText实现Transformer架构的多标签关联多输出回归任务的技术咨询

使用TorchText实现Transformer多输出回归任务的解决方案

嘿,刚好我之前处理过类似的自定义文本任务,来给你一步步拆解解决方案!

先明确两个核心问题的答案

(1) 是否可以使用torchtext实现该任务?

完全可以! TorchText本质是帮你搞定文本数据的预处理、批量加载这些脏活累活,不管是分类、生成还是你这种特殊的多输出回归,只要适配好数据格式,它都能胜任。

(2) 应如何定义标签对应的Field?

这是你这个任务的核心难点——因为你的标签是「目标词+4维小数向量」的可变长度组合,常规LabelField没法直接处理。我们需要自定义一个Field来解析这种结构,把它转换成模型能识别的张量格式,后面会给你具体代码和思路。


具体实现步骤

1. 自定义Field与数据预处理

首先,我们需要定义两个Field:一个处理输入句子,一个处理特殊的标签结构。

输入句子的Field(常规操作)

你的句子已经分词好了,所以这个Field只需要负责构建词表、把词转成索引就行:

from torchtext.legacy import data

# 输入句子的Field:sequential=True表示是序列数据,include_lengths=True返回句子长度方便后续处理
TEXT = data.Field(
    sequential=True,
    tokenize=lambda x: x,  # 已分词,直接用原列表
    lower=False,
    include_lengths=True
)

自定义标签Field

你的标签是[(word, [d1,d2,d3,d4]), ...]这种可变长度结构,我们需要自定义Field来:

  • 把目标词转换成TEXT词表里的索引(复用同一个词表)
  • 把4维小数向量转成张量
  • 处理不同样本标签数量不一致的padding问题
import torch

class CustomLabelField(data.Field):
    def __init__(self, **kwargs):
        # 标签是序列结构,不需要自己构建词表(复用TEXT的)
        super().__init__(sequential=True, use_vocab=False, **kwargs)
    
    def preprocess(self, x):
        # x是单个样本的labels列表:[(word, [d1,d2,d3,d4]), ...]
        processed = []
        for word, vec in x:
            # 用TEXT的词表把目标词转成索引
            word_idx = TEXT.vocab.stoi[word]
            # 把小数列表转成float张量
            vec_tensor = torch.tensor(vec, dtype=torch.float32)
            processed.append((word_idx, vec_tensor))
        return processed
    
    def pad(self, minibatch):
        # 处理一个batch内标签数量不一致的情况,用padding填充到最长长度
        max_label_num = max(len(sample) for sample in minibatch)
        padded_batch = []
        
        for sample in minibatch:
            pad_num = max_label_num - len(sample)
            # 填充的索引用0(对应TEXT词表的<PAD>),向量用全0
            padded_sample = sample + [(0, torch.zeros(4, dtype=torch.float32))] * pad_num
            # 把索引和向量分开整理成张量
            word_indices = torch.tensor([w for w, v in padded_sample], dtype=torch.long)
            vecs = torch.stack([v for w, v in padded_sample])
            padded_batch.append((word_indices, vecs))
        
        # 把整个batch的索引和向量分别堆叠成二维、三维张量
        batch_indices = torch.stack([w for w, v in padded_batch])
        batch_vecs = torch.stack([v for w, v in padded_batch])
        return (batch_indices, batch_vecs)

# 初始化标签Field
LABEL = CustomLabelField()

2. 构建数据集与迭代器

假设你的数据存在一个列表data_list里(就是你给出的0:、1:对应的字典集合),我们把它转换成TorchText的Dataset格式:

# 定义字段映射:把字典的key对应到我们定义的Field
fields = [('sentence', TEXT), ('labels', LABEL)]

# 生成Dataset实例
dataset = data.Dataset(
    examples=[data.Example.fromdict(item, fields) for item in data_list],
    fields=fields
)

# 划分训练集和验证集(按需调整比例)
train_data, valid_data = dataset.split(split_ratio=0.8)

# 给TEXT构建词表,可选加载预训练词向量(比如GloVe)
TEXT.build_vocab(train_data, vectors="glove.6B.100d")

# 构建迭代器:按句子长度排序,减少padding带来的计算浪费
train_iterator, valid_iterator = data.BucketIterator.splits(
    (train_data, valid_data),
    batch_size=32,
    sort_key=lambda x: len(x.sentence),
    device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
)

3. 适配Transformer模型

你的任务是输入句子,针对每个目标词输出4维回归向量,模型需要做一点小调整:

  • 用Transformer Encoder对句子编码,得到每个词的隐藏状态
  • 根据标签里的目标词索引,取出对应位置的隐藏状态
  • 用线性层把隐藏状态映射到4维输出,用MSE损失做回归

示例模型代码:

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

class TransformerRegressor(nn.Module):
    def __init__(self, input_dim, emb_dim, nhead, hidden_dim, nlayers, output_dim, dropout):
        super().__init__()
        # 词嵌入层,可选加载预训练向量
        self.embedding = nn.Embedding(input_dim, emb_dim)
        self.embedding.weight.data.copy_(TEXT.vocab.vectors)
        
        # Transformer编码器
        self.transformer_encoder = nn.TransformerEncoder(
            nn.TransformerEncoderLayer(emb_dim, nhead, hidden_dim, dropout),
            num_layers=nlayers
        )
        # 最后映射到4维输出的线性层
        self.fc = nn.Linear(emb_dim, output_dim)
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, text, text_lengths):
        # text形状:[seq_len, batch_size](TorchText默认序列在前)
        embedded = self.dropout(self.embedding(text))
        # Transformer输入格式刚好是[seq_len, batch_size, emb_dim]
        encoded = self.transformer_encoder(embedded)
        # 转成[batch_size, seq_len, emb_dim]方便后续按索引取词
        encoded = encoded.permute(1, 0, 2)
        return encoded
    
    def predict(self, encoded, target_indices):
        # target_indices形状:[batch_size, num_labels],每个元素是目标词在句子中的索引
        # 用gather取出对应位置的隐藏状态
        target_indices = target_indices.unsqueeze(-1)
        target_hidden = torch.gather(encoded, 1, target_indices.expand(-1, -1, encoded.size(2)))
        # 映射到4维输出
        output = self.fc(target_hidden)
        return output

4. 训练逻辑示例

训练时从迭代器取出batch数据,计算MSE损失即可:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 初始化模型参数
INPUT_DIM = len(TEXT.vocab)
EMB_DIM = 100
NHEAD = 2
HIDDEN_DIM = 200
NLAYERS = 2
OUTPUT_DIM = 4
DROPOUT = 0.5

model = TransformerRegressor(INPUT_DIM, EMB_DIM, NHEAD, HIDDEN_DIM, NLAYERS, OUTPUT_DIM, DROPOUT).to(device)

# 回归任务用MSE损失
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters())

def train(model, iterator, optimizer, criterion):
    model.train()
    epoch_loss = 0
    for batch in iterator:
        text, text_lengths = batch.sentence
        target_indices, target_vecs = batch.labels
        
        optimizer.zero_grad()
        
        # 得到句子编码
        encoded = model(text, text_lengths)
        # 生成预测结果
        predictions = model.predict(encoded, target_indices)
        
        # 计算损失
        loss = criterion(predictions, target_vecs)
        
        loss.backward()
        optimizer.step()
        
        epoch_loss += loss.item()
    
    return epoch_loss / len(iterator)

额外注意事项

  • 因为你的目标词都是句子里的词,训练前可以检查一下所有目标词都在TEXT的词表里(根据你的数据集特征,这一点已经满足),避免KeyError。
  • 计算损失时可以考虑忽略padding部分的影响:在CustomLabelField的pad方法里额外返回一个mask张量,训练时用mask过滤padding的损失,结果会更准确。
  • 如果你用的是TorchText 0.12+的新版本,可以改用torchtext.data的新API,核心思路是一致的,只是数据加载的细节略有不同。

内容的提问来源于stack exchange,提问作者omegap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:42:34