三次元空間のニューラルな表現とNeRF

はじめまして、先進技術部の山内です。入社4年目にしてついに技術ブログを書くことになりました。わたしが文章を書くとどうもペダンティックな文体になりがちなのですが、頑張って書いたので気に食わない表現には適宜目を塞ぎつつお付き合いいただければと思います。今回はニューラルネットワークによる三次元空間表現手法の紹介と NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis[1] という論文の解説です。PyTorch による再現実装も公開しているのでご覧ください。

はじめに

現実世界の意味と構造を理解することは、人工知能研究の大きな目標の一つです。理解するとはどういうことかといえば、この場合は、何らかの行動計画に用立てることのできる良い「表現」を獲得すること、と考えることができるでしょう。というと、表現とは何かという問いが提起されるかもしれませんが、ここでは、それを解釈する何らかの処理系の存在するもの、くらいに定義しておくことにします。現実を描写した文章は人間にとって表現であり、バイト列は計算機にとって表現です。 たとえば、ある画像にたいして「リンゴ」とラベルを付けておきます。ここで文字列「リンゴ」は画像のひとつの表現であって、これを使えばコンピュータ上に保存された膨大な画像の中からリンゴの写っているものを検索してくることができます。これは、画像をただの色(ピクセル値)の集合(もちろんこれもひとつの表現ではあります)とみなしていたのでは不可能な仕事です、というのも一般にコンピュータは画像の内容を理解できないからです。画像の意味内容を文字列というコンピュータにとって馴染深い表現に人の手で変換しておくことによってはじめて、コンピュータは目当ての画像を探してくることができます。画像をラベルという表現に変換できるのは人間の現実理解力だけであり、それがあってはじめて、コンピュータは処理を開始することができる、それゆえいくらコンピュータの性能が向上しようと、入力作業は人間が行う必要がありました。 ところが近年、深層ニューラルネットワークの大躍進によって状況は変わってきました。コンピュータ自身が、画像をラベルに変換できるようになったのです。これでもう人間がぽちぽちとラベルを付けてやる必要はありません。それどころか、画像中の物体を検出して位置座標に変換したり、話し言葉音声を書き起こし文に変換したり、平面画像を深度画像に変換したりと、かつて人間の専売特許であった現実理解力を抜きにしてはやれないような仕事を、コンピュータがこなすようになってきています。たいへん素晴らしいことだと思います。 さて、ニューラルネットワークが現実に与える表現は、なにもラベルや座標値のように、人間に直接解釈可能なものに限りません。例えば word2vec[2] という自然言語処理の手法は、その名の通り単語と数百次元程度のベクトルとを相互変換します。「リンゴ」を word2vec に放り込むと \bf{x}  というベクトルを吐き出し、逆にこの \bf{x} を入力すると「リンゴ」を返してくれる。これだけ聞くとなんの面白みもないですが、word2vec のすごさは、変換先のベクトルが、単語の意味関係を保存しているところにあります。例えば「イギリス」「ロンドン」「日本」を word2vec でベクトルに変換したのち、「ロンドン」から「イギリス」を引いて「日本」を足せば、「東京」が得られます。つまり「ロンドン」引く「イギリス」が一般的な意味での「首都性」を表し、これを「日本」に足すと日本の首都である「東京」が出てくるわけです。意味の足し引きができるベクトルに単語を変換できるということは、文章の意味解析をコンピュータに任せられるということであって、実際 word2vec はチャットボットやレコメンドエンジンなどの裏方に広く利用されています。このように意味の演算が可能な仕方でベクトル空間にデータを落とし込むというアイディアは、自然言語に限らずさまざまに応用例を見ることができ、たとえば Variational Auto-Encoder[3] というニューラルネットワークを使えば、画像をベクトルに変換できます。得られたベクトル同士を足し引きすることで、二つの異なる画像の中間にあたる画像を生成したり、画像に特定の特徴を付与したりといったことができて面白いです。また、ベクトル間の距離が近いということは意味的にも近いことが期待されるわけで、類似画像検索などに用いることもできます。 このように、深層ニューラルネットワークは与えられたデータを様々な種類の表現に変換することができます。表現の性質は、どのようにニューラルネットワークを訓練するかによってさまざまに選ぶことができ、特にコンピュータと親和的な表現を得ることができれば、コンピュータの能力を最大限活用できるという点で、大きな可能性を秘めているのです。

