Tri-MipRF:効率的なアンチエイリアシングのためのTri-Mip表現によるニューラル輝度場

環境構成

Python:3.9.0, Pytorch:1.13.1, Cuda:11.7, Tinycudann:1.7 を使用してインストールしてください。このバージョンに合わせると、tiny-cuda-nnのインストールでエラーが発生しません。

conda create -n trimip python=3.9
conda activate trimip
pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu117

NeROのインストールと同じパッケージであるnvdiffrastもここに記録します。

cd nvdiffrast
pip install .

もう一つのパッケージであるtiny-cuda-nnは、GitHubページの手順に従って手動でインストールする必要があります。cmakeのバージョンが低すぎる問題が発生する可能性があるため、cmakeをダウンロードしてください。

tar -zxvf cmake-3.24.1.tar.gz
cd cmake-3.24.1
./bootstrap

# 中間でエラーが発生した場合
apt-get install libssl-dev

make
make install


# cmakeパスを設定
export ....
source ~/.bashrc

# バージョン確認
cmake --version

Windowsシステムでの問題の記録

nvdiffrast構成時の問題
手順:まずcudaをインストールし、次にvsstudioをインストールし、新しい仮想環境を作成してpytorchをインストールし、cmdの対応するディレクトリでvscodeを起動し、nvdiffrastを構成します。この手順に従えば問題は発生しませんが、コンピュータに既にcudaがインストールされている場合は、すべて再インストールする必要があります。そうしないと依然としてエラーが発生します。

subprocess.CalledProcessError: Command '['where', 'cl']' returned non-zero exit status 1.

このリンクを参照すれば解決できます。Windows上でnvdiffrastが正常に使用できる場合、VSstudioも問題ないはずです。したがって、彼が提供するディレクトリに似たパスを見つけることができます~
環境構成後、cmdでvscodeを再起動(これができることを今知りました!毎日新しいことを学びます!)

code .

SuperNormal環境構成

