已解决!!!有bug不要放弃一定要细心追根溯源,花点时间很正常的。
1:bug出现的地方
根据报错的信息,我们可以定位在损失函数losses = loss_function_train(pred_scales, target_scales),还有在损失函数的原函数处class CrossEntropyLoss2d(nn.Module):
2:什么原因导致的bug:
这是由于维度不匹配导致的,那是什么维度不匹配?,以及那两个维度不匹配的呢?。
①:在网上冲浪了大半天,大部分都是因为view函数使用错误,导致nn.linear函数的输入和输出不匹配。因此需要回模型检查view函数前的维度,通过print函数检查view函数输入前的维度,经过我认真检查维度,对每一个层都进行print后发现模型维度没有任何的错误,所以这个方法不适用于我,但是还把链接放在这里大家检查一下自己的模型batch维度不匹配。
②:然后我就在losses处前面加上print,即打印pred_scales,target_scales的shape。
# print(pred_scales.shape) #torch.Size([8, 40, 448, 448]) # print(target_scales.shape) #torch.Size([8, 448, 448]) losses = loss_function_train(pred_scales, target_scales)
这里还有一个小插曲,刚开始target_scales的size还打印不出来,是因为target_scales是一个列表,里面是totch,经过分析把target_scales旁边的中括号去掉就可以打印了。
这里我们看一下pred_scales,target_scales到底是啥:
pred_scales = model(image, depth)
if modality in ['rgbd', 'rgb']: image = sample['image'].to(device) # print(image.shape) #torch.Size([8, 3, 448, 448]) batch_size = image.data.shape[0] if modality in ['rgbd', 'depth']: depth = sample['depth'].to(device) # print(depth.shape) #torch.Size([8, 1, 448, 448]) batch_size = depth.data.shape[0] # print(batch_size) # 8 target_scales = sample['label'].to(device)
model是我们实例化后的模型,这里将rgb和depth输入,pred_scales就是我们的模型输出,这里是(8,40,448,448),target_scales是标签。这里我们可以看出target_scales是sample列表中['label']索引对应的数据,同理image和depth也是rgb和depth索引对应的数据。
而sample是什么呢?
train_data = Dataset( data_dir=args.dataset_dir, split='train', depth_mode=depth_mode, with_input_orig=with_input_orig, **dataset_kwargs) train_loader = DataLoader(train_data, batch_size=args.batch_size, num_workers=args.workers, drop_last=True, shuffle=True) train_loader, valid_loader = data_loaders for i, sample in enumerate(train_loader):
我们看一下数据传递的流程,首先获取data路径,经过dataset获得图片,然后经过dataloader取一个batch的数据得到trainloader,遍历trainloader的列表,得到索引i和数据sample。因为trainloader取的一个batch=8的数据,所以samle里面包含了image,depth,label他们的大小分别为torch.Size([8, 3, 448, 448]),torch.Size([8, 1, 448, 448]),torch.Size([8, 448, 448])。即
pred_scales大小为(8,40,448,448),我们有40个类别,target_scales大小为torch.Size([8, 448, 448])。
这里延伸一下pytorch如何进行损失函数计算 参考:
标签没有通道,每一个像素代表一个类别,且大小和图片的输入相同,为什么不需要one-hot编码是因为pytorch自动进行编码了。这里有一个坑:预测值和标签进行损失计算,他们两个都必须有batch,否则是不能计算成功的。
下面一个例子演示一下:
inputs_scales = torch.rand(8,40,448,448) targets_scales = torch.rand(8,448,448) for inputs, targets in zip(inputs_scales, targets_scales): # inputs = inputs.unsqueeze(0) # targets = targets.unsqueeze(0) print(inputs.shape) print(targets.shape) loss2 = nn.CrossEntropyLoss() result2 = loss2(inputs, targets.long()) print(result2)
torch.Size([40, 448, 448]) torch.Size([448, 448]) Traceback (most recent call last): File "/tmp/pycharm_project_346/kong.py", line 816, in result2 = loss2(inputs, targets.long()) File "/home/software/anaconda3/envs/pycharm329/lib/python3.7/site-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/home/software/anaconda3/envs/pycharm329/lib/python3.7/site-packages/torch/nn/modules/loss.py", line 1166, in forward label_smoothing=self.label_smoothing) File "/home/software/anaconda3/envs/pycharm329/lib/python3.7/site-packages/torch/nn/functional.py", line 3014, in cross_entropy return torch._C._nn.cross_entropy_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index, label_smoothing) ValueError: Expected input batch_size (40) to match target batch_size (448).
类似于题目中的bug是吧!
我们增加batch维度后:batch为8,所以遍历八次,每次都做损失计算。
inputs_scales = torch.rand(8,40,448,448) targets_scales = torch.rand(8,448,448) for inputs, targets in zip(inputs_scales, targets_scales): inputs = inputs.unsqueeze(0) targets = targets.unsqueeze(0) print(inputs.shape) print(targets.shape) loss2 = nn.CrossEntropyLoss() result2 = loss2(inputs, targets.long()) print(result2)
torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7298) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7283) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7302) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7282) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7296) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7296) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7289) torch.Size([1, 40, 448, 448]) torch.Size([1, 448, 448]) tensor(3.7292)
在损失的定义中:
inputs_scales和 targets_scales的维度分别为torch.Size([8, 40, 448, 448]),torch.Size([8, 448, 448]),遍历inputs_scales和 targets_scales,他们的维度就是如下,他们是不能进行损失计算的。
print(targets.shape) torch.Size([448, 448]) print(inputs.shape) torch.Size([40, 448, 448])
class CrossEntropyLoss2d(nn.Module): def __init__(self, device, weight): super(CrossEntropyLoss2d, self).__init__() self.weight = torch.tensor(weight).to(device) self.num_classes = len(self.weight) + 1 # +1 for void if self.num_classes 0 # 返回一个和源张量同shape、dtype和device的张量,与源张量不共享数据内存,但提供梯度的回溯 targets_m = targets.clone() targets_m -= 1 print(inputs.size()) print(targets_m.size()) loss_all = self.ce_loss(inputs, targets_m.long()) number_of_pixels_per_class = \ torch.bincount(targets.flatten().type(self.dtype), minlength=self.num_classes) divisor_weighted_pixel_sum = \ torch.sum(number_of_pixels_per_class[1:] * self.weight) # without void losses.append(torch.sum(loss_all) / divisor_weighted_pixel_sum) # losses.append(torch.sum(loss_all) / torch.sum(mask.float())) return losses
3:如何解决?
所以我们要给遍历的两个数据增加维度,或者说遍历[8, 40, 448, 448],我们希望的输出是[1,40,448,448],直接增加维度也是同理。然后我们就可以运行了。
inputs = inputs.unsqueeze(0) targets = targets.unsqueeze(0) targets_m = targets.clone()
总结:预测图和标签又要有batch这一维度,才能够匹配,才能够输入到损失函数中。正好就对应了bug,batch的不匹配。