三次元空間の表現

先にみたように大きな進展を成し遂げた深層ニューラルネットワーク研究ではありますが、現実世界を理解するという目標に至るには、越えねばならない壁がまだまだあります。現在のニューラルネットワークは基本的に特定タスクに対して訓練されるものであって、人間が生活のなかで相対するあらゆる問題を解けるような汎用的なモデルはいまだ登場していませんし、ハードウェアに対する能力的要求も含めて、実現にはまだしばらく時間を要するでしょう。それゆえ現段階において現実の問題にニューラルネットワークを適用するためには、個別のタスクで訓練されたネットワークと機械的アルゴリズムとをうまく組み合わせる必要があります。それに際して、さまざまなパイプラインに接続可能な「良い表現」を獲得することが肝要になってくるわけです。とくにロボット制御や自動運転など、現実世界に物理的に関わるタスクに対処するうえで重要になってくるのが、三次元空間をどのように表現するかということです。

点群・メッシュ・ボクセル

ロボット制御や自動運転において三次元空間の情報を活用するためには、まず何らかの仕方で空間を計測し、コンピュータに入力しなければなりません。これには一般に各種センサが利用されます。もちろん人間が手入力してもよいですが、空間のモデリングは専門技術が必要でかつ時間もかかるため、一挙に周辺環境をスキャン可能なセンサが存在するならそちらのほうが好都合です。三次元空間をスキャンする方法としては、人間の両眼視と同じく視差を用いて三角測量するもの、構造化光を照射するもの、レーザーを照射し反射光が返ってくるまでの時間を測定するものなどさまざまなものが存在しますが、これらは基本的に、空間上の点の位置座標を返してきます。レーザーの場合を考えるとわかりやすいですが、レーザービームは線状なので物体表面にぶつかると光の点ができ、これを観測すると物体表面上の点の座標が決定できるわけです。こうして得られた物体表面上の点の集まりは、これ自体ひとつの三次元空間表現と考えることができ、これを点群とか point cloud とか呼びます。点群はもっとも取得しやすい三次元空間表現のひとつであり、さまざまなタスクにおいて、足掛かりとして利用されています。 点群という表現は、玩具ロボットを障害物にぶつからないように動かす程度の目的には十分ですが、より高度なタスクを考えると、それだけでは不足する場合が多いです。連続的な空間を点で表現しているため、物体のトポロジー(ある座標が物体の内にあるか外にあるかなど)がわかりづらく、またその点がいったい何者なのかという意味的な情報を欠いています。路面に落ちているレジ袋を猫と誤認するようでは、自動運転は不可能です。したがって、画像など別のセンサの情報を組み合わせて、オブジェクトのトポロジーを補完し、さらにそれが何であるかも認識する必要があります。 点群に似た三次元表現としては、メッシュやボクセル ( voxel ) があります。メッシュは 3DCG でよく用いられるもので、点群のいくつかの点に多角形の面を張ったものです。ボクセルは画像のピクセル表現の三次元版であり、ゲーム「マインクラフト」の世界を想像していただければイメージはつかめるでしょうか。これらの表現にはそれぞれ一長一短ありますが、共通しているのは、空間を離散化して表現しているということで、点やボクセルが全体として何を構成しているのかという情報は陽には表現されておらず、そこから意味を抽出するには、画像の場合と同様に、もうひと手間必要です。というわけで、近年ではボクセルや点群を直接扱うことのできるニューラルネットワークが登場してきています。

ニューラルネットワークによる三次元表現

