Gemini API デベロッパーコンペティションでBest use of ARCoreを受賞しました

優勝するとデロリアンがもらえるハッカソン、Gemini API デベロッパコンペティションにチームで参加しました。

note.com

そして全世界から3000プロジェクトの応募の中から、9個の賞のうちの1つ、Best use of ARCore を受賞しました。やったー🥳🥳🥳🥳。

ai.google.dev

私達の作ったものは "everies"。身の回りのものすべてと喋ることができるアプリです。動画が短くまとまっているのでぜひ見てください。

www.youtube.com

開発チームメンバーは以下:

せっかくなので、開発の裏側的なものを書こうと思います。


仲間探し

昨年 友人の音楽家 Twothと Google’s Immersive Geospatial Challengeに参加し、幸運にも受賞することができて、ハッカソン怖くない!となった私は、今回も参加してみたいと思い、仲間を募りました。長年Co-creatorとして一緒に作っているWhatever Co.のSlack雑談チャンネルへぽちっと。

Slackで仲間を募集

。。。1時間で最強の仲間が集まりました。みんなノリがいいな!
3000件も応募があるとは思ってなくて、謎の自信にあふれたセリフを吐いている当時の自分を殴りたい。


企画

最初の企画書

最初の1ヶ月くらいはオンラインであつまり、企画をワイワイ考えました。そしてクリエイティブディレクターKyosuke TaniguchiとアートディレクターTaichi Itoの提案してくれた、AR上でキャラクターと喋る案を掘り進めることになりました。

今見返すと、企画書の時点で高い精度で完成形が見えてますね。素晴らしい。


リサーチ & デベロップ

企画と並行して、アプリを作るための技術調査も進めました。
APIの整備されているWebやネイティブアプリはライバルが多そうなので、私の得意分野のUnity x ARを中心にR&Dしていきました。

UnityからGemini APIを使う部分はライブラリとして公開しています。Google Generative ModelのAPIを網羅はしていませんが、今回必要になった以下のような基本的なGemini APIとの連携に対応しました:

  • 生成のストリーム受信
  • UnityのTexture・AudioClipをMultimodal 入力として送る
  • Function Callで自動的にC#メソッドを叩く
  • C#の型定義をOpenAPIスキーマに変換して、JSONモードで受け取る

マルチモーダルが優秀なので、音声認識も画像認識もセリフ作るのも全部をLLMに投げています。音声認識も、日本語、英語、ドイツ語で話しかけましたが全部理解して返答したことに驚きました。

以下の動画は初期のプロトタイプです。オブジェクトから目が出る部分はLLMで毎秒画像を送るわけにもいかないので、TensorFlow LiteでスマホのローカルでEfficiantDetを使ったオブジェクト検出をしています。音声も当初はGoogle TTSを使っていました。

www.youtube.com

ローカルで動く軽量モデルでは認識しないオブジェクトも多々ありますが、ローカル認識していないものをタップすると、Gemini API側のマルチモーダルで画像を認識して、どんなものでもキャラクターになってくれるのがLLMのすごいところです。ローカルで動くレスポンスの早い軽量機械学習モデルと、LLMを組み合わせる実験ができたのは嬉しい成果でした。

その他の依存ライブラリとして、自作の以下3つをDogfoodingしています。

youtu.be

これによりUnity AR FoundationをUnity Editorの中で動かして、AR内でTensorFlow Liteによる画像認識ができるようになりました。Editorと実機で(処理速度以外は)ほぼ同じ挙動が確認できることで、開発のイテレーション回数が上がります。

そして今回の肝となった、個性的なキャラクターの音声は、Makoto Matsutakeが調査を進めてくれました。

色々試す中でElevenLabsが一番個性的な声を出せるということで採用になりました。最初のプロトタイプと比較すると、個性的な声になっていますね。


プロンプトエンジニアリング

未知の分野のプロンプトエンジニアリング。普段はクリエイティブディレクターのKyosuke Taniguchiが、プロンプトエンジニアリングも担当しました。Google AI Studioでプロンプトを練って、画像を送るとキャラ設定とセリフを返してくれるところまで、一行もコードを書かずに作っています。

