日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Positional Encodings in ViTs 近期各视觉Transformer中的位置编码方法总结及代码解析 1

發(fā)布時(shí)間:2025/3/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Positional Encodings in ViTs 近期各视觉Transformer中的位置编码方法总结及代码解析 1 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Positional Encodings in ViTs 近期各視覺Transformer中的位置編碼方法總結(jié)及代碼解析

最近CV領(lǐng)域的Vision Transformer將在NLP領(lǐng)域的Transormer結(jié)果借鑒過來,屠殺了各大CV榜單。對(duì)其做各種改進(jìn)的頂會(huì)論文也是層出不窮,本文將聚焦于各種最新的視覺transformer的位置編碼PE(positional encoding)部分的設(shè)計(jì)思想及代碼實(shí)現(xiàn)做一些總結(jié)。

ViT

[2021-ICLR] AN IMAGE IS WORTH 16X16 WORDS: TRANSFORMERS FOR IMAGE RECOGNITION AT SCALE

論文:https://arxiv.org/abs/2010.11929

代碼:https://github.com/lucidrains/vit-pytorch/blob/main/vit_pytorch

對(duì)于原始的ViT,筆者曾做過一份較為全面的代碼解析及圖解:Vision Transformer(ViT)PyTorch代碼全解析(附圖解),有興趣的讀者可以參考。

論文中的位置編碼方法

PE的設(shè)計(jì)

在ViT中,并沒有對(duì)位置編碼做過多的設(shè)計(jì),只是使用一組可學(xué)習(xí)的參數(shù)來學(xué)習(xí)位置編碼,注意這樣的位置編碼如果在面對(duì)測(cè)試時(shí)的高分辨率圖像時(shí)是無法處理的。

ViT原文是這么說的:

When feeding images of higher resolution, we keep the patch size the same, which results in a larger effective sequence length. The Vision Transformer can handle arbitrary sequence lengths (up to memory constraints), however, the pre-trained position embeddings may no longer be meaningful. We therefore perform 2D interpolation of the pre-trained position embeddings, according to their location in the original image. Note that this resolution adjustment and patch extraction are the only points at which an inductive bias about the 2D structure of the images is manually injected into the Vision Transformer.

大概意思就是:當(dāng)輸入高分圖像時(shí),會(huì)導(dǎo)致序列的長度變長,ViT是可以處理任意長度的,但此時(shí)訓(xùn)練得到的位置編碼就不再有意義了,并且只能通過2D插值實(shí)現(xiàn)。

z=[xclass;xp1E,xp2E,…;xpNE]+Epos,E∈R(P2?C)×D,Epos∈R(N+1)×D(1)\mathbf{z}=[\mathbf{x}_{class};\mathbf{x}^1_p\mathbf{E},\mathbf{x}^2_p\mathbf{E},\dots;\mathbf{x}^N_p\mathbf{E}]+\mathbf{E}_{pos},\ \ \ \mathbf{E}\in\mathbb{R}^{(P^2\cdot C)\times D},\mathbf{E}_{pos}\in \mathbb{R}^{(N+1)\times D} \ \ \ \ \ \ \ \ \ \ \ \ \ (1) z=[xclass?;xp1?E,xp2?E,;xpN?E]+Epos?,???ER(P2?C)×D,Epos?R(N+1)×D?????????????(1)
根據(jù)原文公式(即上式),ViT中位置編碼的維度應(yīng)該為 (N+1)×D(N+1)\times D(N+1)×D ,這里 NNN 是圖塊的個(gè)數(shù),+1是加上class token, DDD 是映射后的每個(gè)token的維度,因?yàn)橐苯酉嗉?#xff0c;所以要保持一致。下面會(huì)用代碼來驗(yàn)證查看。

關(guān)于PE的消融實(shí)驗(yàn)

原文附錄中的實(shí)驗(yàn)也顯示肯定是有位置編碼比沒有效果要好,但是看起來比較有設(shè)計(jì)的二維位置編碼和相對(duì)位置編碼相較于簡單的一維位置編碼性能反而更差。

第一行是完全沒有位置編碼,即沒有提供位置信息,相當(dāng)于將一堆patch直接輸入進(jìn)去;第二行是一維位置編碼,即將輸入patch看作是序列;第三行是二維位置編碼,將輸入看作是二維的patch網(wǎng)格;第四行是相對(duì)位置編碼,考慮到patch之間的相對(duì)距離,將空間信息編碼為而不是其絕對(duì)位置。

注意:如果要使用相對(duì)位置編碼,一定要考慮好自己的任務(wù)需不需要絕對(duì)位置信息,如目標(biāo)檢測(cè),由于要輸出預(yù)測(cè)的邊界框的坐標(biāo),因此絕對(duì)位置信息是必須的,這時(shí)使用相對(duì)位置編碼就不合適了。

關(guān)于PE的可視化實(shí)驗(yàn)

ViT原文對(duì)位置編碼做的可視化實(shí)驗(yàn)如下圖所示,熱力圖的含義是某個(gè)位置的圖塊的位置編碼與全圖其他位置圖塊的位置編碼的余弦相似度。我們可以看到,當(dāng)然與自己相似度最高,然后就是同行同列也比較高,其他的位置就低一些,這也基本符合我們對(duì)位置編碼的基本期望,因?yàn)樗^的位置編碼要的就是圖像塊在原圖中的位置信息,更通俗點(diǎn)說就是行列信息,即某個(gè)圖像塊是在原圖中的哪行哪列。

代碼分析

ViT代碼中的位置編碼:

self.pos_embedding = nn.Parameter(torch.randn(1, num_patches+1, dim)) # ... x += self.pos_embedding[:, :(n+1)]

