/// <summary>
 ///   Start training, fade all controls
 /// </summary>
 private void ButtonStartClick(object sender, EventArgs e)
 {
     netTrainer = new NetTrainer(modelService);
     _tbLearningRate.Enabled = false;
     _tbMomentum.Enabled = false;
     _buttonStart.Enabled = false;
     _buttonPause.Enabled = true;
     _buttonAbort.Enabled = true;
     _cbLog.Enabled = false;
     _tbHiddenUnits.Enabled = false;
     _cmbActivationFunction.Enabled = false;
     _cmbActivationFunctionHidden.Enabled = false;
     _cmbActivationFunctionOutput.Enabled = false;
     startTime = DateTime.Now;
     _tElapsedTime.Enabled = true;
     _tElapsedTime.Start();
     netTrainer.StartTrainingAsync(netToTrain, CallBack);
 }
        /// <summary>
        ///   Start button clicked. Assembling started.
        /// </summary>
        private void BtnStartClick(object sender, EventArgs e)
        {
            Invoke(new Action(() =>
                              {
                                  _btnStart.Enabled = false;
                                  _btnInsert.Enabled = false;
                                  _nudNumberOfGroupsNeuralHasher.Enabled = false;
                                  _nudNumberOfHashesPerKeyNeuralHasher.Enabled = false;
                                  _btnSaveEnsamble.Enabled = false;
                                  _tbSaveToEnsembleFilename.ReadOnly = true;
                              }));

            /*Ensemble*/
            Action action = () =>
                            {
                                List<Network> networks = new List<Network>();
                                /*Load all the networks*/
                                foreach (KeyValuePair<string, bool> item in dictionaryPathToNetworks)
                                {
                                    if (item.Value)
                                    {
                                        networks.Add((Network)SerializeObject.Load(item.Key));
                                        if (networks[networks.Count - 1].MedianResponces == null) networks.RemoveAt(networks.Count - 1);
                                    }
                                }
                                if ((networks.Count*10 /*Number of network outputs*/) < (numberofgroupsneuralhasher*numberofhashesperkeyneuralhasher))
                                {
                                    MessageBox.Show(string.Format("Not enough networks to create an ensemble of such size {0} {1}", numberofgroupsneuralhasher, numberofhashesperkeyneuralhasher));
                                    return;
                                }

                                /*Load a network trainer*/
                                IActivationFunction function = networks[0].GetActivation(0);
                                NetTrainer netTrainer = new NetTrainer(modelService);
                                double[][] inputs = null, outputs = null; /*Normalized input/output pairs*/
                                Dictionary<Int32, List<BasicMLData>> trackIdFingerprints = netTrainer.GetNormalizedTrackFingerprints(function, 10, 10);
                                double[][] binaryCodes = netTrainer.GetNormalizedBinaryCodes(function, 10);
                                Tuple<double[][], double[][]> tuple = netTrainer.FillStandardInputsOutputs(trackIdFingerprints, binaryCodes);
                                inputs = tuple.Item1;
                                outputs = tuple.Item2;

                                /*Construct outputs using median response*/
                                int samplesCount = inputs.Length; /*10240*/
                                NeuralNetworkEnsemble nNEnsembe = new NeuralNetworkEnsemble(networks.ToArray()); /*40 networks*/
                                for (int i = 0; i < samplesCount /*1024 * 10*/; i++)
                                {
                                    byte[] outputVec = nNEnsembe.ComputeHash(inputs[i]); /*Hash the inputs, returns 10*40 = 400*/
                                    outputs[i] = new double[outputVec.Length]; /*400*/
                                    for (int j = 0; j < outputVec.Length; j++)
                                    {
                                        outputs[i][j] = outputVec[j]; /*10240x400 matrix*/
                                    }
                                }

                                /*At this point we have a the 10240 hash vectors [0, 400] which represent the outputs for the actual input*/
                                /*Calculate minimal mutual information between those outputs*/
                                MinimalMutualInfoPattern mmiPattern = new MinimalMutualInfoPattern(numberofgroupsneuralhasher, numberofhashesperkeyneuralhasher);
                                mmiPattern.CreatePattern(outputs);
                                nNEnsembe.HashPattern = mmiPattern;
                                nNEnsembe.Save(pathToEnsemble);
                            };

            action.BeginInvoke((result) =>
                               {
                                   /*Ensemble ended*/
                                   action.EndInvoke(result);
                                   Invoke(new Action(() =>
                                                     {
                                                         _btnStart.Enabled = true;
                                                         _btnInsert.Enabled = true;
                                                         _nudNumberOfGroupsNeuralHasher.Enabled = true;
                                                         _nudNumberOfHashesPerKeyNeuralHasher.Enabled = true;
                                                         _btnSaveEnsamble.Enabled = true;
                                                         _tbSaveToEnsembleFilename.ReadOnly = false;
                                                     }));
                                   MessageBox.Show(Resources.EnsemblingEnded, Resources.Success, MessageBoxButtons.OK, MessageBoxIcon.Information);
                               }, action);
        }