本記事の概要
※Qiitaからはてなブログに引っ越しました!
本記事ではC#向け深層学習用ライブラリKelpNetを使って簡単な学習を行う方法を解説します。 学習のサンプルとしてはFNNでXORの学習を行うコードを作成し、Editor拡張上で学習を実行します。
KelpNet
KelpNetはC#向けの深層学習用ライブラリとして春条さんが作成されたものです。 ソースは全てC#で書かれているため内部の可読性が高く、かつUnityへの導入も比較的簡単にできます。
導入方法
Unity上でKelpNetを使用するためには、まずKelpNetのdllを作成を作成する必要があります。 dllの作成の仕方はこちらの記事が非常に参考になります。 作成したdllをUnityのプロジェクト上に配置することでスクリプト上からKelpNetを呼び出せるようになります。配置するdllは以下の8個です。
- KelpNet.CL.Common.dll
- KelpNet.CL.Function.dll
- KelpNet.CL.Function.Double.dll
- KelpNet.Common.dll
- KelpNet.Function.dll
- KelpNet.Function.Double.dll
- KelpNet.Tools.dll
- KelpNet.Tools.Double.dll
基本的な流れとしては
- KelpNetのプロジェクトを git clone もしくはZipで落としてきて展開
- VisualStudio等でビルドする
- 生成されたdllをAssets以下に専用ファイルを作成して配置する
という形になります。
実装
今回はUnityのエディタ拡張上でKelpNetを用いてFNNによるXORの学習を行います。 XOR(排他的論理和)とは論理演算の一種です。IT用語辞典の説明を引用すると
XORとは、論理演算の一つで、二つの命題のいずれか一方のみが真のときに真となり、両方真や両方偽のときは偽となるもの。論理回路や2進数の数値におけるXORは、二つの入力のうち片方のみが1であるときのみ出力が1となり、両方1や両方0の場合は0となる。
というものです。 このXORと同じ入出力関係を再現できるようにニューラルネットを学習させるのが今回の目的になります。
Assets/EditorにKelpNetTest.csを作成してクラス内にXORの学習を実行するメソッドを記述します。 コードは以下のようになります。
using System; using System.Linq; using UnityEngine; using UnityEditor; using KelpNet; using KelpNet.CPU; using Real = System.Single; public class KelpNetTest { // XORの学習を行うメソッド [MenuItem("KelpNet/Test/XOR")] public static void TestXOR() { // 学習エポック数 const int epochs = 10000; // 学習進行度管理用変数 float progress = 0; // 学習に用いる入力データ Real[][] trainData = { new Real[] {0,0}, new Real[] {0,1}, new Real[] {1,0}, new Real[] {1,1} }; // 学習に用いる出力の正解ラベルデータ int[][] trainLabel = { new[] {0}, new[] {1}, new[] {1}, new[] {0} }; // 層間の結合と活性化関数を積み上げてネットワークを構築する FunctionStack<Real> nn = new FunctionStack<Real>( new Linear<Real>(2,2,name:"l1 Linear"), new Sigmoid<Real>(name:"l1 Sigmoid"), new Linear<Real>(2,2,name:"l2 Linear") ); Debug.Log("学習開始"); // 学習用ループ for(int i = 0; i < epochs; i++) { for(int j = 0; j < trainData.Length; j++) { // 学習用の入力データと正解データを用いてソフトマックス交差エントロピー誤差を計算する // 計算した誤差を減らす方向にネットワークの重みを変化させる Trainer.Train(nn,new[]{trainData[j]},new[]{trainLabel[j]},new SoftmaxCrossEntropy<Real>(),new MomentumSGD<Real>()); } // 学習進行度の計算 progress = (float) i / epochs; // 学習進行度をプログレスバーに表示する EditorUtility.DisplayProgressBar("学習中", "epoch:" + i + "(" + (progress * 100).ToString("F0") + "%)",progress); } // プログレスバー消去 EditorUtility.ClearProgressBar(); Debug.Log("学習終了"); Debug.Log("テスト開始"); // 入力データに対して正しい出力ができるかテストする foreach(Real[] input in trainData) { NdArray<Real> result = nn.Predict(input)[0]; int resultIndex = Array.IndexOf(result.Data,result.Data.Max()); Debug.Log(input[0] + " xor " + input[1] + " = " + resultIndex + " " + result); } Debug.Log("テスト完了"); // 学習済みモデルを保存する ModelIO<Real>.Save(nn,"Assets/TrainedModel/samplexor.nn"); // 学習済みモデルのロードも可能 Function<Real> testnn = ModelIO<Real>.Load("Assets/TrainedModel/samplexor.nn"); } }
結果
Unityのタブから KelpNet/Test/XOR でEditor拡張を使用します。
学習を開始するとプログレスバーが表示され、学習が完了するとテスト結果がコンソール上に出力されます。
上記のコンソール出力を見ると入力が[0,0],[1,1]の時は0を、[0,1],[1,0]の時は1を出力しており、XORの規則が学習できていることが確認できました。
まとめ
今回はKelpNetを使って簡単な学習をUnityのEditor拡張上で実行してみました。 KelpNet以外のC#向け深層学習用ライブラリとしてはTorchSharpというライブラリも新しく出てきているみたいなので、今後そちらも触ってみたいと思います。