├── ScreenShot.PNG ├── NeuralNetwork ├── NeuralNetwork │ ├── packages.config │ ├── App.config │ ├── NetworkModels │ │ ├── Sigmoid.cs │ │ ├── Dataset.cs │ │ ├── Synapse.cs │ │ ├── Neuron.cs │ │ └── Network.cs │ ├── DataExamples │ │ ├── DatasetExample.txt │ │ └── NetworkExample.txt │ ├── Helpers │ │ ├── HelperNetwork.cs │ │ ├── ImportHelper.cs │ │ └── ExportHelper.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── NeuralNetwork.csproj │ └── Program.cs └── NeuralNetwork.sln ├── LICENSE ├── .gitignore └── README.md /ScreenShot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trentsartain/Neural-Network/HEAD/ScreenShot.PNG -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NetworkModels/Sigmoid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NeuralNetwork.NetworkModels 4 | { 5 | public static class Sigmoid 6 | { 7 | public static double Output(double x) 8 | { 9 | return x < -45.0 ? 0.0 : x > 45.0 ? 1.0 : 1.0 / (1.0 + Math.Exp(-x)); 10 | } 11 | 12 | public static double Derivative(double x) 13 | { 14 | return x * (1 - x); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NetworkModels/Dataset.cs: -------------------------------------------------------------------------------- 1 | namespace NeuralNetwork.NetworkModels 2 | { 3 | public class DataSet 4 | { 5 | #region -- Properties -- 6 | public double[] Values { get; set; } 7 | public double[] Targets { get; set; } 8 | #endregion 9 | 10 | #region -- Constructor -- 11 | public DataSet(double[] values, double[] targets) 12 | { 13 | Values = values; 14 | Targets = targets; 15 | } 16 | #endregion 17 | } 18 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/DataExamples/DatasetExample.txt: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Values": [ 4 | 1.0, 5 | 0.0 6 | ], 7 | "Targets": [ 8 | 1.0 9 | ] 10 | }, 11 | { 12 | "Values": [ 13 | 0.0, 14 | 1.0 15 | ], 16 | "Targets": [ 17 | 1.0 18 | ] 19 | }, 20 | { 21 | "Values": [ 22 | 0.0, 23 | 0.0 24 | ], 25 | "Targets": [ 26 | 0.0 27 | ] 28 | }, 29 | { 30 | "Values": [ 31 | 1.0, 32 | 1.0 33 | ], 34 | "Targets": [ 35 | 0.0 36 | ] 37 | } 38 | ] -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NetworkModels/Synapse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NeuralNetwork.NetworkModels 4 | { 5 | public class Synapse 6 | { 7 | #region -- Properties -- 8 | public Guid Id { get; set; } 9 | public Neuron InputNeuron { get; set; } 10 | public Neuron OutputNeuron { get; set; } 11 | public double Weight { get; set; } 12 | public double WeightDelta { get; set; } 13 | #endregion 14 | 15 | #region -- Constructor -- 16 | public Synapse() { } 17 | 18 | public Synapse(Neuron inputNeuron, Neuron outputNeuron) 19 | { 20 | Id = Guid.NewGuid(); 21 | InputNeuron = inputNeuron; 22 | OutputNeuron = outputNeuron; 23 | Weight = Network.GetRandom(); 24 | } 25 | #endregion 26 | } 27 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NeuralNetwork", "NeuralNetwork\NeuralNetwork.csproj", "{1B513876-712C-4699-94A0-6F199CE38BD2}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {1B513876-712C-4699-94A0-6F199CE38BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {1B513876-712C-4699-94A0-6F199CE38BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {1B513876-712C-4699-94A0-6F199CE38BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {1B513876-712C-4699-94A0-6F199CE38BD2}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Trent Sartain 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/Helpers/HelperNetwork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NeuralNetwork.Helpers 5 | { 6 | public class HelperNetwork 7 | { 8 | public double LearnRate { get; set; } 9 | public double Momentum { get; set; } 10 | public List InputLayer { get; set; } 11 | public List> HiddenLayers { get; set; } 12 | public List OutputLayer { get; set; } 13 | public List Synapses { get; set; } 14 | 15 | public HelperNetwork() 16 | { 17 | InputLayer = new List(); 18 | HiddenLayers = new List>(); 19 | OutputLayer = new List(); 20 | Synapses = new List(); 21 | } 22 | } 23 | 24 | public class HelperNeuron 25 | { 26 | public Guid Id { get; set; } 27 | public double Bias { get; set; } 28 | public double BiasDelta { get; set; } 29 | public double Gradient { get; set; } 30 | public double Value { get; set; } 31 | } 32 | 33 | public class HelperSynapse 34 | { 35 | public Guid Id { get; set; } 36 | public Guid OutputNeuronId { get; set; } 37 | public Guid InputNeuronId { get; set; } 38 | public double Weight { get; set; } 39 | public double WeightDelta { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NeuralNetwork")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("NeuralNetwork")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b68eb954-9305-4573-8fa1-16a25c2b6e7f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NetworkModels/Neuron.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace NeuralNetwork.NetworkModels 6 | { 7 | public class Neuron 8 | { 9 | #region -- Properties -- 10 | public Guid Id { get; set; } 11 | public List InputSynapses { get; set; } 12 | public List OutputSynapses { get; set; } 13 | public double Bias { get; set; } 14 | public double BiasDelta { get; set; } 15 | public double Gradient { get; set; } 16 | public double Value { get; set; } 17 | #endregion 18 | 19 | #region -- Constructors -- 20 | public Neuron() 21 | { 22 | Id = Guid.NewGuid(); 23 | InputSynapses = new List(); 24 | OutputSynapses = new List(); 25 | Bias = Network.GetRandom(); 26 | } 27 | 28 | public Neuron(IEnumerable inputNeurons) : this() 29 | { 30 | foreach (var inputNeuron in inputNeurons) 31 | { 32 | var synapse = new Synapse(inputNeuron, this); 33 | inputNeuron.OutputSynapses.Add(synapse); 34 | InputSynapses.Add(synapse); 35 | } 36 | } 37 | #endregion 38 | 39 | #region -- Values & Weights -- 40 | public virtual double CalculateValue() 41 | { 42 | return Value = Sigmoid.Output(InputSynapses.Sum(a => a.Weight * a.InputNeuron.Value) + Bias); 43 | } 44 | 45 | public double CalculateError(double target) 46 | { 47 | return target - Value; 48 | } 49 | 50 | public double CalculateGradient(double? target = null) 51 | { 52 | if (target == null) 53 | return Gradient = OutputSynapses.Sum(a => a.OutputNeuron.Gradient * a.Weight) * Sigmoid.Derivative(Value); 54 | 55 | return Gradient = CalculateError(target.Value) * Sigmoid.Derivative(Value); 56 | } 57 | 58 | public void UpdateWeights(double learnRate, double momentum) 59 | { 60 | var prevDelta = BiasDelta; 61 | BiasDelta = learnRate * Gradient; 62 | Bias += BiasDelta + momentum * prevDelta; 63 | 64 | foreach (var synapse in InputSynapses) 65 | { 66 | prevDelta = synapse.WeightDelta; 67 | synapse.WeightDelta = learnRate * Gradient * synapse.InputNeuron.Value; 68 | synapse.Weight += synapse.WeightDelta + momentum * prevDelta; 69 | } 70 | } 71 | #endregion 72 | } 73 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NeuralNetwork.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1B513876-712C-4699-94A0-6F199CE38BD2} 8 | Exe 9 | Properties 10 | NeuralNetwork 11 | NeuralNetwork 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll 37 | True 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/Helpers/ImportHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | using System.IO; 5 | using System.Linq; 6 | using NeuralNetwork.NetworkModels; 7 | using Newtonsoft.Json; 8 | 9 | namespace NeuralNetwork.Helpers 10 | { 11 | public static class ImportHelper 12 | { 13 | public static Network ImportNetwork() 14 | { 15 | var dn = GetHelperNetwork(); 16 | if (dn == null) return null; 17 | 18 | var network = new Network(); 19 | var allNeurons = new List(); 20 | 21 | network.LearnRate = dn.LearnRate; 22 | network.Momentum = dn.Momentum; 23 | 24 | //Input Layer 25 | foreach (var n in dn.InputLayer) 26 | { 27 | var neuron = new Neuron 28 | { 29 | Id = n.Id, 30 | Bias = n.Bias, 31 | BiasDelta = n.BiasDelta, 32 | Gradient = n.Gradient, 33 | Value = n.Value 34 | }; 35 | 36 | network.InputLayer.Add(neuron); 37 | allNeurons.Add(neuron); 38 | } 39 | 40 | //Hidden Layers 41 | foreach (var layer in dn.HiddenLayers) 42 | { 43 | var neurons = new List(); 44 | foreach (var n in layer) 45 | { 46 | var neuron = new Neuron 47 | { 48 | Id = n.Id, 49 | Bias = n.Bias, 50 | BiasDelta = n.BiasDelta, 51 | Gradient = n.Gradient, 52 | Value = n.Value 53 | }; 54 | 55 | neurons.Add(neuron); 56 | allNeurons.Add(neuron); 57 | } 58 | 59 | network.HiddenLayers.Add(neurons); 60 | } 61 | 62 | //Export Layer 63 | foreach (var n in dn.OutputLayer) 64 | { 65 | var neuron = new Neuron 66 | { 67 | Id = n.Id, 68 | Bias = n.Bias, 69 | BiasDelta = n.BiasDelta, 70 | Gradient = n.Gradient, 71 | Value = n.Value 72 | }; 73 | 74 | network.OutputLayer.Add(neuron); 75 | allNeurons.Add(neuron); 76 | } 77 | 78 | //Synapses 79 | foreach (var syn in dn.Synapses) 80 | { 81 | var synapse = new Synapse { Id = syn.Id }; 82 | var inputNeuron = allNeurons.First(x => x.Id == syn.InputNeuronId); 83 | var outputNeuron = allNeurons.First(x => x.Id == syn.OutputNeuronId); 84 | synapse.InputNeuron = inputNeuron; 85 | synapse.OutputNeuron = outputNeuron; 86 | synapse.Weight = syn.Weight; 87 | synapse.WeightDelta = syn.WeightDelta; 88 | 89 | inputNeuron.OutputSynapses.Add(synapse); 90 | outputNeuron.InputSynapses.Add(synapse); 91 | } 92 | 93 | return network; 94 | } 95 | 96 | public static List ImportDatasets() 97 | { 98 | try 99 | { 100 | var dialog = new OpenFileDialog 101 | { 102 | Multiselect = false, 103 | Title = "Open Dataset File", 104 | Filter = "Text File|*.txt;" 105 | }; 106 | 107 | using (dialog) 108 | { 109 | if (dialog.ShowDialog() != DialogResult.OK) return null; 110 | using (var file = File.OpenText(dialog.FileName)) 111 | { 112 | return JsonConvert.DeserializeObject>(file.ReadToEnd()); 113 | } 114 | } 115 | } 116 | catch (Exception) 117 | { 118 | return null; 119 | } 120 | } 121 | 122 | private static HelperNetwork GetHelperNetwork() 123 | { 124 | try 125 | { 126 | var dialog = new OpenFileDialog 127 | { 128 | Multiselect = false, 129 | Title = "Open Network File", 130 | Filter = "Text File|*.txt;" 131 | }; 132 | 133 | using (dialog) 134 | { 135 | if (dialog.ShowDialog() != DialogResult.OK) return null; 136 | 137 | using (var file = File.OpenText(dialog.FileName)) 138 | { 139 | return JsonConvert.DeserializeObject(file.ReadToEnd()); 140 | } 141 | } 142 | } 143 | catch (Exception) 144 | { 145 | return null; 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/Helpers/ExportHelper.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Windows.Forms; 3 | using Newtonsoft.Json; 4 | using System.Collections.Generic; 5 | using NeuralNetwork.NetworkModels; 6 | 7 | namespace NeuralNetwork.Helpers 8 | { 9 | public static class ExportHelper 10 | { 11 | public static void ExportNetwork(Network network) 12 | { 13 | var dn = GetHelperNetwork(network); 14 | 15 | var dialog = new SaveFileDialog 16 | { 17 | Title = "Save Network File", 18 | Filter = "Text File|*.txt;" 19 | }; 20 | 21 | using (dialog) 22 | { 23 | if (dialog.ShowDialog() != DialogResult.OK) return; 24 | using (var file = File.CreateText(dialog.FileName)) 25 | { 26 | var serializer = new JsonSerializer { Formatting = Formatting.Indented }; 27 | serializer.Serialize(file, dn); 28 | } 29 | } 30 | } 31 | 32 | public static void ExportDatasets(List datasets) 33 | { 34 | var dialog = new SaveFileDialog 35 | { 36 | Title = "Save Dataset File", 37 | Filter = "Text File|*.txt;" 38 | }; 39 | 40 | using (dialog) 41 | { 42 | if (dialog.ShowDialog() != DialogResult.OK) return; 43 | using (var file = File.CreateText(dialog.FileName)) 44 | { 45 | var serializer = new JsonSerializer { Formatting = Formatting.Indented }; 46 | serializer.Serialize(file, datasets); 47 | } 48 | } 49 | } 50 | 51 | private static HelperNetwork GetHelperNetwork(Network network) 52 | { 53 | var hn = new HelperNetwork 54 | { 55 | LearnRate = network.LearnRate, 56 | Momentum = network.Momentum 57 | }; 58 | 59 | //Input Layer 60 | foreach (var n in network.InputLayer) 61 | { 62 | var neuron = new HelperNeuron 63 | { 64 | Id = n.Id, 65 | Bias = n.Bias, 66 | BiasDelta = n.BiasDelta, 67 | Gradient = n.Gradient, 68 | Value = n.Value 69 | }; 70 | 71 | hn.InputLayer.Add(neuron); 72 | 73 | foreach (var synapse in n.OutputSynapses) 74 | { 75 | var syn = new HelperSynapse 76 | { 77 | Id = synapse.Id, 78 | OutputNeuronId = synapse.OutputNeuron.Id, 79 | InputNeuronId = synapse.InputNeuron.Id, 80 | Weight = synapse.Weight, 81 | WeightDelta = synapse.WeightDelta 82 | }; 83 | 84 | hn.Synapses.Add(syn); 85 | } 86 | } 87 | 88 | //Hidden Layer 89 | foreach (var l in network.HiddenLayers) 90 | { 91 | var layer = new List(); 92 | 93 | foreach (var n in l) 94 | { 95 | var neuron = new HelperNeuron 96 | { 97 | Id = n.Id, 98 | Bias = n.Bias, 99 | BiasDelta = n.BiasDelta, 100 | Gradient = n.Gradient, 101 | Value = n.Value 102 | }; 103 | 104 | layer.Add(neuron); 105 | 106 | foreach (var synapse in n.OutputSynapses) 107 | { 108 | var syn = new HelperSynapse 109 | { 110 | Id = synapse.Id, 111 | OutputNeuronId = synapse.OutputNeuron.Id, 112 | InputNeuronId = synapse.InputNeuron.Id, 113 | Weight = synapse.Weight, 114 | WeightDelta = synapse.WeightDelta 115 | }; 116 | 117 | hn.Synapses.Add(syn); 118 | } 119 | } 120 | 121 | hn.HiddenLayers.Add(layer); 122 | } 123 | 124 | //Output Layer 125 | foreach (var n in network.OutputLayer) 126 | { 127 | var neuron = new HelperNeuron 128 | { 129 | Id = n.Id, 130 | Bias = n.Bias, 131 | BiasDelta = n.BiasDelta, 132 | Gradient = n.Gradient, 133 | Value = n.Value 134 | }; 135 | 136 | hn.OutputLayer.Add(neuron); 137 | 138 | foreach (var synapse in n.OutputSynapses) 139 | { 140 | var syn = new HelperSynapse 141 | { 142 | Id = synapse.Id, 143 | OutputNeuronId = synapse.OutputNeuron.Id, 144 | InputNeuronId = synapse.InputNeuron.Id, 145 | Weight = synapse.Weight, 146 | WeightDelta = synapse.WeightDelta 147 | }; 148 | 149 | hn.Synapses.Add(syn); 150 | } 151 | } 152 | 153 | return hn; 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/NetworkModels/Network.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace NeuralNetwork.NetworkModels 6 | { 7 | public class Network 8 | { 9 | #region -- Properties -- 10 | public double LearnRate { get; set; } 11 | public double Momentum { get; set; } 12 | public List InputLayer { get; set; } 13 | public List> HiddenLayers { get; set; } 14 | public List OutputLayer { get; set; } 15 | #endregion 16 | 17 | #region -- Globals -- 18 | private static readonly Random Random = new Random(); 19 | #endregion 20 | 21 | #region -- Constructor -- 22 | public Network() 23 | { 24 | LearnRate = 0; 25 | Momentum = 0; 26 | InputLayer = new List(); 27 | HiddenLayers = new List>(); 28 | OutputLayer = new List(); 29 | } 30 | 31 | public Network(int inputSize, int[] hiddenSizes, int outputSize, double? learnRate = null, double? momentum = null) 32 | { 33 | LearnRate = learnRate ?? .4; 34 | Momentum = momentum ?? .9; 35 | InputLayer = new List(); 36 | HiddenLayers = new List>(); 37 | OutputLayer = new List(); 38 | 39 | for (var i = 0; i < inputSize; i++) 40 | InputLayer.Add(new Neuron()); 41 | 42 | var firstHiddenLayer = new List(); 43 | for (var i = 0; i < hiddenSizes[0]; i++) 44 | firstHiddenLayer.Add(new Neuron(InputLayer)); 45 | 46 | HiddenLayers.Add(firstHiddenLayer); 47 | 48 | for (var i = 1; i < hiddenSizes.Length; i++) 49 | { 50 | var hiddenLayer = new List(); 51 | for (var j = 0; j < hiddenSizes[i]; j++) 52 | hiddenLayer.Add(new Neuron(HiddenLayers[i - 1])); 53 | HiddenLayers.Add(hiddenLayer); 54 | } 55 | 56 | for (var i = 0; i < outputSize; i++) 57 | OutputLayer.Add(new Neuron(HiddenLayers.Last())); 58 | } 59 | #endregion 60 | 61 | #region -- Training -- 62 | public void Train(List dataSets, int numEpochs) 63 | { 64 | for (var i = 0; i < numEpochs; i++) 65 | { 66 | foreach (var dataSet in dataSets) 67 | { 68 | ForwardPropagate(dataSet.Values); 69 | BackPropagate(dataSet.Targets); 70 | } 71 | } 72 | } 73 | 74 | public void Train(List dataSets, double minimumError) 75 | { 76 | var error = 1.0; 77 | var numEpochs = 0; 78 | 79 | while (error > minimumError && numEpochs < int.MaxValue) 80 | { 81 | var errors = new List(); 82 | foreach (var dataSet in dataSets) 83 | { 84 | ForwardPropagate(dataSet.Values); 85 | BackPropagate(dataSet.Targets); 86 | errors.Add(CalculateError(dataSet.Targets)); 87 | } 88 | error = errors.Average(); 89 | numEpochs++; 90 | } 91 | } 92 | 93 | private void ForwardPropagate(params double[] inputs) 94 | { 95 | var i = 0; 96 | InputLayer.ForEach(a => a.Value = inputs[i++]); 97 | HiddenLayers.ForEach(a => a.ForEach(b => b.CalculateValue())); 98 | OutputLayer.ForEach(a => a.CalculateValue()); 99 | } 100 | 101 | private void BackPropagate(params double[] targets) 102 | { 103 | var i = 0; 104 | OutputLayer.ForEach(a => a.CalculateGradient(targets[i++])); 105 | HiddenLayers.Reverse(); 106 | HiddenLayers.ForEach(a => a.ForEach(b => b.CalculateGradient())); 107 | HiddenLayers.ForEach(a => a.ForEach(b => b.UpdateWeights(LearnRate, Momentum))); 108 | HiddenLayers.Reverse(); 109 | OutputLayer.ForEach(a => a.UpdateWeights(LearnRate, Momentum)); 110 | } 111 | 112 | public double[] Compute(params double[] inputs) 113 | { 114 | ForwardPropagate(inputs); 115 | return OutputLayer.Select(a => a.Value).ToArray(); 116 | } 117 | 118 | private double CalculateError(params double[] targets) 119 | { 120 | var i = 0; 121 | return OutputLayer.Sum(a => Math.Abs(a.CalculateError(targets[i++]))); 122 | } 123 | #endregion 124 | 125 | #region -- Helpers -- 126 | public static double GetRandom() 127 | { 128 | return 2 * Random.NextDouble() - 1; 129 | } 130 | #endregion 131 | } 132 | 133 | #region -- Enum -- 134 | public enum TrainingType 135 | { 136 | Epoch, 137 | MinimumError 138 | } 139 | #endregion 140 | } -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/DataExamples/NetworkExample.txt: -------------------------------------------------------------------------------- 1 | { 2 | "LearnRate": 0.4, 3 | "Momentum": 0.9, 4 | "InputLayer": [ 5 | { 6 | "Id": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 7 | "Bias": 0.88011651853104889, 8 | "BiasDelta": 0.0, 9 | "Gradient": 0.0, 10 | "Value": 0.0 11 | }, 12 | { 13 | "Id": "fcf15808-fb11-4a04-9022-638140164c64", 14 | "Bias": -0.12904600665394495, 15 | "BiasDelta": 0.0, 16 | "Gradient": 0.0, 17 | "Value": 0.0 18 | } 19 | ], 20 | "HiddenLayers": [ 21 | [ 22 | { 23 | "Id": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 24 | "Bias": 1.6459098726963641, 25 | "BiasDelta": 6.8129688749504508E-06, 26 | "Gradient": 1.7032422187376126E-05, 27 | "Value": 0.83833657457730759 28 | }, 29 | { 30 | "Id": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 31 | "Bias": -1.3229172632409467, 32 | "BiasDelta": -9.2984227388283447E-06, 33 | "Gradient": -2.3246056847070861E-05, 34 | "Value": 0.21033426055222876 35 | }, 36 | { 37 | "Id": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 38 | "Bias": -0.43095589580981947, 39 | "BiasDelta": 1.2014607576953927E-05, 40 | "Gradient": 3.0036518942384814E-05, 41 | "Value": 0.39389960849056194 42 | } 43 | ] 44 | ], 45 | "OutputLayer": [ 46 | { 47 | "Id": "9c096f95-800c-435b-9ee9-5af125abc8b3", 48 | "Bias": 3.8785304867945971, 49 | "BiasDelta": -5.2888861198121289E-06, 50 | "Gradient": -1.3222215299530321E-05, 51 | "Value": 0.0036428777527120928 52 | } 53 | ], 54 | "Synapses": [ 55 | { 56 | "Id": "3c0e0f3f-beea-4754-af3d-4d00dca4c177", 57 | "OutputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 58 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 59 | "Weight": -4.9046816226955494, 60 | "WeightDelta": 0.0 61 | }, 62 | { 63 | "Id": "201ac151-36b6-403d-a543-d77c0076e99f", 64 | "OutputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 65 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 66 | "Weight": 5.85326693338921, 67 | "WeightDelta": 0.0 68 | }, 69 | { 70 | "Id": "b211a3a2-6deb-4411-8d51-2b47e22c4a10", 71 | "OutputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 72 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 73 | "Weight": 7.1642632394746659, 74 | "WeightDelta": 0.0 75 | }, 76 | { 77 | "Id": "12caa1a0-cadd-4996-bef8-0ac8d0b84768", 78 | "OutputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 79 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 80 | "Weight": 7.4919359894962705, 81 | "WeightDelta": 0.0 82 | }, 83 | { 84 | "Id": "6469fb62-f273-4940-9eb2-b62323a1af0d", 85 | "OutputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 86 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 87 | "Weight": 6.1679853662708544, 88 | "WeightDelta": 0.0 89 | }, 90 | { 91 | "Id": "ac471b71-9850-4e16-acbb-bb650aa57de3", 92 | "OutputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 93 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 94 | "Weight": -2.6579877134228087, 95 | "WeightDelta": 0.0 96 | }, 97 | { 98 | "Id": "d1610867-c424-4588-a2d9-fdfea8135bb3", 99 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 100 | "InputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 101 | "Weight": -9.5047366120987249, 102 | "WeightDelta": -4.4338666730127679E-06 103 | }, 104 | { 105 | "Id": "4ca55472-aaa0-421c-993d-7e6b40ceb2a6", 106 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 107 | "InputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 108 | "Weight": 10.58506658726629, 109 | "WeightDelta": -1.1124339511556304E-06 110 | }, 111 | { 112 | "Id": "ab233d80-e39a-4033-bba1-afbc96696cef", 113 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 114 | "InputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 115 | "Weight": -9.5151417793873545, 116 | "WeightDelta": -2.0832901719451647E-06 117 | } 118 | ] 119 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neural Networks 2 | 3 | Introduction 4 | ------------ 5 | If this is your first foray into Neural Networks, welcome! I hope you enjoy yourself as much as I have. 6 | 7 | This project is an attempt at creating an application that allows for quick interactions with a basic neural network. 8 | 9 | This project is written in C# and uses C# 6.0 Syntax. You will need an environment that is capable of compiling the C# 6.0 syntax in order to use this program. 10 | 11 | ![Alt text](ScreenShot.PNG?raw=true "Optional Title") 12 | 13 | What is a Neural Network? 14 | ----- 15 | Great question! 16 | 17 | A Neural Network can be thought of as a series of nodes (or neurons) that are interconnected, much like they are in the brain. The network can have any number (N) of inputs and any number (M) of outputs. In between the inputs and outputs are a series of "hidden" neurons that make up the hidden layers of the network. These hidden layers provide the meat of the network and allow for some of the neat functionalities we can get out of a Neural Network. 18 | 19 | What are the Parts of a Neural Network? 20 | -------- 21 | Before explaining the pieces of a neural network, it might be helpful to start with an example. 22 | 23 | Building off of [this excellent article from 2013](http://www.codingvision.net/miscellaneous/c-backpropagation-tutorial-xor), let's use the concept of Exclusive Or (XOR). XOR will output true when the inputs differ: 24 | 25 | | Input A | Input B | Output | 26 | |:-----:|:---------:|:-----:| 27 | | false | false | false | 28 | | false | true | true | 29 | | true | false | true | 30 | | true | true | false | 31 | 32 | Considering this, let's break down a Neural Network into its three basic parts: 33 | 34 | 1. The Inputs 35 | * These are the inputs into the Neural Network. From the XOR example above, the inputs would be Input A and Input B. 36 | * Each input can be considered a Neuron whose output is the initial input value. 37 | 2. The Hidden Layers 38 | * This is the meat of the Neural Network. This is where the magic happens. The Neurons in this layer are assigned weights for each of their inputs. These weights start off fairly random, but as the network is "trained" (discussed below), the weights are adjusted in order to make the neuron's output, and therefore the Neural Network's output closer to the expected result. 39 | 3. The Outputs 40 | * These are the outputs from the system. From the XOR example above, the output from the system would be either 'true' or 'false'. In the Neural Network, the Outputs are the last line of Neurons. These Neurons are also assigned a weight for each of their inputs and are "fed" by the Neurons in the hidden layer. 41 | 42 | Using the XOR example, if we were to give our Neural Network the inputs 'true' and 'false' we would expect the system to return 'true'. 43 | 44 | How Does it Work? 45 | ------- 46 | Because I love examples, here's another: 47 | 48 | | Input A | Input B | Input C | Output | 49 | |:-----:|:---------:|:-----:|:------| 50 | | true | false | false | true | 51 | | false | true | true | false | 52 | | true | fase | true | false | 53 | | true | true | true | true | 54 | 55 | In the above table, we can infer the following patterns: 56 | 57 | 1. The output is true if the number of inputs set to true is odd OR the number of inputs set to false is even. 58 | 2. The output is false if the number of inputs set to true is even OR the number of inputs set to false is odd. 59 | 60 | The job of the Neural Network is to try and figure out that pattern. It does this via training. 61 | 62 | #### How Do We Train the Neural Network? 63 | 64 | Training the Neural Network is accomplished by giving it a set of input data and the expected results for those inputs. This data is then continuously run through the Neural Network until we can be reasonably sure that it has a grasp of the patterns present in that data. 65 | 66 | In this project, the Neural Network is trained via the following common Neural Network training methods: 67 | 68 | 1. Back-Propagation 69 | * After each set of inputs is run through the system and an output generated, that output is validated against the expected output. 70 | * The percentage of error that results is then propagated backwards (hence the name) through the Hidden Layers of the Neural Network. This adjusts the weights assigned to each of a neuron's inputs in the Hidden Layers. 71 | * Ideally, each Back-Propagation will bring the Neural Network's output closer to the expected output of the provided inputs. 72 | 2. Biases 73 | * Biases allow us to modify our activation function (discussed below) in order to generate a better output for each neuron. 74 | * [See Here](http://stackoverflow.com/questions/2480650/role-of-bias-in-neural-networks) for an excellent explanation as to what a bias does for a Neural Network. 75 | 3. Momentum 76 | * Used to prevent the system from converging to a local minimum. 77 | * [See Here](https://en.wikibooks.org/wiki/Artificial_Neural_Networks/Neural_Network_Basics#Momentum) 78 | 4. Learning Rate 79 | * This will change the overall learning speed of the system. 80 | * [See Here](https://en.wikibooks.org/wiki/Artificial_Neural_Networks/Neural_Network_Basics#Learning_Rate) 81 | 82 | #### What defines a Neuron's Output? 83 | 84 | A Neuron's output is defined by an [Activation Function](https://en.wikipedia.org/wiki/Activation_function). 85 | 86 | In our case, we are using a [Sigmoid Function](https://en.wikipedia.org/wiki/Sigmoid_function) to define each Neuron's output. The Sigmoid function will convert any value to a value between 0 and 1. In the Neural Network, the Sigmoid functions will be used to generate initial weights and to help update percent errors. 87 | 88 | How Do I Use this Program? 89 | ------ 90 | This program is fairly simple to use and is divided into 3 main menus and a couple sub menus. 91 | 92 | 1. Main Menu 93 | * New Network - Manually input a network's configuration. 94 | * Import Network - Import a network configuration. (See JSON formatting section below) 95 | * Exit - Exit the program 96 | 2. Dataset Menu 97 | * Type Dataset - Manually input datasets to be used. 98 | * Import Dataset - Import a Dataset configuration. 99 | * Test Network - Test the current network by typing in inputs. 100 | * Export Network - Export the current network. (See JSON formatting section below) 101 | * Main Menu - Go back to the Main Menu. 102 | * Exit - Exit the program 103 | 3. Network Menu 104 | * Train Network - Train the current network based on parameters you give. 105 | * Test Network - Test the current network by typing in inputs. 106 | * Export Network - Export the current network. (See JSON formatting section below) 107 | * Export Dataset - Export the current dataset. 108 | * Dataset Menu - Go back to the Dataset Menu. 109 | * Main Menu - Go back to the Main Menu. 110 | * Exit - Exit the program 111 | 112 | 113 | Suggested Neural Net JSON Formatting Standard 114 | ----- 115 | As of yet, I haven't seen a standard serialized format for a Neural Network. In an effort to implement importing and exporting within this program, I wrote a standardized format for the Neural Network so that a network exported from this program could be imported into another one with ease. I imagine it will change a bit over time, but for now, this seems to work well. It's simple and hopefully transferrable. 116 | 117 | Here's an example network that has been exported and can be re-imported into this program. There are examples of this ("NetworkExample.txt") and a serialized Dataset ("DatasetExample.txt") inside of the DataExamples directory. 118 | ```javascript 119 | { 120 | "LearnRate": 0.4, 121 | "Momentum": 0.9, 122 | "InputLayer": [ 123 | { 124 | "Id": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 125 | "Bias": 0.88011651853104889, 126 | "BiasDelta": 0.0, 127 | "Gradient": 0.0, 128 | "Value": 0.0 129 | }, 130 | { 131 | "Id": "fcf15808-fb11-4a04-9022-638140164c64", 132 | "Bias": -0.12904600665394495, 133 | "BiasDelta": 0.0, 134 | "Gradient": 0.0, 135 | "Value": 0.0 136 | } 137 | ], 138 | "HiddenLayers": [ 139 | [ 140 | { 141 | "Id": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 142 | "Bias": 1.6459098726963641, 143 | "BiasDelta": 6.8129688749504508E-06, 144 | "Gradient": 1.7032422187376126E-05, 145 | "Value": 0.83833657457730759 146 | }, 147 | { 148 | "Id": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 149 | "Bias": -1.3229172632409467, 150 | "BiasDelta": -9.2984227388283447E-06, 151 | "Gradient": -2.3246056847070861E-05, 152 | "Value": 0.21033426055222876 153 | }, 154 | { 155 | "Id": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 156 | "Bias": -0.43095589580981947, 157 | "BiasDelta": 1.2014607576953927E-05, 158 | "Gradient": 3.0036518942384814E-05, 159 | "Value": 0.39389960849056194 160 | } 161 | ] 162 | ], 163 | "OutputLayer": [ 164 | { 165 | "Id": "9c096f95-800c-435b-9ee9-5af125abc8b3", 166 | "Bias": 3.8785304867945971, 167 | "BiasDelta": -5.2888861198121289E-06, 168 | "Gradient": -1.3222215299530321E-05, 169 | "Value": 0.0036428777527120928 170 | } 171 | ], 172 | "Synapses": [ 173 | { 174 | "Id": "3c0e0f3f-beea-4754-af3d-4d00dca4c177", 175 | "OutputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 176 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 177 | "Weight": -4.9046816226955494, 178 | "WeightDelta": 0.0 179 | }, 180 | { 181 | "Id": "201ac151-36b6-403d-a543-d77c0076e99f", 182 | "OutputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 183 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 184 | "Weight": 5.85326693338921, 185 | "WeightDelta": 0.0 186 | }, 187 | { 188 | "Id": "b211a3a2-6deb-4411-8d51-2b47e22c4a10", 189 | "OutputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 190 | "InputNeuronId": "f1fea97c-48ba-4e1b-b7eb-fe9d1897758c", 191 | "Weight": 7.1642632394746659, 192 | "WeightDelta": 0.0 193 | }, 194 | { 195 | "Id": "12caa1a0-cadd-4996-bef8-0ac8d0b84768", 196 | "OutputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 197 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 198 | "Weight": 7.4919359894962705, 199 | "WeightDelta": 0.0 200 | }, 201 | { 202 | "Id": "6469fb62-f273-4940-9eb2-b62323a1af0d", 203 | "OutputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 204 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 205 | "Weight": 6.1679853662708544, 206 | "WeightDelta": 0.0 207 | }, 208 | { 209 | "Id": "ac471b71-9850-4e16-acbb-bb650aa57de3", 210 | "OutputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 211 | "InputNeuronId": "fcf15808-fb11-4a04-9022-638140164c64", 212 | "Weight": -2.6579877134228087, 213 | "WeightDelta": 0.0 214 | }, 215 | { 216 | "Id": "d1610867-c424-4588-a2d9-fdfea8135bb3", 217 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 218 | "InputNeuronId": "2cc0c76b-1c40-4c72-803f-97c0997bcc07", 219 | "Weight": -9.5047366120987249, 220 | "WeightDelta": -4.4338666730127679E-06 221 | }, 222 | { 223 | "Id": "4ca55472-aaa0-421c-993d-7e6b40ceb2a6", 224 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 225 | "InputNeuronId": "aeacc65b-101d-4a94-b9cc-ab008a36dfee", 226 | "Weight": 10.58506658726629, 227 | "WeightDelta": -1.1124339511556304E-06 228 | }, 229 | { 230 | "Id": "ab233d80-e39a-4033-bba1-afbc96696cef", 231 | "OutputNeuronId": "9c096f95-800c-435b-9ee9-5af125abc8b3", 232 | "InputNeuronId": "fda1a91b-cb45-4fb0-9d58-b3571ef88777", 233 | "Weight": -9.5151417793873545, 234 | "WeightDelta": -2.0832901719451647E-06 235 | } 236 | ] 237 | } 238 | ``` 239 | 240 | What's Next? 241 | --- 242 | I'm not a fan of the current menu system, so that will probably be next along with a bunch of error handling. 243 | 244 | Code Considerations 245 | --- 246 | This project is licensed under the terms of the MIT license. 247 | 248 | #### Reusability 249 | The Network and its supporting classes are self-contained, meaning that the "UI" portion of the program only serves to gather the necessary information to instantiate the Network object and its supporting classes. You could theoretically take the Network and supporting classes and bring it into your own application with little to no modification. The network only requires the number of inputs, number of hidden neurons, the number of outputs and (optionally) a specified learning rate and momentum. 250 | 251 | #### You Code Funny... 252 | Hopefully my code is readable and and reusable for you. I put a lot of effort into maintaining best practices. It's a learning process and I welcome critique. 253 | 254 | Resources 255 | ----- 256 | 257 | I used a few resources while building this project. I'm super thankful for those who have done a lot of work previously. 258 | 259 | [I am Trask - A Neural Network in 11 Lines of Python](http://iamtrask.github.io/2015/07/12/basic-python-network/) - This piqued my intrest in Neural Networks when it popped up on Reddit recently. 260 | 261 | [The Nature of Code - Chapter 10: Neural Networks](http://natureofcode.com/book/chapter-10-neural-networks/) - This was often able to answer some of my questions and made for a great read. 262 | 263 | [C# Backpropagation Tutorial](http://www.codingvision.net/miscellaneous/c-backpropagation-tutorial-xor) - This was the initial C# project I looked at. I took and modified a few elements that I really liked such as the Sigmoid and Neuron classes. 264 | 265 | [A Step by Step Backpropagation Example](http://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/) - This was an excellent explanation of Back-Propagation and helped me tremendously with some of the math involved. 266 | 267 | [Coding Neural Network Back-Propagation Using C#](https://visualstudiomagazine.com/Articles/2015/04/01/Back-Propagation-Using-C.aspx?Page=1) - This was another great C# example. Dr. James McCaffrey (the author) has a lot of great insights in this article and others that he has written on the subject. 268 | 269 | [Simple C# Artificial Neural Network](http://www.craigsprogramming.com/2014/01/simple-c-artificial-neural-network.html) - This article played a large role in the November 2015 refactoring. This convinced me to get rid of the layer class altogether and helped clean up the network training code. 270 | -------------------------------------------------------------------------------- /NeuralNetwork/NeuralNetwork/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NeuralNetwork.Helpers; 5 | using NeuralNetwork.NetworkModels; 6 | 7 | namespace NeuralNetwork 8 | { 9 | internal class Program 10 | { 11 | #region -- Variables -- 12 | private static int _numInputParameters; 13 | private static int _numHiddenLayers; 14 | private static int[] _hiddenNeurons; 15 | private static int _numOutputParameters; 16 | private static Network _network; 17 | private static List _dataSets; 18 | #endregion 19 | 20 | #region -- Main -- 21 | [STAThread] 22 | private static void Main() 23 | { 24 | Greet(); 25 | InitialMenu(); 26 | } 27 | #endregion 28 | 29 | #region -- Network Setup -- 30 | private static void Greet() 31 | { 32 | Console.WriteLine("C# Neural Network Manager"); 33 | Console.WriteLine("Created by Trent Sartain (trentsartain on GitHub)"); 34 | PrintUnderline(50); 35 | PrintNewLine(); 36 | } 37 | 38 | private static void InitialMenu() 39 | { 40 | Console.WriteLine("Main Menu"); 41 | PrintUnderline(50); 42 | Console.WriteLine("\t1. New Network"); 43 | Console.WriteLine("\t2. Import Network"); 44 | Console.WriteLine("\t3. Exit"); 45 | PrintNewLine(); 46 | 47 | switch (GetInput("\tYour Choice: ", 1, 3)) 48 | { 49 | case 1: 50 | if (SetupNetwork()) DatasetMenu(); 51 | else InitialMenu(); 52 | break; 53 | case 2: 54 | ImportNetwork(); 55 | DatasetMenu(); 56 | break; 57 | case 3: 58 | Exit(); 59 | break; 60 | } 61 | } 62 | 63 | private static void DatasetMenu() 64 | { 65 | Console.WriteLine("Dataset Menu"); 66 | PrintUnderline(50); 67 | Console.WriteLine("\t1. Type Dataset"); 68 | Console.WriteLine("\t2. Import Dataset"); 69 | Console.WriteLine("\t3. Test Network"); 70 | Console.WriteLine("\t4. Export Network"); 71 | Console.WriteLine("\t5. Main Menu"); 72 | Console.WriteLine("\t6. Exit"); 73 | PrintNewLine(); 74 | 75 | switch (GetInput("\tYour Choice: ", 1, 6)) 76 | { 77 | case 1: 78 | if (GetTrainingData()) NetworkMenu(); 79 | else DatasetMenu(); 80 | break; 81 | case 2: 82 | ImportDatasets(); 83 | NetworkMenu(); 84 | break; 85 | case 3: 86 | TestNetwork(); 87 | DatasetMenu(); 88 | break; 89 | case 4: 90 | ExportNetwork(); 91 | DatasetMenu(); 92 | break; 93 | case 5: 94 | InitialMenu(); 95 | break; 96 | case 6: 97 | Exit(); 98 | break; 99 | } 100 | } 101 | 102 | private static void NetworkMenu() 103 | { 104 | Console.WriteLine("Network Menu"); 105 | PrintUnderline(50); 106 | Console.WriteLine("\t1. Train Network"); 107 | Console.WriteLine("\t2. Test Network"); 108 | Console.WriteLine("\t3. Export Network"); 109 | Console.WriteLine("\t4. Export Dataset"); 110 | Console.WriteLine("\t5. Dataset Menu"); 111 | Console.WriteLine("\t6. Main Menu"); 112 | Console.WriteLine("\t7. Exit"); 113 | PrintNewLine(); 114 | 115 | switch (GetInput("\tYour Choice: ", 1, 7)) 116 | { 117 | case 1: 118 | Train(); 119 | NetworkMenu(); 120 | break; 121 | case 2: 122 | TestNetwork(); 123 | NetworkMenu(); 124 | break; 125 | case 3: 126 | ExportNetwork(); 127 | NetworkMenu(); 128 | break; 129 | case 4: 130 | ExportDatasets(); 131 | NetworkMenu(); 132 | break; 133 | case 5: 134 | DatasetMenu(); 135 | break; 136 | case 6: 137 | InitialMenu(); 138 | break; 139 | case 7: 140 | Exit(); 141 | break; 142 | } 143 | } 144 | 145 | private static bool SetupNetwork() 146 | { 147 | PrintNewLine(); 148 | Console.WriteLine("Network Setup"); 149 | PrintUnderline(50); 150 | SetNumInputParameters(); 151 | if (_numInputParameters == 0) return false; 152 | SetNumNeuronsInHiddenLayer(); 153 | if (_numHiddenLayers == 0) return false; 154 | SetNumOutputParameters(); 155 | if (_numOutputParameters == 0) return false; 156 | 157 | Console.WriteLine("\tCreating Network..."); 158 | _network = new Network(_numInputParameters, _hiddenNeurons, _numOutputParameters); 159 | Console.WriteLine("\t**Network Created!**"); 160 | PrintNewLine(); 161 | return true; 162 | } 163 | 164 | private static void SetNumInputParameters() 165 | { 166 | Console.WriteLine("\tHow many input parameters will there be? (2 or more)"); 167 | _numInputParameters = GetInput("\tInput Parameters: ", 2, int.MaxValue) ?? 0; 168 | PrintNewLine(2); 169 | } 170 | 171 | private static void SetNumNeuronsInHiddenLayer() 172 | { 173 | Console.WriteLine("\tHow many hidden layers? (1 or more)"); 174 | _numHiddenLayers = GetInput("\tHidden Layers: ", 1, int.MaxValue) ?? 0; 175 | 176 | Console.WriteLine("\tHow many neurons in the hidden layers? (2 or more)"); 177 | _hiddenNeurons = GetArrayInput("\tNeurons in layer", 2, _numHiddenLayers); 178 | PrintNewLine(2); 179 | } 180 | 181 | private static void SetNumOutputParameters() 182 | { 183 | Console.WriteLine("\tHow many output parameters will there be? (1 or more)"); 184 | _numOutputParameters = GetInput("\tOutput Parameters: ", 1, int.MaxValue) ?? 0; 185 | PrintNewLine(2); 186 | } 187 | 188 | private static bool GetTrainingData() 189 | { 190 | PrintUnderline(50); 191 | Console.WriteLine("\tManually Enter the Datasets. Type 'menu' at any time to go back."); 192 | PrintNewLine(); 193 | 194 | var numDataSets = GetInput("\tHow many datasets are you going to enter? ", 1, int.MaxValue); 195 | 196 | var newDatasets = new List(); 197 | for (var i = 0; i < numDataSets; i++) 198 | { 199 | var values = GetInputData($"\tData Set {i + 1}: "); 200 | if (values == null) 201 | { 202 | PrintNewLine(); 203 | return false; 204 | } 205 | 206 | var expectedResult = GetExpectedResult($"\tExpected Result for Data Set {i + 1}: "); 207 | if (expectedResult == null) 208 | { 209 | PrintNewLine(); 210 | return false; 211 | } 212 | 213 | newDatasets.Add(new DataSet(values, expectedResult)); 214 | } 215 | 216 | _dataSets = newDatasets; 217 | PrintNewLine(); 218 | return true; 219 | } 220 | 221 | private static double[] GetInputData(string message) 222 | { 223 | Console.Write(message); 224 | var line = GetLine(); 225 | 226 | if (line.Equals("menu", StringComparison.InvariantCultureIgnoreCase)) return null; 227 | 228 | while (line == null || line.Split(' ').Length != _numInputParameters) 229 | { 230 | Console.WriteLine($"\t{_numInputParameters} inputs are required."); 231 | PrintNewLine(); 232 | Console.WriteLine(message); 233 | line = GetLine(); 234 | } 235 | 236 | var values = new double[_numInputParameters]; 237 | var lineNums = line.Split(' '); 238 | for (var i = 0; i < lineNums.Length; i++) 239 | { 240 | double num; 241 | if (double.TryParse(lineNums[i], out num)) 242 | { 243 | values[i] = num; 244 | } 245 | else 246 | { 247 | Console.WriteLine("\tYou entered an invalid number. Try again"); 248 | PrintNewLine(2); 249 | return GetInputData(message); 250 | } 251 | } 252 | 253 | return values; 254 | } 255 | 256 | private static double[] GetExpectedResult(string message) 257 | { 258 | Console.Write(message); 259 | var line = GetLine(); 260 | 261 | if (line != null && line.Equals("menu", StringComparison.InvariantCultureIgnoreCase)) return null; 262 | 263 | while (line == null || line.Split(' ').Length != _numOutputParameters) 264 | { 265 | Console.WriteLine($"\t{_numOutputParameters} outputs are required."); 266 | PrintNewLine(); 267 | Console.WriteLine(message); 268 | line = GetLine(); 269 | } 270 | 271 | var values = new double[_numOutputParameters]; 272 | var lineNums = line.Split(' '); 273 | for (var i = 0; i < lineNums.Length; i++) 274 | { 275 | int num; 276 | if (int.TryParse(lineNums[i], out num) && (num == 0 || num == 1)) 277 | { 278 | values[i] = num; 279 | } 280 | else 281 | { 282 | Console.WriteLine("\tYou must enter 1s and 0s!"); 283 | PrintNewLine(2); 284 | return GetExpectedResult(message); 285 | } 286 | } 287 | 288 | return values; 289 | } 290 | #endregion 291 | 292 | #region -- Network Training -- 293 | private static void TestNetwork() 294 | { 295 | Console.WriteLine("\tTesting Network"); 296 | Console.WriteLine("\tType 'menu' at any time to return to the previous menu."); 297 | PrintNewLine(); 298 | 299 | while (true) 300 | { 301 | PrintUnderline(50); 302 | var values = GetInputData($"\tType {_numInputParameters} inputs (or 'menu' to exit): "); 303 | if (values == null) 304 | { 305 | PrintNewLine(); 306 | return; 307 | } 308 | 309 | var results = _network.Compute(values); 310 | PrintNewLine(); 311 | 312 | foreach (var result in results) 313 | { 314 | Console.WriteLine($"\tOutput: {result}"); 315 | } 316 | 317 | PrintNewLine(); 318 | } 319 | } 320 | 321 | private static void Train() 322 | { 323 | Console.WriteLine("Network Training"); 324 | PrintUnderline(50); 325 | Console.WriteLine("\t1. Train to minimum error"); 326 | Console.WriteLine("\t2. Train to max epoch"); 327 | Console.WriteLine("\t3. Network Menu"); 328 | PrintNewLine(); 329 | switch (GetInput("\tYour Choice: ", 1, 3)) 330 | { 331 | case 1: 332 | var minError = GetDouble("\tMinimum Error: ", 0.000000001, 1.0); 333 | PrintNewLine(); 334 | Console.WriteLine("\tTraining..."); 335 | _network.Train(_dataSets, minError); 336 | Console.WriteLine("\t**Training Complete**"); 337 | PrintNewLine(); 338 | NetworkMenu(); 339 | break; 340 | case 2: 341 | var maxEpoch = GetInput("\tMax Epoch: ", 1, int.MaxValue); 342 | if (!maxEpoch.HasValue) 343 | { 344 | PrintNewLine(); 345 | NetworkMenu(); 346 | return; 347 | } 348 | PrintNewLine(); 349 | Console.WriteLine("\tTraining..."); 350 | _network.Train(_dataSets, maxEpoch.Value); 351 | Console.WriteLine("\t**Training Complete**"); 352 | PrintNewLine(); 353 | break; 354 | case 3: 355 | NetworkMenu(); 356 | break; 357 | } 358 | PrintNewLine(); 359 | } 360 | #endregion 361 | 362 | #region -- I/O Help -- 363 | private static void ImportNetwork() 364 | { 365 | PrintNewLine(); 366 | _network = ImportHelper.ImportNetwork(); 367 | if (_network == null) 368 | { 369 | WriteError("\t****Something went wrong while importing your network.****"); 370 | return; 371 | } 372 | 373 | _numInputParameters = _network.InputLayer.Count; 374 | _hiddenNeurons = new int[_network.HiddenLayers.Count]; 375 | _numOutputParameters = _network.OutputLayer.Count; 376 | 377 | Console.WriteLine("\t**Network successfully imported.**"); 378 | PrintNewLine(); 379 | } 380 | 381 | private static void ExportNetwork() 382 | { 383 | PrintNewLine(); 384 | Console.WriteLine("\tExporting Network..."); 385 | ExportHelper.ExportNetwork(_network); 386 | Console.WriteLine("\t**Exporting Complete!**"); 387 | PrintNewLine(); 388 | } 389 | 390 | private static void ImportDatasets() 391 | { 392 | PrintNewLine(); 393 | _dataSets = ImportHelper.ImportDatasets(); 394 | if (_dataSets == null) 395 | { 396 | WriteError("\t--Something went wrong while importing your datasets.--"); 397 | return; 398 | } 399 | 400 | if (_dataSets.Any(x => x.Values.Length != _numInputParameters || _dataSets.Any(y => y.Targets.Length != _numOutputParameters))) 401 | { 402 | WriteError($"\t--The dataset does not fit the network. Network requires datasets that have {_numInputParameters} inputs and {_numOutputParameters} outputs.--"); 403 | return; 404 | } 405 | 406 | Console.WriteLine("\t**Datasets successfully imported.**"); 407 | PrintNewLine(); 408 | } 409 | 410 | private static void ExportDatasets() 411 | { 412 | PrintNewLine(); 413 | Console.WriteLine("\tExporting Datasets..."); 414 | ExportHelper.ExportDatasets(_dataSets); 415 | Console.WriteLine("\t**Exporting Complete!**"); 416 | PrintNewLine(); 417 | } 418 | #endregion 419 | 420 | #region -- Console Helpers -- 421 | 422 | private static string GetLine() 423 | { 424 | var line = Console.ReadLine(); 425 | return line?.Trim() ?? string.Empty; 426 | } 427 | 428 | private static int? GetInput(string message, int min, int max) 429 | { 430 | Console.Write(message); 431 | var num = GetNumber(); 432 | if (!num.HasValue) return null; 433 | 434 | while (!num.HasValue || num < min || num > max) 435 | { 436 | Console.Write(message); 437 | num = GetNumber(); 438 | } 439 | 440 | return num.Value; 441 | } 442 | 443 | private static double GetDouble(string message, double min, double max) 444 | { 445 | Console.Write(message); 446 | var num = GetDouble(); 447 | 448 | while (num < min || num > max) 449 | { 450 | Console.Write(message); 451 | num = GetDouble(); 452 | 453 | } 454 | 455 | return num; 456 | } 457 | 458 | private static int[] GetArrayInput(string message, int min, int numToGet) 459 | { 460 | var nums = new int[numToGet]; 461 | 462 | for (var i = 0; i < numToGet; i++) 463 | { 464 | Console.Write(message + " " + (i + 1) + ": "); 465 | var num = GetNumber(); 466 | 467 | while (!num.HasValue || num < min) 468 | { 469 | Console.Write(message + " " + (i + 1) + ": "); 470 | num = GetNumber(); 471 | } 472 | 473 | nums[i] = num.Value; 474 | } 475 | 476 | return nums; 477 | } 478 | 479 | private static int? GetNumber() 480 | { 481 | int num; 482 | var line = GetLine(); 483 | 484 | if (line.Equals("menu", StringComparison.InvariantCultureIgnoreCase)) return null; 485 | 486 | return int.TryParse(line, out num) ? num : 0; 487 | } 488 | 489 | private static double GetDouble() 490 | { 491 | double num; 492 | var line = GetLine(); 493 | return line != null && double.TryParse(line, out num) ? num : 0; 494 | } 495 | 496 | 497 | private static void PrintNewLine(int numNewLines = 1) 498 | { 499 | for (var i = 0; i < numNewLines; i++) 500 | Console.WriteLine(); 501 | } 502 | 503 | private static void PrintUnderline(int numUnderlines) 504 | { 505 | for (var i = 0; i < numUnderlines; i++) 506 | Console.Write('-'); 507 | PrintNewLine(2); 508 | } 509 | 510 | private static void WriteError(string error) 511 | { 512 | Console.WriteLine(error); 513 | Exit(); 514 | } 515 | 516 | private static void Exit() 517 | { 518 | Console.WriteLine("Exiting..."); 519 | Console.ReadLine(); 520 | Environment.Exit(0); 521 | } 522 | #endregion 523 | } 524 | } 525 | --------------------------------------------------------------------------------