点群やメッシュ、ボクセルといった三次元表現は昔からあるものですが、その一方で、ニューラルネットワークを利用した新たな三次元表現方法も登場してきています。どうせ後からニューラルネットワークに放り込んで利用するのであれば、最初からニューラルネットワーク的な仕方で空間を表現しておけば便利であり、自然な発想ではあります。この種の三次元表現はいまだ研究段階で、現実問題への応用には課題が残されていますが、深層ニューラルネットワークがますますコモディティ化してゆく中で存在感を増してきているもののひとつです。 例えば Generative Query Network ( GQN )[4] という手法は、2018年6月に DeepMind が発表したものですが、入力された複数視点画像から三次元空間の表現を作成するようニューラルネットワークを訓練します。この表現は、先に触れた Variational Auto-Encoder による画像のベクトル表現の三次元版のようなものです。このベクトル表現を用いると、未知の(入力に含まれていない)視点から空間を見た場合にどのように見えるか、画像として出力することができます。また GQN によるベクトル表現を利用することで、ロボットアーム制御を強化学習で訓練する際に、訓練効率を高めることもできるようです 。 GQN とは少し異なるラインでは、三次元オブジェクトを陰関数 ( implicit function ) として表現するというものがあります。陰関数というのは、例えば単位円の方程式 f(x,y)=x^2+y^2-1=0  など、多変数関数によって表される関係のことです。それぞれの三次元オブジェクトに対して、オブジェクト内部では f({\bf x})<0 , 外部では f({\bf x})>0  となるような関数 f  を見つけてやれば、 f({\bf x})=0 を満たす {\bf x}  の集合がオブジェクト境界面ということになります。こうした三次元表現自体は昔から研究されていたようですが、最近になってこの f  をニューラルネットワークによって近似する手法が立て続けに発表されました[5][6]。どれも基本的なアイディアは同じであり、様々な三次元座標 {\bf x}  に対して、それがオブジェクトの内側にあるか外側にあるかを出力するようニューラルネットワークを訓練するというものです。訓練を終えたニューラルネットワークは、対象オブジェクトの形状情報を内部に備えていることになります。この陰関数による三次元表現は、学習に際して教師 3D データが必要であったり、特定オブジェクトに特化していたりといったデメリットもあるのですが、今後有望ではないかと個人的に興味を持っていました。先に触れた GQN の表現ベクトルは人間には直接理解することができず、その内容を引き出すには別途デコーダを訓練する必要があるのですが、その点、陰関数表現は人間(いにしえの CV アルゴリズム)にもニューラルネットにもそこそこフレンドリーな空間表現となっており、必要とあらば点群などへの変換も容易です。またオブジェクトの内/外に加えて、色や意味情報を埋め込むことも可能なはずで、研究の進展の如何によってはさまざまな応用可能性を秘めているように思われました。 そうした矢先に登場したのが NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis[1] という論文でした。これは微分可能な 3DCG レンダリングを介して 3 次元オブジェクトを表現する関数(ニューラルネットワーク)を訓練するという手法で、陰関数表現の発展形とみなすことができます。訓練に必要なデータセットは、オブジェクトを各視点から撮影した画像(とその視点の pose 情報)のみであり、教師 3D データを必要としません。また任意の視点から見た場合の非常に高精細な画像を生成可能です。 たいへん前置きが長くなってしまいましたが、本記事では、この NeRF 論文の内容を概説したのち、弊社で再現実装( TensorFlow 版が論文著者により公開されていますが、こちらは PyTorch 版)した結果を紹介します。

NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

図1:NeRF 全体像

概要

