單目標跟蹤算法:Siamese RPN論文解讀和代碼解析

2021-02-20 3D視覺工坊
1.前言深度學習【目標追蹤】專欄寫過一篇對Siamese FC網絡的解析。接著Siamese網絡在單目標追蹤任務(SOT)上的應用,我們展開對Siamese RPN的論文解讀和代碼解析。提到RPN層,了解雙階段法目標檢測模型(FasterRCNN)的各位必定不會陌生。RPN層全稱叫做Region-Proposal-Network,中文翻譯:區域提議網絡,通過該網絡,產生一些圖像中前景和背景的候選框。但是就只是前景和背景,並沒有對前景候選框中的類別進行詳述。這裡放上FasterRCNN中的RPN層,如下圖FasterRCNN中的RPN層可以看出來,RPN層是有兩個分支的,上面一個特徵圖通道為18(18=9x2),用來獲得所有anchor(先驗框)前景和背景置信度(簡單來說,就是判別這個先驗框anchor中是不是前景或者背景),下面一個特徵圖通道數為36(36=9x4),用來獲得所有anchor(先驗框)的位置調整變量(簡單來說,就是每個先驗框anchor位置是固定的,所以需要通過這四個變量進行調整,成為預測框)。至此,對RPN的簡單介紹就完畢了。那麼RPN層和Siamese網絡如何進行融合,做到比傳統的核方法以及上一篇提到的Siamese FC更好的結果呢?這個疑問將通過本文的代碼解析和論文解讀進行分析,強烈推薦大家去讀原文。代碼連結如下,很輕便的代碼,就兩個py文件:https://github.com/huanglianghua/siamrpn-pytorch本文將對Siamese RPN進行詳細解析,主要從以下幾個部分進行解析2.網絡結構原論文中給了Siamese RPN的兩個網絡結構圖,我們先看第一個,圖上紅色字體是我標註的一些符號,便於後面說明。由此可見,Siamese RPN網絡主要有Siamese 和 RPN網絡構成。Siamese網絡翻譯為孿生網絡比較合適,因為它由兩個分支構成(如上圖),這兩個分支的卷積神經網絡共享權重(實質就是同一個網絡,為了便於理解才這麼說的)。原論文中提到,
Here we use the modified AlexNet , where the groups from conv2 and conv4 are removed .這裡說明Siamese RPN用到了非常簡單的AlexNet網絡進行圖像特徵的提取。有人會問,這論文2018年發表的,那時候特徵提取網絡滿天飛,怎麼還在用老古董AlexNet?這是因為研究者們也嘗試將ResNet作為Siamese圖像特徵提取網絡,但是發現收效甚微,這個原因將在SiameseRPN++進行解析,本篇不做涉及。
self.feature = nn.Sequential(# conv1            nn.Conv2d(3, 192, 11, 2),            nn.BatchNorm2d(192),            nn.ReLU(inplace=True),            nn.MaxPool2d(3, 2),# conv2            nn.Conv2d(192, 512, 5, 1),            nn.BatchNorm2d(512),            nn.ReLU(inplace=True),            nn.MaxPool2d(3, 2),# conv3            nn.Conv2d(512, 768, 3, 1),            nn.BatchNorm2d(768),            nn.ReLU(inplace=True),# conv4            nn.Conv2d(768, 768, 3, 1),            nn.BatchNorm2d(768),            nn.ReLU(inplace=True),# conv5            nn.Conv2d(768, 512, 3, 1),            nn.BatchNorm2d(512))

結構簡單,清晰明了呀!從上面的圖可以清晰看出,該孿生網絡接受兩個輸入,一個叫做template frame(模板幀),是從視頻第一幀中人為框出來(可以理解為原圖中裁剪的一個區域)的物體位置;另一個輸入叫做detection frame(檢測幀),是被檢測的視頻段除了第一幀之外的其他幀。該Siamese(AlexNet)網絡將這兩個圖像分別映射為6x6x256大小的特徵圖  和22x22x256大小的特徵圖  。上面我們有提到過RPN層有兩個分支,一個分支做前景背景區分的(後面稱為分支1),另一個分支用來調整anchor(先驗框)的位置(後面稱為分支2)。我們從上面的圖中也可以看出,該RPN網絡也是由兩個分支組成的,每個分支接受兩個輸入(所以看起來有點像四個分支,其實是兩個,看輸出就知道了)。該RPN網絡的每個分支接受Siamese網絡的兩個輸出  和  通過卷積層 ( 改變通道維度) 後的特徵圖作為輸入,對分支1來說,分別為  和  ,對分支2來說,分別為  和  。值得注意的是,  的通道維度為2k x 256, 的通道維度為4k x 256,這裡的k是anchor的數量,至於為什麼有這個2k和4k,相信接觸過FasterRCNN中RPN層的小夥伴們必定不會陌生。2k中存放著每個cell的k個先驗框中物體為前景和背景的置信度為多少,由於存放兩個信息,所以就是2k。同理,4k包含著每個cell的k個先驗框為了靠近真實框而做的位置移動信息。解釋到這裡,會有人問了,這個256是什麼?其實是這樣的,網絡的輸出 和  是通道為2k和4k的特徵圖,如上圖所示。那麼這個  和  相當於卷積核參數,被卷積的對象是 和  。圖中的五角星運算符就是卷積運算的意思。那麼這個256就是被卷積對象的維度,2k和4k就是卷積核的個數。
class SiamRPN(nn.Module):
def __init__(self, anchor_num=5):super(SiamRPN, self).__init__()self.anchor_num = anchor_numself.feature = nn.Sequential(# conv1 nn.Conv2d(3, 192, 11, 2), nn.BatchNorm2d(192), nn.ReLU(inplace=True), nn.MaxPool2d(3, 2),# conv2 nn.Conv2d(192, 512, 5, 1), nn.BatchNorm2d(512), nn.ReLU(inplace=True), nn.MaxPool2d(3, 2),# conv3 nn.Conv2d(512, 768, 3, 1), nn.BatchNorm2d(768), nn.ReLU(inplace=True),# conv4 nn.Conv2d(768, 768, 3, 1), nn.BatchNorm2d(768), nn.ReLU(inplace=True),# conv5 nn.Conv2d(768, 512, 3, 1), nn.BatchNorm2d(512))
self.conv_reg_z = nn.Conv2d(512, 512 * 4 * anchor_num, 3, 1)self.conv_reg_x = nn.Conv2d(512, 512, 3)self.conv_cls_z = nn.Conv2d(512, 512 * 2 * anchor_num, 3, 1)self.conv_cls_x = nn.Conv2d(512, 512, 3)self.adjust_reg = nn.Conv2d(4 * anchor_num, 4 * anchor_num, 1)
def forward(self, z, x):return self.inference(x, **self.learn(z))
def learn(self, z): z = self.feature(z) kernel_reg = self.conv_reg_z(z) kernel_cls = self.conv_cls_z(z)
k = kernel_reg.size()[-1] kernel_reg = kernel_reg.view(4 * self.anchor_num, 512, k, k) kernel_cls = kernel_cls.view(2 * self.anchor_num, 512, k, k)
return kernel_reg, kernel_cls
def inference(self, x, kernel_reg, kernel_cls): x = self.feature(x) x_reg = self.conv_reg_x(x) x_cls = self.conv_cls_x(x)
out_reg = self.adjust_reg(F.conv2d(x_reg, kernel_reg)) out_cls = F.conv2d(x_cls, kernel_cls)
return out_reg, out_cls

網絡先定義了一些相關層,比如使用AlexNet作為Siamese網絡的特徵提取網絡。代碼中的x和z分別對應上圖中  和  ,其他對應關係如下:·x_reg對應 ·x_cls對應 ·kernel_reg對應 ·kernel_cls對應 ·out_reg 對應 ·out_cls 對應 
out_reg = self.adjust_reg(F.conv2d(x_reg, kernel_reg)) out_cls = F.conv2d(x_cls, kernel_cls)

至此,對SiameseRPN的網絡結構解析就結束了。可以看出來,SiameseRPN網絡並不複雜。有點尷尬的是這段代碼不包含訓練過程,我重新找了一段代碼,代碼連接如下:https://github.com/zllrunning/SiameseX.PyTorch/issues根據上面代碼中的siamese RPN的部分代碼,我們對Siamese RPN的訓練過程進行解析。3.訓練過程詳細解析上面對Siamese RPN網絡的結構進行了詳細的解析,這裡我們根據網絡結構對訓練過程的一些細節進行詳細解析。具體包括:上述連結代碼中的  文件中的函數  前面有這樣的定義,如下
train_loader = torch.utils.data.DataLoader(dataset.listDataset(args.ilsvrc, args.youtube, args.data_type,shuffle=True,transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),]),train=True,
batch_size=args.batch_size,num_workers=args.workers, coco=coco),batch_size=args.batch_size)

