過去の回を通してニューラルネットワークの仕組みと使い方の方向性について書いてきた。
今回は学習させたニューラルネットワークの保存と復元、
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 件のコメント:
コメントを投稿