以下の2つのパッケージには共通の問題が発生する可能性がありますが、どちらの問題であるかは本当に分かりません。順番に従ってください:

  • nerfacc``` pip install -e ./third_parties/nerfacc-0.3.5/nerfacc-0.3.5/

    
    
RuntimeError:
       検出されたCUDAバージョン(9.1)がPyTorchをコンパイルするために使用されたバージョン(11.8)と一致しません。
       同じCUDAバージョンを使用してください。

何度も遭遇したため、ここで詳しく説明します。システムに高バージョンのcudaをインストールすると、自動で下位互換性が提供されますが、低バージョンの場合はシステムのcudaをいじらず、conda仮想環境に追加のcuda+cudatoolkitをインストールし、一時的な環境変数を仮想環境のcudaを指すように設定できます。最も重要な環境変数はCUDA_HOMEです。

参照リンクは、システムのcudaではなくconda仮想環境のcudaを自動的に検出すると指摘しています。したがって、環境変数を設定します:

export CUDA_HOME=/home/yangtongyu/software/anaconda3/envs/sn/lib/python3.8/site-packages/torch/lib
export CUDA_PATH=$CUDA_HOME

ここで新しいエラーが発生することがあります。nvccが見つからないためかもしれません。これはインストールされたcuda-toolkitが不完全な関係かもしれません。cuda-toolkitを再インストールします リンク

conda install nvidia/label/cuda-11.8.0::cuda-toolkit
# nvcc -Vを実行するとバージョンが変更されますが、環境外で実行すると依然としてシステムのcudaバージョンです
CONDA_PREFIX -name 'nvcc'
# /home/yangtongyu/software/anaconda3/envs/sn/bin/nvcc
export CUDA_HOME=$CONDA_PREFIX

# ここはsupernormalファイルのcreate_env.shとは異なります。仮想環境内のcudaパスに変更する必要があります
export PATH=$CUDA_HOME/bin:$PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib:$LD_LIBRARY_PATH

現在のシステム環境変数

$CUDA_HOME /home/yangtongyu/software/anaconda3/envs/sn

# 仮想環境のnvccを使用し、サーバーのローカルnvccを使用しないように記録
export CUDA_HOME=/home/yangtongyu/software/anaconda3/envs/sn
export PATH=$CUDA_HOME/bin:$PATH
export LIBRARY_PATH=$CUDA_HOME/lib64:$LIBRARY_PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH

export CUDA_HOME=/home/yangtongyu/software/anaconda3/envs/trimip
export PATH=$CUDA_HOME/bin:$PATH
export LIBRARY_PATH=$CUDA_HOME/lib64:$LIBRARY_PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH


  • tiny-cuda-nn
    tinycudaを構成するのは既に常識的な問題です。git cloneにはネットワーク問題が関係するため、成功しないことがあります。したがって、GitHubで自分でダウンロードした後、依然としてこれらのコマンドを実行します:
cd tiny-cuda-nn/bindings/torch
python setup.py install

cd ../../..

完了!

更新

AttributeError: 'NoneType' object has no attribute 'ContractionType'このエラーが発生します!
これはNerfAcc: No CUDA toolkit found. NerfAcc will be disabled.という問題によるものです。nvccが見つからないため、環境変数を構成します。方法は以下の通りです:

vim ~/.bashrc 
export LD_LIBRARY_PATH=/usr/local/cuda/lib64
export PATH=$PATH:/usr/local/cuda/bin
source ~/.bashrc
nvcc -V

構成成功後、新しいターミナルを開いて実行する方が安全です。

python main.py --ginc config_files/ms_blender/TriMipRF.gin 

コードの詳細

データ入力

ray_dataset.pyがデータセットを呼び出し、parsersフォルダーには異なるデータセットの読み取り方式が記述されています。

データローダーを初期化中 ...
モデルを初期化中 ...
トレーナーを初期化中 ...

メイン関数trimipRF.pyがnerfaccパッケージを呼び出し、まずTriMipRFModelの初期化を見てみましょう:

# occ gridを作成、パラメータにはregion of interest, resolutionがある
self.ray_sampler = nerfacc.OccupancyGrid(roi_aabb=self.aabb, resolution=occ_grid_resolution)  

次に、このoccupancy gridを更新する独自の関数を作成する必要があります。これはtrain.pyで、各反復の前にself.model.before_iter(step)を呼び出すことに対応します。

# 呼び出し内容はocc grid更新関数
self.ray_sampler.every_n_step(
           step=step,
           occ_eval_fn=lambda x: self.field.query_density(
               x=self.contraction(x),
               level_vol=torch.empty_like(x[..., 0]).fill_(self.occ_level_vol),
           )['density']
           * self.render_step_size,
           occ_thre=5e-3,
       )

主要関数

Tri-MipRF-main/neural_field/field/trimipRF.pyはMLPとエンコーディング方式を定義し、以下の2つの関数を通じてMLPを呼び出してdensityとcolorを取得します。

self.field.query_density(x=positions, level_vol=level_vol, return_feat=True)
入力:
	position サンプリング点座標(n,3)
	level_vol 不明、mip関連のパラメータ
	return_feat 特徴を返す必要があるか(後でcolor mlpに入力する必要がある場合)
出力:以下の2つのキーを持つ辞書
	density (n,1)
	feature (n,15)
機能:positionを入力してdensityを取得(ここでは方向を知る必要はない)

self.field.query_rgb(self, dir, embedding)
入力:
	dir 方向
	embedding 前にdensityと一緒に取得された特徴
出力:
	{"rgb": rgb} 色
機能:featureとdirから色を取得

Tri-MipRF-main/neural_field/model/trimipRF.pyは入力rays_o rays_dを呼び出し、上記の関数を使用してdensityとcolorを取得します。

sigma_fn(t_starts, t_ends, ray_indices)
入力:上記通り
出力:self.field.query_density(positions, level_vol)['density']
機能:positionを与えてquery_densityを呼び出してdensityを取得

rgb_sigma_fn(t_starts, t_ends, ray_indices)
入力:上記通り
出力:rgb, density
機能:positionを与えてquery_densityでdensityとfeatureを取得し、次にquery_rgbでcolorを取得

rendering関数は上記2つの関数を呼び出します

self.rendering(t_starts,t_ends,ray_indices,rays,rgb_sigma_fn=rgb_sigma_fn,render_bkgd=background_color)
入力:上記通り
出力:color, alpha, depths, ...
機能:densityからweightsを求め、体レンダリングでcolorを求め、lossを計算する準備をする

trainとevalの比較

iter_train_loader = iter(self.train_loader)
iter_eval_loader = iter(self.eval_loader)
metrics = self.train_iter(step, data=next(iter_train_loader), ...)
metrics, final_rb, target = self.eval_img(
                   next(iter_eval_loader) if self.varied_eval_img else eval_0,
                   compute_metrics=True,
               )

rb = self.model(step, cam_rays, target.render_bkgd)
rb = self.model(
               flatten_rays[i : i + self.test_chunk_size],
               flatten_target[i : i + self.test_chunk_size].render_bkgd,
           )

入力xと出力levelの関数を追加

# 各回のsdf呼び出しでlevel_volを知る必要がある
def density(x, level_vol)
	self.log2_plane_size = math.log2(plane_size)	# plane_sizeは自分で定義したplaneの解像度
	level = (level_vol if level_vol is None else level_vol + self.log2_plane_size)
	enc = self.encoding(x.view(-1, 3), level=level.view(-1, 1),)	# このlevelはどうやって取得する?

# density関数のlevel_vol
sample_ball_radii = self.compute_ball_radii(distance, radiis, cos)
level_vol = torch.log2(sample_ball_radii / self.feature_vol_radii)  # 実際のレベルは + log2(feature_resolution)すべき

# その中でself.compute_ball_radii()は関数で、self.feature_vol_radiiは変数
self.feature_vol_radii = self.aabb_size[0] / 2.0

self.aabb_size[0]=3 # シーンの立方体の長さ幅高さを表す

以上のことから、ptsとdirsからまずdistance, radiis, cosを求め、次にlevel_volを求め、そしてlevelを求めます。

プロセス

フローチャートに沿って从头から尾まで紹介し、重点を説明!

  1. 公式(3)から得られる円錐内の各接球S(x,r)の半径rは、xの位置に関連しており、つまりtに関連していることがわかります。次に球を3つの平面に投影して3つの円盤Discs={ D x y D_{xy} Dxy​, D x z D_{xz} Dxz​, D y z D_{yz} Dyz​ }を取得します。
  2. D x y D_{xy} Dxy​を例に取ると、公式(5)で D x y D_{xy} Dxy​の半径がTri-Mipエンコーディングのどのレベルに対応するかをクエリできます。M x y L i M_{xy}^{L_i} MxyLi​​と M x y L i + 1 M_{xy}^{L_{i+1}} MxyLi+1​​の間にあることがわかります。次に、(x,y)を中心とする D x y D_{xy} Dxy​を2つのM層に投影し、8つの点を取得し、これらの点に対して三線形補間を行って特徴 f X Y f_{XY} fXY​を取得します。
  3. すべての特徴が取得されたら、concatしてMLPに入力します。
  4. 強調すべき点は、このTri-Mipエンコーディングがランダムに初期化され、学習可能な明示的な表現であり、合計N層あり、各層は前の層の1/2のサブサンプリングです。つまり、最初の層 M x y L 0 M_{xy}^{L_0} MxyL0​​の次元は W × H × C W\times H\times C W×H×C、2層目 M x y L 1 M_{xy}^{L_1} MxyL1​​の次元は W / 2 × H / 2 × C W/2\times H/2\times C W/2×H/2×C…となります。プロセス全体は、内接球に対応するエンコーディングをクエリし、それをconcatして入力として使用することです。

公式3は一晩かけても導けません。どこが間違っているのか全く見えません。どなたかご教授いただけますか??

詳細の記録

self.compute_ball_radii()関数は公式(3)に対応していますが、どのように対応しているかは分かりません。ここではf=1と仮定しているようです:

sample_ball_radii = self.compute_ball_radii(
                   distance, radiis, cos
               )

def compute_ball_radii(distance, radiis, cos):
   inverse_cos = 1.0 / cos
   tmp = (inverse_cos * inverse_cos - 1).sqrt() - radiis
   sample_ball_radii = distance * radiis * cos / (tmp * tmp + 1.0).sqrt()
   return sample_ball_radii

入力:t, r^., z軸負半軸とのなす角の余弦(zは距離)
出力:各サンプリング点のr
機能:各球の半径を計算

重要でない雑記

radiis: 2D平面上、1ピクセルが占める半径。カメラパラメータが1種類しかない場合、radiisも1種類のみ
ray_cos: 光線と水平軸のなす角
ray_cos=torch.matmul(
               directions,
               torch.tensor([[0.0, 0.0, self.sign_z]], device=device).T,
           )	# self.sign_z=1/-1
sample_ball_radii: 各内接球の半径。distance, radiis, ray_cosを知る必要がある
sample_ball_radii = self.compute_ball_radii(distance, radiis, cos)
level/level_vol: 内接球の半径から各点のレベルを求める

sdf(x, encoding, level) # levelを知る必要がある

タグ: NeRF Tri-MipRF ニューラル輝度場 アンチエイリアシング CUDA

5月30日 03:49 投稿