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

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

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データを作ってくれるってすごいことのように思えます。

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

ロボットの頭部をAIでデザインできないかと試してみたい ーまだ始めたばかりですがー

以前に3Dモデルをプログラムで生成するツールを試作していましたが、今年はFusion 360でのモデリング作業が主となっていてなかなか手をつけることができませんでした。1年以上の間、こっちのアプローチの作業はしていない...

ichidaya.hatenablog.jp

ichidaya.hatenablog.jp

 で、最近読んだのがこの本。与えられた画像や音声のパターンを認識するだけではなくて画像やテキストをニューラルネットワークで生成することができるんですね。

 O'Reilly Japan - 生成 Deep Learning

f:id:ichidaya:20201231185910g:plain

生成 Deep Learning

 

 生成される画像データは3次元の配列(縦×横×RGB)なんですが、じゃあ3次元の形状も大きさも定まった配列で表現できれば(そして十分な学習データが用意できれば)センスの有無に関係なくロボットの顔をデザインできる!

そう考えてまず、OBJ形式の3次元データを大きさ固定の配列で表すPythonプログラムを作ってみました。

  1. OBJデータに含まれる点の座標を極座標形式(r, θ,Φ)に変換
  2. 2π/配列サイズの単位でθとΦを離散化、該当するrの値を持つ2次元配列に格納
  3. RGBの値の代わりにθ、Φで決まるベクトル上で最初の点、2番目の点、3番目の点のrを格納していく

Thingiverseで見つけてきた3Dモデルはこんな感じ。

f:id:ichidaya:20201231205638j:plain

ロボットの顔のOBJデータ

64×64×3の配列データに変換して、3Dグラフにプロットしてると以下のようになります。解像度64だとディテールまでは表現できないものの、大雑把な輪郭や特徴的な額のアンテナは再現できそうです。

f:id:ichidaya:20201231210543j:plain

極座標形式に変換してから離散化

学習用のデータを集めるのがたいへんそうだしそもそもニューラルネットの構成をまだ決めていないのですが、来年(2021年)はこの方向の試行も進めていきたいと思っています。

ロボット骨格にボディアーマーを装着する -次郎丸編-

1か月以上かかってしまいましたが、PETGフィラメントで出力したロボット骨格(前回投稿後に改良)にボディアーマーを装着しました。Fusion360上で大きさや位置の合わせをしながら設計していった(下図)のですが、骨格の動きとアーマーが干渉したり、出力してみると強度がたりなかったりで、ずいぶんと試作と廃棄を繰り返すことになりました。

f:id:ichidaya:20201129163322j:plain

骨格とアーマー

下の写真で試作機がポーズをとった足元に転がっていいるのは完成までに犠牲になったパーツの亡骸(の一部)です。実機だったら開発中止になってますね。

f:id:ichidaya:20201129163631j:plain

完成した試作機と廃棄されたパーツ

 

アーマーは骨格にねじ止めしているので、脱着可能です。前と後ろはこんな感じ。現状、関節の裏側はどうしてもむき出しになってしまうのですが、ガンプラなんかではどう処理しているんだろう。

f:id:ichidaya:20201129164411j:plain

アーマー装着時(前と後ろ)

肩から上腕部分は、1軸(胸の内部に埋込み)、2軸、1軸の3つのジョイントで構成しています。両端のジョイントにアーマー部品をねじ止めしています。青いのはボールジョイントを挟みこんだときの緩衝材として塗ったリキッドゴムです。前回はシリコンゴムのチューブを切って貼り付けていたのを今回は違うやり方を試してみたのですが、結果は関節をぐりぐり動かしているうちにゴムがはがれてきてしまいいまいちでした。TPUフィラメントを試してみたいけど、Adventrer3ではヒートヘッドの温度がちょっと足りないかな、と考えあぐねているところです。

f:id:ichidaya:20201129181054j:plain

肩から上腕部分のジョイントとアーマー

アーマーをつけたことによって関節の可動域が制限されてしまった部分(特に腰のあたり)もありますが、いちおうフルアーマー付きでポーズをとる段階になったので試作機に名前を付つけることにしました。

f:id:ichidaya:20201129204117j:plain

アーマー付きでポーズをとる

前回試作機PLR-18-01につけた名前をつけたのは「太郎丸」でした。

ichidaya.hatenablog.jp

今 回の試作機PLR-23-01は「次郎丸」と命名しました。

ロボット骨格の関節可動範囲を改良

前回のBlogで紹介したロボット骨格を改良を続けています。今回は肩と脚のつけ根の関節の自由度を1つ増やしました。

f:id:ichidaya:20201007221213j:plain

肩と脚のつけ根にジョイントを追加

ロボット骨格の関節はPETG製のパーツとバーツ同士を繋げるボルト/ナット、緩衝材として用いるシリコンゴムのチューブから成り立っています。構成は以下の3種類。

①肘や膝の関節に用いる1軸のジョイント

f:id:ichidaya:20201007222154j:plain

1自由度の関節

②腰の部分に用いる1軸のジョイント

 

f:id:ichidaya:20201007222555j:plain

1自由度の関節(腰)

③肩や脚の根本に用いる2軸のジョイント

f:id:ichidaya:20201007222907j:plain

2自由度の関節

③が今回骨格に追加した関節部品です。ボール型のジョイントをシリコンゴムの緩衝材で挟みボルト/ナットで締め付けています。ボール型ジョイントを使うことで2つの自由度を実現しています。以前に試したボールをスナップインではめ込む方法ではどうしてもポーズの保持力に不満が残るのでボルト/ナットを使うことにしました。

f:id:ichidaya:20201008164010j:plain

前バージョンではできなかったポーズをとれる

左の仮面ライダー1号の変身ポーズでは肩の関節が大きく曲がるようになったので手を顔の前までもってくることができるようになっています。ちなみに前バージョンで同じポーズをとろうとしても下の写真のようになってしまいます。

f:id:ichidaya:20201008164327j:plain

前バージョンではこれくらいが限界