5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Principal Component Analysis SOPを使ったバリアント作成

5
Posted at

これはHoudiniApprenticeAdventCalenderの2025/12/15の記事です。

実行環境と注意事項

Windows11 Houdini 21.0.512 Educational License
ベータ扱いの機能を使っていませんので注意事項はありません。

自己紹介と対象読者

こんにちは。私は元グラフィックス・エンジニアで、現在は大学教員をしています。昨年のアドカレではAPEXについて書きました。今年はHoudini19あたりから着々と整備されつつある機械学習系SOPの一つであるPrincipalComponentAnalysisSOPについて書きます。

学生に主成分分析を解説するために作ったサンプルを解説していくことになりますので、残念ながら実用的価値や芸術的価値は全くない記事だと思います。ほかの機械学習系SOPと合わせて主成分分析もざっくりと理解してワークフロー構築に役立てたい、といった方にピンポイントに刺さることを期待して記事を書きます。

記事を書いた経緯と動機

Houdini21でAPEX上にモジュラーリグであるAutoRigBuilderが整備されましたね。大学でさつき先生のレクチャーをしてもらったこともあり、またAPEXについて書こうと思っていたのですが、今年はすでに数名の方がアドカレにAPEX関係の記事を書いておられました。確か、去年はAPEXについて書いたのは私だけだったので人気急上昇ですね。ついにアニメーターが大挙してHoudini勢に加わる日が来るのでしょうか?期待が膨らみます。

さて、後出しでAPEX記事を書くのは気が引けますので代わりに何を書こうかと考えた時に、さつき先生がレクチャーでおっしゃっていたことを思い出しました。学生のリアルタイム・クロース・シミュレーションに関する卒業研究にアドバイスをもらっていた時に「長いスカートの裾や着物の振り袖などの変形はVellumなどのシミュレーションをするしかない。しかし、比較的身体に密着した衣服のシワや歪みなどメッシュの変形がスケルトンポーズと1対1対応しているような場合は機械学習を用いるのが一般的になっている。」というお話がありました。

image.png

Houdiniでデータセットを作って、機械学習をして、推論モデルを作るところまでやる。出来た推論モデルをゲームエンジンに読み込んでリアルタイム推論ということだと思います。勉強不足で追いついていないのですが、Houdini19あたりから機械学習系のSOPが続々と追加されていることは知っていました。複数の学生がそのような機能を使えそうな卒業研究を考えていることもあり、自分の勉強も兼ねて主成分分析を扱うPrincipalComponentAnalysisSOPについて書くことにしました。

Houdiniではお約束ですがSOPのドキュメントを読んでもサッパリ理解することが出来なかったので、あまりこのSOPを使った公式サンプルは見当たらないんですが、Vellumシミュレーションの振動ノイズを除去するサンプルを解析することで理解を深めました。

余談になりますが、物理シミュレーション界隈では計算手法が従来のXPBDからVBDに移行しつつあるとさつき先生がおっしゃってました。どなたか記事を書いてくださると良いのですが...

機械学習における次元圧縮と主成分分析

例えば、猫と犬を見分けるニューラルネットワークを機械学習するとします。まずは入力となる画像データ(犬か猫が映っている)と、出力となる正解ラベルデータ(犬なのか、猫なのか)のセットを大量に用意します。ここで、例えば縦横256ピクセルのグレースケール画像は256x256=65,536次元空間上のある1点と考えます。入力画像の解像度がすべて同じであるという前提を置けば、すべての入力画像をこの空間の点として扱う事ができます。それらの平均や偏差といった統計量を計算する事で、点群がどのような形で空間に分散しているかがわかります。その点群を猫グループと犬グループに分ける境界線を引くことができれば、点の位置によって犬か猫かを判別できます。この境界線を回帰分析と呼ばれる計算を繰り返して最適化していくのが、猫と犬を見分けるニューラルネットワークの機械学習です。

さて、そうなるとこのニューラルネットの入力は65,536次元のベクトルということになります。こんなに低い解像度の画像でもすでに計算量がすごいことになりますし、多くのピクセルは犬や猫とは関係がないノイズですので精度もあまり上がらないでしょう。そこで、計算時間の短縮と精度の向上を目的として入力ベクトルの次元圧縮が行われます。その際に用いられる統計手法の代表格が主成分分析です。主成分分析の厳密な理解には分散・共分散といった統計量や、固有ベクトル・固有値といった線形代数の概念を理解しておく必要がありますが、それらは素晴らしい動画や記事がたくさんあるのでそちらを参照してください。

