LaneATT调试笔记
代碼地址為 https://github.com/lucastabelini/LaneATThttps://github.com/lucastabelini/LaneATT
首先說這個Label,因?yàn)閕nput肯定是一張圖片,這個毫無疑問,這個Label的構(gòu)建主要是在LaneDataset中,該類首先構(gòu)建一個dataset,比如我這里是TuSimple,其數(shù)據(jù)集的Label是車道線的坐標(biāo)點(diǎn),不過是十行(像素)取一個x點(diǎn)的坐標(biāo),所以lane就是x點(diǎn)坐標(biāo),而h_samples就是y的坐標(biāo),主要也就是一個json文件,這部分還好理解
然后這個lane不是直接傳進(jìn)去訓(xùn)練的,會把lane再處理成label,核心是lane_dataset中的transform_annotation函數(shù),其會調(diào)用sample_lane來把lane處理成label,
這個label中是不包含y坐標(biāo)的,只有x坐標(biāo),y坐標(biāo)是通過一個超參數(shù)S=72計(jì)算出來的,也就是大概整個畫面會橫切為72份,然后對應(yīng)的x的坐標(biāo),就是label,這一部分也不難理解,
但是會產(chǎn)生一個問題,是不是每條線都有72個x坐標(biāo)?答案是否定的,因?yàn)楫嬅娴纳戏?其實(shí)就是駕駛員的遠(yuǎn)方,是天空,天空這部分畫面肯定是沒有車道線的,所以也就沒有x坐標(biāo),
那上面部分缺失,近處部分就是完整的呢?答案也是否定的,因?yàn)楫嬅娴淖髠?cè)或右側(cè),緊鄰的還能看見,但左側(cè)車道的左側(cè)車道線,可能就切割了,右側(cè)車道的右側(cè)車道線也一樣,所以,y的起點(diǎn)也未必是畫面的最下方,那么在label中如何體現(xiàn)車道線是否完整呢?
函數(shù)sample_lane中,是把近處的車道線補(bǔ)全了,
extrap = np.polyfit(two_closest_points[:, 1], two_closest_points[:, 0], deg=1)
利用已知坐標(biāo)點(diǎn),擬合出了未知坐標(biāo)點(diǎn),那這部分坐標(biāo)點(diǎn),其實(shí)是在畫面外,但這部分坐標(biāo)點(diǎn)也作為了label的一部分進(jìn)行訓(xùn)練,所以label中x坐標(biāo)的起點(diǎn),是畫面的最下方,盡管其中包含了超出畫面部分的x,然后label中會記錄下來有幾個點(diǎn)在畫面外,以此為開始就是真實(shí)的車道線label
?
lanes[lane_idx, 2] = len(xs_outside_image) / self.n_strips
搞懂了label,那就回過頭來看model
model就是class LaneATT,backbone是resnet34,然后,forward中,x的shape為[8, 3, 360, 640],當(dāng)然8是batchsize,后面是圖片尺寸,
feature_extractor之后的batch_features的shape是[8, 512, 12, 20],就是壓縮了32倍,后面又跟了一個conv,變?yōu)榱薣8, 64, 12, 20],
下面先停一下,看一下anchor,這里當(dāng)然主要是anchor點(diǎn),他是依次沿畫面左側(cè),再依次遍歷left_angles的角度,所得出的點(diǎn)的坐標(biāo),那么,我們可以想象,得出的坐標(biāo)點(diǎn),是有可能在畫面外的;同樣的,也沿畫面右側(cè),遍歷right_angles的角度,也得出一堆a(bǔ)nchor,再遍歷畫面底部,遍歷bottom_angles的角度,再得出一堆a(bǔ)nchor,
這樣得出的anchor有一大堆,left_anchors有[432, 77],right_anchors有[432, 77],bottom_anchors有[1920, 77],最后cat一起有,[2784, 77],當(dāng)然這里面有大量的點(diǎn)是離譜了,比如從左上角向左劃一條線,這個就沒太大意義,所以這里面會有一個mask, anchors_freq_path就是'data/tusimple_anchors_freq.pt',這個文件是工程中自帶的,應(yīng)該是統(tǒng)計(jì)出來的,各個line的有效性的次數(shù),然后用該mask來提取出有效性最高的topk_anchors根線,也就是1000根線,最終self.anchors的尺寸為[1000, 77],
而self.anchors_cut,我沒看出來與self.anchors的區(qū)別,目前感覺就是切的stride不一樣,anchors是切72刀,而 anchors_cut 是切10刀,
下面是計(jì)算切片索引,也就是cut_xs,cut_ys,cut_zs,cut_zs就比較簡單,就是0-63重復(fù)了11編,再重復(fù)一千遍,就是64*11*1000個數(shù),cut_ys也比較簡單,就是0-10重復(fù)64 * 1000 遍,總共也就是 11 * 64 * 1000 個數(shù), cut_xs 是吧 anchors_cut 中的數(shù)據(jù) [1000, 11] 重復(fù)了64遍
然后回到上面, 用 cut_xs,cut_ys,cut_zs 來采樣 [8, 64, 12, 20] 的 feature, 得到 batch_anchor_features 的 shape 為 [8, 1000, 64, 11, 1], 然后進(jìn)行了一下維度變換,變?yōu)榱?[8000, 704], 后面經(jīng)過一個 attention,注意力機(jī)制,生成 attention_features,[8, 1000, 704],batch_anchor_features也resize回[8000, 704],cat一下變成[8000, 1408],
把1408送到1408*2的全連接層,進(jìn)行分類,得到 cls_logits [8000, 2],然后reshape為 [8, 1000, 2]
把1408送到1408*73的全連接層,進(jìn)行分類,得到 reg [8000, 73],然后reshape為 [8, 1000, 73]
然后構(gòu)建 reg_proposals,把 self.anchors, cls_logits, reg都合并到一塊去,
最后送到nms去,不過這個nms會調(diào)用cpp的代碼的nms,所以暫未debug,
后面計(jì)算損失,中間一大部分應(yīng)該是匹配正負(fù)樣本的,看的有點(diǎn)迷糊,總之,最后會匹配到一些正樣本和負(fù)樣本,損失大概分為兩部分,一部分是坐標(biāo)部分,另一部分是二分類部分,坐標(biāo)部分的損失是l1 loss,就是差值的絕對值,求和,二分類用的是focal_loss
最后,分類損失會乘以一個系數(shù)10,和坐標(biāo)部分的loss相加,得到總的損失,
總結(jié)
以上是生活随笔為你收集整理的LaneATT调试笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 训练LaneATT遇到CUDA_HOME
- 下一篇: blazeface学习笔记