コード例 #1
0
ファイル: NeuralNetwork.cs プロジェクト: LiruJ/NeuralNetwork
        /// <summary> Using the given <paramref name="trainingSet"/>, trains the neural network with the given <paramref name="batchSize"/> over the given <paramref name="epochs"/>. </summary>
        /// <param name="random"> The random number generator used to shuffle the <paramref name="trainingSet"/>. </param>
        /// <param name="trainingSet"> The <see cref="IDataSet"/> against which to train. </param>
        /// <param name="epochs"> The number of times to go over the <paramref name="trainingSet"/>. </param>
        /// <param name="batchSize"> The number of <see cref="IDataPoint"/>s to process before applying learning. </param>
        /// <param name="logger"> <see cref="INetworkLogger"/> used to log the progress of the training. If this is <c>null</c>, no logging will happen. </param>
        /// <param name="testSet"> Another <see cref="IDataSet"/>, with <see cref="IDataPoint"/>s that are not in the <paramref name="trainingSet"/>. If this is given, the network will be tested against the <paramref name="testSet"/> after every epoch. </param>
        public void LearnOverData(Random random, IDataSet trainingSet, int epochs, int batchSize, INetworkLogger logger = null, IDataSet testSet = null)
        {
            // Create the various required arrays once, then just fill them with data. This cuts down on memory allocations, dramatically speeding up the training.
            float[] input         = new float[inputLayer.Count];
            float[] output        = new float[outputLayer.Count];
            float[] desiredOutput = new float[outputLayer.Count];
            float[] error         = new float[outputLayer.Count];

            // Calculate how many batches are required with the given batch size.
            int numberOfBatches = trainingSet.Count / batchSize;

            // Create the change to be made to the network.
            NetworkChange networkChange = new NetworkChange(this);

            // Do the given amount of epochs.
            for (int currentEpoch = 0; currentEpoch < epochs; currentEpoch++)
            {
                // For each epoch, shuffle the training data randomly.
                trainingSet.Shuffle(random);

                // The percentage of data correctly guessed per batch.
                float lastBatchPercentage = 0.0f;

                // Do the given amount of batches.
                for (int batch = 0; batch < numberOfBatches; batch++)
                {
                    // How many data were correctly guessed in this batch.
                    int batchGuesses = 0;

                    // Do the calculated number of training data in the batch.
                    for (int dataIndex = 0; dataIndex < batchSize; dataIndex++)
                    {
                        // Get the next data and set the input array to its data.
                        IDataPoint currentData = trainingSet[batch * batchSize + dataIndex];
                        currentData.GetFloatData(ref input);

                        // Process the data through the network, saving its output.
                        ProcessInput(input, ref output);

                        // Get the output that the network guessed with the most confidence.
                        int bestGuess = output.GetIndexOfHighestValue();

                        // Create the desired output.
                        desiredOutput.ApplyVectorisedFunction((int g) => g == currentData.Label ? 1 : 0);

                        // If the guess was correct, track it.
                        if (bestGuess == currentData.Label)
                        {
                            batchGuesses++;
                        }

                        // Calculate the error.
                        CalculateError(desiredOutput, output, ref error);

                        // Learn from the output compared to the desired output, save the results in the previous network change.
                        CalculateChanges(networkChange, error);

                        // If a logger has been given, log the state of the network as of this iteration.
                        logger?.Log(currentEpoch, epochs, batch, numberOfBatches, dataIndex, batchSize, lastBatchPercentage);
                    }

                    // Calculate how many of the data in the batch were correctly guessed.
                    lastBatchPercentage = (float)batchGuesses / batchSize;

                    // Apply the changes.
                    ApplyChanges(networkChange, batchSize);
                    networkChange.Reset();
                }

                // If a logger was given and should log output, log the output of the epoch.
                if (logger != null && (logger.OutputOptions & OutputOptions.WhenFinished) == OutputOptions.WhenFinished)
                {
                    // Log that the epoch finished.
                    logger.Log($"\nEpoch {currentEpoch} finished");

                    // If test data was given, test against it and log the output.
                    if (trainingSet != null)
                    {
                        logger.Log($", correctly guessed {PercentageOfCorrectTestData(random, testSet, ref input, ref output):P2} of the test data");
                    }

                    // Log the full stop and line end.
                    logger.Log(".\n");
                }
            }

            // If a logger was given, log that the training finished.
            logger?.Log("Training finished.");
        }