はじめに
今回はUnity公式のニューラルネットワーク推論ライブラリであるBarracuda
を触ってみるという記事になります。
ただ最初に言っておくと機械学習について私は生まれたばかりの赤子並みの知識しかないので、間違ったことも多く含んでいる可能性があるのであしからず。
概要
Barracuda
はクロスプラットフォームで動作可能(ビルドすることのできるプラットフォームであればいける)な軽量ニューラルネットワーク推論ライブラリです。
The Barracuda package is a lightweight cross-platform neural network inference library for Unity.
Barracuda can run neural networks on both the GPU and CPU. For details, see Supported platforms.
Introduction to Barracuda | Barracuda | 3.0.0
またCPU
だけでなくGPU
を利用した動作も可能だそう。(プラットフォームによる規制あり)
Barracuda supports the following platforms:
CPU inference: all Unity platforms are supported.
GPU inference: all Unity platforms are supported except:
OpenGL ES on Android/iOS: use Vulkan/Metal.
OpenGL Core on Mac: use Metal.
WebGL: use CPU inference.
Supported platforms | Barracuda | 3.0.0
Barracuda
を利用するにあたって、以下のステップを踏みます。
ONNX
ファイルをPytorch
,TensorFlow
やKeras
から出力する.onnx
をプロジェクトにインポート- アセットからモデルを読み込む
- 推論エンジン(
Worker
)を作成 - モデルを実行する
- 結果を取得する
また現在(2021/4/13)でのBarracuda
の最新のバージョンがv3.0.0
で、Unity2019.4以上で利用可能になっています。
環境
Unity 2020.3.29f1
Barracuda v3.0.0
インストール
PackageManager
のGit
経由(それかmanifest.json
)でcom.unity.barracuda
と打ち込めばインストールできます。


onnxを用意する
まず.onnx
を用意するところからですが、ネットに転がっていた手書き文字認識のONNXモデル(mnist-8.onnx
)を利用させていただきます。
github.com
こちらをUnityのAsset
以下の好きなところにインポートすればOKです。

コードからモデルを読み込む
NNModel
をインスペクターから読み込み、ランタイムで利用する際にModel
型に変換を行う必要があります。
[SerializeField] private NNModel model; private void Start() { // 利用する際はrun-time model(Model型)に変換する Model runtimeModel = ModelLoader.Load(model); }
推論エンジン(Worker)を構築する
Worker
はモデルを実行可能なタスクに分解し、CPU
もしくはGPU
にスケジュールをします。
A Worker breaks down the model into executable tasks and schedules them on the GPU or CPU.
Introduction to Barracuda | Barracuda | 3.0.0
private void Start() { // 利用する際はrun-time model(Model型)に変換する Model runtimeModel = ModelLoader.Load(model); // Workerを作成する IWorker worker = WorkerFactory.CreateWorker(runtimeModel); // GPU worker = WorkerFactory.CreateWorker(WorkerFactory.Type.ComputePrecompiled, runtimeModel); worker = WorkerFactory.CreateWorker(WorkerFactory.Type.Compute, runtimeModel); // slow - GPU path worker = WorkerFactory.CreateWorker(WorkerFactory.Type.ComputeRef, runtimeModel); // CPU worker = WorkerFactory.CreateWorker(WorkerFactory.Type.CSharpBurst, runtimeModel); worker = WorkerFactory.CreateWorker(WorkerFactory.Type.CSharp, runtimeModel); // very slow - CPU path worker = WorkerFactory.CreateWorker(WorkerFactory.Type.CSharpRef, runtimeModel); }
モデルの実行
モデルの読み込みとWorker
の作成ができたら、モデルの実行をすることができます。
また入力する画像データ(Mnist
は28x28のグレースケール)に対応したTensor
を生成します。
// Mnistは28x28のグレースケールな画像なので、1x28x28x1のTensorを用意 Tensor input = new Tensor(n: 1, h: 28, w: 28, c: 1);
Working with data | Barracuda | 3.0.0
生成したTensor
にデータを入れなければいけないのですが、こちらは後でサンプルを用意しておきます。
// 以下のように値を代入していく input[0, 10, 12, 0] = 0.4f;
ちなみにonnx
の入出力のテンソルのbatch
, height
, width
, channels
はインスペクターより確認できたりします。

推論を開始するのは以下のコードを書くだけです。
worker.Execute(input);
今までの処理のサンプルは以下の通り。
// 利用する際はrun-time model(Model型)に変換する Model runtimeModel = ModelLoader.Load(model); // Workerを作成する IWorker worker = WorkerFactory.CreateWorker(runtimeModel); // Mnistは28x28のグレースケールな画像なので、1x28x28x1のTensorを用意 // inputに情報を書き込む処理を書く必要あり Tensor input = new Tensor(n: 1, h: 28, w: 28, c: 1); // 推論を実行する worker.Execute(input);
出力を取得する
出力を取得するにはworker.PeekOutput()
を使います。
// 利用する際はrun-time model(Model型)に変換する Model runtimeModel = ModelLoader.Load(model); // Workerを作成する IWorker worker = WorkerFactory.CreateWorker(runtimeModel); // Mnistは28x28のグレースケールな画像、画像を1x28x28x1のTensorに変換する // inputに情報を書き込む処理を書く必要あり Tensor input = new Tensor(n: 1, h: 28, w: 28, c: 1); // 推論を実行する worker.Execute(input); // 出力を取得する Tensor output = worker.PeekOutput(); // 結果を出力する Mnistは「0」~「9」の確率が出力されます。 for (var i = 0; i < output.channels; i++) { Debug.Log($"[{i}] : {output[0,0,0,1]}"); } // 使い終わったらお片付け input.Dispose(); worker.Dispose();
コメントにも記載しましたが、Mnist
は0~9
までの確率が出力されます。
※ softmax
関数を通すと、全体を1としたときの0 ~ 1
の確率の値になります。
/// <summary> /// SoftMax関数 /// </summary> public static IEnumerable<float> SoftMax(this IEnumerable<float> source) { var exp = source.Select(Mathf.Exp).ToArray(); var sum = exp.Sum(); return exp.Select(x => x / sum); }

手書きできるようにする
手書きをして、それを当てられるようにコードを追記しました。
ただブログにベタッと貼ると長くなってしまうので、Github
に上げておきましたので気になる方は見てみてください。
github.com
Unity公式のニューラルネットワーク推論ライブラリBarracudaで、手書き文字認識(Mnist利用)してみました
— はなちる@ゲーム制作 (@hanaaaaaachiru) March 25, 2022
毎フレーム処理してもFPS出てるし、APIが分かりやすいしで良き pic.twitter.com/HBpAaocPUe