初期のプロトタイプ

ちょうどこの頃、実装担当の私とMakoto Matsutakeが無謀なことに締切の被っている本業に忙殺されていました。このハッカソンもやりたいが仕事優先、全然終わらん〜となっているところに、Whatever CTOのSaqoosha が助っ人に来てくれました。心強すぎる!!嵐のような早さで残タスクを進めていってくれました。CTOに手伝ってもらうというチート技を使ってしまった。

Promptを本番と同じワークフローで詰めるためにWebでPrompt Editorを作ってくれました。最終的に使った3ステップの生成を通して、様々な画像でユニークなキャラクターになるようなプロンプトを調整していきました。

Prompt Editor

Geminiはレスポンス時間とAPI金額を考慮してGemini Falsh 1.5 を使っています。Gemini Proモデルより性能は劣りますが、レスポンスは早く、使用料も締め切り前で沢山テストした8月で500円程度に収まりました。
組み込んでいるプロンプトでは、王道のプロンプトエンジニアリングだけでは変化の幅が少ないと判断し、プロンプトのテキスト自体もランダムに入れ替わるという古典的も手法を組み合わせています。

この段階までは日本語でプロンプトを考えていましたが、コンペティションの応募はすべて英語が条件。英語にするときに困った…とSaori Nakakariyaにプロンプトを英語でも動作させるのを手伝ってもらいました。最終的にはプロデューサー業、提出から受賞のemailのやりとりまで、すべてをお任せしてしまった。

C#がOpenAPI Schemaになる
C#として取得できる

今回LLMとプログラムの連携を本格的に試してみて、JSONモードに可能性を感じました。LLMは自由にテキストを生成するので、自分の必要な情報をパースするのに一手間かかります。しかしJSONモードを使うと、まるで自分専用のAPIが存在するかのような手触りに変わります。


キャラクター作り

Taichi Itoのデザイン案を基に、キャラクターのモデリングBlenderで行いました。キャラクターの個性である口は柔らかさを出すために、ボーンではなく、すべてShape Keyを使って作りました。

youtu.be

編集点を少なくするため、カーブでShape Keyをつくり、スクリプトで自動的にMeshのShape Keyに変換。FBXへ書き出しています。

FBXをUnityへ読み込んだ後、Blend Shapeの全パラメーターをAnimatorでブレンドして、様々なバリエーションの顔を作りました。


テスト!

締め切り間近。テスト、バグ取り、そしてデモ動画提出へ向け、日本と台湾のWhateverチームにアプリを配りテスト動画を撮影してもらいました。お陰で素敵なデモ動画も完成。


今後について

普段のお仕事にも色々ストーリーはあるのですが、制作の過程を包み隠さず話せるのは自主プロジェクトならでは。
こんな感じで多くの人の力を借りて作っています。

せっかく受賞もしたことだし、時間を見つけて…と言っていると絶対やらないので年明けにリリースへ向けてブラッシュアップして公開したいです。

KAGAMI公演情報

Technical Artistとして参加していたKAGAMIが世界中で公演しています。情報まとめました。

www.instagram.com

asus4.hatenablog.com

Onnx RuntimeをUnityで動かす

Onnx Runtimeをネイティブプラグインとして、Unity上で動かす実験とサンプルを公開しています。

github.com

開発の動機

4年前に、TensorFlow LiteをUnityで動かす実験を初めて、 はじめは全くの趣味で始めたものが、今では海外からいただく相談の半分以上が機械学習関連になっています。

四年前に始めた実験↓ asus4.hatenablog.com

ところが、実際にシェアを見ると、研究関連ではPytorchのシェアが圧倒的。Unityの公式推論ライブラリBarracudaやTensorFlow Liteで動かすために一旦Onnxに変換するなどの事例なども増え始め、速度的にはTFLiteは非常に満足していますが、サクッとモデルを試してみたいという時に、変換するのが億劫になってきていました。公式ツールで変換しようにもOnnxやPytorchのNCHWからTFLiteのNHWCに変換するときに大量のTransposeが挟まり速度が逆に遅くなることがあるのが不満でもありました。(この辺の高速化は PINTOさんのonnx2tfなどのツールでも対応されています)

