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

PyTorch模型单样本与批量推理预测结果不一致问题咨询

PyTorch模型单样本与批量推理预测结果不一致问题咨询

您好,我发现用PyTorch训练的Transformer模型,在单样本推理和批量推理时,同一个样本的预测结果差异非常明显:单样本推理输出是[0.37732467 0.2642143 0.35846105],但把这个样本放到批量里推理时,输出变成了[0.3185594 0.40971586 0.2717247 ]。想请教如何保证两种场景下的预测结果一致?

以下是我的完整代码:

from transformers import Trainer, TrainingArguments, PreTrainedModel, PretrainedConfig
from torch.utils.data import Dataset
import torch
import torch.nn.functional as F
import numpy as np

# Number of Features
num_of_features = 128

# Dataset Class
class SequenceDataset(Dataset):
    def __init__(self, X, y):
        self.X = torch.tensor(X, dtype=torch.float32)
        self.y = torch.tensor(y, dtype=torch.long)

    def __len__(self):
        return len(self.y)

    def __getitem__(self, idx):
        return {"input_ids": self.X[idx], "labels": self.y[idx]}


# Configuration Class
class SequenceConfig(PretrainedConfig):
    model_type = "sequence_transformer"

    def __init__(self, num_features=num_of_features, num_classes=3, d_model=1024, nhead=4, num_layers=4, dim_feedforward=512, **kwargs):
        self.num_features = num_features
        self.num_classes = num_classes
        self.d_model = d_model
        self.nhead = nhead
        self.num_layers = num_layers
        self.dim_feedforward = dim_feedforward
        super().__init__(**kwargs)


# Transformer Model
class SequenceTransformer(PreTrainedModel):
    config_class = SequenceConfig

    def __init__(self, config):
        super().__init__(config)
        self.embedding = torch.nn.Linear(config.num_features, config.d_model)
        self.positional_encoding = torch.nn.Parameter(torch.zeros(1, config.d_model))
        encoder_layer = torch.nn.TransformerEncoderLayer(
            d_model=config.d_model, 
            nhead=config.nhead, 
            dim_feedforward=config.dim_feedforward, 
            batch_first=True
        )
        self.transformer_encoder = torch.nn.TransformerEncoder(encoder_layer, num_layers=config.num_layers)
        self.fc = torch.nn.Linear(config.d_model, config.num_classes)

    def forward(self, input_ids, labels=None):
        src = self.embedding(input_ids) + self.positional_encoding
        output = self.transformer_encoder(src)
        logits = self.fc(output)
        probs = F.softmax(logits, dim=-1)

        loss = None
        if labels is not None:
            loss_fct = torch.nn.CrossEntropyLoss()
            loss = loss_fct(logits, labels)
            
        return {"loss": loss, "logits": logits, "probs": probs} if labels is not None else logits


# Training Code
config = SequenceConfig()
model = SequenceTransformer(config)

# Training Arguments
batchSize=32
numWarmUpSteps=int(np.shape(train_image)[0]/batchSize/numOfBreakpointsPerEpoch/10)
training_args = TrainingArguments(
    output_dir=path,
    num_train_epochs=1, 
    per_device_train_batch_size=batchSize,
    per_device_eval_batch_size=320,
    warmup_steps=numWarmUpSteps,
    weight_decay=0.1,
    logging_strategy='no',
    eval_strategy="epoch",
    save_strategy="epoch",
    metric_for_best_model="accuracy",
    save_only_model=True,
)

# Trainer Initialization
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=val_dataset,
    compute_metrics=compute_metrics
)

# Train the Model
train_output = trainer.train()

# Save Model and Training Arguments
trainer.save_model("./SavedModels")
torch.save(training_args, "./SavedModels/training_args.bin")

# Prediction Code
training_args_loaded = torch.load("./SavedModels/training_args.bin")
model_save_path = "./SavedModels/"
model = SequenceTransformer(config).from_pretrained(model_save_path)

trainer = Trainer(model=model, compute_metrics=compute_metrics, args=training_args_loaded)
test_data = np.random.rand(10, num_of_features)  # Example test data
test_predictions = trainer.predict(torch.tensor(test_data, dtype=torch.float32))

# Output Test Predictions
print(test_predictions)

问题分析与解决方案

这种单样本和批量结果不一致的情况,大概率是模型模式或数据处理的问题,下面是具体的排查和修复步骤:

  • 强制切换模型到评估模式
    模型在训练时会启用dropout、动态层归一化等训练专属行为,推理时必须关闭这些才能保证结果稳定。你加载模型后没有显式调用model.eval(),虽然Trainer.predict()会自动切换模式,但如果自己手动做单样本推理时忘了切换,就会出现差异。
    建议在所有推理代码前加上:

    model.eval()
    

    同时搭配torch.no_grad()禁用梯度计算,既节省内存也避免干扰:

    with torch.no_grad():
        # 单样本推理示例
        single_sample = torch.tensor(test_data[0:1], dtype=torch.float32)
        single_logits = model(single_sample)
        single_probs = F.softmax(single_logits, dim=-1)
        print(single_probs.numpy())
    
  • 确保数据预处理完全一致
    检查单样本和批量样本的预处理流程是否完全同步:比如数据类型是否都是float32、有没有遗漏的归一化步骤、输入形状是否匹配(单样本要保持(1, num_features)的批量维度,不能直接传(num_features)的张量)。你当前的测试数据是随机生成的,看起来没问题,但实际场景中要严格对齐。

  • 验证Trainer的单样本预测行为
    可以直接用Trainer来做单样本预测,对比结果是否和批量一致:

    single_test_dataset = SequenceDataset(test_data[0:1], np.array([0]))
    single_pred_result = trainer.predict(single_test_dataset)
    print(single_pred_result.predictions)
    

    如果结果和批量一致,说明问题出在你自己手动单样本推理时的模式切换或数据处理上。

  • 排查设备与精度问题
    偶尔GPU和CPU的浮点数计算精度差异,或者混合精度训练的残留影响会导致微小差异,但你这里的差异很大,所以这个可能性较低。可以尝试把模型和数据都放到同一个设备(比如统一用CPU或GPU)再测试。


备注:内容来源于stack exchange,提问作者Dishant Dua

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 18:19:51