NeRF はカリフォルニア大学バークレー校の研究者らが2020年3月に発表した研究です。Radiance Fields は直訳すれば「輝度場」で、論文の趣旨に沿っていえば、空間上の各座標に色と密度を対応付けるベクトル場になります。ここで密度というのはその点の不透明度、つまりそこに何かしらの物体が存在することを示す指標です。したがって物体が存在する座標の密度が高くなるような Radiance Fields を得ることができれば、三次元空間の形状を表現できたことになります。このベクトル場をニューラルネットワークで近似するというのが NeRF のアイディアです。座標と何らかの値を対応付ける関数を考える点で、陰関数表現と似ています。実際 Radiance Fields を近似するネットワークの構造は、陰関数表現手法のひとつである DeepSDF[5] を参考にしています。 問題はこの Radiance Fields をどのように近似するかということです。もっとも率直な方法は、あらかじめ作成しておいた座標と輝度のペアを用いて訓練することですが、データセットの作成に手間がかかります。そこで NeRF では Radiance Fields (のニューラルネットワーク表現)を用いて画像のレンダリングを行い、それと実際に撮影された画像とを比較することで Radiance Fields を訓練していきます。 図 2 をご覧ください。これは論文中からとってきたものです。 F_\Theta が Radiance Fields を表現するニューラルネットワークで、立方体(点線)で囲われているのが三次元オブジェクト、その外側に置かれているのが異なる視点からオブジェクトを見た場合のビューです。
図2:NeRFのレンダリング
この図を理解するためにはまず、これらのビューが生成される仕組み、つまりカメラ撮影の仕組みについて理解する必要があります。詳細な解説は書籍やインターネットに大量にある[7]のでそちらにゆずるとして、ごく簡単に概略を述べておきましょう。かなり単純化した説明になっていますので、細部が多少犠牲になっている点はご了承ください。 カメラの数学的モデルでは一般に、世界座標系とカメラ座標系のふたつの座標系を考えます。世界座標系は三次元オブジェクトやカメラが配置されている座標系で、カメラ座標系は特定のカメラの焦点を原点に置いた座標系です。カメラ一台の場合は世界座標系とカメラ座標系を区別する必要はないのですが、複数台のカメラを扱う場合は、世界座標系を基準に各カメラの位置関係を考えるほうが便利です。さて、あるカメラのカメラ座標系と世界座標系との関係を記述するパラメタを、そのカメラの外部パラメタと呼びます。外部パラメタには、カメラ座標系の、世界座標系に対する回転と平行移動の情報が含まれており、これを使うと、カメラ座標系上の点と世界座標系上の点とを対応付けることができます。ちなみに外部パラメタがあれば内部パラメタも存在し、こちらは焦点距離 f  やレンズ歪み係数(レンズ歪みについては今回は考えません)などを含みます。 世界観の説明が終わったので撮影の話に移りましょう。カメラ座標系上に xy 平面に平行で z=f の一枚の平面を考えます[8]。ここで f は関数ではなく焦点距離のほうです(単位はピクセルであることに注意)。この平面を画像平面と呼ぶことにしましょう。画像平面上の格子点( xy 座標がともに整数になる点)がいわゆるピクセルです。カメラ撮影とは、カメラ座標系の原点(焦点)から画像平面上の各ピクセルに向けて直線を伸ばしていき、その直線と交わった空間上の色を採取してくることにほかなりません。すなわち、画像上の点 (u,v) の色は、画像平面上の点 (u,v,f) と焦点 (0,0,0) を結んだ直線上に存在するのです。この直線が、空間上の点から焦点へとやってくる光線ということになります。(注意!:実際には、画像上の座標は画像左上を原点とし右方向を x 軸、下方向を y 軸とする座標系で考えるので、上記の (u,v,f) は正確には (u-cx,- v+cy,f) となります。 (cx,cy) は画像中心と呼ばれるパラメタで、画像平面とカメラ座標系 z 軸の(画像上での)交点です。)
図3:カメラモデル
だいぶ駆け足な説明になりましたが、最低限の準備はできたので NeRF の説明に戻りましょう。図中の目から延びるオレンジの直線が、先ほどの説明にもあった、焦点とピクセルを結ぶ直線(光線)です。Radiance Fields はこの直線上の各点について色と密度を返してくれるので、この直線に沿って Radiance Fields を積算してやれば一つの色を得ることができます。同じことを全ピクセルに対して行えば、一枚の画像を生成することができるわけで、これがいわゆるレンダリングです。未学習の F_\Theta でレンダリングしたところで出てくるのは無意味な画像ですが、これと実際の画像が一致するよう F_\Theta を更新していく(具体的には二乗和誤差の最小化)ことで、レンダリング結果は本物のそれに近づいていきます。結果として F_\Theta は三次元空間の表現 ( Radiance Fields ) になっていくというわけです。

Volume Rendering with Radiance Fields

前節で NeRF の概略を述べたので、これから詳細の解説に入っていきます。まず F_\Theta は正確には次のような関数です。

F_\Theta :(x,y,z,\theta,\phi) \rightarrow (R,G,B,\sigma)

ここで (x,y,z) は空間上の座標で、 (\theta,\phi) は視線の角度です。光の性質により、物体を見る角度によって色は変化するため、位置座標だけではなく視線の角度も入力に加えることにしています。また (R,G,B) は色、 \sigma は密度です。本手法では F_\Theta をマルチレイヤーパーセプトロンとして実装しています。ネットワークアーキテクチャについては後ほど触れる予定です。 ところで上記の式中では角度を (\theta,\phi) と表現していますが、代わりに今後は 3 次元単位ベクトルによる角度表現 \bf d を使います。また空間上の座標を {\bf x} = (x,y,z)^T と書くことにします。 {\bf d} を用いると、焦点の座標を {\bf o} として、光線 {\bf r} {\bf r} (t) = {\bf o}+t {\bf d} という具合に t でパラメタ表示できます。 t は焦点からの距離です。 さて、ここから F_\Theta を色 {\bf c(x,d)} 、密度 \sigma({\bf x}) と分けて書くことにします。すると volume rendering は以下のような積分の式で書くことができます。 C({\bf r}) は光線 {\bf r} の焦点から見た色で、 t_n, t_f はそれぞれレンダリングにおいて考慮する距離の下限、上限を意味します。やっていることは単純で、色と密度をかけたものを光線上で積分するだけです。

