3Dモデルをいろいろ作ってみたい

3Dモデルをいろいろ作ろうとがんばっています。苦労した点、役に立ちそうな情報を発信していきます。

ひさびさにロボット骨格の新バージョン

前回のBlogからちょっと期間があいてしまいましたが、実はDeep Learningのプログラムでハマっておりました。デバッグのためのルールや方法を確立できず、機械学習フレームワークを変えていちから試してみたりと、低レベルから試行錯誤をやりなおしているところです。

気分を変えるため、お休みしていたロボットデザインの作業を進めようかと思うのですがこっちはこっちで煮詰まっているんですよね。基本となるロボットの骨格(と関節)を何度も繰り返している状態で、なかなか外装や変形機構の設計にたどりつけない..

そうはいっても何かしら新しいやりかたを試してみようということで、今回は下に示すような限られた種類のパーツを多数3Dプリントしておいてそれらを組み上げてロボットの骨格を作るということを試してみました。

f:id:ichidaya:20210721140932j:plain

ロボット骨格パーツの例(一部)

それぞれのパーツはFusion 360で設計していますが全体としてどんな形の骨格になるかはでたとこ勝負です。

f:id:ichidaya:20210721141648j:plain

骨格の仮組イメージ

パーツをAdventurer3で出力したら並べてみてこんなかたちにしようかと考えて後はネジを締めて組み立てました。

f:id:ichidaya:20210721142313j:plain

パーツを組み上げた骨格

モデリングにかかった時間は今までの中では一番短かったです。

ただ、関節の自由度は前のバージョンより少ないしポーズの保持力もいまいち。

ネジの数がやたらと多くなってしまったのはご愛敬。

このアプローチももう少し試してみようかなと思っています。

Deep Learningで3Dデータ生成 -高解像度の3Dモデルを目指して-

RTX3090 GPUボードのおかげでDeep Learningの学習のスピードは相当(200倍程度)速くなることは確認できたのですが、3次元データの解像度を単純に上げていくとGPUメモリ容量の制約でGPU並列処理ができなくなる、すなわち事実上実行不能になるという制約に変わりはありません。24GBの容量があっても3次元の畳込み層を使うと処理できるテンソルのサイズは32x32x32まででした。モデルの解像度を128x128x128ぐらいに上げてかつGPUでそこそこの速度をだしたいということで、学習のためのネットワーク構成を再検討することにしました。

基本的な考え方は128x128x128の3Dのテンソルではなく128x128の断面画像に相当するテンソル128枚分を入力として用いるということです。128x128の2次元データを畳込み層に適用してそれぞれのサイズを小さくしてからConcatenate層(Tensorflow/Kerasにはちゃんとマージのための層が用意されている)で1枚の2次元画像にマージし、全結合層(Dense層)につなぐことにしました。これだと(縦横サイズの大きい)入力に近い側では2次元データを処理すればよいのでGPUメモリの範囲内に収めることができます。高さ方向では層間の畳込みを行っていない点でちょっと学習能力は落ちる気はしますが、とりあえずはこの方針で試すことにしました。

生成用Deep Learningアーキテクチャは前回のGAN(敵対的生成ネットワーク)ではなく、Auto Encoderです。前回は本に載っていたGANのプログラムコードを少し変更することで実現したのですが、今回は入出力の構造が大きく変わっているため自分でいちからコーディングしました。そのぶん、Kerasの勉強をしながらになるのでGANに比べて構造が単純なAuto Encoder に則してネットワークを作ることにしました。

Auto Encoderは入力の3Dデータに対して畳込み層、全結合層を適用してベクトルデータを出力するエンコーダとベクトルデータを入力として3Dデータを出力するデコーダから成ります。エンコーダへの入力とデコーダの出力の差を最小化するように学習を行います。学習後のエンコーダー->ベクトルデータ->デコーダの処理はデータの圧縮と復元を表し、乱数で生成したベクトルデータ->デコーダの処理が新たな3Dデータ(ロボットの顔)の生成になります。(ただし、文献でAuto Encoderは汎化能力に乏しいことがわかっているため本格的3Dデータ生成には向かないだろうとは予想しています。)

