簡介
BEV即Bird's Eye View(鳥瞰視圖)是一種從空中俯視場景的視角。由多張不同視角采集的圖像通過不同的空間轉換方式形成,如下圖所示,左側為6張不同位置的相機采集的圖像,右側為轉換的BEV圖像。
BEV感知模型指的是直接輸出BEV坐標系下的感知結果,如動靜態檢測目標,車道線,路面標識等。BEV坐標系好處是:
1. 成本低。相比3D點云的方式來補充3維信息,純視覺方案的成本更低;
2. 可以直接給到下游任務,例如預測和規劃;
3. 可以在模型中融合各視角的特征,提升感知效果;
4. 可以更好的和各類傳感器進行融合。
對于下游的預測和規控任務而言,需要的是3D的目標,因此在傳統的自動駕駛方案中,2D的感知推理結果需要通過復雜的后處理去解決3D坐標提升的問題。而BEV感知模型是更接近于一種端到端的解決方案。
當前主要的BEV 轉換方式為以下三種:
? IPM-based:基于地面平坦假設的逆透視映射方式,技術簡單成本低,但是對上下坡情況擬合效果不好。
? LSS-based:通過顯示的深度估計方式構建三維視錐點云特征,也是較常用的轉換方式。
? Transformer-based:用transformer機制學習3D query和2D 圖像特征之間的關系來建模。部署時global attention的計算量較大, 需要考慮端側運行時對性能的影響。
在實際部署時,需要考慮算法的端側性能。地平線的參考算法目前已賦能多家客戶實現BEV感知算法在征程5上的部署和開發,多家客戶已實現BEV demo開發。本文以LSS范式的BEV感知算法為例,介紹地平線提供的參考算法如何在公版的基礎上做算法在征程5芯片的適配和模型的優化。
整體框架
BEV 感知架構
BEV系列的模型使用多視圖的當前幀的6個RGB圖像作為輸入。輸出是目標的3D Box和BEV分割結果。多視角圖像首先使用2D主干獲取2D特征。然后投影到3D BEV視角。接著對BEV feature 編碼獲取BEV特征。最后,接上任務特定的head,輸出多任務結果。模型主要包括以下部分:
Part1—2D Image Encoder:圖像特征提取層。使用2D主干網絡(efficientnet)和FastSCNN輸出不同分辨率的特征圖。返回最后一層--上采樣至1/16原圖大小層,用于下一步投影至3D BEV坐標系中;
Part2—View transformer:采用不同的轉換方式完成圖像特征到BEV 3D特征的轉換;
Part3—BEV transforms:對BEV特征做數據增強,僅發生在訓練階段;
Part4—3D BEV Encoder:BEV特征提取層;
Part5—BEV Decoder:分為Detection Head和Segmentation Head。
LSS方案
公版的LSS方案如下:
公版的LSS方案分為3個部分:
1. 將圖像從2d平面提升到3d空間,生成3d視錐(frustum)點云,并對點云上所有的點預測context特征,生成context特征點云;
2. 對視錐點云和context特征點云進行 “Splat” 操作,在BEV網格中構建BEV特征;
3. BEV特征后,可通過“Shooting”完成特定的下游任務,比如Motion Planning。
模型部署分析
在部署之前,需要對公版模型做部署分析,避免模型中有BPU無法支持的算子和某些對性能影響較大的算子。對于無法支持的算子,需要做替換;對于影響性能的算子需要做優化。同時為了達到更好的精度會增加訓練策略的優化和量化策略的優化。本章節先對公版模型做部署分析,最后給出地平線的優化方式。
問題1 大尺寸運算導致性能瓶頸
由于深度特征的增加,feature的維度是高于4維的,考慮到transpose算子的耗時問題和部署問題,LSS方案中會存在維度的折疊,對feature做view和H維度的折疊。對應的操作為:depth_feature會做view和Dim、H和W的折疊。維度折疊會導致feature的維度變大,在生成視錐點云時,其涉及的操作mul操作的輸入也就增大了,在做部署時會導致DDR帶寬問題。因此公版的步驟1中的大尺寸算子計算需要做對應的優化。
問題2 BEVpooling的索引操作支持問題
公版在做2D到3D轉換時,從圖像空間的index映射到BEV空間的index,相同的BEV空間index相加后再賦值到BEV tensor上,即公版的步驟二。考慮到征程5對索引操作無法支持,因此該操作在部署時需要做替換。
問題3 分割頭粒度太粗
地平線提供的是多任務的BEV感知算法,對于多任務模型來說不同的任務需要特定的范圍和粒度,特別是對于分割模型來說,分割的目標的粒度較小,因此相比于檢測任務來說feature需要細化,即用更大的分辨率來表示。
問題4 grid 量化精度誤差問題
對于依賴相機內外參的模型來說,轉換時的點坐標極其重要,因此需要保障該部分的精度。同時grid的表示范圍需要使用更大比特位的量化。
針對以上4個問題,本章節會介紹該部分在征程5的實現方式使其可以在板端部署并高速運行。
性能優化
mul的性能優化
為了減少大量的transpose操作和優化mul算子的耗時問題, 我們選擇把深度和 feature 分別做grid_sample后執行mul操作,具體操作如下:
Python #depth B, N, D,H, W depth = tensor(B,N,D,H,W) feat = tensor(B,N,C,H,W) #depth B, 1, N *D, H*W depth = depth.view(B, 1, N*D, H*W) #feat -> B,C,N,H,W-> B, C, N*H, W feat = feat.permute(0, 2, 1, 3, 4).view(B, C, N*H, W) for i in range(self.num_points): homo_feat = self.grid_sample( feat, fpoints[i * B : (i + 1) * B], ) homo_dfeat = self.dgrid_sample( dfeat, dpoints[i * B : (i + 1) * B], ) homo_feat = self.floatFs.mul(homo_feat, homo_dfeat) homo_feats.append(homo_feat)
mul操作的計算量大幅減少,性能上提升4~5倍!
BEV_pooling部署優化
使用grid_sample代替公版的3D空間轉換。即從原來的前向wrap-從圖像空間特征轉換到BEV空間特征,改為從BEV空間拉取圖像空間特征。
公版實現:
a.通過一個深度估計變成6D的tensor
Python volume = depth.unsqueeze(1) * cvt_feature.unsqueeze(2) volume = volume.view(B, N, volume_channel_index[-1], self.D, H, W) volume = volume.permute(0, 1, 3, 4, 5, 2)
b.從圖像空間的index映射到BEV空間的index,相同的BEV空間index相加后再賦值到BEV tensor上
Python def voxel_pooling(self, geom_feats, x): ... # flatten x x = x.reshape(Nprime, C) # flatten indices geom_feats = ((geom_feats - (self.bx - self.dx/2.)) / self.dx).long() geom_feats = geom_feats.view(Nprime, 3) ... # filter out points that are outside box kept = (geom_feats[:, 0] >= 0) & (geom_feats[:, 0] < nx[0]) & (geom_feats[:, 1] >= 0) & (geom_feats[:, 1] < nx[1]) & (geom_feats[:, 2] >= 0) & (geom_feats[:, 2] < nx[2]) geom_feats = geom_feats[kept] x = x[kept] ... # argsort and get tensors from the same voxel next to each other ranks = geom_feats[:, 0] * (nx[1] * nx[2] * B) + geom_feats[:, 1] * (nx[2] * B) + geom_feats[:, 2] * B + geom_feats[:, 3] sorts = ranks.argsort() x, geom_feats, ranks = x[sorts], geom_feats[sorts], ranks[sorts] ... return final
2. 地平線實現:
使用grid_sample代替公版的3D空間轉換。grid_sample為采樣算子,通過輸入圖像特征和2D點坐標grid,完成圖像特征到BEV特征的轉換,其工作原理見下圖。
Grid_Samples 原理圖
horizon_plugin_pytorch提供的grid_sample算子和公版輸入略有差異,地平線已支持公版的grid_sample算子。
由于該轉換方式是前向映射,前向映射會產生的BEV index并不均勻,最多的一個voxel有100多個點,最少有效點為0。我們在提供的源代碼中使用了每個voxel使用了10個點,如果想要提升精度可以考慮增加每個voxel的有效點。
Python #num_point為10 for i in range(self.num_points): homo_feat = self.grid_sample( feat, fpoints[i * B : (i + 1) * B], ) homo_dfeat = self.dgrid_sample( dfeat, dpoints[i * B : (i + 1) * B], ) homo_feat = self.floatFs.mul(homo_feat, homo_dfeat) homo_feats.append(homo_feat)
精度優化
多任務模型的精度優化
參考BEVerse模型對多任務根據不同粒度進行細化,在分割頭做解碼之前,將BEV feature的分辨率增大,map size為[200,400],實現上由grid_sample完成。
Python #init map module if (self.bev_size and self.task_size and self.task_size != self.bev_size): self.grid_sample = hnn.GridSample( mode="bilinear", padding_mode="zeros", ) #decoder module forward def forward(self, feats: Tensor, meta: Dict) -> Any: feat = feats[self.task_feat_index] if hasattr(self, "grid_sample"): batch_size = feat.shape[0] new_coords = self.new_coords.repeat(batch_size, 1, 1, 1) feat = self.grid_sample(feat, self.quant_stub(new_coords)) feat = [feat] pred = self.head(feat) return self._post_process(meta, pred)
浮點模型精度的優化
在浮點模型的訓練上,使用數據增強來增強模型的泛化能力,通過嘗試不同的增強方式,最終選取BEVRotate方式對輸入數據做transform。相比于未做數據增強的浮點模型mAP提升1.5個點,NDS提升0.6個點。詳細實驗記錄見實驗結果章節。
該實驗結果為中間結果,非最終精度數據
量化精度的優化
BEV_LSS的量化訓練采用horizon_plugin_pytorch的Calibration方式來實現的,通過插入偽量化節點對多個batch的校準數據基于數據分布特征來計算量化系數,從而達到模型的量化。BEV_LSS模型無需QAT訓練就可以達到和浮點相當的精度。
除了量化方式上的優化,地平線對輸入的grid也做了優化,包括了
1. 手動計算scale,使用固定的scale作為grid的量化系數。
Python #fix scale def get_grid_quant_scale(grid_shape, view_shape): max_coord = max(*grid_shape, *view_shape) coord_bit_num = math.ceil(math.log(max_coord + 1, 2)) coord_shift = 15 - coord_bit_num coord_shift = max(min(coord_shift, 8), 0) grid_quant_scale = 1.0 / (1 << coord_shift) return grid_quant_scale #get grid_quant_scale grid_quant_scale = get_grid_quant_scale(grid_size, featview_shape) ##init self.quant_stub = QuantStub(grid_quant_scale)
2.grid_sample算子的輸入支持int16量化,為了保障grid的精度,地平線選擇int16量化。
Python self.quant_stub.qconfig = qconfig_manager.get_qconfig( activation_qat_qkwargs={"dtype": qint16, "saturate": True}, activation_calibration_qkwargs={"dtype": qint16, "saturate": True}, )
基于以上對量化精度的優化后,最終定點精度達到和浮點相當的水平,量化精度達到99.7%!
實驗結果
1.性能和精度數據
數據集 | Nuscenes | |
Input shape | 256x704 | |
backbone | efficientnetb0 | |
bev shape | 128x128 | |
FPS(單核) | 138 | |
latency(ms) | 8.21 | |
分割精度(浮點/定點)iou | divider | 46.55/47.45 |
ped_crossing | 27.91/28.44 | |
Boundary | 47.06/46.03 | |
Others | 85.59/84.49 | |
檢測精度(浮點/定點) | NDS | 0.3009/0.3000 |
mAP | 0.2065/0.2066 |
注:grid_sample的input_feature H,W ∈ [1, 1024] 且 H*W ≤ 720*1024
2. 不同數據增強方式對浮點模型的精度影響。
該實驗結果為中間結果,非最終精度數據
3.地平線征程5部署LSS范式的BEV模型通用建議
?選用BPU高效支持的算子替換不支持的算子。
? num_point會直接影響性能和精度,可以根據需求做權衡。處于訓練速度考慮使用topk選擇點,若想要更高的精度可以對點的選擇策略做優化。
? grid使用fixed scale來保障量化精度,如超過int8表示范圍則開啟int16量化,具體見grid量化精度優化章節。
?對于分辨率較大導致帶寬瓶頸或不支持問題,可以拆分為多個計算,緩解帶寬壓力,保障模型可以順利編譯。
?對于常量計算(例如:grid計算)編譯時可以作為模型的輸入,提升模型的運行性能。
總結
本文通過對LSS范式的BEV多任務模型在地平線征程5上量化部署的優化,使得模型在該計算方案上用遠低于1%的量化精度損失,得到latency為8.21ms的部署性能,同時,通過LSS范式的BEV模型的部署經驗,可以推廣到基于該范式的BEV模型的優化中,以便更好的在端側部署。
審核編輯:劉清
-
NDS
+關注
關注
0文章
6瀏覽量
6622 -
LSS
+關注
關注
0文章
8瀏覽量
1954 -
pytorch
+關注
關注
2文章
807瀏覽量
13200
原文標題:好算法更要配好用的芯片 —— 基于LSS范式的BEV感知算法優化部署詳解
文章出處:【微信號:horizonrobotics,微信公眾號:地平線HorizonRobotics】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論