C({\bf r}) = \int_{t_n}^{t_f} \! T(t) \sigma({\bf r}(t)) {\bf c}({\bf r}(t), {\bf d}) \, \mathrm{d}t, ~ \mathrm{where} ~ T(t) = \exp(- \int_{t_n}^t \! \sigma({\bf r}(s)) \, \mathrm{d}s)

ただし T(t) は、ある点から焦点へと向かう光が、それより前(焦点側)にある点によって妨げられる状況を表現しています。 {\bf r}(s), ~ (t_n \leq s < t) に密度の高い点があった場合、exponential の中身が小さくなるため T(t) 0 に近づき、 {\bf r}(t) から出た光は C({\bf r}) に影響しなくなるというからくりです。 Volume rendering の仕組みは上記の通りなのですが、この積分は計算しづらいため離散化して総和計算に書き換えます。そのさい積分区間 [t_n, t_f] を区切ってやる必要があるわけですが、NeRF ではこの区切り方に一工夫加えています。その工夫については後で触れるとして、積分区間が t_1,\cdots,t_N によって区切られたとしましょう。すると volume rendering は以下のように書き換えられます。

\hat{C}({\bf r}) = \sum_{t_n}^{t_f} T_i (1 - \exp(-\sigma_i \delta_i)) {\bf c}_i, ~ \mathrm{where} ~ T_i = \exp(- \sum_{j=1}^{i-1} \sigma_j \delta_j)

ただし、 {\bf c}_i \sigma_i はそれぞれ {\bf x}_i = {\bf o} + t_i {\bf d} における色と密度で、また \delta_i = t_{i+1} - t_i です。これらの式はニューラルネットワークフレームワークで提供されている backprop 可能なオペレータのみで書けるので、ニューラルネットワークの訓練に利用できるというわけです。

Hierarchical volume sampling

さて 3D レンダリングを介してニューラルネットワークを訓練する方法はわかりました。本質的な部分の説明は以上で終わりなのですが、論文ではさらにいくつかの工夫を加えています。ひとつ目は、訓練時に「粗い ( coarse )」レンダリングと「細かい ( fine )」レンダリングの二度のレンダリングを行うというものです。二度のレンダリングの違いは、先ほど触れた積分区間の区切り方 t_i  の決定方法にあります。 粗いレンダリングでは、 [t_n,t_f] N_c 個(論文では N_c=64 )の区間に分割し、それぞれの区間から一様分布に従って一つ t_i をサンプリングしています。決め打ちではなくランダムにしているのは、ニューラルネットワークを滑らかにするためです。摂動する入力に対してニューラルネットワークを訓練することによって、連続的な三次元空間表現を得る狙いがあります。 一方の細かいレンダリングでは、粗いレンダリングの結果を利用して、物体の存在しそうな場所(密度の高い場所)から重点的にサンプリングを行います。こうすることによってむやみにサンプリング点数を増やすことなくレンダリング結果を精緻化できるわけです。もう少し具体的に述べておくと、粗いレンダリングにおける T_i (1-\exp⁡(-\sigma_i \delta_i ) ) の比率(これは各点のレンダリング結果への影響度とみなせます)に従って N_f 個(論文では N_f=128 )の区切り t_i をサンプリングし、これと粗いレンダリングで使った区切りを合わせたものを最終的に利用します。 ちなみに論文では、これら二度のレンダリングにおいてそれぞれ異なる(同一アーキテクチャの)ニューラルネットワークを使っています。細かいレンダリングにおいて最適な色・密度が、粗いレンダリングにおいても最適である保証はないので、同一のネットワークを使うと学習が不安定になるのではないかと思います。

Positional encoding

