这个是一个常用的模块,就是我们可以对输入的特征嵌入位置编码。
位置编码(Positional Encoding)是一种将空间位置信息嵌入到特征中的方法,通常用于帮助模型更好地理解特征的空间关系。
这里介绍的这个是相对位置编码,代码如下:
def _make_coord(batch, height, width):xv, yv = torch.meshgrid([torch.arange(0, height), torch.arange(0, width)])xv_min = (xv.float() * 2 - width) / widthyv_min = (yv.float() * 2 - height) / heightxv_max = ((xv + 1).float() * 2 - width) / widthyv_max = ((yv + 1).float() * 2 - height) / heightxv_ctr = (xv_min + xv_max) / 2yv_ctr = (yv_min + yv_max) / 2hmap = torch.ones(height, width) * (1. / height)wmap = torch.ones(height, width) * (1. / width)coord = torch.cat([xv_min.unsqueeze(0), yv_min.unsqueeze(0),xv_max.unsqueeze(0), yv_max.unsqueeze(0),xv_ctr.unsqueeze(0), yv_ctr.unsqueeze(0),hmap.unsqueeze(0), wmap.unsqueeze(0)], dim=0)coord = coord.unsqueeze(0).repeat(batch, 1, 1, 1)return coord
这个模块怎么用?
比如说你现在特征大小是2x64x4x4,batchsize是2,通道数64,宽和高是4
给定参数宽和高就可以生成位置编码,生成的位置编码是8维的,然后直接复制到跟batchsize保持一致就行
就得到了bx8xHxW的位置编码,然后直接和特征进行拼接,拼接完了直接卷积融合就行,就可以实现位置编码的嵌入
解释一下这个模块:
根据代码来讲解
我们假设特征
batch_size = 2 # 批量大小
height = 4 # 特征图高度
width = 4 # 特征图宽度
首先
xv, yv = torch.meshgrid([torch.arange(0, height), torch.arange(0, width)])
# 生成两个网格矩阵 xv 和 yv,分别表示每个像素的横坐标和纵坐标。
可能有点抽象,具体来说
xv如下(每一个位置的数代表该位置像素的横坐标)
[0,0,0,0],
[1,1,1,1],
[2,2,2,2],
[3,3,3,3]
yv如下(每一个位置的数代表该位置像素的纵坐标)
[0,1,2,3],
[0,1,2,3],
[0,1,2,3],
[0,1,2,3]
随后就是
xv_min = (xv.float() * 2 - width) / widthyv_min = (yv.float() * 2 - height) / height
这个计算就是进行相对位置编码,前面两行的计算公式:(xv.float() * 2 - width) / width
这就是将坐标映射到[-1,1)
上去,注意,左闭右开,不会映射到1,因为从0开始的。
xv_max = ((xv + 1).float() * 2 - width) / widthyv_max = ((yv + 1).float() * 2 - height) / height
那么这个max也是一样,这个是映射到(-1,1]
上去
最终得到的矩阵如下:
xv_min
如下
[-1 ,-1 ,-1 ,-1 ],
[-0.5,-0.5,-0.5,-0.5],
[0 ,0 ,0 ,0 ],
[0.5 ,0.5 ,0.5 ,0.5 ]
yv_min
如下
[-1 ,-0.5 ,0 ,0.5 ],
[-1 ,-0.5 ,0 ,0.5 ],
[-1 ,-0.5 ,0 ,0.5 ],
[-1 ,-0.5 ,0 ,0.5 ]
xv_max
如下
[-0.5,-0.5,-0.5,-0.5],
[0 ,0 ,0 ,0 ],
[0.5 ,0.5 ,0.5 ,0.5 ],
[1 ,1 ,1 ,1 ]
yv_max
如下
[-0.5 ,0 ,0.5 ,1 ],
[-0.5 ,0 ,0.5 ,1 ],
[-0.5 ,0 ,0.5 ,1 ],
[-0.5 ,0 ,0.5 ,1 ]
这个东西的意义是什么?就是你把xv_min
和yv_min
组合起来,左上角为[-1,-1],其余坐标都是相对左上角的坐标。
你把xv_max
和yv_max
组合起来,右下角为[1,1],其余坐标都是相对右下角的坐标。
xv_min
和 yv_min
表示每个像素相对于左上角的坐标,xv_max
和 yv_max
表示每个像素相对于右下角的坐标。
紧接着,是计算每个像素的中心坐标,即像素的几何中心位置。
xv_ctr = (xv_min+xv_max)/2
yv_ctr = (yv_min+yv_max)/2
这个计算出来得到的是相对中心值,就是你相对左上角的值加上相对右下角的值,除以2,就是个平均值,就是中间的值
xv_ctr
如下
[-0.75,-0.75,-0.75,-0.75],
[-0.25,-0.25,-0.25,-0.25],
[0.25 ,0.25 ,0.25 ,0.25 ],
[0.75 ,0.75 ,0.75 ,0.75 ]
yv_ctr
如下
[-0.75,-0.25,0.25,0.75],
[-0.75,-0.25,0.25,0.75],
[-0.75,-0.25,0.25,0.75],
[-0.75,-0.25,0.25,0.75]
然后下面两行,这个计算的就是宽度步长和高度步长,换句话说:分别表示每个像素的高度和宽度的归一化值。
hmap = torch.ones(height, width) * (1. / height)
wmap = torch.ones(height, width) * (1. / width)
计算出来hmap
和wmap
都如下所示,一样的,因为设置的宽高是一样的,1/4都是0.25
[0.25,0.25,0.25,0.25],
[0.25,0.25,0.25,0.25],
[0.25,0.25,0.25,0.25],
[0.25,0.25,0.25,0.25]
将上述计算的 8 个通道(xv_min
, yv_min
, xv_max
, yv_max
, xv_ctr
, yv_ctr
, hmap
, wmap
)拼接在一起,形成一个 8×H×W 的张量。
使用 unsqueeze(0)
将其扩展为 1×8×H×W,然后通过 repeat(batch, 1, 1, 1)
将其复制到每个样本上,最终得到一个 B×8×H×W 的张量。
这个 8 维位置编码包含了以下信息:
- 每个像素左上角的归一化坐标(
xv_min
,yv_min
)。 - 每个像素右下角的归一化坐标(
xv_max
,yv_max
)。 - 每个像素中心的归一化坐标(
xv_ctr
,yv_ctr
)。 - 每个像素的相对高度和宽度(
hmap
,wmap
)。
这些信息为模型提供了丰富的空间位置信息,有助于模型更好地理解特征图中像素之间的空间关系。