new double[]{0.2, 0.7} => new NeuralTask { Preview = new double[]{0.25, 0,75, 1}, Input=new double[] {0,1,1,1}, Output=new double[]{1}}
var Convertion = (double[] random, double value) => { var input = new double[]{Math.Floor(random [0]*0x4)/0x4, Math.Floor(random [1]*0x4)/0x4}, byte x = (byte)(input[0] * 4); byte y = (byte)(input[1] * 4); int res = (y > value * 4 ? 1 : 0); return new NeuralTask() { input = new double[4]{ (x&2)>>1, x&1, (y&2)>>1, y&1}, output = new double[1] { res }, preview = new double[3] { input[0], input[1], res } }; };
public class Synaps { private double weight; /// <summary> </summary> virtual public double Weight { get { return weight; } set { if (weight != value) { weight = value; if (axon != null) ChangeActionPotentialHandler(axon.ActionPotential); } } } /// <summary> . , , , , .</summary> private IAxon axon; // , . public IAxon Axon { get { return axon; } set { // , . if (axon != null) axon.RemoveChangeActionPotentialHandler(ChangeActionPotentialHandler); axon = value; if (axon != null) { axon.AddChangeActionPotentialHandler(ChangeActionPotentialHandler); ChangeActionPotentialHandler(axon.ActionPotential); } } } public double ActionPotential; /// <summary> , .</summary> protected Action WhenActionPotentialhanged; public void AddActionPotentialChangeHandler(Action handler) { WhenActionPotentialhanged += handler; } public void RemoveActionPotentialChangeHandler(Action handler) { WhenActionPotentialhanged -= handler; } virtual protected void ChangeActionPotentialHandler(double axonActionPotential) { ActionPotential = axonActionPotential * weight; // , . if (WhenActionPotentialhanged != null) WhenActionPotentialhanged); // } }
public interface IAxon { /// <summary> .</summary> double ActionPotential { get; } /// <summary> .</summary> void AddChangeActionPotentialHandler(Action<double> handler); void RemoveChangeActionPotentialHandler(Action<double> handler); /// <summary>, .</summary> PointF Position { get; set; } /// <summary> .</summary> string Name { get; set; } }
public class SensoryNeuron : IAxon { protected double actionPotential; public double ActionPotential { get { return actionPotential; } set { if (actionPotential != value) { actionPotential = value; if (WhenChangeActionPotential != null) WhenChangeActionPotential(actionPotential); } } } }
/// <summary> . </summary> public class Neuron : IAxon { /// <summary> , . , , .</summary> public Synaps[] Synapses = new Synaps[0]; /// <summary> , , .</summary> protected bool synapsPotentialChanged = false; /// <summary> . , , . </summary> public void AppendSinaps(Synaps target) { // . , , , , . Synapses = Synapses.Concat(new Synaps[1] { target }).ToArray(); target.AddActionPotentialChangeHandler(ChangeSynapsPotentialHandler); // . synapsPotentialChanged = true; } virtual protected void ChangeSynapsPotentialHandler() { synapsPotentialChanged = true; } /// <summary> . , .</summary> protected DTransferFunction transferFunctionDelegate; public virtual DTransferFunction TransferFunction { get { return transferFunctionDelegate; } set { transferFunctionDelegate = value; } } /// <summary> . </summary> public virtual void Excitation() { if (!synapsPotentialChanged) return; // synapsPotentialChanged = false; synapsPotentials = 0; for (int i = 0; i < Synapses.Length; i++) synapsPotentials += Synapses[i].ActionPotential; double newValue = transferFunctionDelegate(synapsPotentials); if (actionPotential != newValue) { // . , . actionPotential = newValue; if (WhenChangeActionPotential != null) WhenChangeActionPotential(actionPotential); } } }
/// <summary> . </summary> /// <param name="argument"> </param> /// <returns> </returns> public delegate double DTransferFunction(double argument); DTransferFunction BarrierTransferFunction = (double x) => x <= 0 ? 0 : 1;
abstract public class NeuralNetwork { /// <summary> </summary> public SensoryNeuron[] Input = new SensoryNeuron[0]; /// <summary> /// , . . /// , . /// </summary> public Neuron[] ExcitationOrder = new Neuron[0]; /// <summary> </summary> public Neuron[] Output = new Neuron[0]; /// <summary> , </summary> /// <param name="input"> - </param> /// <param name="output"> </param> abstract public void create(uint input, uint output); public void execute(double[] data) { // for (int i = 0; i < Input.Length && i < data.Length; i++) { Input[i].ActionPotential = data[i]; } for (int i = 0; i < ExcitationOrder.Length; i++) ExcitationOrder[i].Excitation(); } public double[] Result() { // return output.Select(s => s.ActionPotential).ToArray(); //TODO Linq . double[] res = new double[Output.Length]; for (int i = 0; i < res.Length; i++) res[i] = Output[i].ActionPotential; return res; } } public class PerceptronClassic : NeuralNetwork { // , public int neuronCountsOverSensoric = 15; // public int ANeuronSynapsCount; // public Neuron[] Layer; // override public void create(uint inputCount, uint outputCount) { rnd = rndSeed >= 0 ? new Random(rndSeed) : new Random(); // this.Input = new SensoryNeuron[inputCount]; for (int i = 0; i < inputCount; i++) Input[i] = new SensoryNeuron() {Name = "S" + i}; // - Layer = new Neuron[inputCount + neuronCountsOverSensoric]; for (int i = 0; i < Layer.Length; i++) { // Layer[i] = new RosenblattNeuron(); // SensoryNeuron[] sub = Input.OrderBy((cell) => rnd.NextDouble()).Take(ANeuronSynapsCount).ToArray(); // , for (int j = 0; j < sub.Length; j++) { Synaps s = new Synaps(); s.Axon = sub[j]; s.Weight = rnd.Next(2) * 2 - 1; Layer[i].AppendSinaps(s); } } // . for (int i = 0; i < Layer.Length; i++) Layer[i].Name = "A" + i; // - Output = new Neuron[outputCount]; for (int i = 0; i < Output.Length; i++) { Output[i] = new RosenblattNeuron(); Output[i].Name = "R" + i; // for (int j = 0; j < Layer.Length; j++) { Synaps s = new Synaps(); s.Axon = Layer[j]; Output[i].AppendSinaps(s); // 0 } } // int lastIndex = 0; ExcitationOrder = new Neuron[Layer.Length + Output.Length]; foreach (Neuron cell in Layer) ExcitationOrder[lastIndex++] = cell; foreach (Neuron cell in Output) ExcitationOrder[lastIndex++] = cell; } } /// <summary> .</summary> public class ErrorCorrection : LearningAlgorythm { // , override protected double LearnNet(double[] required) { double error = 0; for (int i = 0; i < required.Length && i < net.Output.Length; i++) { if (required[i] != net.Output[i].ActionPotential) { error += 1; // for (int j = 0; j < (net as PerceptronClassic).Layer.Length; j++) // , if ((net as PerceptronClassic).Layer[j].ActionPotential > 0) // foreach (RosenblattNeuron cell in net.Output) // , // – , , – . . cell.Synapses[j].Weight += required[i] <= 0 ? -1 : 1; } } return error; } /// <summary> </summary> public void LearnTasksSet() { if (data == null) { Console.WriteLine(" "); return; } data.Reset(); LearnedTaskSetsCount++; ErrorsInSet = LearnedTasksInSetCount = 0; int max = 1000; while (data.MoveNext() && --max >= 0) LearnCurrentTask(); // , . } /// <summary> .</summary> /// <param name="loops"> </param> public void LearnSetManyTimesUntilSuccess(int loops) { for (int i = 0; i < loops; i++) { LearnTasksSet(); if (ErrorsInSet == 0) { break; } } } }
Enumerable<NeuralTask>
and with each Enumerable<NeuralTask>
it rearranges points in a sequence in random order. /// <summary> . </summary> /// <param name="argument"> </param> /// <param name="funcResult"> , </param> /// <returns> .</returns> public delegate double DTransferFunctionDerivative(double argument, double funcResult);
DTransferFunction Function = (x) => Math.Tanh(x), DTransferFunctionDerivative Derivative = (x, th) => (1 - th) * (1 + th)
public class NeuronWithDerivative : Neuron { /// <summary> . .</summary> protected DTransferFunctionDerivative transferFunctionDerivativeDelegate; /// <summary></summary> override public DTransferFunctionDerivative TransferFunction { get { return transferFunctionDerivativeDelegate; } set { transferFunctionDerivativeDelegate = value; } } /// <summary> </summary> protected double actionPotentialDerivative = 0; /// <summary> .</summary> public double ActionPotentialDerivative { get { return actionPotentialDerivative; } } /// <summary> . , . .</summary> public double BackProprigationParametr = 0; public override void Excitation() { base.Excitation(); actionPotentialDerivative = transferFunctionDerivativeDelegate(synapsPotentials, actionPotential); } }
static class Tools { /// <summary> .</summary> /// <param name="source"> .</param> /// <param name="func">, .</param> public static void Each<SequenceType>(this IEnumerator<SequenceType> source, Action<SequenceType> func) { while (source.MoveNext()) func(source.Current); } /// <summary> .</summary> /// <param name="source"> .</param> /// <param name="func">, . - . . - .</param> public static void Each<SequenceType>(this IEnumerator<SequenceType> source, Action<SequenceType, int> func) { for (int i = 0; source.MoveNext(); i++) func(source.Current, i); } /// <summary> .</summary> /// <param name="source"> .</param> /// <param name="func">, .</param> public static void Each<SequenceType>(this IEnumerable<SequenceType> source, Action<SequenceType> func) { source.GetEnumerator().Each(func); } /// <summary> .</summary> /// <param name="source"> .</param> /// <param name="func">, . - . . - .</param> public static void Each<SequenceType>(this IEnumerable<SequenceType> source, Action<SequenceType, int> func) { source.GetEnumerator().Each(func); } }
// . public class RumelhartPerceptron : NeuralNetwork { /// <summary> . .</summary> DTransferFunctionDerivative TransferFunctionDerivative; /// <summary> , </summary> public int[] NeuronsCount = new int[0]; override public void create(uint input, uint output) { // . Input = (new SensoryNeuron[input]).Select((empty, index) => new SensoryNeuron(){Name = "S[" + index + "]"}).ToArray(); // Func<string, NeuronWithDerivative> create = (name) => { NeuronWithDerivative neuron = new NeuronWithDerivative(); neuron.Name = name; neuron.TransferFunction = TransferFunction; neuron.TransferFunctionDerivative = TransferFunctionDerivative; return neuron; }; Func<IAxon, Synaps> createSynaps = (axon) => { Synaps s = new Synaps(); s.Axon = axon; return s; }; /// <summary> </summary> // NeuronWithDerivative[][] Layers = NeuronsCount.Select((count, layer) => Enumerable.Range(0, count).Select(index => create("A[" + layer + "][" + index + "]")).ToArray()).ToArray(); // // Output = Enumerable.Range(0, (int)output).Select(index => create("R[" + index + "]")).ToArray(); // . Layers[0].Each(neuron => { Input.Select(createSynaps).Each(synaps => { neuron.AppendSinaps(synaps); }); }); // , , . Layers.Skip(1).Each((layer, layerIndex) => { layer.Each(neuron => { Layers[layerIndex].Select(createSynaps).Each(synaps => { neuron.AppendSinaps(synaps); }); }); }); // Output.Each(neuron => { Layers.Last().Select(createSynaps).Each(synaps => { neuron.AppendSinaps(synaps); }); }); // ExcitationOrder = Layers.SelectMany(layer => layer).Concat(Output).ToArray(); // -1 +1 Random rnd = new Random(); ExcitationOrder.Each(neuron => neuron.Synapses.Each(synaps => synaps.Weight = rnd.NextDouble() * 2 - 1)); } }
public class BackPropagationLearning : LearningAlgorythm { // , public double LearningSpeed = 0.01; override protected double LearnNet(double[] required) { double[] errors = net.Output.Select((neuron, index) => neuron.ActionPotential - required[index]).ToArray(); // . , . net.ExcitationOrder.Cast<NeuronWithDerivative>().Each(neuron => { neuron.BackProprigationParametr = 0; }); // BackProprigationParametr dE/dS[i] = dE/dO[i] * F'[i](S[i]) // . BP[i] = dE/dO[i] * F'[i] = 2*(O[i]-T[i])*F'[i]; net.Output.Cast<NeuronWithDerivative>().Each((neuron, index) => { neuron.BackProprigationParametr = 2 * errors[index] * neuron.ActionPotentialDerivative; }); // , BP[j] = SUM( dE/dO[i] * F'[i] * W[j,i] ) * F'[j] = SUM ( BP[i] * W[j,i] * F'[j]) net.ExcitationOrder.Reverse().Cast<NeuronWithDerivative>().Each(neuron => { neuron.Synapses.SkipWhile(synaps => !(synaps.Axon is NeuronWithDerivative)).Each(synaps => { (synaps.Axon as NeuronWithDerivative).BackProprigationParametr += neuron.BackProprigationParametr * (synaps.Axon as NeuronWithDerivative).ActionPotentialDerivative * synaps.Weight; }); }); // , delta W[i,j] = -speed * dE/dS[j] * X[i]; net.ExcitationOrder.Reverse().Cast<NeuronWithDerivative>().Each(neuron => { neuron.Synapses.Each(synaps => { synaps.Weight += -LearningSpeed * neuron.BackProprigationParametr * synaps.Axon.ActionPotential; }); }); // . ( , ). return errors.Select(e => e * e).Average(); } public void LearnSomeTime(int sek) { DateTime begin = DateTime.Now; while (TimeSpan.FromTicks(DateTime.Now.Ticks - begin.Ticks).Seconds < sek) { LearnTasksSet(); } } }
<rumelhart> <input> <SensoryNeuron name="S[0]" potential="0,0396039603960396"/> <SensoryNeuron name="S[1]" potential="0,232673267326733"/> </input> <excitationOrder> <Neuron name="A[0][0]" potential="1"> <synaps weight="999,800400355468" axon="S[0]" potential="39,5960554596225" /> <synaps weight="999,545226476388" axon="S[1]" potential="232,5674536851" /> </Neuron> <Neuron name="A[0][1]" potential="0,116342019068401"> <synaps weight="1,13712492177543" axon="S[0]" potential="0,0450346503673436" /> <synaps weight="0,308744483692756" axon="S[1]" potential="0,0718365877898986" /> </Neuron> <Neuron name="A[0][2]" potential="0,29693700450834"> <synaps weight="-0,0240967983057654" axon="S[0]" potential="-0,000954328645772886" /> <synaps weight="1,31992553337836" axon="S[1]" potential="0,307111386479124" /> </Neuron> <Neuron name="A[1][0]" potential="0,683083451961352"> <synaps weight="1,02404884109051" axon="A[0][0]" potential="1,02404884109051" /> <synaps weight="-0,649771926175146" axon="A[0][1]" potential="-0,0755957778251805" /> <synaps weight="-0,382508459201211" axon="A[0][2]" potential="-0,113580916074308" /> </Neuron> <Neuron name="A[1][1]" potential="0,0324886810522597"> <synaps weight="-0,404744328902586" axon="A[0][0]" potential="-0,404744328902586" /> <synaps weight="0,161865952018599" axon="A[0][1]" potential="0,0188318116762727" /> <synaps weight="1,40909563283595" axon="A[0][2]" potential="0,418412636280091" /> </Neuron> </excitationOrder> <output> <Neuron name="R[0]" potential="-0,707598983150799"> <synaps weight="-1,36308077548559" axon="A[1][0]" potential="-0,931097921420856" /> <synaps weight="1,50019153981243" axon="A[1][1]" potential="0,0487392444542643" /> </Neuron> </output> </rumelhart>
Source: https://habr.com/ru/post/219647/
All Articles