これまでの説明では 3 次元ベクトル {\bf x, d} をニューラルネットワークの入力とするような書き方をしてきましたが、実は {\bf x, d} をそのまま使うには問題があります。というのも、それが表現している三次元オブジェクトの都合上、各点の色・密度 {\bf c}, \sigma {\bf x, d} の微細な変化に対してめまぐるしく変化するわけですが、実はニューラルネットワークはこの手の高周波な関数の近似が苦手なのです。そこで本論文では著者らが positional encoding と呼んでいる手法を使って {\bf x, d} を高次元の空間に埋め込んでいます。この埋め込み表現が高周波であれば、ニューラルネットワーク自体は低周波な関数を近似するだけでよい、というのがみそです。これがふたつ目の工夫になります。 本論文では以下のような関数 \gamma {\bf x, d} を埋め込んでいます。 L {\bf x} については 10 で, {\bf d} については 4 を採用しています。結果として \gamma({\bf x}), \gamma({\bf d}) はそれぞれ 60 次元、 24 次元のベクトルとなり、これらがニューラルネットワークに入力されます。

\gamma(p)=(\sin(2^0 \pi p), \cos(2^0 \pi p) , \cdots , \sin(2^{L-1} \pi p), \cos(2^{L-1} \pi p) )

実装

Radiance Fields としては以下のようなアーキテクチャのネットワークを利用しています(図4)。矢印は Linear 層を表し、線の違いは活性化関数の違いを表現しています。黒は ReLU、点線はシグモイド、オレンジは活性化関数なしです。矩形はベクトルを表し、中の数字は次元数です。また ”+” はベクトルの concatenate を意味します。 位置情報 {\bf x} を二か所から入力し(これは DeepSDF を真似たそうです)、角度情報 {\bf d} はかなり後段になってから入力しているのが特徴でしょうか。密度 \sigma は見る位置によって変わってほしくないということで、 {\bf d} を入力する前に \sigma を取り出しています。シグモイド関数によって RGB [0,1] の値におさめられます。
図4:ネットワーク構造
学習は一般的な分類タスクなどと違って、画像単位ではなく光線単位で行います。論文ではバッチサイズ 4096 、最適化アルゴリズムには Adam を使い(ハイパーパラメタは論文を参照してください)、Nvidia V100 GPU で 1~2 日煮込めばよいとのことでした。これでなかなかコンパクトなニューラルネットワークだなあと感じるのは、感覚がおかしくなってきているのかもしれません。

結果

NeRF の学習結果については、著者プロジェクトページ[1]の動画を見てみるといろいろ載っており、さまざまな視点から見た高精細な画像を生成可能であることがわかります。視点による反射光の違いなども表現できています。
図5:比較
これも論文中の図なのですが、LEGO 製ブルドーザーを NeRF に学習させたものを例に挙げて View Dependence (角度情報 {\bf d} )と positional encoding の効果を調べています。当然といえば当然ですが、角度情報がない場合は履帯の光の反射を反映できていません。また positional encoding がない場合はブロックの微細な形状を再現できていないことがわかります。

再現実験について

