From c4d5f23cc81981da26ed6bfefb881c0397dee79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Pu=C5=A1?= <pusradek@fit.cvut.cz> Date: Sat, 2 Nov 2019 00:41:47 +0100 Subject: [PATCH] save to DB functionality for neural network --- Core/Core/Data/Model.cs | 25 ++++-- Core/Core/Models/Network.cs | 37 ++++++++ .../NeuralNetNamespace/Layers/ILayer.cs | 2 + .../NeuralNetNamespace/Layers/InputLayer.cs | 10 +++ .../NeuralNetNamespace/Layers/Layer.cs | 14 +++ .../NeuralNetNamespace/NeuralNet.cs | 33 +++++++ .../NeuralNetNamespace/Neurons/INeuron.cs | 3 + .../NeuralNetNamespace/Neurons/Neuron.cs | 15 ++-- Core/NeuralNetwork/Program.cs | 89 +++++++++++++++++-- 9 files changed, 209 insertions(+), 19 deletions(-) create mode 100644 Core/Core/Models/Network.cs diff --git a/Core/Core/Data/Model.cs b/Core/Core/Data/Model.cs index 75623b0..cbc2cd2 100644 --- a/Core/Core/Data/Model.cs +++ b/Core/Core/Data/Model.cs @@ -32,16 +32,18 @@ namespace Core.Data public DbSet<ForeignPayment> ForeignPayments { get; set; } public DbSet<Repetition> Repetitions { get; set; } + public DbSet<Network> Networks { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity<Expense>().ToTable("Expense"); + SetRelations(modelBuilder); + SetTableNames(modelBuilder); + base.OnModelCreating(modelBuilder); + } - modelBuilder.Entity<Account>().ToTable("Account"); - modelBuilder.Entity<ConstantSymbol>().ToTable("ConstantSymbol"); - modelBuilder.Entity<Person>().ToTable("Person"); - //modelBuilder.Entity<Transaction>().ToTable("Transaction"); + private void SetRelations(ModelBuilder modelBuilder) + { modelBuilder.Entity<Transaction>() .HasOne(t => t.RecipientAccount) .WithMany(a => a.RecipientTransactions) @@ -56,8 +58,15 @@ namespace Core.Data .OnDelete(DeleteBehavior.Restrict); modelBuilder.Entity<User>().HasIndex(u => u.Username).IsUnique(); - modelBuilder.Entity<User>().ToTable("Users"); + } + private void SetTableNames(ModelBuilder modelBuilder) + { + modelBuilder.Entity<Expense>().ToTable("Expense"); + modelBuilder.Entity<Account>().ToTable("Account"); + modelBuilder.Entity<ConstantSymbol>().ToTable("ConstantSymbol"); + modelBuilder.Entity<Person>().ToTable("Person"); + modelBuilder.Entity<User>().ToTable("Users"); modelBuilder.Entity<AccountType>().ToTable("AccountType"); modelBuilder.Entity<TransactionType>().ToTable("TransactionType"); modelBuilder.Entity<Kind>().ToTable("Kind"); @@ -65,10 +74,8 @@ namespace Core.Data modelBuilder.Entity<MinistryPredefined>().ToTable("MinistryPredefined"); modelBuilder.Entity<ReservedSymbol>().ToTable("ReservedSymbol"); modelBuilder.Entity<ForeignPayment>().ToTable("ForeignPayment"); - modelBuilder.Entity<Repetition>().ToTable("Repetition"); - - base.OnModelCreating(modelBuilder); + modelBuilder.Entity<Network>().ToTable("Network"); } } } diff --git a/Core/Core/Models/Network.cs b/Core/Core/Models/Network.cs new file mode 100644 index 0000000..7ae69fa --- /dev/null +++ b/Core/Core/Models/Network.cs @@ -0,0 +1,37 @@ +using Core.Data; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace Core.Models +{ + public class Network + { + [Key] + public long ID { get; set; } + public ICollection<Layer> Layer { get; set; } + } + + public class Layer + { + [Key] + public long ID { get; set; } + public ICollection<Neuron> Neuron { get; set; } + } + + public class Neuron + { + [Key] + public long ID { get; set; } + public ICollection<Weight> Weight { get; set; } + } + + public class Weight + { + [Key] + public long ID { get; set; } + public double Value { get; set; } + } +} diff --git a/Core/NeuralNetwork/NeuralNetNamespace/Layers/ILayer.cs b/Core/NeuralNetwork/NeuralNetNamespace/Layers/ILayer.cs index b0b5a74..4e9d824 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/Layers/ILayer.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/Layers/ILayer.cs @@ -14,5 +14,7 @@ namespace NeuralNetwork.NeuralNetNamespace.Layers void Evaluate(DenseVector inputVector); void Propagate(DenseVector error); void AdjustWeights(); + List<List<double>> Export(); + void Import(List<List<double>> list); } } diff --git a/Core/NeuralNetwork/NeuralNetNamespace/Layers/InputLayer.cs b/Core/NeuralNetwork/NeuralNetNamespace/Layers/InputLayer.cs index 98c506d..6b96ea9 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/Layers/InputLayer.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/Layers/InputLayer.cs @@ -37,6 +37,16 @@ namespace NeuralNetwork.NeuralNetNamespace.Layers NextLayer.Evaluate(inputVector); } + public List<List<double>> Export() + { + return new List<List<double>> { new List<double> { Size } }; + } + + public void Import(List<List<double>> list) + { + throw new NotImplementedException(); + } + public void Propagate(DenseVector error) { return; diff --git a/Core/NeuralNetwork/NeuralNetNamespace/Layers/Layer.cs b/Core/NeuralNetwork/NeuralNetNamespace/Layers/Layer.cs index 085f199..274d74a 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/Layers/Layer.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/Layers/Layer.cs @@ -74,5 +74,19 @@ namespace NeuralNetwork.NeuralNetNamespace.Layers if (PrevLayer != null) PrevLayer.Propagate(layerError); } + + public List<List<double>> Export() + { + List<List<double>> layer = new List<List<double>> (Neurons.Count); + for (int i = 0; i < Neurons.Count; i++) + layer.Add(Neurons[i].Export()); + return layer; + } + + public void Import(List<List<double>> layers) + { + for (int i = 0; i < layers.Count; i++) + Neurons[i].Import(layers[i]); + } } } diff --git a/Core/NeuralNetwork/NeuralNetNamespace/NeuralNet.cs b/Core/NeuralNetwork/NeuralNetNamespace/NeuralNet.cs index 2086545..724cb03 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/NeuralNet.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/NeuralNet.cs @@ -16,6 +16,8 @@ namespace NeuralNetwork.NeuralNetNamespace public NeuralNet CreateEmpty(List<int> layerSizes) { + layers = new List<ILayer>(layerSizes.Count); + ILayer prevLayer = new InputLayer(layerSizes[0]); layers.Add(prevLayer); @@ -35,6 +37,37 @@ namespace NeuralNetwork.NeuralNetNamespace return this; } + /// <summary> + /// weights for neurons in corresponding layers + /// (net 1:N > layer 1:N > neuron 1:N > weight) + /// </summary> + /// <returns>weigts for individual neurons (+layers)</returns> + public List<List<List<double>>> ExportNet() + { + List<List<List<double>>> net = new List<List<List<double>>>(layers.Count); + for (int i = 0; i < layers.Count; i++) + net.Add(layers[i].Export()); + + return net; + } + + public void Import(List<List<List<double>>> net) + { + //instance initialization first + List<int> shape = new List<int>(net.Count); + + shape.Add((int)net[0][0][0]); + for (int i = 1; i < net.Count; i++) + shape.Add(net[i].Count); + + CreateEmpty(shape); + + //fill with data + + for (int i = 1; i < net.Count; i++) + layers[i].Import(net[i]); + } + public double LastResult { get; private set; } public bool EvaluateInput(List<double> input) diff --git a/Core/NeuralNetwork/NeuralNetNamespace/Neurons/INeuron.cs b/Core/NeuralNetwork/NeuralNetNamespace/Neurons/INeuron.cs index 8703e11..82ebadf 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/Neurons/INeuron.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/Neurons/INeuron.cs @@ -12,5 +12,8 @@ namespace NeuralNetwork.NeuralNetNamespace.Neurons DenseVector Propagate(double error); void AdjustWeights(); double Output { get; } + + List<double> Export(); + void Import(List<double> list); } } diff --git a/Core/NeuralNetwork/NeuralNetNamespace/Neurons/Neuron.cs b/Core/NeuralNetwork/NeuralNetNamespace/Neurons/Neuron.cs index d8c36f2..7bad697 100644 --- a/Core/NeuralNetwork/NeuralNetNamespace/Neurons/Neuron.cs +++ b/Core/NeuralNetwork/NeuralNetNamespace/Neurons/Neuron.cs @@ -7,7 +7,6 @@ using System.Text; namespace NeuralNetwork.NeuralNetNamespace.Neurons { - //TODO: Abs() pro WeightTotal - buď ano nebo ne //TODO: komentáře //TODO: dekompozice class Neuron : INeuron @@ -21,10 +20,6 @@ namespace NeuralNetwork.NeuralNetNamespace.Neurons private int PropagationIterator; public DenseVector Weights { get; private set; } - /// <summary> - /// sum of all weights in Weights vector - /// </summary> - private double WeightTotal; private DenseVector Corrections; @@ -108,5 +103,15 @@ namespace NeuralNetwork.NeuralNetNamespace.Neurons return $"({Output.ToString()} # {str})"; } + + public List<double> Export() + { + return new List<double>(Weights.ToArray()); + } + + public void Import(List<double> list) + { + Weights.SetValues(list.ToArray()); + } } } diff --git a/Core/NeuralNetwork/Program.cs b/Core/NeuralNetwork/Program.cs index 04c9d66..bd7ff27 100644 --- a/Core/NeuralNetwork/Program.cs +++ b/Core/NeuralNetwork/Program.cs @@ -9,7 +9,85 @@ namespace NeuralNetwork private static int startSize; static void Main(string[] args) { - XORGenerator(); + NeuralNet ann = TestTrain(infinite: false); + + Console.WriteLine("evaluate trained:"); + EvaluationTest(ann); + + Console.WriteLine("evaluate trained 2:"); + EvaluationTest(ann); + + Console.WriteLine("exporting:"); + List<List<List<double>>> export = ann.ExportNet(); + Console.WriteLine("done"); + + Console.WriteLine("evaluate trained 3:"); + EvaluationTest(ann); + + Console.WriteLine("importing to new net:"); + NeuralNet import = new NeuralNet(); + import.Import(export); + Console.WriteLine("done"); + + Console.WriteLine("test:"); + EvaluationTest(import); + Console.WriteLine("done"); + + Console.WriteLine("importing to old net:"); + ann.Import(export); + Console.WriteLine("done"); + + Console.WriteLine("test:"); + EvaluationTest(ann); + Console.WriteLine("done"); + } + + private static KeyValuePair<bool, List<double>> GetGenerator() + { + return OddEvenGenerator(); + } + + private static void EvaluationTest(NeuralNet ann) + { + int passed = 0; + int failed = 0; + double yes = 0; + double predictionYes = 0; + double no = 0; + double predictionNo = 0; + const int iterations=1000; + for (int i = 0; i < iterations; i++) + { + var data = GetGenerator(); + bool guess = ann.EvaluateInput(data.Value); + bool result = data.Key; + + if (guess == result) + passed++; + else + failed++; + + if (result) + yes++; + else + no++; + + if (guess) + predictionYes++; + else + predictionNo++; + } + + double localResult = ((double)passed / iterations) * 100; + Console.WriteLine($"succes rate: {localResult}% (p:{passed} vs. f:{failed})"); + Console.WriteLine($"Actualyes: {yes}, Actualno:{no}"); + Console.WriteLine($"predictionYes: {predictionYes}, predictionNo:{predictionNo}"); + Console.WriteLine("_-_-_-_-_-_-_-_-_-_-_-_-_"); + } + + private static NeuralNet TestTrain(bool infinite) + { + GetGenerator(); List<int> widths = new List<int>() { startSize, 3, 3, 1 }; NeuralNet ANN = new NeuralNet().CreateEmpty(widths); @@ -29,9 +107,9 @@ namespace NeuralNetwork const int adjust = 100; //const int step = 20; //const int adjust = 3; - for (int i = 0; true || i < 1000; i++) + for (int i = 0; infinite || i < 10000; i++) { - var data = XORGenerator(); + var data = GetGenerator(); bool guess = ANN.EvaluateInput(data.Value); bool result = data.Key; @@ -54,7 +132,7 @@ namespace NeuralNetwork if (i % adjust == 0 && i > adjust) ANN.AdjustWeights(); - if (i % step == 0) + if (i>1 && i % step == 0) { Console.WriteLine(ANN.ToString()); Console.WriteLine("_-_-_-_-_-_-_-_-_-_-_-_-_"); @@ -73,7 +151,8 @@ namespace NeuralNetwork } } - Console.WriteLine("Hello World!"); + + return ANN; } private static KeyValuePair<bool, List<double>> XORGenerator() -- GitLab