private static Task <Tuple <long, TrainedNework_Simple> > TrainAsync(Tuple <string, EncogOCR_SketchData[]>[] sketches, long token, bool shouldGenerateGarbage, CancellationTokenSource cancel) { CancellationToken cancelToken = cancel.Token; return(Task.Run(() => { string[] outputMap = sketches. Select(o => o.Item1). ToArray(); int inputSize = sketches[0].Item2[0].NNInput.Length; #region Training Data List <double[]> inputs = new List <double[]>(); List <double[]> outputs = new List <double[]>(); int groupIndex = 0; foreach (var group in sketches) { double[] output = Enumerable.Range(0, outputMap.Length). Select((o, i) => i == groupIndex ? 1d : 0d). ToArray(); foreach (var input in group.Item2) { inputs.Add(input.NNInput); outputs.Add(output); } groupIndex++; } if (shouldGenerateGarbage) { GenerateGarbageData(sketches.SelectMany(o => o.Item2).ToArray(), outputMap.Length, inputs, outputs); } #endregion //NOTE: If there is an exception, the network couldn't be trained BasicNetwork network = null; try { network = UtilityEncog.GetTrainedNetwork2(inputs.ToArray(), outputs.ToArray(), 20, 300, cancelToken).NetworkOrNull; } catch (Exception) { } var returnProps = new TrainedNework_Simple() { InputSize = inputSize, Outputs = outputMap, Network = network, }; return Tuple.Create(token, returnProps); }, cancelToken)); }
private static Visual3D TestSamples_Draw(SketchSample[] sketches, double[] hues) { const double RADIUS = .5; const double DOTRADIUS = .035; #region Materials SpecularMaterial specular = new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("50FFFFFF")), 2); var material_Color = hues.Select(o => { ColorHSV color = new ColorHSV(o, 75, 75); MaterialGroup material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(color.ToRGB()))); material.Children.Add(specular); return(new { Color = color, Material = material }); }).ToArray(); ColorHSV color_Gray = new ColorHSV(0, 0, 50); MaterialGroup material_Gray = new MaterialGroup(); material_Gray.Children.Add(new DiffuseMaterial(new SolidColorBrush(color_Gray.ToRGB()))); material_Gray.Children.Add(specular); #endregion Model3DGroup group = new Model3DGroup(); foreach (SketchSample sketch in sketches) { int?matchIndex = UtilityEncog.IsMatch(sketch.NNOutput); Material material; if (matchIndex == null) { sketch.IsMatch = false; sketch.Color = color_Gray; material = material_Gray; } else { sketch.IsMatch = true; sketch.Color = material_Color[matchIndex.Value].Color; material = material_Color[matchIndex.Value].Material; } sketch.Position = Math3D.GetRandomVector_Spherical(RADIUS).ToPoint(); sketch.Translate_3DDot = new TranslateTransform3D(sketch.Position.ToVector()); // Geometry Model GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; geometry.Geometry = UtilityWPF.GetSphere_Ico(DOTRADIUS, 1, true); geometry.Transform = sketch.Translate_3DDot; group.Children.Add(geometry); } ModelVisual3D visual = new ModelVisual3D(); visual.Content = group; return(visual); }
/// <summary> /// Nearly identical to the above method, but the 4 corner values are shifted a bit /// </summary> private void btnXORPosNeg2_Click(object sender, RoutedEventArgs e) { try { _trainingData = null; _results = null; #region Training data int numDirtySteps; if (!int.TryParse(txtNumSteps2.Text, out numDirtySteps)) { MessageBox.Show("", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning); return; } double stepSize = 1d / numDirtySteps; double otherStepSize = stepSize / 6d; List <double[]> trainingInput = new List <double[]>(); List <double[]> trainingOutput = new List <double[]>(); // Good Values (pure) trainingInput.Add(new[] { 0d, 0d }); trainingOutput.Add(new[] { -1d }); trainingInput.Add(new[] { 1d, 0d }); trainingOutput.Add(new[] { 1d }); trainingInput.Add(new[] { 0d, 1d }); trainingOutput.Add(new[] { 1d }); trainingInput.Add(new[] { 1d, 1d }); trainingOutput.Add(new[] { -1d }); // Good Values (shifted) trainingInput.Add(new[] { otherStepSize, otherStepSize }); trainingOutput.Add(new[] { -1d }); trainingInput.Add(new[] { 1d - otherStepSize, otherStepSize }); trainingOutput.Add(new[] { 1d }); trainingInput.Add(new[] { otherStepSize, 1d - otherStepSize }); trainingOutput.Add(new[] { 1d }); trainingInput.Add(new[] { 1d - otherStepSize, 1d - otherStepSize }); trainingOutput.Add(new[] { -1d }); // Bad Values for (int cntr1 = 0; cntr1 <= numDirtySteps; cntr1++) { double dirtyValue1 = cntr1 * stepSize; for (int cntr2 = 0; cntr2 <= numDirtySteps; cntr2++) { if ((cntr1 == 0 || cntr1 == numDirtySteps) && (cntr2 == 0 || cntr2 == numDirtySteps)) { continue; } double dirtyValue2 = cntr2 * stepSize; trainingInput.Add(new[] { dirtyValue2, dirtyValue1 }); trainingOutput.Add(new[] { 0d }); trainingInput.Add(new[] { dirtyValue1, dirtyValue2 }); trainingOutput.Add(new[] { 0d }); } } _trainingData = GetDrawDataFromTrainingData(trainingInput.ToArray(), trainingOutput.ToArray()); #endregion BasicNetwork network = UtilityEncog.GetTrainedNetwork(trainingInput.ToArray(), trainingOutput.ToArray(), maxSeconds_PerAttempt: MAXSECONDSPER, maxSeconds_Total: MAXSECONDSTOTAL).NetworkOrNull; #region Test //NOTE: I initially ran a bunch of tests, but the network always returns exactly the same result when given the same inputs //var test = Enumerable.Range(0, 1000). // Select(o => new { In1 = _rand.Next(2), In2 = _rand.Next(2) }). var test = trainingInput. Select(o => new { In1 = Convert.ToInt32(o[0]), In2 = Convert.ToInt32(o[1]) }). Select(o => new { o.In1, o.In2, Expected = XORPosNeg(o.In1, o.In2), NN = CallNN(network, o.In1, o.In2), }). Select(o => new { o.In1, o.In2, o.Expected, o.NN, Error = Math.Abs(o.Expected - o.NN) }). OrderByDescending(o => o.Error). ToArray(); #endregion #region Test intermediate values // It was only trained with inputs of 0 and 1. Let's see what it does with values in between var intermediates = Enumerable.Range(0, 1000). Select(o => new { In1 = _rand.NextDouble(), In2 = _rand.NextDouble() }). Select(o => new { o.In1, o.In2, NN = CallNN(network, o.In1, o.In2), }). //OrderBy(o => o.In1). //ThenBy(o => o.In2). OrderBy(o => o.NN). ToArray(); #endregion #region Store results double[] matchValues = new[] { -1d, 1d }; double matchRange = .06; //+- 5% of target value would be considered a match _results = intermediates. Select(o => Tuple.Create(new Point(o.In1, o.In2), o.NN, IsMatch(o.NN, matchValues, matchRange))). ToArray(); #endregion } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } finally { RedrawResults(); } }
private void RecognizeImage() { const string BORDER_STAND = "mildBorder"; const string BORDER_FOUND = "validGuessBorder"; lblCurrentGuess.Text = ""; pnlCurrentGuess.Style = (Style)this.Resources[BORDER_STAND]; grdGuessDetails.Children.Clear(); grdGuessDetails.RowDefinitions.Clear(); if (_network == null || _currentSketch == null || _currentSketch.NNInput.Length != _network.InputSize) { return; } // Recognize double[] output = _network.Network.Compute(_currentSketch.NNInput); var allOutputs = output. Select((o, i) => new { Value = o, Index = i, Name = _network.Outputs[i] }). OrderByDescending(o => o.Value). ToArray(); #region Show results Brush percentStroke = new SolidColorBrush(UtilityWPF.ColorFromHex("60000000")); Brush percentFill = new SolidColorBrush(UtilityWPF.ColorFromHex("30000000")); foreach (var outputEntry in allOutputs) { grdGuessDetails.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) }); // Name TextBlock outputText = new TextBlock() { Text = outputEntry.Name, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center, }; Grid.SetColumn(outputText, 0); Grid.SetRow(outputText, grdGuessDetails.RowDefinitions.Count - 1); grdGuessDetails.Children.Add(outputText); // % background Rectangle rectPerc = new Rectangle() { Height = 20, Width = outputEntry.Value * 100, HorizontalAlignment = HorizontalAlignment.Left, Fill = percentFill, }; Grid.SetColumn(rectPerc, 2); Grid.SetRow(rectPerc, grdGuessDetails.RowDefinitions.Count - 1); grdGuessDetails.Children.Add(rectPerc); // % border rectPerc = new Rectangle() { Height = 20, Width = 100, HorizontalAlignment = HorizontalAlignment.Left, Stroke = percentStroke, StrokeThickness = 1, }; Grid.SetColumn(rectPerc, 2); Grid.SetRow(rectPerc, grdGuessDetails.RowDefinitions.Count - 1); grdGuessDetails.Children.Add(rectPerc); // % text TextBlock outputPerc = new TextBlock() { Text = Math.Round(outputEntry.Value * 100).ToString(), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, }; Grid.SetColumn(outputPerc, 2); Grid.SetRow(outputPerc, grdGuessDetails.RowDefinitions.Count - 1); grdGuessDetails.Children.Add(outputPerc); } #endregion #region Show final guess //int? matchIndex = UtilityEncog.IsMatch(allOutputs.Select(o => o.Value).ToArray()); int?matchIndex = UtilityEncog.IsMatch(allOutputs.Select(o => o.Value).ToArray(), .4, .51); // when using softmax, the threshold needs to be lower if (matchIndex != null) { lblCurrentGuess.Text = allOutputs[matchIndex.Value].Name; pnlCurrentGuess.Style = (Style)this.Resources[BORDER_FOUND]; } else { lblCurrentGuess.Text = ""; pnlCurrentGuess.Style = (Style)this.Resources[BORDER_STAND]; } #endregion }
/// <summary> /// Call this if a new dot is added, or if the network gets swapped out /// NOTE: EnsureDotCreated needs to be called first /// </summary> private void ReconstructDot(Dot dot) { if (_dots == null) { return; } #region Remove Existing // Remove distances _dots.Distances_Input.RemoveAll(o => o.Item1.Token == dot.Token || o.Item2.Token == dot.Token); _dots.Distances_Output.RemoveAll(o => o.Item1.Token == dot.Token || o.Item2.Token == dot.Token); // Remove the 3D dot from visual if (dot.Geometry_3DDot != null) { _dots.ModelGroup.Children.Remove(dot.Geometry_3DDot); dot.Geometry_3DDot = null; dot.Translate_3DDot = null; } // Remove the 2D visual dot.Image = null; #endregion if (_network == null || _networkInputs == null || _networkOutputs == null) { return; } #region Test against network if (dot.VectorSource != null) { // Make sure the input is correct dot.VectorSource.GenerateBitmap(_networkInputs.ImageHeightWidth); dot.NNInput = dot.VectorSource.NNInput; } if (dot.NNInput == null || dot.NNInput.Length != _networkInputs.Size) { return; } // Run it through the network dot.NNOutput = _network.Net.Network.Compute(dot.NNInput); #endregion #region Draw int?matchIndex = UtilityEncog.IsMatch(dot.NNOutput); // Material Material material; if (matchIndex == null) { dot.IsMatch = false; dot.Color = _networkOutputs.ColorGray; material = _networkOutputs.DotGray; } else { dot.IsMatch = true; dot.Color = _networkOutputs.DotColors[matchIndex.Value].Item1; material = _networkOutputs.DotColors[matchIndex.Value].Item2; } dot.Translate_3DDot = new TranslateTransform3D(dot.Position.ToVector()); // Geometry dot.Geometry_3DDot = new GeometryModel3D() { Material = material, BackMaterial = material, Geometry = UtilityWPF.GetSphere_Ico(DOTRADIUS, 1, true), Transform = dot.Translate_3DDot, }; _dots.ModelGroup.Children.Add(dot.Geometry_3DDot); #endregion #region Distances var inputs = new List <Tuple <Dot, Dot, double> >(); var outputs = new List <Tuple <Dot, Dot, double> >(); foreach (Dot other in _dots.Dots.Where(o => o.Token != dot.Token && o.NNInput != null && o.NNOutput != null)) // when the network gets reset, it sets all the dots' NNInput/Output to null. Then goes through each dot and reconstructs. So if I/O is null, it just hasn't been reconstructed yet { double distance = (dot.NNInput.ToVectorND() - other.NNInput.ToVectorND()).Length * _networkInputs.DistanceMult; inputs.Add(Tuple.Create(dot, other, distance)); distance = (dot.NNOutput.ToVectorND() - other.NNOutput.ToVectorND()).Length * _networkOutputs.DistanceMult; outputs.Add(Tuple.Create(dot, other, distance)); } _dots.Distances_Input.AddRange(inputs); _dots.Distances_Output.AddRange(outputs); #endregion }