環境構成
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を求めます。
プロセス
フローチャートに沿って从头から尾まで紹介し、重点を説明!
- 公式(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 }を取得します。
- 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を取得します。
- すべての特徴が取得されたら、concatしてMLPに入力します。
- 強調すべき点は、この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を知る必要がある