/// <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); }
/// <summary> /// Adds a recogniser to the collection, replacing it if it already exists /// </summary> private void RegisterRecogniser(Recogniser <TSymbol> recogniser) { // TODO could change to Dictionary<TSymbol, List<Recogniser<TSymbol>>> for training multiple inputs for the same symbol?? _recognisers[recogniser.Symbol] = recogniser; }