以下、800個の3Dデータで1000エポック学習(GPUを使用して半日ぐらい)させたのち、そのうちの1個のデータをエンコーダに入力、デコーダから出力させた各断面の画像です。

f:id:ichidaya:20210526223050j:plain

入力とAuto Encoder出力の各断面図

3次元データとして表示するとこんな感じ。128x128x128の3Dデータをいちど128次元のエンコーダでベクトルデータにおとし、デコーダで復元しています。

f:id:ichidaya:20210526223641j:plain

3Dデータの復元結果

Auto Encoderは汎化能力に乏しいためランダムデータから新しいロボットの頭部を作れるかというと残念ながらうまくいきません。

f:id:ichidaya:20210526224806j:plain

ランダムデータをもとに生成した3Dデータ

次は断面図リストを入出力とするアプローチでGANを試そうと思っています。

新しいパソコンでDeep Dreamを試してみた

今回購入したパソコンの筐体はいわゆるフルタワー、このサイズのパソコンを買ったのは30年ぶりぐらいかな。中を開けるとこんな感じです。

f:id:ichidaya:20210430131605j:plain

本体の側面カバーを開けたところ

電子部品としてはマザーボードとグラフィックボード(GEFORCE RTX 3090)だけである意味スカスカですが、熱対策が重要なんでしょうね。昔では考えられなかったようなでっかいファンがいくつもついています。

f:id:ichidaya:20210430132215j:plain

グラフィックボードRTX3090

このスペックならいろんなDeep Learningニューラルネットワークを動かすことができそうです。そこで(3Dモデリングとは直接関係ないのですが)、Deep Dreamというおもしろそうなアプリケーションがあったので試してみました。雲の流れとは天井板の木目模様とかをじっと眺めていると、人の顔とか動物に見えてくることがありますよね。Deep Dreamはこういった錯覚(幻覚?)をニューラルネットでエミュレート(今回は下記のURLのコードを利用)することでいわゆる「悪夢」のような画像を作り出してくれます。

https://www.tensorflow.org/tutorials/generative/deepdrea

左端はオリジナル画像、中と右端が徐々にDeep Dreamの効果を強めて処理していった結果です。

f:id:ichidaya:20210430140622j:plain

Deep Dream実行例

このDeep Dreamの実装ではInceptionV3という定義済のニューラルネットワークを使い、ImageNetという画像データベースを使って学習した状態で提供されています。画像の処理に要する時間は1枚当たり数秒程度でした(処理の瞬間のCUDAs使用率は100%近くに達しています)。

 

GPUでDeep Learningの学習がどれだけ速くなるか

先週、オーダーしていた新しいPCが届きました。グラフィックカードGEFORCE RTX 3090を搭載、メモリ64Gバイト、CPUは8コア2.5GHzという自分史上最高スペックのマシンです。週末にTensorflow等のDeep Learning用ソフトウェアのセットアップを行い、GPUによる高速化効果を確認しました。

比較に用いたGPU無しの環境はふだん使っているノートパソコンですが、AMD RYZEN(8コア、1.7GHz)、メモリ32Gバイトとそれなりに強力な(と思う)マシンです。

下の表に時間計測の結果をまとめましたが、当然ながらGPUの効果(どれだけ速くなるか)はタスクの内容(ネットワークの層の数、ニューロンの数)によってだいぶ異なっていました。

学習タスク GPU無し GPUあり GPUの効果 CUDA使用率
A.画像分類               59秒             32秒    1.8倍     63%
B.3DデータのVAE 4時間17分36秒        1分11秒    217.7倍     100%

 

Aの画像分類のタスクは教科書に載っているもので写真に写っている鳥や馬、自動車など10種類の動物や乗り物を識別するというものです。

f:id:ichidaya:20210415225248j:plain

画像分類の結果