直接用可學(xué)習(xí)的參數(shù)torch.Parameter()作為位置編碼直接加到token序列中,跟隨整個(gè)訓(xùn)練過程一起學(xué)習(xí)。(關(guān)于torch.Parameter()的介紹可見博客:PyTorch中的torch.nn.Parameter() 詳解)

另外,我們?cè)儆么a來檢查一下ViT中的位置編碼的維度形狀,這里我們直接借用timm庫中的實(shí)現(xiàn):

import timm model = timm.create_model('vit_base_patch16_224', pretrained=True, num_classes=10) pos_embed = model.state_dict()['pos_embed'] print(pos_embed.shape)

輸出:

torch.Size([1, 197, 768])

我們是將224x224的圖像分為14x14個(gè)圖塊,共196塊,再加上class token 為197,而768則是我們指定的維度,符合我們的預(yù)期。

CPVT

Conditional Positional Encodings for Vision Transformers

論文:https://arxiv.org/abs/2102.10882

代碼:https://github.com/Meituan-AutoML/Twins (原文中給的鏈接中沒有實(shí)做代碼,實(shí)做代碼發(fā)布在這個(gè)倉庫了)

論文中的位置編碼方法

CPVT與ViT的位置編碼的區(qū)別在下圖中體現(xiàn)的很明顯,ViT的位置編碼PE沒有過多的設(shè)計(jì),直接加到patch token和cls token得到的embedding上,然后就送到后面的多個(gè)transformer block(圖中encoder)中,注意ViT中的PE必須顯示地指定好token序列的長度。而CPVT則是先不加PE,在第一個(gè)transformer block之后,僅過PEG(Postional Encoding Generator)來生成位置編碼,在加到第一層的輸出上,在進(jìn)行后面的計(jì)算,這樣長度就不需要顯式指定,可以隨輸入變化而變化,因此被稱為隱式的條件位置編碼。

其中的PEG模塊是用來產(chǎn)生條件位置編碼的模塊,其框架如下圖所示:

在 PEG 中,將上一層 Encoder 的 1D 輸出變形成 2D,再使用 F 學(xué)習(xí)其位置信息,最后重新變形到 1D 空間,與之前的 1D 輸出相加之后作為下一個(gè) Encoder 的輸入。

具體來說,在上圖中,為了根據(jù)局部領(lǐng)域,我們首先將DeiT flatten過的輸入序列 X∈RB×N×CX\in \mathbb{R}^{B\times N\times C}XRB×N×C? reshape回二維圖像空間 X′∈RB×H×W×CX'\in\mathbb{R}^{B\times H\times W\times C}XRB×H×W×C? 。然后某個(gè)函數(shù) F\mathcal{F}F? 會(huì)反復(fù)作用于 X′X'X? 中的局部圖塊來生成條件位置編碼 EB×H×W×CE^{B\times H\times W\times C}EB×H×W×C? ,PEG可以由二維卷積高效地實(shí)現(xiàn),其卷積核 k>=3k>=3k>=3?,并且有零填充 k?12\frac{k-1}{2}2k?1?? 。注意這里的零填充是很重要的,它可以使模型感知到絕對(duì)位置, F\mathcal{F}F? 可以是多種形式,比如可分離卷積。

代碼分析

在CPVT的代碼實(shí)現(xiàn)中,我們主要來看PEG部分:

class PosCNN(nn.Module):def __init__(self, in_chans, embed_dim=768, s=1):super(PosCNN, self).__init__()self.proj = nn.Sequential(nn.Conv2d(in_chans, embed_dim, 3, s, 1, bias=True, groups=embed_dim), )self.s = sdef forward(self, x, H, W):B, N, C = x.shapefeat_token = xcnn_feat = feat_token.transpose(1, 2).view(B, C, H, W)if self.s == 1:x = self.proj(cnn_feat) + cnn_featelse:x = self.proj(cnn_feat)x = x.flatten(2).transpose(1, 2)return xdef no_weight_decay(self):return ['proj.%d.weight' % i for i in range(4)]

可以看到,與原文中對(duì)PEG的介紹一致:將第一層Encoder 的1D 輸出變形成 2D,再使用F學(xué)習(xí)其位置信息,最后重新變形到 1D 空間,與之前的 1D 輸出相加之后作為下一個(gè) Encoder 的輸入。

這里的self.proj就是文中的轉(zhuǎn)換函數(shù) F?。

我們?cè)賮砜碢EG模塊在整個(gè)CPVT中的使用:

class CPVTV2(PyramidVisionTransformer):def __init__(self, ...)# ...self.pos_block = nn.ModuleList( # 實(shí)例化一個(gè)PEG模塊[PosCNN(embed_dim, embed_dim) for embed_dim in embed_dims])# ...def forward_features(self, x):B = x.shape[0]for i in range(len(self.depths)):x, (H, W) = self.patch_embeds[i](x)x = self.pos_drops[i](x)for j, blk in enumerate(self.blocks[i]):x = blk(x, H, W)if j == 0:x = self.pos_block[i](x, H, W) # PEG模塊 在這里使用if i < len(self.depths) - 1:x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()x = self.norm(x)return x.mean(dim=1)

可以看到,只有在第一個(gè)encoder之后(for循環(huán)中j=0時(shí)),使用PEG模塊計(jì)算位置編碼,后面正常進(jìn)行其他的其他Encoder的計(jì)算,與論文原文一致。

本文將保持持續(xù)更新,讀者如果遇到有趣的Vision Transformer的改進(jìn)方法,也歡迎分享討論。

總結(jié)

以上是生活随笔為你收集整理的Positional Encodings in ViTs 近期各视觉Transformer中的位置编码方法总结及代码解析 1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。