Ⅶ. ngp_pl

7hu95b發表於2024-05-28

作者實現的 ngp_pl 程式碼還存在的兩個問題:

  1. 收斂後的取樣點數比NGP多(這導致計算量變大,渲染幀率下降);
  2. 有些場景會失敗;

一、資料準備

程式碼都在 dataset 資料夾下面。

作者支援大部分演算法的資料集格式,包括:

  1. NSVF:講解的時候展示了 nsvf.py 這個檔案,但是自己沒找到它
  2. NeRF++
  3. COLMAP data
  4. RTMV: NeRF專用資料集,600個場景,但是因為下載賊慢,導致很少人用;

720ae158f76d0c8b66fd5e37144d0da7.png

補充:建立自己的資料集可以參考 _synth_nerf_dataset_creator 這個專案。

補充說明

第一:作者預設所有相機的內參一致,如果需要支援多個相機,需要自己在資料集讀取程式碼中新增多個K。

第二:座標系的轉換。作者把NeRF的座標系改成了常見的相機座標系(都是右手系,只不過z軸的方向不同,如下圖左側所示)。

第三:範圍的修改。以NSVF的合成資料集(SYN)為例,合成資料集是指定了 bounding box 的範圍,但是物體不一定處於座標系正中心,所以需要使用 shift 操作使之置於原點,此外還需要使用 scale 操作把範圍值歸一化到 \([-0.5, 0.5]\) 內。如下圖所示:
830f323e1750dabdff0d68d4e8b54a93.png
但是真實場景(real)中,box 的範圍其實是不確定的,此時需要調整 scale 進行試錯(trial and error)達到最好的效果(也不一定能訓練成功,太大的場景需要借鑑 MipNeRF360 的 contraction 想法,把無限遠的場景“投影”到比較近的地方)。

第四:取樣策略。要麼從所有圖片中取取樣點,要麼只從一幅圖片中取,這兩種和NeRF一脈相承,分別是下面程式碼中的 all_imagessame_image 兩種策略。
815d4b2127c3042db26fb5a4516518a9.png

還有一種做法是:從一幅圖片中取某個小區域,因為所有點都在小區域內,所以它們之間是存在某種聯絡的,從而引入 perceptual similarity,這樣會對最後的 Loss 計算提供幫助(因為現階段所有的 Loss 計算都是二範數的形式,只是據說採取這種做法效果可能會更好,作者沒有實現這種做法)。
189d123ea70c3954c10e66ebc17db7cd.png

二、模型構造

(一)訓練

訓練部分程式碼在 models/networks.py

網路結構:總共可以分成三大部分。xyz 輸入到 HashGrid 中得到 16 維特徵向量,它的第一個位元使用 \(e^x\) 作為 \(\sigma\) ;方向向量透過Spherical harmonics(一系列的正餘弦計算),生成16維向量,二者 concat 後輸入神經網路,得到最後的 RGB 值。
09fbb3f64c6e33adfe50c09ef1a1e5b3.png

如果得到/實時更新 occupancy grid ?
以訓練是否超過256步為界:前256步階段會取得所有的格子 get_all_cells,從cell中隨機取一個點作為 xyz 投入上圖中,計算其 \(\sigma\) 值,以此判斷該 cell 為 0 or 1(threshold,預設值是 0.01);超過256步後,減少取樣的程度,uniform 是隨機取樣(取所有格子的 \(\frac{1}{4}\) 出來),或者只從有東西的 cell 取 \(\frac{1}{4}\) 出來。
0c43d125776270de2685c3dbf2f60e5f.png

(二)渲染

程式碼在 models/rendering.py

如何進行渲染?volume Rendering
首先計算射線和 box 的交點(有現成的方法,速度其實很快)。根據訓練和測試兩個階段的任務需求不同,具體做法也不同。

(1)render_ray_train

對於 syn 合成資料,box 的邊長是 1,步長是 \(\frac{\sqrt{3}}{1024}\)(對角線長度);對於 real 真實場景,離光心越遠,步長越大,這樣既加快計算,又把關注點放在最近的物體中,範圍是 \(\frac{\sqrt{3}}{1024}\)\(\frac{1}{256}\)。並且,每走一步要根據 occupancy field 是否有東西,決定是否放置取樣點。
412cc8d82b46f412217f8f34ea1b93fc.png

(2)render_ray_test

判斷射線是否和 box 有交點,逐步向前 marching,直到遇到 occupancy filed 中有東西的交點,如果沒有交點那麼說明這條射線不用渲染,就可以把計算資源分配給其他射線;其他射線便繼續往前 marching 重複這個過程,直到走完。並且,取樣點數是逐步分配、增加的。

如果 transimitance 已經很小了(幾乎所有的顏色都被決定了,沒必要再繼續了),就可以停止渲染。early ray termination

三、定義Loss

作者在 MSE 的基礎上(渲染的 RGB 和原始 RGB 的差值的平方),還引入了:

  • opacity loss: 讓 opacity 的值要麼是 0 要麼是 1,避免出現小數值,而且還能減少漂浮物。這樣做是忽略了透明的物體,所以會對透明物體的效果不太好(Depth NeRF 針對透明物體做了最佳化);
  • distortion Loss:MipNeRF360 中提出的新演算法。原始NeRF會更傾向於所有的都是半透明的,累加在一起成為不透明,導致有很多沒有用的“雲”(漂浮物);當加了這個Loss後,最後的結果更傾向於只有表面一層,而沒有後面那些半透明的雲,從而減少取樣、加快計算。