1. 程式人生 > >《Frustum PointNets for 3D Object Detection from RGB-D Data》論文及程式碼學習

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文及程式碼學習

《Frustum PointNets for 3D Object Detection from RGB-D Data》論文及程式碼學習

《Frustum PointNets for 3D Object Detection from RGB-D Data》一文是Charles R.Qi等人發表在CVPR2018上的文章(提前版本2017.11.22發表,2018.04.13提交了更新版本,主要修改了附件),這裡是論文程式碼。本文中記錄了博主在學習論文和除錯程式碼中遇到的問題。更新於2018.09.18。

環境配置中有Tensorflow、opencv、cv2、mayavi的安裝教程,如果只需要教程的話可以直接看

這裡,就不用看這一大堆啦。

真是服了……之前沒寫好的版本竟然直接給我發出去了,說好的存成草稿呢……所以新的編輯器下面是不能直接點儲存變成草稿了,坑

文章目錄

論文學習

這篇論文的作者之前發表過兩篇與frustum pointnets相關的論文,分別是PointNetPointNet++。這三篇論文主要是解決3D點雲下的目標分割和識別問題的,這裡主要總結frustum pointnets,關於另外兩篇論文的學習總結如果有需要會寫出來。

Frustum PointNets是直接以RGB-D影象(即點雲資料)為輸入,實現3D場景下的目標識別的網路。其基本過程是,給定RGB影象後,網路先利用一個2D目標識別演算法(任意一個都可以,論文中並未對此部分單獨提出演算法)確定目標在RGB影象中的位置。在給定這個位置後,其對應的四稜臺區域和其對應的點雲子集就可以確定了。隨後,演算法依賴一系列座標系平移的輔助,基於之前提出的兩種影象分割演算法,實現3D場景下的目標識別。演算法的輸出為目標所在立體區域的中心座標以及目標模型化的長方體(也就是能夠將目標全部包含的長方體)的尺寸和朝向。損失函式監測的內容為:分割情況、長方體的朝向、中心位置、三邊尺寸、三個角的位置。用於座標平移的是一個單獨的T-NET。

下面具體說一下每個部分:

座標系轉換

下圖是frustum pointnets座標轉換步驟的示意圖。圖(a)是原始座標系,也就是相機座標系;圖(b)是相機座標系經過旋轉得到的四稜臺座標系,改動就是將z軸旋轉至稜臺的中軸線,x軸則與中軸線正交;圖©是經過mask的座標系,改動是將稜臺座標系平移至目標點雲的圖心(centroid,程式碼裡的具體實現就是求了被判定為目標的點座標平均值);圖©是目標座標系,也就是最終估計目標模型的座標系,由T-Net學習得到(具體實現方法看程式碼分析部分)。
座標轉換

損失函式

由於這是一個多工優化演算法,因此在損失函式中應包含用於影象分割的Pointnet的損失 L s e g L_{seg} 、用於座標平移的T-Net的損失、和用於框出目標的PointNet的損失三部分組成。具體的公式如下:
\begin{split}
L_{multi-tast}=&L_{seg}+\lambda(l_{c1-reg}+L_{c2-reg}+L_{h-cls}+\
&L_{h-reg}+L_{s-cls}+L_{s-reg}+\gamma L_{corner})
\end{split}
其中, l c 1 r e g l_{c1-reg} L c 2 r e g L_{c2-reg} 分別對應T-Net的座標平移損失和box estimation的中心迴歸損失(也就是判斷長方體模型中心產生的損失)。 L h c l s L_{h-cls} L h r e g L_{h-reg} 分別對應朝向的類別損失和迴歸損失(這是因為frustum pointnet給box的朝向規定了幾個量化的方向,在程式碼中既包含了這些方向的標號,也會將這些標號轉成連續的弧度值)。 L s c l s L_{s-cls} L s r e g L_{s-reg} 分別代表box尺寸的類別損失和迴歸損失,與朝向類似,尺寸也是被規定出了幾個標準尺寸,但是在計算損失的時候也會將這些量化尺寸轉化成連續的尺寸損失。

類別判定過程中用的是Softmax方法,迴歸問題用的是smooth- l 1 l_1 (huber)損失。

(這裡插一句,在神經網路的訓練過程中經常可以看到Softmax和Softmax損失,需要注意的是,這兩個並不是同一個東西。在分類任務中,Softmax其實是為了實現找到max值的作用,但是由於max運算無法求導,因此用softmax替代。具體可以參見我的另一篇部落格。)

上面的損失公式將box的尺寸和角度等引數視為獨立的變數計算損失,但實際情況是box的尺寸和角度共同決定了box的資訊,而最終得到的box的資訊才是我們想要的。因此,frumstum pointnet引入了box的角損失,也就是上面的損失公式中的 L c o r n e r L_{corner} ,具體的計算公式為:

L c o r n e r = j = 1 N S j = 1 N H δ i j min { k = 1 8 P k i j P k 8 , k = 1 8 P k i j P k } L_{corner}=\sum_{j=1}^{NS}\sum_{j=1}^{NH}\delta_{ij}\min\{\sum_{k=1}^8\Vert P_k^{ij}-P_k^8\Vert,\sum_{k=1}^8\Vert P_k^{ij}-P_k^{**}\Vert \}

注意最後一項中是對 k k 求和的,論文中這裡寫的是對 i i 求和,博主認為根據文章要表達的意思,這裡應該是寫錯了。最後兩項之間找一個最小值的原因是,frusmtum pointnet演算法認為估計得到的box上下顛倒其實並不影響最終給出的結果,因此將box上下旋轉180度,取最小的那個損失。

網路模型

下圖是frustum pointnet的概念性網路結構示意圖。其中,最左邊的3D instance segmentation pointnet是用於影象分割的(也就是pointnet或pointnet++),右上角的T-Net是用於座標系平移的(估計以目標中心為原點的座標系),右下角的amodel 3D Box Estimation PointNet是用來估計框出目標的box的各項引數的(朝向、尺寸)。
網路結構

具體的網路結構如下圖所示:
這裡寫圖片描述

其中,v1 3D Instance Segmentation PointNet對應的是PointNet,v2 3D Instance Segmentation PointNet對應的是PointNet++。v1和v2兩個網路結構共用同一個T-Net結構平移座標系,但是分別對應了各自的Box Estimation網路。

結構中的mlp是multi-layer perceptron(多層感知機)的簡稱,括號中表示的是感知機中hidden layer的神經元個數。關於兩個影象分割網路的具體分析,如果有需要,會在單獨分析這兩個網路的博文中寫。

資料庫

frustum pointnet用的是KITTI的3D目標識別資料庫(還有一個博主沒有研究過),用到了左圖、點雲、相機引數和訓練樣本標籤。KITTI中一共有三類樣本,分別是人、車、自行車。程式碼中提供了檢視資料庫的程式,直接執行就可以檢視3D資料。用於訓練網路的資訊為標籤、點雲和3D框(box)。程式碼中也給出了論文作者處理好的資料和訓練得到的模型引數,可以直接下載。

實驗設定

訓練過程中的主要評價指標是IoU(Intersection over Union),閾值為0.7。
最優化方法用的ADAM;學習率0.001,每60k次迭代衰減一半;多工損失公式中 λ = 1 \lambda =1 γ = 10 \gamma=10 ;朝向和尺寸的迴歸損失部分用的係數為10,從而能夠與其他資料量級匹配;除了最後的分類層或迴歸層,其他的層都用了batch normalization(初始衰減率0.5,逐步降為0.99(每20k次迭代衰減一半));v1的batch size為32,v2的是24。所有網路都是端到端訓練。
裝置:GTX 1080 GPU。
訓練時長:v1網路(全部三個部分)200次迭代需要兩天;v2網路(全部三個部分)200次迭代需要六天。實驗中結果評估用到的迭代次數為200次的實驗結果。


程式碼學習

環境配置

1. 安裝Tensorflow

(論文的版本用的是TF1.2或TF1.4,因此版本不要太新):

pip install tensorflow==1.4.0

如果提示pip找不到命令,則先更新pip,再安裝:

pip install --upgrade pip

安裝tensorflow可能需要一段時間,安心等待就好~

2. 安裝opencv和cv2

如果沒有安裝opencv就先按照下面的步驟安裝opencv(這裡安裝的版本是3.1.0),也可以按照官方文件安裝:
a) 安裝opencv的支援庫:

sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

b)克隆opencv包(網速不好需要很久,耐心等等):

cd ~/<my_working_directory>
git clone https://github.com/Itseez/opencv.git
git clone https://github.com/Itseez/opencv_contrib.git

c)用CMake安裝

cd ~/opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..

在上一步有可能出現卡在下載 ippicv_2017u3_lnx_intel64_general_20170815.tgz這個地方,那麼證明網速不是很好。如果實在不行,可以嘗試根據這裡的方法,預先下載這個tgz檔案,在camke。
d)上一步成功之後,在build資料夾下執行:

make -j8

e)可以選擇安裝文件(也可以省略):

cd ~/opencv/build/doc/
make -j7 html_docs

f)安裝libraries,在build目錄下執行:

sudo make install

g)最後,可以測試以下程式:
[optional] Running tests
Get the required test data from OpenCV extra repository.
For example

git clone https://github.com/Itseez/opencv_extra.git

set OPENCV_TEST_DATA_PATH environment variable to <path to opencv_extra/testdata>.
execute tests from build directory.
For example

 <cmake_build_dir>/bin/opencv_test_core

至此,opencv就安裝成功了。
安裝cv2只需要執行下面的命令就可以了:

pip install opencv-python

3. 安裝mayavi

執行下面的命令即可:

pip install mayavi

至此,所有的依賴庫已經安裝完畢,當然,為了執行程式,電腦上還應該裝有python,建議安裝2.7,不要安裝3,以免程式出現問題。

程式碼說明

每個程式碼檔案的學習筆記博主將會整理出來貼上連結,此處到時僅作檔案功能說明用。