예제 #1
0
        /// <summary>
        /// Trains the model to recognise the specified input as the specified symbol
        /// </summary>
        public void Train(WrappedBitmap inputData, TSymbol representedValue, uint rounds)
        {
            var initialGeneration = Enumerable.Range(0, (int)rounds)
                                    .Select(i => new Scorer(new TuningParams.Scoring())) // TODO nested constructors is smelly
                                    .Select(s => new ScorerScorePair(s, s.Score(inputData)))
                                    .AsParallel()
                                    .OrderByDescending(s => s.Score);

            // Having acquired the initial set of sampling pixels via sheer randomness, we'll work with
            // the best we've got and try and massage them into something better.
            var mutParams             = new TuningParams.Mutation();
            var initialBestCandidates = initialGeneration.Take(100);            // TODO parameterise magic value (which was decided totally arbitrarily anyway)
            var initialBestCandidatesWithMutatedVariants = from p in initialBestCandidates
                                                           let mutatedOffspring = p.Scorer.MutateMany(mutParams)
                                                                                  let mutatedScores = from m in mutatedOffspring
                                                                                                      let mutatedScore = m.Score(inputData)
                                                                                                                         select new ScorerScorePair(m, mutatedScore)
                                                                                                                         select new ParentChildScoreCollection(p, mutatedScores);

            var bestOftheMutantStrains = initialBestCandidatesWithMutatedVariants
                                         .SelectMany(x => x.Children)
                                         .OrderByDescending(s => s.Score)
                                         .First();

            // Compute some stats for these mutations. These stats are for interest only, they don't affect any computation.
            Benchmarking.Mutation.AddDataPoints(initialBestCandidatesWithMutatedVariants);

            var rec = new Recogniser <TSymbol>(representedValue, bestOftheMutantStrains.Scorer);

            RegisterRecogniser(rec);
        }
예제 #2
0
        /// <summary>
        /// Randomises the sampled pixels, but keeps them relatively close to their existing locations.
        /// </summary>
        public IScorer Mutate(TuningParams.Mutation tuningParams)
        {
            var newPixels = new List <Point>(_pixelsToSample);

            int n = _randomNumGenerator.Next(tuningParams.PixelRandomChurn);

            for (int i = 0; i < n; i++)
            {
                // Remove one of the pixels at random
                newPixels.RemoveAt(_randomNumGenerator.Next(TuningParams.ImageSize));
            }

            // Skew some of the remaining ones
            n = _randomNumGenerator.Next(tuningParams.PixelRandomSkewNumber);
            for (int i = 0; i < n; i++)
            {
                // TODO the same pixels could be skewed more than once (does that even matter?)
                int xOffset  = _randomNumGenerator.Next(tuningParams.PixelRandomSkewOffset) - tuningParams.PixelRandomSkewOffset;
                int yOffset  = _randomNumGenerator.Next(tuningParams.PixelRandomSkewOffset) - tuningParams.PixelRandomSkewOffset;
                int pixIndex = _randomNumGenerator.Next(newPixels.Count - 1);
                newPixels[pixIndex] = ConstrainPixelToImage(
                    newPixels[pixIndex].X + xOffset,
                    newPixels[pixIndex].Y + yOffset);
            }

            // Add some more random new ones (approx the same number to replace those that were removed or "churned")
            n = _randomNumGenerator.Next(tuningParams.PixelRandomChurn);
            for (int i = 0; i < n; i++)
            {
                // NOTE - it's possible to get duplicates, in which case the same pixel is counted twice
                // TODO check for off-by-ones (can we hit the image edges?)
                newPixels.Add(
                    new Point(
                        _randomNumGenerator.Next(TuningParams.ImageSize),
                        _randomNumGenerator.Next(TuningParams.ImageSize)
                        )
                    );
            }

            // modify the negative/positive offset randomly
            //_positiveScoreOffset = (byte)(_positiveScoreOffset + _randomNumGenerator.Next(tuningParams.PositiveRandOffset) - TuningParams.PositiveRandOffset / 2);
            //_negativeScoreOffset = (byte)(_negativeScoreOffset + _randomNumGenerator.Next(TuningParams.Scoring.NegativeRandOffset) - TuningParams.NegativeRandOffset / 2);
            // TODO keeping these params the same as our parent for now, and only randomoising on the sampled pixels. the randomisation of varying parameters could go on forever!!!

            return(new Scorer(_tuningParams, newPixels));
        }
예제 #3
0
 public IEnumerable <IScorer> MutateMany(TuningParams.Mutation tuningParams)
 {
     return(Enumerable.Range(0, tuningParams.SpawnedDescendants)
            .Select(i => Mutate(tuningParams)));
 }