這裡引出了一個簡單的數據集定義  ,我們進入該數據集定義中,找到 __getitem__(self, index)定義中的下面代碼:
 elif self.data_type == 'RPN':
z, x, gt_box, regression_target, label = load_data_rpn(pair_infos, self.coco, rpnpp=self.rpnpp)
if self.transform is not None: z = self.transform(z) x = self.transform(x)
regression_target = torch.from_numpy(regression_target) label = torch.from_numpy(label)
return z, x, regression_target, label

我們進入函數load_data_rpn中,代碼定義如下
def load_data_rpn(pair_infos, discrim, train=True, rpnpp=False):if not rpnpp:anchors = generate_anchor(8, [8, ], [0.33, 0.5, 1, 2, 3], 17)gt = np.zeros((1, 17, 17))else:anchors = generate_anchor(8, [8, ], [0.33, 0.5, 1, 2, 3], 25)gt = np.zeros((1, 25, 25))gt[:, :, :] = -1 #所有都設置為-1gt[0, 8, 8] = 1. #中心設置為1
img_path1 = pair_infos[0][0] #圖片地址img_path2 = pair_infos[1][0]
bs1 = pair_infos[0][1] # xmin xmax ymin ymaxbs2 = pair_infos[1][1]
gt1 = Rectangle(bs1[0], bs1[2], bs1[1] - bs1[0], bs1[3] - bs1[2]) #xmin ymin w hgt2 = Rectangle(bs2[0], bs2[2], bs2[1] - bs2[0], bs2[3] - bs2[2])
gt1 = convert_bbox_format(gt1, to='center-based') # x_cer,y_cer,w,hgt2 = convert_bbox_format(gt2, to='center-based')
img1 = Image.open(img_path1).convert('RGB')img2 = Image.open(img_path2).convert('RGB')
zbox1 = get_zbox(gt1, 0.25)zbox2 = get_zbox(gt2, 0.25)
scales_w = 1.04 ** (random.random() * 6 - 3) # 1.08..scales_h = 1.04 ** (random.random() * 6 - 3)
zbox2_scaled = Rectangle(zbox2.x, zbox2.y, zbox2.width * scales_w, zbox2.height * scales_h)
dx = 0
dy = 0
xbox2 = get_xbox(zbox2_scaled, dx, dy) # we assume second is the search region
z = gen_xz(img1, zbox1, to='z')x = gen_xz(img2, xbox2, to='x')
info = [dx, dy, gt2.width / scales_w / zbox2.width, gt2.height / scales_h / zbox2.height]
gt_box = np.array([-info[0] * 64, -info[1] * 64, info[2] * 128, info[3] * 128])
anchor_xctr = anchors[:, :1]anchor_yctr = anchors[:, 1:2]anchor_w = anchors[:, 2:3]anchor_h = anchors[:, 3:]gt_cx, gt_cy, gt_w, gt_h = gt_box
target_x = (gt_cx - anchor_xctr) / anchor_wtarget_y = (gt_cy - anchor_yctr) / anchor_htarget_w = np.log(gt_w / anchor_w)target_h = np.log(gt_h / anchor_h)regression_target = np.hstack((target_x, target_y, target_w, target_h))
iou = compute_iou(anchors, gt_box).flatten() # print(np.max(iou))
pos_index = np.where(iou > 0.4)[0]neg_index = np.where(iou < 0.3)[0]
label = np.ones_like(iou) * -1label[pos_index] = 1label[neg_index] = 0
return z, x, gt_box, regression_target, label

