自从transformer应用到cv领域以后,对图片的分割需求便越加重了,但是图像分割说起来容易,实际操作起来还是有很多地方不懂(主要还是code能力太弱)。

我们知道,对张量的处理一般又两种,一种是view/reshape这样的,先将数据按行展开,再按照指定形状排列数据;另一种是permute/transpose这种,是把数据按照维度进行变化,也就是把数据排列的先后顺序转换一下(后面具体介绍)。所以分割图片就用到了两者的结合

实验:

原图:

pytorch实现快速图像风格迁移 pytorch unet 图像分割_pytorch实现快速图像风格迁移

1:我们先看直接reshape的结果:将原图片切割为8份

pytorch实现快速图像风格迁移 pytorch unet 图像分割_pytorch_02

pytorch实现快速图像风格迁移 pytorch unet 图像分割_数据_03

pytorch实现快速图像风格迁移 pytorch unet 图像分割_pytorch_04

完全没法看好吧!

原因就是上面说的,reshape是把整张图片按行(这里是按照通道数3,实际上也确实应该把通道数调到最后,按照通道展开,原因后面介绍)展开。

2:我们看一下正确的做法:

pytorch实现快速图像风格迁移 pytorch unet 图像分割_pytorch_05

pytorch实现快速图像风格迁移 pytorch unet 图像分割_数据_06

 

pytorch实现快速图像风格迁移 pytorch unet 图像分割_深度学习_07

pytorch实现快速图像风格迁移 pytorch unet 图像分割_深度学习_08

pytorch实现快速图像风格迁移 pytorch unet 图像分割_深度学习_09

 可以看到分割的很完美!

接下来解释一下原因:

1:通道数必须放到最后一个维度:首先,我们知道再张量数据是连续的情况下,其数据是按行展开排序的,也就是按照张量最后一个维度展开排序,所以,对于一个三通道的RGB图像(3,H, W)它本来是按照宽度展开的,但这样在分割的时候就存在问题了,因为,分割一张图片,应该是三个通道一起分割,故,我们第一步应该把通道数调到最后一个维度(这里因为是用cv2打开的图片,通道数已经在最后一维 ,所以不用再单独转换,但如果需要转换的话,注意,不可以用reshape或者view,只能用permute/或者transpose)

2:宽和高的分割必须先在自己的维度分割,即对于一组(B,C,H, W)的图片,在把C转换到最后一维后为(B,H,W,C),分割(此时用reshape)应该先按照(B,H/H分割size,H分割size,W/W分割size,W分割size,C)展开,然后再用permute,或者tanspose转化为(B,H/H分割size,W/W分割size,H分割size,W分割size,C),最后,再用contiguous().view转化为(B,(H/H分割size)*(W/W分割size),H分割size,W分割size,C),解释如下:

张量的维度,实际上表述数据的方向和排列顺序,越靠后的维度越先排列,所以,对于(B, H W, C),如果只是进行reshape或者view的话,他始终是会先把宽W排完之后再排高,所以,为了要把图片分成一份一份的,那么就必须让宽和高交替出现,也就是要改变数据的排列顺序,这正是permute和transpose的作用,它们相当于在保持现有数据在内存中顺序的基础上,改变数据的排列顺序,这里(B,H/H分割size,H分割size,W/W分割size,W分割size,C)H/H分割size,H分割size都代表高;W/W分割size,W分割size都代表宽,也就是(B,高,高,宽,宽,C),将H分割size和W/W分割size转换以后则为(B,高,宽,高,宽,C )

pytorch实现快速图像风格迁移 pytorch unet 图像分割_数据_10