過去の回を通してニューラルネットワークの仕組みと使い方の方向性について書いてきた。
今回は学習させたニューラルネットワークの保存と復元、
3階層だったのをN階層まで可変できるようにしたソースコードを置いておきます。
次回はこれを使ってニューラルネットワークの様々な使い方について記載予定です。
次回はこれを使ってニューラルネットワークの様々な使い方について記載予定です。
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
NeuralNetwork nn;
var data1 = new List()
{
new TeachingData(new float[] { 0.0f, 0.0f }, new float[] { 0.0f }),
new TeachingData(new float[] { 0.0f, 1.0f }, new float[] { 1.0f }),
new TeachingData(new float[] { 1.0f, 0.0f }, new float[] { 1.0f }),
new TeachingData(new float[] { 1.0f, 1.0f }, new float[] { 0.0f }),
};
var data2 = new List()
{
new TeachingData(new float[] { 0.0f, 0.0f, 0.0f }, new float[] { 0.0f }),
new TeachingData(new float[] { 0.0f, 0.0f, 1.0f }, new float[] { 1.0f }),
new TeachingData(new float[] { 0.0f, 1.0f, 0.0f }, new float[] { 1.0f }),
new TeachingData(new float[] { 0.0f, 1.0f, 1.0f }, new float[] { 0.0f }),
new TeachingData(new float[] { 1.0f, 0.0f, 0.0f }, new float[] { 1.0f }),
new TeachingData(new float[] { 1.0f, 0.0f, 1.0f }, new float[] { 0.0f }),
new TeachingData(new float[] { 1.0f, 1.0f, 0.0f }, new float[] { 0.0f }),
new TeachingData(new float[] { 1.0f, 1.0f, 1.0f }, new float[] { 1.0f }),
};
if (File.Exists("neuron.json"))
{
nn = Json.Load("neuron.json");
Show(nn, data2);
}
else
{
nn = NeuralNetwork.CreateInstance(3, 3, 1); //ニューロン作成
nn.Teach(data2); //学習
Show(nn, data2); //学習結果
Json.Save(nn, "neuron.json"); //保存
}
}
static void Show(NeuralNetwork nn, List data)
{
foreach (var dat in data)
{
Console.Write("[");
foreach (var output in dat.Outputs)
{
Console.Write(" " + output.ToString("F2"));
}
Console.Write(" ]");
nn.Calculate(dat.Inputs);
Console.WriteLine(nn.Dump());
}
Console.ReadKey();
}
}
#region "neuron"
public class TeachingData
{
public float[] Inputs { get; set; }
public float[] Outputs { get; set; }
public TeachingData(float[] inputs, float[] outputs)
{
Inputs = inputs;
Outputs = outputs;
}
}
[DataContract]
public class NeuralNetwork
{
static Random random = new Random();
static public float GetRandom() => (float)(Math.Sign(random.NextDouble() - 0.5) * random.NextDouble());
static ILossFunc LossFunc = new Sigmoid();
public static float Activate(float input) => LossFunc.Activate(input);
public static float DeActivate(float result) => LossFunc.DeActivate(result);
public float Gain { get; set; }
[DataMember] public List neurons { get; set; } = new List();
public static NeuralNetwork CreateInstance(params int[] neuronArrays)
{
var result = new NeuralNetwork();
var prevCount = 0;
foreach (var neurons in neuronArrays)
{
result.neurons.Add(Neurons.Create(neurons, prevCount));
prevCount = neurons;
}
return result;
}
public void Calculate(params float[] signals)
{
for (var i = 0; i < signals.Length; i++) neurons[0][i].Output = signals[i];
for (var i = 1; i < neurons.Count; i++) foreach (var hidden in neurons[i]) (hidden).Calc(neurons[i - 1]);
}
public void Teach(List data)
{
var sum = 0.0f;
var idx = neurons.Count - 1;
Gain = 1.0f;
do
{
sum = 0.0f;
foreach (var dat in data)
{
Calculate(dat.Inputs);
for (var i = 0; i < dat.Outputs.Length; i++)
{
var diff = dat.Outputs[i] - neurons[idx][i].Output;
if (0.0 < Math.Abs(diff))
{
neurons[idx][i].Teach(this, idx, diff);
}
sum += Math.Abs(diff);
}
}
sum /= data.Count;
Gain = sum;
if (1.0f < Gain)
{
Gain = 1.0f;
}
else if(0.2f > Gain)
{
Gain = 0.2f;
}
}
while (0.04f < sum);
}
public override string ToString() => Json.ToJson(this);
public string Dump()
{
var result = "";
neurons.ForEach(_ => result += $" => {_.ToString()}");
return result;
}
}
[DataContract]
public class Neurons : IEnumerable
{
public IEnumerator GetEnumerator() => Data.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
[DataMember]
public List Data { get; set; } = new List();
public static Neurons Create(int neurons, int weights)
{
var result = new Neurons();
for (var i = 0; i < neurons; i++)
{
var hidden = new Neuron();
for (var j = 0; j < weights; j++) hidden.Weights.Add(NeuralNetwork.GetRandom());
result.Data.Add(hidden);
}
return result;
}
public Neuron this[int index] => Data[index];
public override string ToString()
{
var result = "";
Data.ForEach(_ => result += (0 > _.Output) ? $" {_.Output.ToString("F2")}" : $" +{_.Output.ToString("F2")}");
return $"[{result} ]";
}
}
[DataContract]
public class Neuron
{
[DataMember] public float Bias { get; set; } = NeuralNetwork.GetRandom();
[DataMember] public List Weights { get; set; } = new List();
public float Output { get; set; }
public void Teach(NeuralNetwork nn, int layer_no, float value)
{
var _value = value * NeuralNetwork.DeActivate(Output) * nn.Gain;
for (var i = 0; i < Weights.Count; i++)
{
Weights[i] += _value * nn.neurons[layer_no - 1][i].Output;
if (1 < layer_no) nn.neurons[layer_no - 1][i].Teach(nn, layer_no - 1, _value);
}
Bias += _value;
}
public float Calc(Neurons prev_neurons)
{
Output = Bias;
for (var i = 0; i < Weights.Count; i++) Output += Weights[i] * prev_neurons[i].Output;
Output = NeuralNetwork.Activate(Output);
return Output;
}
public override string ToString() => Json.ToJson(this);
}
#endregion
#region "lossFunc"
public interface ILossFunc
{
float Activate(float input);
float DeActivate(float result);
}
public class Sigmoid : ILossFunc
{
public float Activate(float input) => 1.0f / (1.0f + (float)Math.Exp(-input));
public float DeActivate(float result) => result * (1.0f - result);
}
public class Tanh : ILossFunc
{
public float Activate(float input) => (float)Math.Tanh(input);
public float DeActivate(float result) => (1.0f - result * result);
}
public class ReLU : ILossFunc
{
public float Activate(float input) => Math.Max(0.0f, input);
public float DeActivate(float result) => (0.0f < result) ? 1.0f : 0.0f;
}
public class Softsign : ILossFunc
{
public float Activate(float input) => input / (1.0f + Math.Abs(input));
public float DeActivate(float result) => (float)Math.Pow(1.0f - Math.Abs(result), 2);
}
#endregion
#region "json"
public static class Json
{
public static T Load(string filename)
{
if (File.Exists(filename))
{
return ToObject(File.ReadAllText(filename));
}
else
{
return (T)Activator.CreateInstance(typeof(T));
}
}
public static void Save(T model, string filename)
{
File.WriteAllText(filename, ToJson(model));
}
static T ToObject(string jsonString)
{
var serializer = new DataContractJsonSerializer(typeof(T));
var jsonBytes = Encoding.UTF8.GetBytes(jsonString);
using (var sr = new MemoryStream(jsonBytes))
{
return (T)serializer.ReadObject(sr);
}
}
public static string ToJson(T model)
{
if (null == model)
{
return "{}";
}
using (var ms = new MemoryStream())
{
new DataContractJsonSerializer(typeof(T)).WriteObject(ms, model);
var bytes = ms.ToArray();
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
}
}
#endregion
}
0 件のコメント:
コメントを投稿