Edited at

Unityでディープラーニングする方法調べた


概要

ARで深度推定とかするのにml-agentsだけだと足りなかったので

Unityで学習済みモデルを扱う方法を調べて試してみました。


実施内容

学習済みモデルVGG19を利用してUnity内に表示した画像の分類を行う。

キャプチャ.PNG


モデルの形式

モデル名
VGG-19

入力
224×224×3

出力
1000

データセット
ImageNet (ILSVRCA2012)


前処理


  1. 8bitで表された画像を0-1範囲に変換 = pixel / 255

  2. RGBの各値を平均{ 0.485f, 0.456f, 0.406f } 標準偏差 { 0.229f, 0.224f, 0.225f }で正規化


環境

OS
Windows10 Home

CPU
Intel(R) Core(TM) i7-7700K

Unity
2019.1.0f2(64-bit)

tensorflow
1.14.0

今回、ライブラリの導入にNuGetを利用しました。

UnityではVisualStudioのNuGetパッケージマネージャーは使えないので以下の2手法を利用します。


  1. NugetForUnity Assetの利用
    AssetStoreからNuget For Unityをインストールして利用します。

  2. 公式ドキュメント記載の方法
    公式ドキュメント 「NuGetからUnity プロジェクトにパッケージを追加する」を参照してください。

どちらの手法でもパッケージ同士の依存関係は手動で特定する必要があります。

参考:

Unity であらゆる C#(.NET) パッケージを使う(例:opencv)

 https://qiita.com/kingyo222/items/11100e8f7be396b98453


手法一覧


  1. Onnx形式で学習済みモデルを扱う


    • Onnx Runtime

    • OpenCVSharp



  2. C#から直接tensorflowを扱う


    • TensorFlowSharp



  3. 今回実施できなかった手法


    • WindowsML

    • ML. Net

    • CoreML

    • IronPython



  4. おまけ


    • ml-agents

    • The Unity Inference Engine




1. Onnx形式で学習済みモデルを扱う


概要

機械学習モデルの標準形式であるOnnx(Open Neural Network Exchange)形式を利用します。

この形式に変換することで、TensorflowやPytorch,Chainerといった

主要な深層学習ライブラリで学習したモデルを色々なライブラリで利用できるようになります。

参考:

ONNX Model Zoo(訓練済みモデルの配布場所)

 https://github.com/onnx/models


- Onnx Runtime

Onnx形式を扱う事に特化した推論エンジンです。

2018/12/04にOSS(MITライセンス)化されたこともあり、使い所は色々とありそうです。

    private InferenceSession session;

public void LoadModel (string model_name) {
string model_path = Application.dataPath + @"/MLModel/" + model_name + ".onnx";

var opitions = new SessionOptions ();
session = new InferenceSession (model_path);
}
public int Inference (Texture2D input) {
var input_nodes_name = session.InputMetadata.First().Key;
var input_nodes_dim = session.InputMetadata.First().Value.Dimensions;

// Texture2Dをモデルの入力に合った形に整形、正規化する。
var input_floats = GetFloatFromTex2DWithFlip (input);
var input_tensor = new DenseTensor<float> (input_floats, input_nodes_dim);

// OnnxRuntimeでの入力形式であるNamedOnnxValueを作成する
var input_onnx_values = new List<NamedOnnxValue> {
NamedOnnxValue.CreateFromTensor (input_nodes_name, input_tensor)
};

// 推論を実行
var results = session.Run (input_onnx_values);
var scores = results.First().AsTensor<float>().ToArray ();

return GetBestScorePos(scores);
}


  • 利点


    • モデルの扱いが単純

    • 前処理など数値の扱いが容易



  • 欠点


    • 依存関係のあるパッケージの特定に時間がかかる

    • モデルの読み込みが不安定(環境依存?)



総評:

入力・モデルの扱い共に非常に簡単です。

モデルの読み込みが最初の数秒不安定ですが、それ以降は特に問題なく実行できます。

参考:

C#でONNXファイルを利用して手書き数字を認識する方法:

 https://kagasu.hatenablog.com/entry/2019/05/21/162445