·讀取search image 和template image 並進行裁剪,獲取相應的region·產生anchor,並獲得ground true box。·anchor與ground true box 之間的offset進行編碼,產生 regression_target·根據anchor與ground true box 之間的IOU產生正樣本和負樣本,作為置信度label最後,根據真實的標籤和網絡輸出的預測值,進行損失函數的設定即可這裡我們回到  中的函數  中,找到以下代碼段
 # 預測pred_score, pred_regression = model(z, x)
pred_conf = pred_score.reshape(-1, 2, 5 * 17 * 17).permute(0, 2, 1)
pred_offset = pred_regression.reshape(-1, 4, 5 * 17 * 17).permute(0, 2, 1)
# 目標targetregression_target = regression_target.type(torch.FloatTensor).cuda()conf_target = conf_target.type(torch.LongTensor).cuda()
# 損失cls_loss = rpn_cross_entropy(pred_conf, conf_target)reg_loss = rpn_smoothL1(pred_offset, regression_target, conf_target)
loss = cls_loss + reg_loss

我們發現Siamese RPN中分類損失採用了交叉熵,回歸損失採用了smoothL1。至此,對Siamese RPN的解析就結束了。有空的話大家可以跑一跑模型,或者對代碼中的細節進行深度解讀,相信大家會有更多收穫的。3.總結本文我們介紹了一種單目標檢測器Siamese RPN網絡,並對該網絡結構和訓練的一些細節進行了詳細的解析,當然由於時間問題並沒有對一些更小的細節進行解析,如果後面時間充裕,會進行一些補充,謝謝大家支持!