今回に限っては主成分分析とは超高次元に散在する点群を、比較的低次元な空間にマッピングする手法であると理解してもらってよいと思います。主成分分析の結果、点群の平均位置を原点とする新しい座標系が得られるのですが、都合が良いことにこの座標系の座標軸は点群の分散が大きい順、つまり、画像の特徴をとらえた重要度の高いものから順に並んでいるのです。そこで、ほとんどノイズと言えるような下位の座標軸はバッサリと捨てて上位何%かの座標軸だけを使い、元の点群の形をだいたい表現できる程度に座標軸の数を減らしてしまいます。この次元圧縮された空間上の点をニューラルネットの入力とすることで計算量の削減と精度の向上が期待できます。

主成分分析を使ってHoudiniでやってみたこと

今回もう一つ重要なのは不完全であっても次元圧縮された低次元空間の点を、もとの高次元空間へ逆マッピングできるという点です。例えばMegaScanなどから岩の3Dモデルを複数ダウンロードしてきたとします。前章で、画像のピクセル値を並べた超高次元ベクトルを主成分分析で次元圧縮したのと同様に、3Dモデルの頂点を並べた超高次元ベクトルを主成分分析にかけて、例えば、5次元に圧縮できたとします。すると、5つのパラメーターを調整するだけで岩のバリアントを大量に作り出すことができるはずです。

先述の通り、機械学習をHoudiniのワークフローに組み込むためのSOPがHoudini19以降たくさん追加されています。学習データを吟味したり、どのくらい次元圧縮するかを調整したり、望み通りのバリアントを生成するSOPネットワークはアーティスト自身が作れるはずですし、作ったSOPネットワークは樹木や地形にも適用可能なはずです。これはHoudiniとは独立した生成AIで3Dモデルを作ってインポートするといったワークフローよりも遥かに効率が良さそうですし、アーティストの創意工夫が細かいところまで行き届くAI活用と言えそうです。

学習データの用意

そんな時代を見据えて主成分分析を理解するためのサンプルを学生向けに作ってみました。まずはMegaScanデータの代わりに尖った赤い三角石と、青い丸石のバリエーションを10個づつ作ります。

image.png

image.png

同じSphereから変形しているのでポイント数はすべて1442個に揃えられているというのが重要です。そして一つのポイントにつきX,Y,Z,R,G,Bの6つのデータがありますので、入力ベクトルは1442x6=8652次元ということになります。

image.png

先述の通り入力ベクトルの次元数(頂点数、ピクセル数、ボクセル数)はすべての学習データで同じである必要があります。実際にMegaScanデータなどを使う場合はTopologyTransferを使って頂点数を揃えたり、一旦ヴォリュームに変換するなどの工夫が必要です。

主成分分析

ここから20個のジオメトリを主成分分析にかけて8652次元のベクトルを6次元空間にマッピングしていきます。二つのグループを分ける大まかな特徴をコトバで表現するとしたら「赤くて三角」と「青くて丸」です。先述の通り、主成分分析の結果、最初に抽出される座標軸はこの最大の特徴量を表現している(最も分散が大きい)はずです。そして「ゴツゴツした」とか「波打った」といったディテールを表現する5つの座標軸がそれに続いて抽出されると予想できます。PrincipalComponentAnarysisSop(以下PCASop)を使って確かめます。

まず、20個の入力ジオメトリをすべてマージした状態にします。
image.png
image.png

それをPCASopの第一入力につなぎます。

image.png

SOPパラメーターは以下のとおりにします。

  • DataType & Attributes : ポイントのPとCdを主成分分析にかける。
  • Mode:Analyzeにしておくと第一入力を主成分分析します
  • PointsPerSample : ジオメトリの頂点数
  • NumberOfComponents : 抽出する座標軸の数。なんとなく6個

image.png

するとこのようなジオメトリが出力されます。プリミティブは無くなっておにぎりのような形に分散した白の点と、原点付近に固まった黒い点だけになっているように見えます。これらは一体何でしょうか?

image.png

スプレッドシートで確認すると、ポイント番号は0始まりで10093まであるので全部で10094個です。7で割ってやると10094÷7=1442と入力したジオメトリの頂点数が出てきます。なるほど、どうやら入力ジオメトリのポイントと同数のポイントが7セット並んでいるようです。そのセット毎にcomponentとevalというアトリビュートにユニークな値がセットされています。最後の頂点までスクロールしてcomponent番号が変わるところだけをすべてリストしてみます。ポイント番号とそれに対応するcomponentとevalの値の変化に注目してください。

image.png