Unity SentisのOnnx対応

Unityの公式ML推論ライブラリBarracudaもOnnxフォーマットを読み込みます。今年リニューアルしてSentisという名前になりました。 unity.com

実際試したことがある方はわかるかも知れませんが、SentisではOnnxフォーマットを読み込みますが、実際の実行エンジンはUnityが独自開発しているため、対応オペレーターに結構差があります。Onnx Runtimeで動いてもSentisで動かないことがままあります。(体感的には読み込み成功の打率は半分以下な気がします。)

Sentisの前身、Barracudaでの説明ではありますが、KeijiroさんによるCEDEC公演でも、後半、結構トリッキーなことをして、Onnxモデルの非対応オペラーターをBrracuda上で対応する構造に書き換えるということをしています。

youtu.be

Sentis自体はマルチプラットフォーム対応を謳い、今後対応オペレーターの互換性も増えていくと思いますが、Onnx自体の進化も早く、今後完全なOnnx互換となることは難しいように思います。

もちろんNintendo Switch, PlaystationからWeb Playerまでを対応しなくては行けないUnityが、独自推論エンジンSentis開発を進めることは正しく思いますが、私のようにiOS,Android,PC,macOSくらいで動けば良いユーザーからすると、Onnxの互換性が高くなると嬉しいなと思っていました。

Onnx Runtimeの対応プラットフォーム

一方、Onnx Runtimeの方の進化も早く、最新のHardware Acceleration対応を見ると、

と、はじめからPC, Mobile, さらにRaspberry PiのようなEdge Deviceまでを考慮に入れたプラットフォーム対応に見えます。
Googleの開発するTensorFlow Liteが、PC上でのHardware Accelerationが未だに公式にサポートされてないことを考えると、Onnx Runtimeのマルチプラットフォーム対応は、もしUnityでそのまま動けば大きな強みになりそうです。

またMicrosoftが開発していることもありC#によるC FFIライブラリのWrapperが、はじめからほぼ全て整備されていることも魅力でした。
TensorFlow Liteのときは半分以上自分でC#FFI Wrapperを作っていたので、関心しました。

実際のサンプル

という経緯から、OnnxがUnity上で動くか試し始めたのですが、
Onnx RuntimeのC#設計が良いのかTFLiteでの経験が生きているのか、Unityで動かすのは、すんなりいきました。
現在、macOS, iOS, Androidでの動作を確認しています。

AppleMobile OneというImage Classificationが100fpsで動く例↓

Yoloxが60fps以上で動く例↓

またライブラリに含めるサンプルも4年前からアップデートして、新し目のモデルを選んだので、4年間でのモデルの精度、高速化技術の向上に驚きました。

Onnx Runtime for Unityの使い方

シンプルな事例、Image ClassificationモデルMobile Oneで説明します。

MobileOne Network

Netronでモデルの入出力をみてみるとMobileOneは224x224のRGB画像を受取り、ImageNetの1000種類の画像分類それぞれの確率を返すシンプルなモデルです。

画像を入力として受け取るクラスでやることは大体同じなので、ImageInference.csというPreprocessingをやってくれる抽象クラスを用意しました。

Preprocess

通常はImageInference内でやってくれるので、気にする必要はありませんが、概要だけ書きます。

  • UnityのWebカメラはPC上では問題ないが、スマートフォンでは回転したままなので、デバイスの向きに応じて回転を補正する。TextureSource内で自動でやってくれます。
  • モデルの入力に合わせて、画像をリサイズする。3種類のリサイズ方法を用意しているので、用途に合わせて使い分けてください。
    Aspect Mode
  • Onnxモデルの入力に合わせたTensorを作る。
    • mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]の正規化をする。
    • カメラ画像のテクスチャはNHWC(N=1)のメモリ配列なので、Onnxのメモリ配列NCHWに並べ替える。

Onnx実行