隠れ層の数は2、学習するパラメータ数は646,260、32x32 のRGB画像5万枚を学習に使っていて機械学習のタスクとしては軽いほうだと思います。GPU有りと無しの環境とで処理時間は1.8倍程度にしか上がっていません。CPUのクロック差で速くなっている分もあると考えるとGPUの効果はかなり限定的といえます。

一方のBはロボットの3Dモデル生成のために私が作成中の変分オートエンコーダー(VAE)と呼ばれるタイプのネットワークの学習です。隠れ層、畳込み層の数は9、学習するパラメータ数は7,395,841、64x64x64の3Dモデル1280個を学習に使っています。こちらはGPU有無の差が200倍以上になっています。タスクの規模が比較的大きくて、かつ計算処理の中で並列に実行できる割合が高ければCUDAコア数の分だけ並列に(つまり高速に)実行できるということなんでしょう。ちなみにRTX 3090は10496個のCUDAコアを持っていますが、学習タスクを走らせているあいだはほぼ100%使われていました。

 

 

 

 

やっぱり速いPCが欲しい、という話

 GAN(敵対的生成ネットワーク)で生成する3Dモデルの精度やバリエーションをもっと改善したいと学習するモデル解像度を32x32x32から64x64x64にスケールアップしたのですが、結果は惨憺たるものでした。得られた生成モデルに何を入力しても、どれも同じような丸っこい形しか出力されません。学習データの数が足りないのか、ネットワークモデルの構成に問題があるのか、分析したいのですがそこでボトルネックになるのがネットワーク学習の処理時間です。

手持ちのPCでの処理は遅くて論外です。1バッチ分の学習に5分から10分かかるので、仮に3000回学習したらまる10日以上かかってしまう。いくつかDeep Learning用にPCインスタンスを提供してくれるクラウドサービスを試してみて、AWSのEC2サービス(GPU1個のインスタンス)を使ったのですがそれでも1回の学習に数時間かかってしまいました。このインスタンスの使用料は1時間当り$4.19です。インスタンスを起動する度に時計がリセットされて課金が始まるので、起動・10分使用・停止を3回繰り返すと3時間分の課金になります。

本番の学習処理に数千円かかるのはしょうがないにしても、プログラムやデータのロードなど環境の変更などのちょっとしたお試しで短時間インスタンスを立ち上げるたびに400円強ずつの出費が積み重なっていくというのはがまんできない..

以上、物欲に負けた言い訳をつらつらと書きましたが自分でそこそこの実験ができる環境を確保しようとポチッとしてしまったのがこのグラフィックカードを採用したBTOパソコン。

AWSで動かした経験だとGPUのメモリが16GBだと大きなテンソルデータを処理するのに容量的にギリギリだったのでRTX3090で24GBメモリがあればとりあえず十分かなと思っています。納期は4~5週間ということで、到着を楽しみにしています。

 

ロボットの頭部をAIでデザインできないかと試してみたい ー3Dの畳込み層を使ってみるー

前回の試作では3Dモデル生成のためのGAN(敵対的生成ネットワーク)の構成は2次元の画像を生成するのと全く同じでした。3次元座標情報をさながら地球儀を紙の世界地図に展開するようなかたちで2次元に展開し、ネットワークに入力していたわけです。その後、GANの実装に使われているTensorFlowライブラリの仕様を調べていたらConv3DとかUpSampling3Dといった3次元情報を直接処理する層が用意されていることを知りました。それなら、Conv2Dの代わりにConv3D、UpSampling2Dの代わりにUpSampling3Dを使えば3次元データを直接学習、生成できるだろうということで試してみたのが今回の報告です。
前回は3次元空間上の点を極座標形式(r, θ,Φ)で表して n等分したθ,Φに対してrの値を計算して3Dモデルとしていました。今回はすなおに3次元空間上の座標を(x, y, z)で表現しn×n×n個の座標に対してそこに点があるかどうか(1~-1、値が大きいほどそこに点がある可能性が高いとする)を計算して3Dモデルとします。

