在我的 PyTorch 训练迭代器中,如何解决 ValueError:只有一个元素张量可以转换为 Python 标量?

问题描述

如何解决ValueError: only one element tensors can convert to Python scalars

我正在密切关注有关构建 Question Answering Bot in PyTorch 的教程。然而,在训练时,我的代码无法保存检查点,给了我前面提到的 ValueError。错误发生在 torch.save(torch.tensor(train_loss_set),os.path.join(output_dir,'training_loss.pt'))

下面是我对应的训练迭代器的代码

num_train_epochs = 1

print("***** Running training *****")
print("  Num examples = %d" % len(dataset))
print("  Num Epochs = %d" % num_train_epochs)
print("  Batch size = %d" % batch_size)
print("  Total optimization steps = %d" % (len(train_DataLoader) // num_train_epochs))

model.zero_grad()
train_iterator = trange(num_train_epochs,desc="Epoch")
set_seed()

for _ in train_iterator:
    epoch_iterator = tqdm(train_DataLoader,desc="Iteration")
    for step,batch in enumerate(epoch_iterator):
        if step < global_step + 1:
            continue
            
        model.train()
        batch = tuple(t.to(device) for t in batch)
        
        inputs = {'input_ids':       batch[0],'attention_mask':  batch[1],'token_type_ids':  batch[2],'start_positions': batch[3],'end_positions':   batch[4]}
        
        outputs = model(**inputs)
        
        loss = outputs[0]
        train_loss_set.append(loss)
        loss.sum().backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(),1.0)

        tr_loss += loss.sum().item()
        optimizer.step()
        model.zero_grad()
        global_step += 1

        if global_step % 1000 == 0:
            print("Train loss: {}".format(tr_loss/global_step))
            output_dir = 'checkpoints/checkpoint-{}'.format(global_step)
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
            model_to_save = model.module if hasattr(model,'module') else model  # Take care of distributed/parallel training
            model_to_save.save_pretrained(output_dir)
            torch.save(torch.tensor(train_loss_set),'training_loss.pt'))
            print("Saving model checkpoint to %s" % output_dir)

编辑 print(train_loss_set[:10]) 返回以下内容

[tensor([5.7099,5.7395],device='cuda:0',grad_fn=<GatherBackward>),tensor([5.2470,5.4016],tensor([5.1311,5.0390],tensor([4.4326,4.8475],tensor([3.4740,3.9955],tensor([4.8710,4.5907],tensor([4.4294,4.3013],tensor([2.7536,2.9540],tensor([3.8989,3.3436],tensor([3.3534,3.2532],grad_fn=<GatherBackward>)]

这可能与我使用 DataParallel 的事实有关吗?

解决方法

这是pytorch的一个奇怪的行为。

基本上你不能使用张量列表来创建张量。

但是你可以做三件事。

  1. 是的,保存张量列表时不需要 torch.tensor,所以这应该可以工作。
torch.save(train_loss_set,os.path.join(output_dir,'training_loss.pt'))
  1. 改用 torch.stack
torch.save(torch.stack(train_loss_set),'training_loss.pt'))
  1. 这有点反直觉,但您可以将里面的张量转换为 ndarray。你可以使用 torch.tensor
train_loss_set.append(loss.cpu().detach().numpy())