ここからはわたしの行った再現実験の話です。最終的なスクリプトはこちらにあります。人様に見せられるようなものでもないですが、ご参考までに。ちまたでは眉を顰められがちな(?) jupyter notebook 一本という構成です。著者実装よりはだいぶ小さくまとまっているので(低機能ともいう)理解はしやすいのではないかと思います。 唐突に NeRF を実装してみようと思ったのは二週間ほど前で、SLAM 系の勉強・実験をしていて頭が煮詰まっていたのと、生成されるビューの奇麗さを見て感動したからでした。その時点では著者実装は公開されていなかったような気がしますが、わたしの見落としかもしれません。というわけで特に公式実装は参照せず再現実装しています。 三次元の幾何学的な計算はよくやっているのでそんなに時間はかからないだろうと思い、実際、とりあえず動くものができたのは二日後くらいでした。が、実はかなり最初のほうに致命的なバグを埋め込んでおり、そのデバッグにかなり時間を取られました。このバグについては後述します。 この手の論文を実装する際は、データセットの準備・理解から入るのが最も楽だというのが個人的な認識で、今回は論文中で利用されていた DeepVoxels[9] データセットなるものを眺めながら実装の方針を決めました。このデータセットは多視点から撮影(レンダリング)された三次元オブジェクトの実画像および CG 画像を含んでおり、各カメラの内部/外部パラメタも付属しています。最初はできるだけ簡単なデータで試してみるのがよいだろうということで、 CG 画像のほうを使うことにしました。
図6:利用した三次元オブジェクトのひとつ。謎の物体
カメラ外部パラメタを調べてみると、どのカメラもおおむね原点を向いていて、各カメラの座標は各軸 [-2, 2] あたりに収まりそうです。Positional encoding のためには、各座標値は [-1, 1] の範囲に収まる必要があるので、本当はきちんとカメラパラメタを正規化する必要があったわけですが、今回は {\bf x, d} を tanh に通してお茶を濁すことにしています。たぶん大きな問題はないはずです。 いくつか手間取った点。まず細かい方のレンダリングに使う区間のサンプリング方法には少し悩みました。今回の実装では、 [0,1] の一様乱数からサンプリングした値 u を、以下のような区分的な一次関数 t=f(u) で変換しています(図7)。もう少しうまいやり方はあると思いますが、速度的・機能的に問題はなさそうです。
図7:区分的な一次関数
それから、背景の問題。学習に使ったデータは背景が白色になっていました。最初はこのことを特に気にせずネットワークを訓練していたのですが、よく考えてみると、学習しているニューラルネットワークからすればこの白色光はどこから来た光なのかいまいちわからないわけで、最終的に背景色にレンダリング結果を足し合わせる方法に変えました。あとで公式実装を読んでみるとやはり背景色を指定するオプションがあり、論文に書かれてはいないが自明に気にするべきこうした点について自分はまだまだ経験が足りないなと思いました。 そんなこんなでちまちま調整していくと、だいぶそれらしい画像が出てくるようになりひとまず喜んでいたのですが、しかし論文に記載されていた 2 日という期間学習を回しても論文レベルの画像は出てくるようになりません。どこで失敗しているのだろうかとレンダリングの計算を見直したり学習率を変えてみたり活性化関数をいじってみたりと様々なことを試した挙句、ようやくデータセットの作成方法を間違っていたことに気づきました。 今回の再現実装では、あらかじめ学習データの全ピクセルを光線に変換し numpy 配列として保存していました。光線単位で学習を行う都合上、毎回画像を読み込んでピクセルを光線に変換するのでは無駄が多かったからです。先に述べたように光線は {\bf r} (t) = {\bf o}+t {\bf d} で表現されるので、各光線の {\bf o, d} を計算しておけばよいことになります。これにはカメラ外部パラメタを利用します。 外部パラメタには回転行列 {\bm R} と平行移動ベクトル {\bf t} が含まれており、これを使って {\bm R} {\bf x}_c + {\bf t} とやるとカメラ座標系上の点 {\bf x}_c を世界座標系上の点 {\bf x} に変換できます。たとえばカメラ座標系の原点(焦点) {\bf o}_c = (0,0,0)^T は、世界座標系上では {\bf t} の位置にあることが分かるわけです。 ややこしいのは {\bf d} の算出です。これは、各カメラ焦点の座標から視線方向に焦点距離 f だけ離れた平面を考え、この平面上のピクセルと焦点の位置関係を考えれば計算できます。見方を変えると、カメラ座標標系上の z=f 平面上(画像平面)にピクセルを配置し、これを外部パラメタで世界座標系上に変換したのち、それから焦点座標を引いてやればよいわけです。式で書くと次のようになります。 {\bf x}_c は画像平面上のピクセルです。(実際には {\bf d} はさらに正規化してノルム 1 にする必要があります。)

{\bf d} = {\bm R} {\bf x} + {\bf t} - {\bf o}

ミスというのは実はここにあり、なんと最後に {\bf o} を引くのを忘れていたのです[10]。結果としてデータセットは空間的につじつまの合わないものとなり、つまりわたしはニューラルネットワークに滅茶苦茶な世界を見せて「学べ!」と強要していたことになります。これはニューラルネットワークに対する明らかな虐待であり、彼らに人権が認められた暁には訴えられてもしょうがない……という冗談はさておき、間違った設定下でもある程度学習してしまうというニューラルネットワークの表現力はデバッグ作業においてはなかなか厄介です。学習フローをじっくり丁寧に確認する必要があります。 さて、すべてのバグをつぶした(はず)最終的なモデルによるレンダリング結果は以下のようになります(図8-10)。光線を区切ってレンダリングしている都合上、微妙に細部を再現できていない部分もありますが、ほとんど訓練データと見まがう画像を生成できています。これらは2日ほど訓練したものですが、1 時間程度の訓練でも十分見られる画像を生成できるようになります。ぜひ試してみてください。
図8:謎の物体。容量の関係で gif 版
図9:花瓶。複雑な模様も再現できている
図10:バス。やや治安が悪そう

