protected double[] LearnerHistoryToWeights(PipelinePattern[] history, bool isMaximizingMetric) { int numLearners = AvailableLearners.Length; double[] weights = new double[numLearners]; int[] counts = new int[numLearners]; Dictionary <string, int> labelToIndex = new Dictionary <string, int>(); double maxWeight = history.Length > 0 ? history.Max(w => w.PerformanceSummary.MetricValue) : 0d; // Map categorical values to their index for (int j = 0; j < numLearners; j++) { labelToIndex[AvailableLearners[j].LearnerName] = j; } // Add mass according to performance foreach (var pipeline in history) { if (AvailableLearners.All(l => l.LearnerName != pipeline.Learner.LearnerName)) { continue; } weights[labelToIndex[pipeline.Learner.LearnerName]] += AutoMlUtils.ProcessWeight(pipeline.PerformanceSummary.MetricValue, maxWeight, isMaximizingMetric); counts[labelToIndex[pipeline.Learner.LearnerName]]++; } // Take average mass for each learner for (int i = 0; i < weights.Length; i++) { weights[i] /= counts[i] > 0 ? counts[i] : 1; } // If any learner has not been seen, default its average to 1.0 // to encourage exploration of untried algorithms. for (int i = 0; i < weights.Length; i++) { weights[i] += counts[i] == 0 ? 1 : 0; } // Normalize weights to sum to one and return return(SweeperProbabilityUtils.Normalize(weights)); }
private TransformInference.SuggestedTransform[] SampleTransforms(RecipeInference.SuggestedRecipe.SuggestedLearner learner, PipelinePattern[] history, out long transformsBitMask, bool uniformRandomSampling = false) { var sampledTransforms = new List <TransformInference.SuggestedTransform>( AutoMlUtils.GetMandatoryTransforms(AvailableTransforms)); var remainingAvailableTransforms = AvailableTransforms.Where(t => !sampledTransforms.Any(t.Equals)).ToArray(); var mask = AutoMlUtils.TransformsToBitmask(sampledTransforms.ToArray()); foreach (var transform in remainingAvailableTransforms) { // Add pseudo-mass to encourage sampling of untried transforms. double maxWeight = history.Length > 0 ? history.Max(w => w.PerformanceSummary.MetricValue) : 0d; double allWeight = Math.Max(maxWeight, 1d); double learnerWeight = Math.Max(maxWeight, 1d); int allCounts = 1; int learnerCounts = 1; // Add mass according to performance. foreach (var pipeline in history) { if (pipeline.Transforms.Any(transform.Equals)) { allWeight += AutoMlUtils.ProcessWeight(pipeline.PerformanceSummary.MetricValue, maxWeight, IsMaximizingMetric); allCounts++; if (pipeline.Learner.LearnerName == learner.LearnerName) { learnerWeight += pipeline.PerformanceSummary.MetricValue; learnerCounts++; } } } // Take average mass as weight, and take convex combination of // learner-specific weight and unconditioned weight. allWeight /= allCounts > 0 ? allCounts : 1; learnerWeight /= learnerCounts > 0 ? learnerCounts : 1; var lambda = MathUtils.Sigmoid(learnerCounts - 3); var combinedWeight = uniformRandomSampling ? 0.5 : lambda * learnerWeight + (1 - lambda) * allWeight; // Sample transform according to combined weight. if (ProbUtils.SampleUniform() <= combinedWeight / maxWeight) { mask |= 1L << transform.AtomicGroupId; } } // Add all chosen transforms. sampledTransforms.AddRange(remainingAvailableTransforms.Where(t => AutoMlUtils.AtomicGroupPresent(mask, t.AtomicGroupId))); // Add final features concat transform. NOTE: computed bitmask should always // exclude the final features concat. If we forget to exclude that one, will // cause an error in verification, since it isn't included in the original // dependency mapping (i.e., its level isn't in the dictionary). sampledTransforms.AddRange(AutoMlUtils.GetFinalFeatureConcat(Env, FullyTransformedData, DependencyMapping, sampledTransforms.ToArray(), AvailableTransforms, DataRoles)); transformsBitMask = mask; return(sampledTransforms.ToArray()); }