SessionOptions.Run()を実行するだけです。 いくつかInput/Output Tensorの取得方法があるのですが、生のbyte配列を受け渡すより、OrtValueを使う方法がおすすめされているようです。 こちらも通常はImageInference内でやってくれます。

// 事前にモデルから読み込んでOrtValueを作っておく
string[] inputNames;
OrtValue[] inputs;
string[] outputNames;
OrtValue[] outputs;

public void Run()
{
   // inputsで画像をTensorへいれる。
   PreProcess();

   // 実行
   session.Run(null, inputNames, inputs, outputNames, outputs);

   // outputsから値を取り出す。
   PostProcess();
}

Postprocess

MobieOne.cs内でPostProcessメソッドをoverrideしています。

protected override void PostProcess()
{
    // Output Tensorから値を読み込み
    var output = outputs[0].GetTensorDataAsSpan<float>();
    for (int i = 0; i < output.Length; i++)
    {
        labels[i].score = output[i];
    }
    // スコア順に並べる
    TopKLabels = labels.OrderByDescending(x => x.score).Take(topK);
}

以上です。C#APIがよく出来ているので、カスタマイズも色々出来そうですが、ひとまずは一番シンプルな方法を使いました。

まとめ

Onnx RuntimeをネイティブプラグインとしてUnityで動かしているプロジェクトをこちらで公開しています。 github.com

細かい開発記録はZenn Scrapへ残しています。 zenn.dev

もし需要がありそうなら時間を見つけて、Windows, Linux対応も追加したいと思います。
また少し難易度は高そうですが、Web Player対応も出来るといいなと考えています。

Unity ARFoundaitonを録画してUnity Editorで再生する方法

ARFoundationReplayというARを録画してUnity Editor上で再生するライブラリを開発中です。

GitHubリポジトリはこちら↓ github.com

ARFoundaitonReplayで出来ること

Unity Editor内で動作するAR Foundationです。ARを録画した専用動画をEditorで再生することが出来ます。私が普段参加するARプロジェクトでは、Unity Editor上でAR Foundaitonが動かないため、 #if UNITY_EDITORなどを用いて処理をまるっと分けることが思いです。しかしこの分岐が原因で実機でテストすると思わぬバグに出くわすことも多々あります。

このライブラリではUnity Editor上で録画したARをAR Foundationの上で動かすことで、そのような分岐をまるっとなくすことを目的としています。

仕組みはARを独自の映像フォーマットとして保存します。mp4は動画や音声を保存するフォーマットですが、字幕データを保存したり出来るように、実はバイナリデータも同時に保存できます。
UnityのKeijiroさん作Bibcamをベースに、タイムラインと同期する任意のバイナリを保存出来るようにしました。これは、ARCoreやARKitで行われているAR録画と似たような仕組みです。

Video Format for ARFoundaitonReplay

この動画フォーマットには6DOFのカメラ座標、認識した床や壁などの平面メッシュなどのARの再生に必要なメタデータが含まれているので、以下の動画のように、Unity Editor上で再生して、シミュレーションすることが出来ます。

どうして作った?

開発にあたりいくつかのライブラリを調査しました。

- AR Foundation Simuraiton

実はARFoundation5からは、ARFoundation内にARシュミレーション環境がつきました。 Unityで、3Dモデルで部屋を作って、その部屋の中でARを動かしているシュミレーションが出来ます。

Fig for ARFoundation Simulation

以前のUnity公式xRシミュレーションUnity Maseは一年600ドルという、中々手を出しづらい金額でしたが、こちらは無料です。AR Foundation公式という安心感もあります。

しかしVPS(ビジュアルポジショニングシステム)という屋外の自分のいる位置をGPSとカメラ画像などのセンサから推定するARが流行り始めて、私の実際の案件でもARFoundation Simulationでは対応できないケースが増え始めました。

- AR Foundation Remote 2.0

多くのAR開発者に実際に使われているソリューションとしては、AR Foundation Remote 2.0でしょうか。ほとんどの機能をサポートしていて、VPSも使えます。実際私も使っています。