まとめと感想

本記事では、NeRF を中心にニューラルネットワークによる三次元表現手法について解説し、また NeRF の再現実験の結果を紹介しました。NeRF はシンプルな手法で複雑な三次元オブジェクトを表現することができ、この方面の今後の展開が期待されます。たとえば NeRF は {\bf x, d} に対して RGB, \sigma を返しますが、ここで \sigma の代わりに直接深度を返すようにできないか(訓練には再投影誤差を使う?)とか、マルチレイヤーパーセプトロンよりも三次元表現に適切(学習が速いとか、三次元オブジェクトについての自然な仮定が入っているとか)なネットワーク構造があるのではないかとか、個人的に試してみたいところです。NeRF 的な方法を利用した三次元物体計測の仕組みを作って精度評価してみても面白いかもしれません。何かしらの成果が出れば、またブログ等でご紹介したいと思います。 最後になりますが、ALBERT ではリサーチャー・アナリストを募集しています。ニューラルネットワークに現実世界を教えてみたいという方がいらっしゃいましたら、ぜひご応募ください。お待ちしています。

参考文献など

  1. Mildenhall, B., Srinivasan, P.P., Tancik, M., Barron, J.T., Ramamoorthi, R., Ng, R., 2020. NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis. arXiv:2003.08934 [cs].
    プロジェクトページ: http://www.matthewtancik.com/nerf
  2. Mikolov, T., Sutskever, I., Chen, K., Corrado, G.S., Dean, J., 2013. Distributed Representations of Words and Phrases and their Compositionality, in: Burges, C.J.C., Bottou, L., Welling, M., Ghahramani, Z., Weinberger, K.Q. (Eds.), Advances in Neural Information Processing Systems 26. Curran Associates, Inc., pp. 3111–3119.
  3. Kingma, D.P., Welling, M., 2014. Auto-Encoding Variational Bayes. arXiv:1312.6114 [cs, stat].
  4. Eslami, S.M.A., Rezende, D.J., Besse, F., Viola, F., Morcos, A.S., Garnelo, M., Ruderman, A., Rusu, A.A., Danihelka, I., Gregor, K., Reichert, D.P., Buesing, L., Weber, T., Vinyals, O., Rosenbaum, D., Rabinowitz, N., King, H., Hillier, C., Botvinick, M., Wierstra, D., Kavukcuoglu, K., Hassabis, D., 2018. Neural scene representation and rendering. Science 360, 1204–1210. https://doi.org/10.1126/science.aar6170
  5. Park, J.J., Florence, P., Straub, J., Newcombe, R., Lovegrove, S., 2019a. DeepSDF: Learning Continuous Signed Distance Functions for Shape Representation. Presented at the Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pp. 165–174.
  6. Chen, Z., Zhang, H., 2019a. Learning Implicit Fields for Generative Shape Modeling. Presented at the Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pp. 5939–5948.
  7. オンラインで読めるものとしては、MathWorks の『カメラキャリブレーションとは』や OpenCV の『カメラキャリブレーションと3次元再構成』が分かりやすかったです。
  8. カメラ外部パラメタによっていかようにもなるので、カメラ座標系の軸の取り方は任意です。ただし一般的には 3 番目の軸がカメラ視線方向になるようモデル化されます。
  9. Sitzmann, V., Thies, J., Heide, F., Niessner, M., Wetzstein, G., Zollhofer, M., 2019. DeepVoxels: Learning Persistent 3D Feature Embeddings. Presented at the Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pp. 2437–2446. Sitzmann, V., Thies, J., Heide, F., Nießner, M., Wetzstein, G., Zollhöfer, M., 2018. DeepVoxels: Learning Persistent 3D Feature Embeddings. arXiv:1812.01024 [cs].
    データセットは https://vsitzmann.github.io/deepvoxels/ にてダウンロードできます。
  10. {\bf o = t} が分かっていたならなぜ単に {\bm R} {\bf x} を計算しなかったのかと不思議に思われそうですが、データセットでは外部パラメタが {\bm R}, {\bf t} をまとめた 4×4 行列で格納されており、その辺に敗因があります。

山内

先進技術部所属。ニューラルネットワークが好き。大学では哲学をやっていました。