最近做简单的网络训练,需要自写DataLoader,涉及到了图像数据的预处理,主要集中在getItem()函数里面。
上代码:
由于用到了BCEWithLogitsLoss,这个损失函数要求label与pred的维度保持一致,即label也需要有channel这一维度,所以涉及到了reshape与permute两个函数
这里不用to_tensor,不需要归一化,因此需要手动处理维度
先用reshape,再astensor
image = cv2.imread(image_path)
label = cv2.imread(label_path)
label = cv2.cvtColor(label, cv2.COLOR_BGR2GRAY)
image = image.reshape(-1, image.shape[0], image.shape[1])
label = label.reshape(-1, label.shape[0], label.shape[1])
img = torch.as_tensor(image.copy(), dtype=torch.float32).contiguous().permute(2,0,1)
label_t = torch.as_tensor(label.copy(), dtype=torch.float32).contiguous()
return img, label_t
然后在遍历,重构图像,检测结果
for image, label in train_loader:
if index in show:
img = image.cpu().detach().type(torch.ByteTensor).numpy()
lab = label.cpu().detach().type(torch.ByteTensor).numpy()
img = img.reshape(img.shape[2],img.shape[3],img.shape[1],img.shape[0]).squeeze(3)
lab = lab.reshape(lab.shape[2],lab.shape[3],lab.shape[1],lab.shape[0]).squeeze(3)
发现图像发生位移。
变成类似这样的图(这是手画的,实际使用的数据不在此处显示)
原因:
view(3,2)或reshape(3,2),得到的tensor并不是转置的效果,而是相当于将原tensor的元素按行取出,然后按行放入到新形状的tensor中。
因此,换成permute:
image = cv2.imread(image_path)
label = cv2.imread(label_path)
label = cv2.cvtColor(label, cv2.COLOR_BGR2GRAY)
img = torch.as_tensor(image.copy(), dtype=torch.float32).contiguous().permute(2,0,1)
label_t = torch.as_tensor(label.copy(), dtype=torch.float32).contiguous().unsqueeze(0)
for image, label in train_loader:
if index in show:
img = image.squeeze(0).permute(1,2,0).cpu().detach().type(torch.ByteTensor).numpy()
lab = label.squeeze(0).permute(1,2,0).cpu().detach().type(torch.ByteTensor).numpy()
输出图像正常–permute作用为调换Tensor的维度,参数为调换的维度。例如对于一个二维Tensor来说,调用tensor.permute(1,0)意为将1轴(列轴)与0轴(行轴)调换,相当于进行转置。
reshape和view在改变维度的同时,会导致像素位置发生变化,而permute不会
注意:
千万不要img用了F.to_tensor(image.copy()),
然后label为了统一size,使用了reshape(-1,label.shape[0],shape[1]),然后使用torch.as_tensor转tensor。
这样会样本与标签不对应,训练结果炸裂。
虽然reshape看起来像是加了一种相对位移的数据增强,但个人选用了permute,担心即使img与label同事使用reshape,如果img的channel与labe不一致的话,会导致样本与标签不对应。