C# でゼロから Deep Learning を実装する挑戦の続き。
4 章もようやく終盤で、いよいよ機械学習に入る。
今回はニューラルネットワークに対する勾配を実装してみた。
using System;
using System.Linq;
using MathNet.Numerics.LinearAlgebra;
namespace GradientSimpleNet
{
class Program
{
static void Main(string[] args)
{
var net = new SimpleNet();
var x = Vector<double>.Build.DenseOfArray(new[] { 0.6, 0.9 });
var p = net.Predict(x);
Console.WriteLine("予測");
Console.WriteLine(p);
var t = Vector<double>.Build.DenseOfArray(new[] { 0, 0, 1.0 });
var loss = net.Loss(x, t);
Console.WriteLine("損失関数の値");
Console.WriteLine(loss);
Func<Matrix<double>, double> f = W => net.Loss(x, t);
var dW = Gradient.NumericalGradient(f, net.W);
Console.WriteLine("勾配");
Console.WriteLine(dW);
Console.ReadLine();
}
}
static class Functions
{
<summary>
</summary>
public static Vector<double> Softmax(Vector<double> a)
{
var c = a.Max();
var exp_a = a.Map(x => Math.Exp(x - c));
var sum_exp_a = exp_a.Sum();
var y = exp_a.Map(x => x / sum_exp_a);
return y;
}
<summary>
</summary>
public static double CrossEntropyError(Vector<double> y, Vector<double> t)
{
var delta = 1e-7;
return -(y + delta).PointwiseLog().PointwiseMultiply(t).Sum();
}
}
static class Gradient
{
<summary>
</summary>
public static Matrix<double> NumericalGradient(Func<Matrix<double>, double> f, Matrix<double> x)
{
var h = 1e-4;
var grad = Matrix<double>.Build.Dense(x.RowCount, x.ColumnCount);
for (int row = 0; row < x.RowCount; row++)
{
for (int column = 0; column < x.ColumnCount; column++)
{
var tmpVal = x[row, column];
x[row, column] = tmpVal + h;
var fxh1 = f(x);
x[row, column] = tmpVal - h;
var fxh2 = f(x);
grad[row, column] = (fxh1 - fxh2) / (2.0 * h);
x[row, column] = tmpVal;
}
}
return grad;
}
}
class SimpleNet
{
<summary>
</summary>
public Matrix<double> W { get; }
public SimpleNet()
{
W = Matrix<double>.Build.DenseOfArray(new double[,]
{
{ 0.47355232, 0.9977393, 0.84668094 },
{ 0.85557411, 0.03563661, 0.69422093 }
});
}
public Vector<double> Predict(Vector<double> x)
{
return x * W;
}
public double Loss(Vector<double> x, Vector<double> t)
{
var z = Predict(x);
var y = Functions.Softmax(z);
var loss = Functions.CrossEntropyError(y, t);
return loss;
}
}
}
実行結果は次の通り。
『ゼロから作る Deep Learning』と同じような傾向になっている。
完全に一致しないのは、自分の実装が間違っているんだろうか。