この記事は公開から2年以上経過しています。
過去の記事「C#と機械学習でコロナ感染の今後を予測してみる」ではML.NETを用いた機械学習を紹介しましたが、今回はディープラーニング入門の題材としてお馴染みのXORゲート
の実装を、Python実行環境に依存しない.NETのオープンソース機械学習ライブラリTorchSharp
で行う方法について紹介します。
この手の題材ではMNISTが良く利用されますが、多層パーセプトロンによる非線形分類でXORを実現するサンプルはシンプルで原理を理解しやすいため、初学にもオススメです。
ニューラルネットワーク構成とデータ
今回作成するニューラルネットワークと教師データ以下のとおりです。
入力層のニューロンが2個、中間層のニューロンが2個、活性化関数にシグモイド、出力層のニューロンが1個で損失関数に平均二乗誤差(MSE)、最適化アルゴリズムに確率的勾配降下法(SGD)を使用します。
ニューラルネットワーク:
教師データ:
xa | xb | t |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
サンプルソースコード(.NET 6/C#)
NuGetでTorchSharpのライブラリ本体TorchSharp
と、CUDA用の
TorchSharp-cuda-*
、またはCPU用のTorchSharp-cpu
のLibTorchライブラリのインストールが必要です。
*
は、お使いのOSプラットフォーム名です。
TorchSharpTest220910.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TorchSharp" Version="0.97.3" />
<PackageReference Include="TorchSharp-cuda-linux" Version="0.97.3" />
</ItemGroup>
</Project>
NVIDIA GPU環境ではCUDAを利用可能ですが、本サンプルソースはCPUで計算しています。
Program.cs
using TorchSharp;
using static TorchSharp.torch;
using static TorchSharp.torch.nn;
using static TorchSharp.torch.nn.functional;
// ウエイトとバイアスの乱数シードを固定
torch.random.manual_seed(1);
// 例題データ(xa, xb)
var trainData = new float[,]
{
{0, 0},
{1, 0},
{0, 1},
{1, 1}
};
// 正解ラベル(t)
var trainLabel = new float[,]
{
{0},
{1},
{1},
{0}
};
// ニューラルネットワークを作成
var nn = Sequential(
// 線形変換1
Linear(2, 2),
// 非線形変換
Sigmoid(),
// 線形変換2
Linear(2, 1)
);
// トレーニングモードに設定
nn.train();
// 入力データと教師データのテンソルを作成
var x = tensor(trainData);
var y = tensor(trainLabel);
// 学習回数
const int epochs = 10000;
// 学習レート
const double lr = 0.1;
// 損失関数(MSE)
var criterion = mse_loss(Reduction.Sum);
// 最適化アルゴリズム(SGD)
var optimizer = optim.SGD(nn.parameters(), lr);
// トレーニング
for (var epoch = 1; epoch <= epochs; ++epoch)
{
// 予測値を計算
var eval = nn.forward(x);
// 損失を計算
var loss = criterion(eval, y);
// 勾配をゼロに設定
optimizer.zero_grad();
// 勾配を計算
loss.backward();
// パラメーター更新
optimizer.step();
if (epoch % 100 == 0)
Console.WriteLine($"Epoch:{epoch} Loss:{loss.ToSingle()}");
}
// モデルの評価モードをオン
nn.eval();
// トレーニング済モデルで予測を実施
// 0 ⊻ 0
nn.forward(torch.tensor(new float[] { 0, 0 })).print();
// 1 ⊻ 0
nn.forward(torch.tensor(new float[] { 1, 0 })).print();
// 0 ⊻ 1
nn.forward(torch.tensor(new float[] { 0, 1 })).print();
// 1 ⊻ 1
nn.forward(torch.tensor(new float[] { 1, 1 })).print();
プログラム実行結果
プログラムを実行するとモデルのトレーニング状況と、その学習済モデルを使ってXOR演算を実行した結果を表示します。
今回はウエイトとバイアスの初期値を固定していますが、ランダムな場合でも2000回弱程度で学習が完了しています。
学習状況:
Epoch 100 Loss 1.0004306
Epoch 200 Loss 0.9991347
Epoch 300 Loss 0.99808025
Epoch 400 Loss 0.99659425
Epoch 500 Loss 0.99390364
Epoch 600 Loss 0.9881315
Epoch 700 Loss 0.9734776
Epoch 800 Loss 0.931382
Epoch 900 Loss 0.8085038
Epoch 1000 Loss 0.3204054
Epoch 1100 Loss 0.005906186
Epoch 1200 Loss 2.8943105E-05
Epoch 1300 Loss 1.2655367E-07
Epoch 1400 Loss 5.5336E-10
Epoch 1500 Loss 8.149925E-12
・
・
・
Epoch 10000 Loss 8.149925E-12
推論結果:
[1], type = Float32, device = cpu
1.8477e-06
[1], type = Float32, device = cpu
1
[1], type = Float32, device = cpu
1
[1], type = Float32, device = cpu
8.9407e-07
.NETのディープラーニングライブラリとしては日本製のKelpNetなどもありますが、TorchSharpは.NET Foundationに移行したということもあり、今後はML.NETに続き.NETの機械学習環境の幅が更に広がることが期待できそうです。
参考ウェブサイトなど
以上です。