onnx runtime 公式 github:

 https://github.com/microsoft/onnxruntime


- OpenCVSharp

画像処理ライブラリとして有名ですが、Onnxを読み込む機能がサポートされているので使ってみました。

    private Net model;

public void LoadModel (string model_name) {
string model_path = Application.dataPath + @"/MLModel/" + model_name + ".onnx";
model = Net.ReadNetFromONNX (model_path);
}
public int Inference (Texture2D input) {
// Texture2Dをモデルの入力に合った形に整形する
Mat img = FixTexture2Input (input);

// OpenCVSharpでの入力形式であるblobを作成、同時に正規化を行う。
Scalar mean = new Scalar (0.485f, 0.456f, 0.406f);
var blob = CvDnn.BlobFromImage (img, 1.0 / 255.0 / 0.225f,
new Size (input.width, input.height),
mean, swapRB : true, crop : false);
model.SetInput (blob);

// 推論を実行
Mat scores = model.Forward ();

return GetBestScorePos(scores);
}


  • 利点


    • モデルの扱いが単純

    • Nuget For Unityで簡単にプラグインを導入できる



  • 欠点


    • 画像をMat形式で扱うため、指定の前処理を行えないことがある



総評:

読み込みが早く、動作も安定しています。

画像関係のモデルを扱うならばこれだけで十分そうです。

参考:

3Dの姿勢推定のOnnxのモデルでUnityちゃんを動かしてみた

 https://qiita.com/yukihiko_a/items/386e3a86a5e523757707


2. Unityから直接tensorflowを扱う


TensorFlowSharp

C#から直接Tensorflowを利用するためのライブラリです。

といっても学習済みモデルの利用が主な機能なので実質推論環境みたいなものです。


private TFGraph model;
public void LoadModel(string model_name)
{
string model_path = Application.dataPath + @"/MLModel/" + model_name + ".pb";

var model_input = File.ReadAllBytes(model_path);
model = new TFGraph();
model.Import(model_input);

loaded = true;
}
private bool loaded = false;
public bool GetLoaded() { return loaded; }

public int Inference(Texture2D input)
{
var session = new TFSession(model);

// Texture2Dをモデルの入力に合った形に整形、正規化する。
var float_values = GetFloatFromTex2DWithFlip(input);

// TensorFlowSharpでの入力形式であるTFTensorを作成する
var shape = new TFShape(1, input.width, input.height, 3);
var input_tensor = TFTensor.FromBuffer(shape, float_values, 0, float_values.Length);

// データの入力・推論
// input_2:0およびoutput_node0:0はpbファイル作成時につけた入力ノードと出力ノードの名前。
var runner = session.GetRunner();
runner.AddInput(model["input"][0], input_tensor);
runner.Fetch(model["content_vgg/prob"][0]);

// 推論を実行
var output = runner.Run();
var scores = ((float[][])output[0].GetValue(true))[0];

return GetBestScorePos(scores);
}


  • 利点


    • TensorFlowでサポートされているモデルを全て実行できる(onnxでは一部のパーツが非対応)

    • 参考になるドキュメントが多い

    • 前処理など数値の扱いが容易



  • 欠点


    • 推論が非常に遅い(OnnxRuntime 0.2[sec]に対し16.8[sec])

    • Python・TensorFlowが使えることが前提となる

    • モデルの保存・読み込み方法が複雑



総評:

バージョン変更によるAPIの変化やpbファイル(TensorFlowのモデル出力形式)の扱いづらさに加え、

推論速度も今回試した手法の中で圧倒的に遅いです。

Unityでディープラーニングをしたいだけなら他を選んだ方がよいと思います。

TensorFlowを使い慣れていて、複雑なモデルを利用したい場合には使えるかもしれません。

参考:

C#でTensorFlowのCNNを動かす。

 https://qiita.com/Tama_maru/items/6e50edfd8f8dea184d18

Unityで学習済みのVGG16による1000クラスの画像識別

 https://qiita.com/dipmizu/items/e46591bd4ab03b02ad38


3. 今回実施できなかった手法

自分の能力不足や環境の問題で扱えなかった手法です。


- WindowsML

