PyTorch深度学习实战—3.4 命名张量

目录

一、为什么要对张量进行命名

二、具体实例(将RGB三维图像转换为灰度一维图像)


一、为什么要对张量进行命名

       张量的维度或坐标轴通常用来表示诸如像素位置或颜色通道的信息,比如说通道数、图像的宽(列数)、图像的高(行数),那么由于我们在计算时需要相应的通道数、宽高等对应计算,并且有时数据存储并不一定都是按照[channels, rows, columns]这种顺序进行存储,也可能以[ rows, columns,channels]或[channels, columns, rows]等形式,这意味着当我们要把一 个张量作为索引时,我们需要记住维度的顺序并按此顺序编写索引,所以这种情况很容易混淆从而计算不一致出现计算错误,因此可以通过对张量进行命名来避免此种情况的发生,因为命名后可以实现对应维度索引的元素进行相应的计算。

二、具体实例(将RGB三维图像转换为灰度一维图像)

img_t = torch.randn(3, 5, 5) # shape [channels, rows, columns] 
'''channels 图片的通道数
   rows 图片的高度或者行数
   columns 图片的宽度或者列数
   img_t为单张RGB图像
   torch.randn()表示利用均值为0,方差为1的随机函数生成三维的大小为(3,5,5)的张量'''
weights = torch.tensor([0.2126, 0.7152, 0.0722]) '''三个通道对应的权重,注意这里不是
channels和0.2126对应,rows和0.7152对应然后columns和0.0722对应,而是一共有三个通道,
每个通道对应有一个权重,这里权重之和为1,也就是对三个通道的彩色RGB图像进行降维时可以通过
加权平均的方式,当然也可以通过直接进行平均的方式。'''
batch_t = torch.randn(2, 3, 5, 5) ''' shape [batch, channels, rows, columns] 
batch_t表示一批图像,该批图像中每一幅图像均为RGB图像'''
img_gray_naive = img_t.mean(-3) '''对于img_t的倒数第三维度也就是channels该维度进行平均'''
batch_gray_naive = batch_t.mean(-3) '''对于batch_t的倒数第三维度也就是channels该维度进行平均'''
img_gray_naive.shape, batch_gray_naive.shape '''(torch.Size([5, 5]), torch.Size([2, 5, 5]))
求平均也是相当于降维的操作,对哪一维进行平均就是消去了哪一维'''

以上就是采用直接平均的方式对三维RGB图像进行降维转换为灰度图像的方法,下面是利用加权平均的方式来进行降维转换的过程。

      因为现在我们有了权重,该权重张量现在为torch.Size([3]),而PyTorch 将允许我们对相同形状的张量进行乘法运算,也允许与给定维度中其中一个操作数大小为 1 的张量进行运算。它还会自动附加大小为 1 的前导维度,这个 特性被称为广播。形状为(2,3,5,5)的 batch_t 乘一个形状为(3,1,1) unsqueezed_weights 张量,得到 一个形状为(2,3,5,5)的张量,由此我们可以从末端开始对第三维(3 个通道)进行求和:

unsqueezed_weights = weights.unsqueeze(-1).unsqueeze_(-1) #  unsqueeze()是升维作用,两次之后将权重张量由[3]转变为[3, 1, 1] 
img_weights = (img_t * unsqueezed_weights) # 得到[2, 3, 5, 5]的张量
batch_weights = (batch_t * unsqueezed_weights) # 得到[2, 3, 5, 5]的张量 
img_gray_weighted = img_weights.sum(-3) # 对倒数第三维也即channels进行加和
batch_gray_weighted = batch_weights.sum(-3) # 对倒数第三维也即channels进行加和
batch_weights.shape, batch_t.shape, unsqueezed_weights.shape

 以上这种方式如果数据排列有不同时,则容易出现混乱,所以需要改进这种方式,下面这种方法里面用到的torch.einsum()为爱因斯坦求和(用于简洁的表示乘积、点积、转置等方法),

img_gray_weighted_fancy = torch.einsum('...chw,c->...hw', img_t, weights) # c代表channel,h代表高度,w代表宽度
# 即权重只和channel维度进行相乘计算,将共有的维度c合并
batch_gray_weighted_fancy = torch.einsum('...chw,c->...hw', batch_t, weights) 
batch_gray_weighted_fancy.shape 

 上面这种方式如果有些维度相距很远则也容易混乱出错,所以有人提出为张量命名来改进这种问题。当我们已经有一个张量并且想要为其添加名称但不改变现有的名称时,我们可以对其调用 refine_names()方法。与索引类似,省略号(…)允许你省略任意数量的维度。使用 rename()兄弟 方法,还可以覆盖或删除(通过传入 None)现有名称:

weights_named = torch.tensor([0.2126, 0.7152, 0.0722], names=['channels']) 
weights_named # tensor([0.2126, 0.7152, 0.0722], names=('channels',))
img_named=img_t.refine_names(...,'channels','rows','columns')
# 此处命名是从后面往前一一对应的,没有对应上的即没有命名
batch_named=batch_t.refine_names(...,'channels','rows','columns')
print("img named:",img_named.shape,img_named.names) # img named: torch.Size([3, 5, 5]) ('channels', 'rows', 'columns')
print("batch named:",batch_named.shape,batch_named.names) # batch named: torch.Size([2, 3, 5, 5]) (None, 'channels', 'rows', 'columns')

 现在如果weights_named与img_named直接进行计算的话,由于weights_named与img_named命名的数目不同并且维度不同,PyTorch 会检查张量名称,所以需要显示解决该问题使得两者能够运算,align_as()方法返回一个张量,其中添加了 缺失的维度,现有的维度按正确的顺序排列如下:

weights_aligned=weights_named.align_as(img_named) # 也即让weights_aligned与img_named两个张量在维度和张量名称两个方面进行对齐
weights_aligned.shape,weights_aligned.names # (torch.Size([3, 1, 1]), ('channels', 'rows', 'columns'))

之后就可以利用命名后的张量进行计算了

gray_named=(img_named*weights_aligned).sum('channels') # 相乘之后在channels维度上进行相加求和
gray_named.shape,gray_named.names # (torch.Size([5, 5]), ('rows', 'columns'))

你可能感兴趣的:(PyTorch深度学习,深度学习,pytorch,python)