相關焦點

  • 單目標跟蹤論文綜述:SiamFC、Siam系列和GradNet
    關於單目標跟蹤本人不了解傳統的相關濾波法,所有想法總結僅僅建立在深度學習的基礎上。對於單目標跟蹤而言一般的解釋都是在第一幀給出待跟蹤的目標,在後續幀中,tracker能夠自動找到目標並用bbox標出。關於SOT(single object track),有兩條思路。第一種,我們可以把跟蹤粗暴地當做一個配對問題,即把第一幀的目標當做模板,去匹配其他幀。
  • 目標跟蹤最強算法開源:商湯SiamRPN系列解讀
    雷鋒網(公眾號:雷鋒網) AI 科技評論消息,日前,商湯科技智能視頻團隊首次開源其目標跟蹤研究平臺 PySOT。PySOT 包含了商湯科技 SiamRPN 系列算法,以及剛被 CVPR2019 收錄為 Oral 的 SiamRPN++。此篇文章將獨家解讀目標跟蹤最強算法 SiamRPN 系列。
  • 挑戰目標跟蹤算法極限,商湯開源SiamRPN系列算法解讀
    商湯科技智能視頻團隊首次開源其目標跟蹤研究平臺 PySOT。PySOT 包含了商湯科技 SiamRPN 系列算法,以及剛被 CVPR2019 收錄為 Oral 的 SiamRPN++。此篇文章將解讀目標跟蹤最強算法 SiamRPN 系列。
  • 商湯開源最大目標跟蹤庫PySOT,代碼已正式上線!
    商湯開源最大目標跟蹤庫PySOT:含SiamRPN++和SiamMask等算法,介紹了來自商湯科技的STVIR(SenseTime Video Intelligence Research team)開源的目標跟蹤庫:PySOT。當時PySOT並沒有上傳代碼,所以之前的文章僅介紹了新特性,但得到大家廣泛關注。
  • 論文盤點:基於圖卷積GNN的多目標跟蹤算法解析
    的發展,其對於關係的建模特性也被引入了多目標跟蹤領域,這次我通過對這兩年基於 GNN 的 MOT 算法的介紹來分析其特點。>論文連結:https://arxiv.org/abs/1907.05315代碼連結:https://github.com/peizhaoli05/EDA_GNN從算法的示意圖可以看到,作者通過一個孿生網絡求得了觀測目標 j 與當前目標軌跡 i 的表觀相似度,然後取目標軌跡的歷史位置為輸入,通過 LSTM 得到預測的位置
  • 計算機視覺中,究竟有哪些好用的目標跟蹤算法(上)
    相信很多來到這裡的人和我第一次到這裡一樣,都是想找一種比較好的目標跟蹤算法,或者想對目標跟蹤這個領域有比較深入的了解,雖然這個問題是經典目標跟蹤算法,但事實上,可能我們並不需要那些曾經輝煌但已被拍在沙灘上的tracker(目標跟蹤算法),而是那些即將成為經典的,或者就目前來說最好用、速度和性能都看的過去的tracker。
  • Siamese:CVPR 2019 接收論文作者為你解讀視頻跟蹤領域 | CVPR 2019
    對於目標跟蹤而言,一般論文開篇通常都會說在第一幀給定目標位置,在後續幀中預測目標的位置。然而如何對後續幀中表述的定義直接影響了整個跟蹤領域的發展。為了方便表述,早期的跟蹤算法都是坐標軸對齊的的矩形框。但隨著跟蹤精度的不斷提升,數據集的難度在不斷提升,在 VOT2015 時即提出使用旋轉矩形框來作為標記。
  • 計算機視覺中,有哪些比較好的目標跟蹤算法?(上)
    相信很多來這裡的人和我第一次到這裡一樣,都是想找一種比較好的目標跟蹤算法,或者想對目標跟蹤這個領域有比較深入的了解,雖然這個問題是經典目標跟蹤算法,但事實上,可能我們並不需要那些曾經輝煌但已被拍在沙灘上的tracker(目標跟蹤算法),而是那些即將成為經典的,或者就目前來說最好用、速度和性能都看的過去tracker。
  • 最強目標跟蹤算法SiamRPN++開源了,商湯出品
    經年累月,團隊死磕孿生網絡,用這類算法來做目標跟蹤。在這之中,SiamRPN赫然挺立,中選了CVPR 2018的Spotlight。SiamRPN:把檢測算法引入跟蹤這隻AI的誕生,是因為團隊發現:雖然孿生網絡能對目標快速定位,但不能對目標框作出調整,也就不能調節目標的形狀。可目標跟蹤並不是只要定一個點,目標所在的範圍也同樣重要。
  • Siamese network 孿生神經網絡--一個簡單神奇的結構
    答:是的,在代碼實現的時候,甚至可以是同一個網絡,不用實現另外一個,因為權值都一樣。對於siamese network,兩邊可以是lstm或者cnn,都可以。大家可能還有疑問:如果左右兩邊不共享權值,而是兩個不同的神經網絡,叫什麼呢?答:pseudo-siamese network,偽孿生神經網絡,如下圖所示。
  • 孿生網絡入門(上) Siamese Net及其損失函數
    >圖像分割必備知識點 | Dice損失 理論+代碼3D卷積入門 | 多論文筆記 | R2D C3D P3D MCx R(2+1)D醫學AI論文解讀 | 超聲心動圖在臨床中的自動化檢測後來好像還有基於Siamese網絡的視覺跟蹤算法,這個我還沒有了解,以後有機會的話我看一看這個論文。《Fully-convolutional siamese networks for object tracking》。先挖一個坑。
  • 目標跟蹤論文筆記:Deeper Wider Siamese Tracker(CVPR2019)
    Deeper and Wider Siamese Networks for Real-Time Visual Tracking本文來自微軟研究院和中科院王強團隊出品,研究方向是實時目標跟蹤算法,已經被CVPR2019收錄,單目標的跟蹤算法現在基本都是基於Siamese框架,本文的重點其實在於對Siamese框架的跟蹤算法進行了比較系統的分析
  • 近兩年目標跟蹤資源全匯總(論文、模型代碼、優秀實驗室)
    極市導讀:目標跟蹤是計算機視覺領域中非常熱門且具有挑戰性的研究主題之一。近年來,基於深度學的的目標跟蹤取得了巨大的進展,為了方便大家研究學習,極市整理了一份2019年至2020年的目標跟蹤相關資源合集,包括頂會論文(CVPR/ECCV/ICCV)、算法匯總以及目標跟蹤國內外優秀實驗室,詳見下文:頂會論文(由於篇幅有限,以下每個分題均展示前5篇,完整版可前往閱讀原文
  • 深度長文:計算機視覺中,目前有哪些經典的目標跟蹤算法?
    (這麼做的理論依據是:一篇論文,在它之前的工作可以看它的引用文獻,之後的工作可以看誰引用了它;雖然引用量並不能說明什麼,但好的方法大家基本都會引用的(表示尊重和認可);之後還可以通過限定時間來查看某段時間的相關論文,如2016-2017就能找到最新的論文了,至於論文質量需要仔細甄別;其他方向的重要論文也可以這麼用,順藤摸瓜,然後你就知道大牛是哪幾位,接著關注跟蹤一下他們的工作 )這樣我們就大致知道目標跟蹤領域的最新進展應該就是相關濾波無疑了
  • 基於深度學習的多目標跟蹤:從UMA Tracker出發談談SOT類MOT算法
    ©PaperWeekly 原創 · 作者|黃飄學校|華中科技大學碩士生研究方向|多目標跟蹤之前的文章中我們介紹了聯合檢測和跟蹤的多目標跟蹤框架,這類框架最大優勢在於可以利用優秀的檢測器平衡不同觀測輸入的質量。
  • 融合視頻目標檢測與單目標、多目標跟蹤,港中文開源視頻感知平臺
    該框架基於 PyTorch 寫成,支持單目標跟蹤、多目標跟蹤與視頻目標檢測,目前已開源。GitHub 地址:https://github.com/open-mmlab/mmtrackingMMTracking 效果展示。據介紹,MMTracking 具備以下主要特性:1.
  • 融合視頻目標檢測與單目標、多目標跟蹤,港中文開源一體化視頻感知...
    新年伊始,香港中文大學多媒體實驗室(MMLab)OpenMMLab 又有新動作,發布了一款一體化視頻目標感知平臺 MMTracking。該框架基於 PyTorch 寫成,支持單目標跟蹤、多目標跟蹤與視頻目標檢測,目前已開源。GitHub 地址:https://github.com/open-mmlab/mmtracking
  • 計算機視覺中,有哪些比較好的目標跟蹤算法?(下)
    相信很多來這裡的人和我第一次到這裡一樣,都是想找一種比較好的目標跟蹤算法,或者想對目標跟蹤這個領域有比較深入的了解,雖然這個問題是經典目標跟蹤算法,但事實上,可能我們並不需要那些曾經輝煌但已被拍在沙灘上的tracker(目標跟蹤算法),而是那些即將成為經典的,或者就目前來說最好用、速度和性能都看的過去tracker。
  • 2017目標跟蹤算法綜述
    2017目標跟蹤算法綜述本文所提的跟蹤主要指的是單目標跟蹤,多目標跟蹤暫時不作為考慮範圍。
  • 多目標跟蹤:SORT和Deep SORT
    >SORT全稱為Simple Online And Realtime Tracking, 對於現在的多目標跟蹤,更多依賴的是其檢測性能的好壞,也就是說通過改變檢測器可以提高18.9%,本篇SORT算法儘管只是把普通的算法如卡爾曼濾波(Kalman Filter)和匈牙利算法(Hungarian algorithm)結合到一起,卻可以匹配2016年的SOTA算法,且速度可以達到