void Clustering() { pca = new PrincipalComponentAnalysis(); //pca pca.Learn(inputImgArray.ToArray()); var pcaRes = pca.Transform(inputImgArray.ToArray()); dn = new DistanceNetwork(pcaRes[0].Length, mainForm.closestSquareNumber(totalData)); som = new SOMLearning(dn); Console.WriteLine("Learning"); for (var i = 0; i < maxEpoch; i++) { var error = som.RunEpoch(pcaRes); if (error < errorGoal) { break; } if (i % 10 == 0) { Console.WriteLine($"Report Cluster error {i} : {error}"); } } dn.Save(savedDNNetwork); }
static void GenerateReport(Maze maze, List <Triplet> triplets, DistanceNetwork network) { foreach (Triplet t in triplets) { double[] x0 = OneHot(t.x0, maze.StatesCount, 1.0); double[] g = OneHot(t.g, maze.StatesCount, 1.0); double[] x1 = new double[maze.StatesCount]; //empty double[] input = x0.Concat(g).ToArray().Concat(x1).ToArray(); double[] output = network.Compute(input); int maxIndex = maze.StatesCount * 2; for (int i = 0; i < maze.StatesCount; i++) { if (output[maze.StatesCount * 2 + i] > output[maxIndex]) { maxIndex = maze.StatesCount * 2 + i; } } if (maxIndex != t.x1) { Console.WriteLine("Post training error on " + t.ToString()); Console.WriteLine("Predicted " + maxIndex + "(" + output[maxIndex].ToString("N2") + ")"); } } }
void SearchSolution() { // create network DistanceNetwork network = new DistanceNetwork(2, neurons); // set random generators range foreach (var neuron in network.Layers.SelectMany(layer => layer?.Neurons).Where(neuron => neuron != null)) { neuron.RandGenerator = new UniformContinuousDistribution(new Range(0, 1000)); } // create learning algorithm ElasticNetworkLearning trainer = new ElasticNetworkLearning(network); double fixedLearningRate = learningRate / 20; double driftingLearningRate = fixedLearningRate * 19; double[,] path = new double[neurons + 1, 2]; double[] input = new double[2]; int i = 0; while (!needToStop) { // update learning speed & radius trainer.LearningRate = driftingLearningRate * (iterations - i) / iterations + fixedLearningRate; trainer.LearningRadius = learningRadius * (iterations - i) / iterations; // set network input int currentCity = rand.Next(citiesCount); input[0] = map[currentCity, 0]; input[1] = map[currentCity, 1]; // run one training iteration trainer.Run(input); // show current path for (int j = 0; j < neurons; j++) { path[j, 0] = network.Layers[0].Neurons[j].Weights[0]; path[j, 1] = network.Layers[0].Neurons[j].Weights[1]; } path[neurons, 0] = network.Layers[0].Neurons[0].Weights[0]; path[neurons, 1] = network.Layers[0].Neurons[0].Weights[1]; chart.UpdateDataSeries("path", path); i++; SetText(currentIterationBox, i.ToString()); if (i >= iterations) { break; } } // enable settings controls EnableControls(true); }
public void somTraining() { double[][] input_data = new double[Data.instance.images.Count][]; for (int i = 0; i < images.Count; i++) { Bitmap image = new Bitmap(images[i]); image = preProcess(image); ImageToArray converter = new ImageToArray(0, 1); converter.Convert(image, out input_data[i]); } pca = new PrincipalComponentAnalysis(PrincipalComponentMethod.Center); pca.Learn(input_data); double[][] input_pca = pca.Transform(input_data); //o Clusters(Groups) Count: 4 som_network = new DistanceNetwork(input_pca[0].Count(), 4); som_learning = new SOMLearning(som_network); //o Error Goals: 0.001 //o Max Epochs: 100000 int maxIter = 100000; double maxError = 0.001; for (int i = 0; i < maxIter; i++) { double error = som_learning.RunEpoch(input_pca); if (error < maxError) { break; } } System.Windows.Forms.MessageBox.Show("SOM Training Complete"); }
static DistanceNetwork CreateSOM(string tagname) { int samples = 2 * 31 * 24; int retro = 3; var context = new TagDbContext(); var data = context.TagValues .Where(t => t.Tag.TagName == tagname) .OrderByDescending(v => v.DateTime) .Select(v => new double[] { (double)v.DateTime.Hour, (double)v.DateTime.DayOfWeek, v.Value }) .Take(samples + retrospective + 3) .AsEnumerable() .Reverse() .ToArray(); double[][] trainingSet = new double[data.Length][]; for (int index = 0; index < samples; index++) { trainingSet[index] = new double[] { data[index + 3][0], data[index + 3][1], data[index + 3][2], data[index + 2][2], data[index + 1][2], data[index][2] }; } var networkSize = 15; var iterations = 500; var learningRate = 0.3; var learningRadius = 3; Neuron.RandRange = new Range(0, 255); // create network DistanceNetwork network = new DistanceNetwork(2, networkSize * networkSize); // create learning algorithm SOMLearning trainer = new SOMLearning(network, networkSize, networkSize); // create map //map = new int[networkSize, networkSize, 3]; double fixedLearningRate = learningRate / 10; double driftingLearningRate = fixedLearningRate * 9; // iterations int i = 0; // loop while (true) { trainer.LearningRate = driftingLearningRate * (iterations - i) / iterations + fixedLearningRate; trainer.LearningRadius = (double)learningRadius * (iterations - i) / iterations; // run training epoch trainer.RunEpoch(trainingSet); // increase current iteration i++; // stop ? if (i >= iterations) { break; } } return(network); }
public void DistanceNetworkTest1() { string basePath = Path.Combine(NUnit.Framework.TestContext.CurrentContext.TestDirectory, "dn"); #region doc_example // Assure results are reproducible Accord.Math.Tools.SetupGenerator(0); int numberOfInputs = 3; int hiddenNeurons = 25; // Create some example inputs double[][] input = { new double[] { -1, -1, -1 }, new double[] { -1, 1, -1 }, new double[] { 1, -1, -1 }, new double[] { 1, 1, -1 }, new double[] { -1, -1, 1 }, new double[] { -1, 1, 1 }, new double[] { 1, -1, 1 }, new double[] { 1, 1, 1 }, }; // Create a new network var network = new DistanceNetwork(numberOfInputs, hiddenNeurons); // Create a teaching algorithm var teacher = new SOMLearning(network); // Use the teacher to learn the network double error = Double.PositiveInfinity; for (int i = 0; i < 10; i++) { error = teacher.RunEpoch(input); } string fileName = Path.Combine(basePath, "ann.bin"); // Save the network to a file path: Serializer.Save(network, fileName); // Load the network back from the stream DistanceNetwork target = Serializer.Load <DistanceNetwork>(fileName); #endregion // Make sure the network we loaded is exactly the same Assert.AreEqual(network.InputsCount, target.InputsCount); for (int i = 0; i < network.Layers.Length; i++) { Assert.AreEqual(network.Layers[i].InputsCount, target.Layers[i].InputsCount); for (int j = 0; j < network.Layers[i].Neurons.Length; j++) { Assert.AreEqual(network.Layers[i].Neurons[j].InputsCount, target.Layers[i].Neurons[j].InputsCount); Assert.AreEqual(network.Layers[i].Neurons[j].Weights, target.Layers[i].Neurons[j].Weights); } } }
/// <summary> /// Deserialization Constructor /// </summary> /// <param name="info"></param> /// <param name="ctxt"></param> public ElasticNetworkLearning(SerializationInfo info, StreamingContext ctxt) { //Get the values from info and assign them to the appropriate properties network = (DistanceNetwork)info.GetValue("network", typeof(DistanceNetwork)); distance = (double[])info.GetValue("distance", typeof(double[])); learningRate = (double)info.GetValue("learningRate", typeof(double)); learningRadius = (double)info.GetValue("learningRadius", typeof(double)); squaredRadius2 = (double)info.GetValue("squaredRadius2", typeof(double)); }
/// <summary> /// Deserialization Constructor /// </summary> /// <param name="info"></param> /// <param name="ctxt"></param> public SOMLearning(SerializationInfo info, StreamingContext ctxt) { //Get the values from info and assign them to the appropriate properties network = (DistanceNetwork)info.GetValue("network", typeof(DistanceNetwork)); width = (int)info.GetValue("width", typeof(int)); height = (int)info.GetValue("height", typeof(int)); learningRate = (double)info.GetValue("learningRate", typeof(double)); learningRadius = (double)info.GetValue("learningRadius", typeof(double)); squaredRadius2 = (double)info.GetValue("squaredRadius2", typeof(double)); }
// Worker thread void SearchSolution() { // create network DistanceNetwork network = new DistanceNetwork(2, networkSize * networkSize); // set random generators range foreach (var layer in network.Layers) { foreach (var neuron in layer.Neurons) { neuron.RandGenerator = new UniformContinuousDistribution( new Range(0, Math.Max(pointsPanel.ClientRectangle.Width, pointsPanel.ClientRectangle.Height))); } } // create learning algorithm SOMLearning trainer = new SOMLearning(network, networkSize, networkSize); // create map map = new int[networkSize, networkSize, 3]; double fixedLearningRate = learningRate / 10; double driftingLearningRate = fixedLearningRate * 9; // iterations int i = 0; // loop while (!needToStop) { trainer.LearningRate = driftingLearningRate * (iterations - i) / iterations + fixedLearningRate; trainer.LearningRadius = (double)learningRadius * (iterations - i) / iterations; // run training epoch trainer.RunEpoch(trainingSet); // update map UpdateMap(network); // increase current iteration i++; // set current iteration's info SetText(currentIterationBox, i.ToString()); // stop ? if (i >= iterations) { break; } } // enable settings controls EnableControls(true); }
public Form() { InitializeComponent(); rbCheck(); chartType(); Accord.Math.Random.Generator.Seed = 0; for (int i = 0; i < 101; i++) { Graph[i] = new Boolean[101]; Clusters[i] = new int[101]; for (int j = 0; j < 100; j++) { Graph[i][j] = false; Clusters[i][j] = 0; } } #region Инициализация персептрона /* * netAtt = new ActivationNetwork(new SigmoidFunction(0.2), Configuration[0], Configuration.Skip(1).ToArray()); * netAtt.ForEachWeight(z => rnd.NextDouble()); * teachAtt = new BackPropagationLearning(netAtt); * teachAtt.LearningRate = 1; * * netMed = new ActivationNetwork(new SigmoidFunction(0.2), Configuration[0], Configuration.Skip(1).ToArray()); * netMed.ForEachWeight(z => rnd.NextDouble()); * teachMed = new BackPropagationLearning(netMed); * teachMed.LearningRate = 1; * * network = new ActivationNetwork(new SigmoidFunction(6), Configuration[0], Configuration.Skip(1).ToArray()); * network.ForEachWeight(z => rnd.NextDouble()*2-1); * teacher = new BackPropagationLearning(network); * teacher.LearningRate = 1; */ #endregion network = new DistanceNetwork(2, NetworkWidth * NetworkHeight); for (int x = 0; x < NetworkWidth; x++) { for (int y = 0; y < NetworkHeight; y++) { var n = network.Layers[0].Neurons[x * NetworkHeight + y]; n.Weights[0] = Rnd.NextDouble() * 0.2 + 0.4; n.Weights[1] = Rnd.NextDouble() * 0.2 + 0.4; } } learning = new SOMLearning(network, NetworkWidth, NetworkHeight); learning.LearningRadius = LearningRadius; learning.LearningRate = LearningRate; Timer = new System.Windows.Forms.Timer(); Timer.Tick += (sender, args) => { Learning(); this.Invalidate(true); }; Timer.Interval = 1000; }
/// <summary> /// Initializes a new instance of the <see cref="SOMLearning"/> class /// </summary> /// /// <param name="network">Neural network to train</param> /// <param name="width">Neural network's width</param> /// <param name="height">Neural network's height</param> /// /// <remarks>The constructor allows to pass network of arbitrary rectangular shape. /// The amount of neurons in the network should be equal to <b>width</b> * <b>height</b>. /// </remarks> /// public SOMLearning(DistanceNetwork network, int width, int height) { // check network size if (network[0].NeuronsCount != width * height) { throw new ArgumentException("Invalid network size"); } this.network = network; this.width = width; this.height = height; }
public Form1() { InitializeComponent(); if (File.Exists("BPNNBrain.net")) { an = (ActivationNetwork)ActivationNetwork.Load("BPNNBrain.net"); } else if (File.Exists("SOMBrain.net")) { dn = (DistanceNetwork)DistanceNetwork.Load("SOMBrain.ann"); } }
/// <summary> /// Initializes a new instance of the <see cref="SOMLearning"/> class. /// </summary> /// /// <param name="network">Neural network to train.</param> /// <param name="width">Neural network's width.</param> /// <param name="height">Neural network's height.</param> /// /// <remarks>The constructor allows to pass network of arbitrary rectangular shape. /// The amount of neurons in the network should be equal to <b>width</b> * <b>height</b>. /// </remarks> /// /// <exception cref="ArgumentException">Invalid network size - network size does not correspond /// to specified width and height.</exception> /// public SOMLearning(DistanceNetwork network, int width, int height) { // check network size if (network.Layers[0].Neurons.Length != width * height) { throw new ArgumentException("Invalid network size."); } this.network = network; this.width = width; this.height = height; }
private void btnTraining_Click(object sender, EventArgs e) { double[][] input_data = new double[Data.getInstance().images.Count][]; double[][] output_data = new double[Data.getInstance().images.Count][]; int max = Data.getInstance().classes.Count - 1; int min = 0; for (int i = 0; i < Data.getInstance().images.Count; i++) { Bitmap image = Data.getInstance().preprocessing(Data.getInstance().images[i]); ImageToArray converter = new ImageToArray(0, 1); converter.Convert(image, out input_data[i]); output_data[i] = new double[1]; output_data[i][0] = Data.getInstance().class_indexes[i]; output_data[i][0] = 0 + (output_data[i][0] - min) * (1 - 0) / (max - min); } pca = new PrincipalComponentAnalysis(); pca.Method = PrincipalComponentMethod.Center; pca.Learn(input_data); double[][] input_from_pca = pca.Transform(input_data); int a = 0; int output_count = 0; while (a < Data.getInstance().classes.Count) { output_count = a * a; a++; } som_network = new DistanceNetwork(input_from_pca[0].Count(), output_count); som_learning = new SOMLearning(som_network); int max_iteration = 10000; double max_error = 0.0001; for (int i = 0; i < max_iteration; i++) { double error = som_learning.RunEpoch(input_from_pca); if (error < max_error) { break; } } btnBrowseClustering.Enabled = true; btnTraining.Enabled = false; }
//initialize public findForm(DistanceNetwork dn) { InitializeComponent(); this.dn = dn; listView1.LargeImageList = imgList; //Predicting Method som = new SOMLearning(this.dn); init(); getTrainedDataArray(); getClassMap(); classMapChecker(); }
private NeuralEngine() { _allData = GetTrainingData(); _imageToArray = new ImageToArray(0, 1); _classificationNetwork = File.Exists("BPNNBrain.net") ? Network.Load("BPNNBrain.net") as ActivationNetwork : new ActivationNetwork(new SigmoidFunction(), 100, 10, 1); _clusteringNetwork = File.Exists("SOMBrain.net") ? Network.Load("SOMBrain.net") as DistanceNetwork : CreateNewDistanceNetwork(); }
/// <summary> /// Initializes a new instance of the <see cref="SOMLearning"/> class /// </summary> /// /// <param name="network">Neural network to train</param> /// /// <remarks>This constructor supposes that a square network will be passed for training - /// it should be possible to get square root of network's neurons amount.</remarks> /// public SOMLearning(DistanceNetwork network) { // network's dimension was not specified, let's try to guess int neuronsCount = network[0].NeuronsCount; width = (int)Math.Sqrt(neuronsCount); if (width * width != neuronsCount) { throw new ArgumentException("Invalid network size"); } // ok, we got it this.network = network; }
// Constructor public MainForm() { InitializeComponent(); // Create network network = new DistanceNetwork(3, 100 * 100); // Create map bitmap mapBitmap = new Bitmap(200, 200, PixelFormat.Format24bppRgb); // RandomizeNetwork(); UpdateSettings(); }
public override void addModality(Signal s, string label = null) { base.addModality(s, label); //Each time we add a modality the structure of the network changes int inputCount = 0; foreach (Signal mod in modalities) { inputCount += mod.Width * mod.Height; } network = new DistanceNetwork(inputCount, output.Width * output.Height); teacher = new SOMLearning(network, output.Width, output.Height); }
// Worker thread void SearchSolution( ) { // set random generators range Neuron.RandRange = new DoubleRange(0, Math.Max(this.pointsPanel.ClientRectangle.Width, this.pointsPanel.ClientRectangle.Height)); // create network var network = new DistanceNetwork(2, this.networkSize * this.networkSize); // create learning algorithm var trainer = new SOMLearning(network, this.networkSize, this.networkSize); // create map this.map = new int[this.networkSize, this.networkSize, 3]; var fixedLearningRate = this.learningRate / 10; var driftingLearningRate = fixedLearningRate * 9; // iterations var i = 0; // loop while (!this.needToStop) { trainer.LearningRate = driftingLearningRate * (this.iterations - i) / this.iterations + fixedLearningRate; trainer.LearningRadius = (double)this.learningRadius * (this.iterations - i) / this.iterations; // run training epoch trainer.RunEpoch(this.trainingSet); // update map UpdateMap(network); // increase current iteration i++; // set current iteration's info this.currentIterationBox.Text = i.ToString( ); // stop ? if (i >= this.iterations) { break; } } // enable settings controls EnableControls(true); }
static void ReportPath(Maze maze, DistanceNetwork network, int start, int end) { Console.WriteLine("From " + start + " to " + end); List <int> path = new List <int>(); int rd = 0; bool pathFound = FindPath(maze, network, start, end, ref path, ref rd); string pathStr = "Computed path = "; foreach (int step in path) { pathStr += step + " --> "; } Console.WriteLine(pathStr); }
//Going to Find Form private void btnFind_Click(object sender, EventArgs e) { //validate existence of files if (System.IO.File.Exists(savedDNNetwork)) { //Load Networks dn = (DistanceNetwork)DistanceNetwork.Load(savedDNNetwork); //Go to Form var form = new findForm(dn); form.ShowDialog(); } else { MessageBox.Show($"{savedDNNetwork} not Found"); } }
/// <summary> /// Initializes a new instance of the <see cref="SOMLearning"/> class. /// </summary> /// /// <param name="network">Neural network to train.</param> /// /// <remarks><para>This constructor supposes that a square network will be passed for training - /// it should be possible to get square root of network's neurons amount.</para></remarks> /// /// <exception cref="ArgumentException">Invalid network size - square network is expected.</exception> /// public SOMLearning(DistanceNetwork network) { // network's dimension was not specified, let's try to guess var neuronsCount = network.Layers[0].Neurons.Length; var width = (int)System.Math.Sqrt(neuronsCount); if (width * width != neuronsCount) { throw new ArgumentException("Invalid network size."); } // ok, we got it this.network = network; this.width = width; this.height = width; }
// Constructor public MainForm( ) { // // Required for Windows Form Designer support // InitializeComponent( ); // Create network network = new DistanceNetwork(3, 100 * 100); // Create map bitmap mapBitmap = new Bitmap(200, 200, PixelFormat.Format24bppRgb); // RandomizeNetwork( ); UpdateSettings( ); }
/// <summary> /// Trains Network for Clustering (Distance Network, Self Organizing Map) /// </summary> /// <param name="epoch">Number of epoch</param> /// <returns>Neural network Error</returns> // TODO: Build the correct clustering network public double TrainClusteringNetwork(int epoch = 10000) { _clusteringNetwork = CreateNewDistanceNetwork(); var pcaResult = ComputePca(RemoveFromCategory(_allData.Values.ToList())); var trainer = new SOMLearning(_clusteringNetwork); var error = 0d; for (var i = 0; i < epoch; i++) { error = trainer.RunEpoch(pcaResult); if (error < 0.0001) { break; } } return(error); }
private void SetHopfieldNetworkClick(object sender, EventArgs e) { int cities, neurons; if ((int.TryParse(txtbxCities.Text, out cities) && int.TryParse(txtbxNeurons.Text, out neurons)) && (cities > 0) && (neurons > 0)) { this.dstNet = new DistanceNetwork(cities, neurons); citiesMap = new double[1][]; citiesMap[0] = new double[cities]; Random r = new Random(); for (int i = 0; i < cities; i++) { citiesMap[0][i] = r.NextDouble(); } } else { MessageBox.Show("Wrong input !"); } }
public MainForm() { InitializeComponent(); picturesPath = Application.StartupPath + @"\pictures"; listAllImages = new List <String>(); // Check BPNNBrain.net file if (File.Exists("BPNNBrain.net")) { // Load BPNNBrain.net file Network.loadActivationNetwork = (ActivationNetwork)ActivationNetwork.Load("BPNNBrain.net"); } // Check SOMBrain.net file if (File.Exists("SOMBrain.net")) { // Load SOMBrain.net file Network.loadDistanceNetwork = (DistanceNetwork)DistanceNetwork.Load("SOMBrain.net"); } // Check pictures directory if (Directory.Exists(picturesPath)) { // Load All Images listAllImages = LoadImages(); // It means that user added some art if (Network.checkAddArt) { checkListAllImages = true; } else { checkListAllImages = false; } } }
/// <summary> /// Initializes a new instance of the <see cref="ElasticNetworkLearning"/> class. /// </summary> /// /// <param name="network">Neural network to train.</param> /// public ElasticNetworkLearning(DistanceNetwork network) { this.network = network; // precalculate distances array int neurons = network.Layers[0].Neurons.Length; double deltaAlpha = Math.PI * 2.0 / neurons; double alpha = deltaAlpha; distance = new double[neurons]; distance[0] = 0.0; // calculate all distance values for (int i = 1; i < neurons; i++) { double dx = 0.5 * Math.Cos(alpha) - 0.5; double dy = 0.5 * Math.Sin(alpha); distance[i] = dx * dx + dy * dy; alpha += deltaAlpha; } }
/// <summary> /// Initializes a new instance of the <see cref="ElasticNetworkLearning"/> class /// </summary> /// /// <param name="network">Neural network to train</param> /// public ElasticNetworkLearning( DistanceNetwork network ) { this.network = network; // precalculate distances array int neurons = network[0].NeuronsCount; double deltaAlpha = Math.PI * 2.0 / neurons; double alpha = deltaAlpha; distance = new double[neurons]; distance[0] = 0.0; // calculate all distance values for ( int i = 1; i < neurons; i++ ) { double dx = 0.5 * Math.Cos( alpha ) - 0.5; double dy = 0.5 * Math.Sin( alpha ); distance[i] = dx * dx + dy * dy; alpha += deltaAlpha; } }
/// <summary> /// Initializes a new instance of the <see cref="ElasticNetworkLearning"/> class /// </summary> /// /// <param name="network">Neural network to train</param> /// public ElasticNetworkLearning(DistanceNetwork network) { this.network = network; // precalculate distances array var neurons = network[0].NeuronsCount; var deltaAlpha = Math.PI * 2.0 / neurons; var alpha = deltaAlpha; this.distance = new double[neurons]; this.distance[0] = 0.0; // calculate all distance values for (var i = 1; i < neurons; i++) { var dx = 0.5 * Math.Cos(alpha) - 0.5; var dy = 0.5 * Math.Sin(alpha); this.distance[i] = dx * dx + dy * dy; alpha += deltaAlpha; } }
// Update map private void UpdateMap(DistanceNetwork network) { // get first layer Layer layer = network[0]; // lock Monitor.Enter(this); // run through all neurons for (int i = 0, n = layer.NeuronsCount; i < n; i++) { var neuron = layer[i]; var x = i % this.networkSize; var y = i / this.networkSize; this.map[y, x, 0] = (int)neuron[0]; this.map[y, x, 1] = (int)neuron[1]; this.map[y, x, 2] = 0; } // collect active neurons for (var i = 0; i < pointsCount; i++) { network.Compute(this.trainingSet[i]); var w = network.GetWinner( ); this.map[w / this.networkSize, w % this.networkSize, 2] = 1; } // unlock Monitor.Exit(this); // this.mapPanel.Invalidate( ); }
// Update map private void UpdateMap(DistanceNetwork network) { // get first layer Layer layer = network.Layers[0]; // lock Monitor.Enter(this); // run through all neurons for (int i = 0; i < layer.Neurons.Length; i++) { Neuron neuron = layer.Neurons[i]; int x = i % networkSize; int y = i / networkSize; map[y, x, 0] = (int)neuron.Weights[0]; map[y, x, 1] = (int)neuron.Weights[1]; map[y, x, 2] = 0; } // collect active neurons for (int i = 0; i < pointsCount; i++) { network.Compute(trainingSet[i]); int w = network.GetWinner(); map[w / networkSize, w % networkSize, 2] = 1; } // unlock Monitor.Exit(this); // mapPanel.Invalidate(); }