まず、component番号0のポイントグループは入力されたすべてのジオメトリのPとCdの平均です。これが圧縮された空間の原点に対応します。 先ほど白く見えていたのがcomponent番号0のポイントグループですが、ポイントのサイズを拡大して背景を黒くすると確かに色がついているのがわかりますね。

image.png

component番号1から6までのポイントグループは圧縮された空間の座標軸(次元圧縮の影響を受けない固有ベクトル)を表現しています。 今回は6次元空間に圧縮するので、座標軸も6個出てくるわけですね。component番号に対応するevalの値は3402, 179, 168, 164....と急激に小さくなり最後の方はほとんど変化がなくなります。このevalは座標軸の重要度と考えてよいと思います。(evalはおそらく固有値eigen valueの略) 今回の例では最初の二つの座標軸でほとんどの入力ジオメトリを指定できるという事ですね。人が見て何かがわかるものではないと思いますが視覚化してみたところ、なんとなく上位の座標軸が視覚化されたものの方が特徴のある形をしているように見えますね。面白いものです。
image.png

バリアントの元となる素体ジオメトリを作成

さて、6次元に圧縮された空間の原点(component0)と座標軸(component1-6)が手に入りました。あとはこの空間内の一点を元の高次元空間に逆マッピングしてやればバリアントを作り出せます。

まずは原点となるジオメトリを作っておきましょう。このジオメトリはすべての特徴量が0、逆に言うとどのような特徴量も自在に追加していける、無垢の素体ジオメトリという事ができます。先述の通り、すべての学習データはsphereから作成していますのでsphereのポイントをcomponent0のポイントで上書きしてやればよいことになります。結果を見てみると、確かに角がとれてつるっとしてますよね。(deleteはcomponent0以外の点を消していますがcomponent0は常に先頭なのでやらなくても良いです。)

image.png

素体ジオメトリを次元圧縮された空間にマッピング

image.png

先ほどは主成分分析をするためにPCASopのモードをAnalyzeにして利用しましたが、今度はProjectモードにして次元圧縮された空間に素体ジオメトリをマッピングします。主成分分析のワークフローではこのようにモードを切り替えて複数回PCASopをつなぐことになります。少しわかりにくいのでそのうちプリセットが出るかもしれませんね。

image.png

モードがAnalyzeではないときに出てくるIncludeMeanWeightフラグは必ず外してください。そうしないとcomponent0に対してもウェイトを作ってしまいます。

素体ジオメトリは次元圧縮された空間の原点にいるので、すべての座標値は0になっているはずです。ジオメトリスプレッドシートを見て確認してみます。6個のポイントにweightアトリビュートが付いていて、値はすべて0になっています。

image.png

低次元空間でパラメーター調整

次のWrangleでこのweight値を調整しています。これは次元圧縮された空間の6つの座標値を調整して素体ジオメトリを原点から移動させる事に相当します。この新しい点がバリアントになるわけです。ここはアーティスティックデシジョンなのでweight値の範囲に特に制限はないと思います。私は-10~10にしました。

image.png

もとの高次元空間に逆マッピング

低次元空間で作ったバリアントを元の高次元空間に逆マッピングしてやります。

image.png

今度はPCASopのモードをReconstructにして、第1入力に先ほどの低次元空間のバリアント、第2入力に主成分分析の結果を渡します。
image.png

くどいですが、モードがAnalyzeではないときに出てくるIncludeMeanWeightフラグは必ず外してください。そうしないとcomponent0に対してもウェイトを作ってしまいます。

出力をジオメトリスプレッドシートで確認するとcomponentやevalはなくなって、単にCdアトリビュートを持つポイントが1442個出てきています。よさそうですね。

image.png

ポイントだけでは寂しいので、次のWrangleは素体ジオメトリのポイントを新しく得られたポイントで上書きしてプリミティブとして見られるようにしています。
image.png

バリアント調整

後は先ほどWrangleで調整できるようにしたweightをいじってバリアントを実際にモデリングして行きます。

長めの動画へのリンク

Animation2.gif

まとめ

PCASopを用いて入力ジオメトリと似たような特徴を持ったジオメトリを大量に生成するSOPネットワークを作りました。この程度ではブレンドシェイプと何が違うんかいな?という感じですが、どんな対象であれ入力ジオメトリのポイント数が合っていればこのSOPネットワークに入力できるというのが面白いところだと思います。

今後このような機械学習系のSOPがますます充実していって、小規模な生成AIモデルならSOPネットワークとして簡単に作れるようになるのかもしれません。これが、少なくとも私には、正しいAIの活用方法な気がします。そのようなことを考えているアーティストに、なにがしか役に立つ記事になっていれば良いなと思います。

ではメリークリスマスです。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?