Windows 10に搭載されている機械学習のための実行環境です。

Onnx形式をUWP(Universal Windows Platform)アプリで使うのに最適化されています。


  • 利点


    • パッケージの導入を必要としない

    • 参考となるドキュメントがやや多い



  • 欠点


    • テストの度にビルドしなくてはならない

    • 非同期処理が基本となっており、扱いにある程度知識が必要



総評:

一応試してはみましたが、UWPアプリが良くわからなかったので一旦保留にしました。

HoloLens界隈でよく使われているようです。

非同期処理が分かるようになったらまた挑戦します。

参考:

公式GitHub

 https://github.com/Microsoft/Windows-Machine-Learning/tree/master

HoloLensでWindowsMLを試してみる(Unity利用編)

 http://akihiro-document.azurewebsites.net/post/hololens_windowsmachinelearningunity/


- ML. Net

C#上で機械学習を行うためのフレームワークです。

モデル構築・訓練まで行えるので、Unityでの入力で直接学習を進めたりできそうです。

今回はランタイムエラーがどうしても解決できなかったため未実施です。

ネット上のドキュメントも少ないのでしばらくは保留にすると思います。

参考:

公式ドキュメント・チュートリアル

 https://docs.microsoft.com/ja-jp/dotnet/machine-learning/


- CoreML

WindowsMLを紹介したのでこちらも一応。

iOS向けの推論環境で、こちらはOnnxを専用形式に変換してから利用します。

今回はメイン環境がWindowsだったので未実施です。

一応実施例が一つだけありましたが、中でswiftを使っているみたいなので

素のUnityでCoreMLが使えるのかどうかは不明です。

(少なくともNugetにはCoreMLはありませんでした)

参考:

UnityVision-iOS

 https://github.com/possiblecee/UnityVision-iOS


- IronPython

Unity上でpythonのコードを扱えるようになるライブラリです。

python3.x系がサポートされておらず、自分の環境ではtensorflowが動かないので諦めました。

macやLinuxを使っていて、どうしてもPythonしか書きたくない場合には使えるかもしれません。

(Unityでそんな状況が起こるのかは知りませんが)

参考:

公式ページ

 https://ironpython.net


4. おまけ


- ML-Agents Toolkit

Unity Technorogyが公式に提供している機械学習用アセットです。

機械学習用アセットとは言うものの、サポートしている機能は強化学習だけなので

画像や音声、文章を扱うモデルには適用できません。

大変面白い機能ですが、今回の目的とは合わないのでおまけ扱いに。

参考:

公式ドキュメント

ML-Agents Installation

 https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Installation.md

Basic Guide

 https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Basic-Guide.md


- The Unity Inference Engine(Barracuda)

ml-agents v0.7から導入されたUnity Labs謹製推論エンジンです。

Unityに対応する全てのプラットフォームで推論できる事を目的に開発されているようですが、

現段階ではml-agentsを経由しないと利用できない様子です。

(多分そんなことはないのだけれど、コードを読んでもよくわかりませんでした)

将来的には独立したUnityパッケージとして

他の深層学習アプリケーションにも対応する予定らしいので、

リリースされたらまた調べてみようと思います。

参考:

公式ブログの該当記事

 https://blogs.unity3d.com/jp/2019/03/01/unity-ml-agents-toolkit-v0-7-a-leap-towards-cross-platform-inference/


おわりに

あまり時間をかけすぎるのも効率が悪いので一旦打ち切りましたが、

WindowsMLやCoreMLあたりはベースになる言語を勉強した上で再挑戦したいと思います。


今回の内容(gihubにあげました)

プロジェクトファイル

 https://github.com/highnoRQ/Unity_ML_Test

Assets/MLModel下に以下のモデルファイルを置いてください

VGG19 tensorflow pbファイル

 https://drive.google.com/file/d/10XFhmr43zIZD4dPKP55hUg9YxKUZ3cBV/view?usp=sharing

VGG19 onnxファイル

 https://github.com/onnx/models/tree/master/vision/classification/vgg

また、ビルドしてテストする場合。

ビルド済みフォルダのDataフォルダにMLModelフォルダごと移してください。