前回、WindowsでOnnxRuntimeで探索を動かせるようになったので、Androidでも動くようにした。
後で書くが、Unity Barracudaでもコルーチンを使うことでメインスレッドで非同期処理ができるようになったので、OnnxRuntimeは必須ではなくなった。
OnnxRuntimeをAndroidで動かすのに苦労したので、方法を残しておく。
Android版OnnxRuntimeインストール
NuGetForUnityでインストールするMicrosoft.ML.OnnxRuntime.Managedの他に、Android版OnnxRuntimeのバイナリが必要になる。
NuGetでMicrosoft.ML.OnnxRuntimeをインストールすると、Assets/Packeges/Microsoft.ML.OnnxRuntime.1.10.0の中にmicrosoft.ml.onnxruntime.1.10.0.nupkgがあるので、zipで解凍し、runtimes/android/native/にある「onnxruntime.aar」をAssets/Pluginsにコピーする。
Unityエディタで、「onnxruntime.aar」を選択し、インスペクタで、「Android」にチェックを入れる。
モデルのダウンロード
モデルファイル(.onnx)は、Assets/StreamingAssetsに格納する。
OnnxRuntimeは、モデルをファイルパスか、byte配列で受け取る必要があるが、Androidでは、StreamingAssetsにあるファイルは、jarで圧縮されるため、ファイルパスに指定できない。
Unityのドキュメントに記載のある通り、UnityWebRequestを使って読み込む必要がある。
ストリーミングアセット - Unity マニュアル
読み込み処理は、公式のサンプルにあるようにコルーチンを使用して読み込む。
Unity - Scripting API: Networking.UnityWebRequest.Get
void Start() { StartCoroutine(InitSearcher()); } IEnumerator InitSearcher() { using (UnityWebRequest webRequest = UnityWebRequest.Get(System.IO.Path.Combine(Application.streamingAssetsPath, modelFileName))) { // Request and wait for the desired page. yield return webRequest.SendWebRequest(); byte[] model = webRequest.downloadHandler.data; _searcher = new UctSearcher(16, model); } }
ここで、StartCoroutineを使うとメインスレッドで非同期処理ができることに気付いたので、Unity Barracudaも非同期処理で使えることが分かったが、ひとまずOnnxRuntimeで続行する。
実機でテスト
Androidの実機(Pixcel5)でテストしてみた。
探索ノード64だと、1手3秒近くかかる。
探索ノード16に減らしても、2秒近くかかる。
探索のみのテストだと1秒以内になる想定なので、推論以外に遅くなる原因がありそうである。
Task.Runでマルチスレッドで実行していたのを疑い、上記で使い方の分かったコルーチンに変更してみた。
1プレイアウトごとに、yield returnを行いUIが止まらないようにした。
1秒くらいで実行できるようになった。
Unityは毎フレームごとゲームオブジェクトの処理がされるので、マルチスレッドを使うとスレッドのスイッチが頻発するので、Unityではマルチスレッドは使わない方がよいかもしれない。
全てメインスレッドで処理されるようになったので、Unity Barracudaで実行できるようになった。
Unity Barracudaでも体感速度はほぼ変わらなかった。
まとめ
OnnxRuntimeをAndoroidで動かすことができた。
試したのはCPUのみのため、NNAPI版も試してみたい。
Unity BarracudaではGPUにするとかえって遅くなったが、OnnxRuntimeのNNAPI版で速くなるか確認したい。
ただし、OnnxRuntimeが対応しているのはARM64のみのため、対応デバイスを増やすにはUnity Barracudaを使うのが無難そうだ。
実機テストしていて1手2秒だともっさり感を感じたが、ぴよ将棋でも確認したらLv8でも1手2秒以上かかっていた。
もっさり感を感じないのは、効果音と駒の移動のアニメーションがあるためだと気付いた。
駒のアニメーションがあるとその間思考できるので、待たされている時間を感じにくくなる効果がある。
自分のアプリでもぜひ駒のアニメーションは実装したい。