かなり理想形なのですが、Unity Editorとつなげて録画が必要なので、開発者以外の人がARを録画するのが難しいという難点がありました。TestFlightで配布したアプリだけで録画できるとベストです。

- ARCore, ARKit ReplayData

ARFoundationは、Android ARCore, iOS ARKitのラッパーでもあります。そして、
iOS ARKitではReality ComposerというアプリからReplay Dataという動画ファイルを録画して、実機で再生できます。
Android ARCoreにも録画再生の仕組みがあります。更にAnrdoidでは独自の追加トラックもいれることが出来ます。

もちろんUnity製アプリでもビルドした状態で、これらの機能を使うことは出来ます。しかしこれらの機能はEditorからは使えません。Unityの良さのEditor上でアプリを動かしながら、いろんなパラメーターをいじって、開発のイテレーションを回すということができませんでした。


このような理由から、自分の理想に近かったUnity JapanのKeijiroさんの開発していたBibcamをベースに開発を始めました。

開発大変

去年の12月くらいにふと思いたち、手を動かし初めてみたものの、一歩でもUnityの内部挙動に踏み込んだ機能を作ろうとするとUnityのバグに突き当たり、開発が中断したりと大変でした…。私のライセンスではUnity内部のソースコードにアクセス出来なかったので、ただ修正を待つしかないのが辛かったです。Unreal Engineなら自分で直す余地もあるのですが。

いくつか起こった出来事を抜粋します。

  • M1 Macでフリーズする (修正済)

当初はM1 Mac上でを使うとフリーズする状態でした。AR Foundation Remoteの作者&コミュニティと私くらいしか困っていなかったけど、1年以上も進展がなかった後(AR Foundation Simulation機能を開発して気づいたのかもしれません)、修正されました。

  • UnityのVideoPlayerクラスがデグレーション (修正済)

URP14.0.2のバグ対応のためにUnityのバージョンを上げなくてはいけないけれども、アップデートしたUnityバージョンではVideo Playerがリニューアルされ、今まで動いていた動画ファイルが再生できない…という進むにも戻るにもできない状態になりました。 再現可能なミニマムプロジェクトを添付したバグレポを提出して2ヶ月修正を待ちました。(自分のターゲットにしている2022LTSにバックポートされるまでには半年待ちました。) - Unity Issue Tracker上のバグ詳細

  • XR SDKのドキュメントにない仕様

AR FoundationはUnity XR SDKというXR用のネイティブライブラリの元で動いているのですが、サンプルプログラムは動作するのに、自分のプロジェクトにサンプルプログラムをコピペすると全く動かない…という問題がありました。数日あーだこーだ悩んだ後、EditorでXR SDKを動かす場合は、package.jsonkeywordsxreditorsubsystemという文字が入っていないと認識しないという仕様でした…。XR SDKのドキュメントを見渡しても一切書いてなく、そのキーワードに言及しているのはAR Foundation Remoteの作者とNeedle Toolesの作者だけでした。package.jsonの設定項目じゃなくて検索用のkeywordsにこんな重要な設定項目をいれるなんて思いませんでした。

キーワード知ってないとこのリンクにもたどり着かないし、キーワードを知ってるということは解決済みという悲しいやつです。せめてこの記事を見つけた方に届きますように。

もし開発記録に興味があれば、Zennのスクラップに残しているのでご覧ください。 zenn.dev

まとめ

現在開発中のARFoundationReplayを紹介しました。

前回の記事で作ったARアプリでは、このライブラリを実際に使っています。別のAR案件では、Editor上では動くのに実機では動かないということが頻発することがよくありましたが、このプロジェクトではほぼその問題が起こりませんでした。実機のみで起こったの現象としてはAndroidでメモリが足りなくて落ちるくらいでした。

asus4.hatenablog.com

まだ自分が使うSubsystem部分しか作ってはいませんが、Unity Editor上で実機ARと同じデータがみれることで、ARアプリであるあるの実機で現場にテストした時に動かない…。現場でラップトップを開いてビルドし直す…。みたいなケースがほんの少しだけ減る気がします。 今後も、AR案件をやるたびにちまちま自分で使う機能を追加しようと思います。