問題は2次元から3次元になったことで学習に必要な計算量が飛躍的に増大したことです。普段使っているPCでは1回のバッチ分の計算にも1時間近くかかる始末、何千回の繰り返しなんてとてもおぼつかない。そのため今回の学習にはGoogle Colaboratory(略称: Colab)というクラウドサービスを使わせていただきました。連続して使用できる時間などに制限はありますが、アクセラレータ付きのサーバー上でPythonプログラムを無料で実行することができます。

それでもn=64(64×64×64)の分割ではすぐにリソース制限にひっかかってしまうので、今回はn=32(32×32×32)の分割で処理を行うことにしました。学習が終わればネットワークの重み係数のファイルをダウンロードして、3Dモデルの生成を自分のPCで行うことができます。100次元の値ランダム(1~-1)のベクトルを生成して生成用のネットワークで処理するのですが1個数十秒程度で3Dモデル(32×32×32のnumpy配列)が生成されます。

ノイズの消去や閾値処理等を行ってからOBJ形式に変換(点だけの情報に面情報を付加するプログラムを作成)したのが以下のような感じ。

f:id:ichidaya:20210220171418j:plain

OBJ形式に変換直後の3Dモデル

ここから先は自分でプログラムを作るのはめんどくさいのでZBrushに読み込んで行うことにします。まず、離れ小島のような塊を削除してから左右対称に整形します。

f:id:ichidaya:20210220171724j:plain

左右対称に整形

自作のOBJ生成のロジックがいまいちでメッシュが汚いのでダイナメッシュをかけてスムーズにします。

f:id:ichidaya:20210220172026j:plain

ダイナメッシュ適用後

前回よりはだいぶロボットの顔らしくなってる! そう思いたい..

以下にいくつか生成例を載せています。

f:id:ichidaya:20210220172644j:plain

ロボット頭部の生成例1

f:id:ichidaya:20210220172722j:plain

ロボット頭部の生成例2

f:id:ichidaya:20210220172807j:plain

ロボット頭部の生成例3

頭部全体の輪郭が人の形っぽいものや、平べったいかたち、アンテナ(角?)っぽいものがついたもの、前回の極座標形式での生成よりもバリエーションが増えた気がします。

 

ロボットの頭部をAIでデザインできないかと試してみたい ー単純に適用してみたー

OBJ形式の3Dモデルをニューラルネットへの入力であるNumpy形式に変換するプログラム、逆にニューラルネットの出力のNumpy形式をOBJ形式に変換するプログラムを作ったので、参考書で定義されているGAN(敵対的生成ネットワーク)で3Dデータを生成してみました。学習データはThingiverseで見つけてきたロボットの3Dデータ。ガンダム、パシフィックリムなどのロボットの3DデータをZBrushで編集して頭部だけのデータを60体分集めました。これだけでは全然足りないので、1体分のデータを縦/横に少しずつ引き延ばして25のバリエーションを作成、全部で1500ほどを学習データ(1データは64×64次元、3チャンネル)として準備しました。

ニューラルネットの構成はセレブの顔を生成する例を何も考えずそのまま使用、人間が決めないといけないハイバーパラメータもそのまま使っています。GANではではランダムに発生させた3Dデータから出発してロボットの頭部っぽい3Dデータを生成するネットワークと本物の頭部(学習データ)と人工的に生成された頭部っぽい3Dデータを区別するネットワークが競い合って3Dモデルを発展させていきます。

で、試してみると学習の初期段階で生成されている3Dデータがこんな感じ。

f:id:ichidaya:20210131220434j:plain

学習初期段階で生成される3Dモデル

そもそもなんのかたちにもなっていないという感じですが、学習プロセスを5000回ぐらい繰り返すと、以下のようななんか(?)のかたちにはなってきました。

f:id:ichidaya:20210131220829j:plain

5000回学習後に生成された3Dモデルの例

「どこがロボットじゃーい!!?」と突っ込まれそうですが、ランダムノイズのようなデータからコンピュータが勝手にここまでの3Dデータを作ってくれるってすごいことのように思えます。

もう少し勉強していけばいろいろおもしろいことができそうです。