pytorch 运行时错误:输入、输出和索引必须在当前设备上

ttvkxqim  于 2023-03-18  发布在  其他
关注(0)|答案(2)|浏览(173)

bounty将在2天后过期。回答此问题可获得+50声望奖励。MichiganMagician希望引起更多人关注此问题。

我的训练在这条线上失败了:outputs = model(**{key: torch.squeeze(value.to(self.training_device), 1) for key, value in inputs.items()})
我尝试用torch.nn.DataParallel()训练https://huggingface.co/docs/transformers/model_doc/layoutlmv2模型。我在AWS Sagemaker中使用了一个4 GPU的节点示例。但是,当代码到达上面一行时,它失败了,并在标题中显示了指定的错误。
我试着在网上看了一下,建议似乎是把模型和输入都移到GPU上,但我想我已经这样做了。另外,我不能调用inputs = inputs.to(self.training_device),因为输入是一个字典:dict_keys(['input_ids', 'token_type_ids', 'attention_mask', 'bbox', 'labels', 'image'])
这是我的培训师课程:

class LanguageModelTrainer(Trainer):
    def __init__(self, *args, class_weights=None, l1_coef=0, **kwargs):
        self.class_weights = class_weights
        self.l1_coef = l1_coef
        self.training_device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        super().__init__(*args, **kwargs)

    def compute_loss(self, model, inputs, return_outputs=False):
        model = torch.nn.DataParallel(model)
        model.to(self.training_device)

        loss_fn = torch.nn.CrossEntropyLoss(weight=self.class_weights)
        outputs = model(**{key: torch.squeeze(value.to(self.training_device),
                                              1) for key, value in inputs.items()})
        loss = loss_fn(outputs.logits.view(-1, model.config.num_labels), inputs["labels"].view(-1))

        if self.l1_coef:
            l1_norm = sum(torch.linalg.norm(p.flatten(), 1) for n, p in model.named_parameters() if 'bias' not in n)
            loss += self.l1_coef * l1_norm
        
        return (loss, outputs) if return_outputs else loss

对于DataParallel部分,我只是按照这个教程:https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html

a64a0gku

a64a0gku1#

你的输入字典有“bbox”和“image”,我认为这是一个Tensor非Tensor。“torch.squeeze”函数不能应用于非Tensor输入。这可能是问题所在。如果我误解了信息,请忽略以下内容。
要解决上述问题,请应用
torch.squeeze
使用验证后,仅对Tensor输入起作用
是示例(v, Torch ,Tensor)
检查一个值是否是Tensor。非Tensor输入应保持不变。
然后将修改后的输入传递给模型以训练/生成输出。
将输入移动到GPU并挤压Tensor的修改代码可能类似于以下代码:

inputs_gpu = {k: v.to(self.training_device) if isinstance(v, torch.Tensor) else v for k, v in inputs.items()}
inputs_gpu = {k: torch.squeeze(v, 1) if isinstance(v, torch.Tensor) else v for k, v in inputs_gpu.items()}
outputs = model(**inputs_gpu)

此修改应允许您将Tensor输入移动到GPU并对其应用挤压函数,而不会影响非Tensor输入。

vs3odd8k

vs3odd8k2#

compute_loss()方法中,在使用DataParallel Package 模型之前,应将其移动到self.training_device

def compute_loss(self, model, inputs, return_outputs=False):
    model.to(self.training_device)
    model = torch.nn.DataParallel(model)

然后将输入移动到与模型相同的设备:

inputs = {key: value.to(self.training_device) for key, value in inputs.items()}

然后将输入传递给模型,而不调用torch.squeeze

loss_fn = torch.nn.CrossEntropyLoss(weight=self.class_weights)
    outputs = model(**inputs)

并保持其余代码不变。

相关问题