public T Run(T startSolution, Func <T, double, T> mutationFunction, Func <T, double> objectiveFunction) { if (startSolution == null) { throw new ArgumentNullException("startSolution"); } if (mutationFunction == null) { throw new ArgumentNullException("mutationFunction"); } if (objectiveFunction == null) { throw new ArgumentNullException("objectiveFunction"); } T bestSolution = startSolution; double minObjective = objectiveFunction(bestSolution); int lastUpdateIteration = 0; int currentIteration = 0; int iterationsFromLastReannealing = 0; double prevObjective = minObjective; T prevSolution = bestSolution; while (currentIteration < this.MaxIterations && currentIteration - lastUpdateIteration < this.MaxStallingIterations) { double temperature = CalcTemperature(iterationsFromLastReannealing); T currentSolution = mutationFunction(prevSolution, temperature); double currentObjective = objectiveFunction(currentSolution); double acceptanceProb = CalcAcceptanceProbability(prevObjective, currentObjective, temperature); if (Random.Double() < acceptanceProb) { prevObjective = currentObjective; prevSolution = currentSolution; } if (currentObjective < minObjective) { lastUpdateIteration = currentIteration; minObjective = currentObjective; bestSolution = currentSolution; DebugConfiguration.WriteDebugText("Best solution update: {0:0.000}", minObjective); } ++currentIteration; if (currentIteration % this.reportRate == 0) { DebugConfiguration.WriteDebugText("Iteration {0}", currentIteration); if (this.AnnealingProgress != null) { this.AnnealingProgress(this, new SimulatedAnnealingProgressEventArgs <T>(currentSolution, bestSolution)); } } if (iterationsFromLastReannealing >= this.ReannealingInterval) { iterationsFromLastReannealing = 0; prevSolution = bestSolution; DebugConfiguration.WriteDebugText("Reannealing"); } else { ++iterationsFromLastReannealing; } } return(bestSolution); }
public static Mixture <VectorGaussian> Fit(MicrosoftResearch.Infer.Maths.Vector[] data, int componentCount, int retryCount, double tolerance = 1e-4) { Debug.Assert(data != null); Debug.Assert(data.Length > componentCount * 3); Debug.Assert(componentCount > 1); Debug.Assert(retryCount >= 0); int dimensions = data[0].Count; // Find point boundary MicrosoftResearch.Infer.Maths.Vector min = data[0].Clone(); MicrosoftResearch.Infer.Maths.Vector max = min.Clone(); for (int i = 1; i < data.Length; ++i) { Debug.Assert(dimensions == data[i].Count); for (int j = 0; j < dimensions; ++j) { min[j] = Math.Min(min[j], data[i][j]); max[j] = Math.Max(max[j], data[i][j]); } } // Initialize solution MicrosoftResearch.Infer.Maths.Vector[] means = new MicrosoftResearch.Infer.Maths.Vector[componentCount]; PositiveDefiniteMatrix[] covariances = new PositiveDefiniteMatrix[componentCount]; for (int i = 0; i < componentCount; ++i) { GenerateRandomMixtureComponent(min, max, out means[i], out covariances[i]); } double[] weights = Enumerable.Repeat(1.0 / componentCount, componentCount).ToArray(); // EM algorithm for GMM double[,] expectations = new double[data.Length, componentCount]; double lastEstimate; const double negativeInfinity = -1e+20; bool convergenceDetected; double currentEstimate = negativeInfinity; do { lastEstimate = currentEstimate; convergenceDetected = false; // E-step: estimate expectations on hidden variables for (int i = 0; i < data.Length; ++i) { double sum = 0; for (int j = 0; j < componentCount; ++j) { expectations[i, j] = Math.Exp(VectorGaussian.GetLogProb(data[i], means[j], covariances[j])) * weights[j]; sum += expectations[i, j]; } for (int j = 0; j < componentCount; ++j) { expectations[i, j] /= sum; } } // M-step: // Re-estimate means for (int j = 0; j < componentCount; ++j) { means[j] = MicrosoftResearch.Infer.Maths.Vector.Zero(dimensions); double sum = 0; for (int i = 0; i < data.Length; ++i) { means[j] += data[i] * expectations[i, j]; sum += expectations[i, j]; } means[j] *= 1.0 / sum; } // Re-estimate covariances for (int j = 0; j < componentCount; ++j) { Matrix covariance = new Matrix(dimensions, dimensions); double sum = 0; for (int i = 0; i < data.Length; ++i) { MicrosoftResearch.Infer.Maths.Vector dataDiff = data[i] - means[j]; covariance += dataDiff.Outer(dataDiff) * expectations[i, j]; sum += expectations[i, j]; } covariance *= 1.0 / sum; covariances[j] = new PositiveDefiniteMatrix(covariance); if (covariances[j].LogDeterminant() < -30) { DebugConfiguration.WriteDebugText("Convergence detected for component {0}", j); if (retryCount == 0) { throw new InvalidOperationException("Can't fit GMM. Retry number exceeded."); } retryCount -= 1; GenerateRandomMixtureComponent(min, max, out means[j], out covariances[j]); DebugConfiguration.WriteDebugText("Component {0} regenerated", j); convergenceDetected = true; } } if (convergenceDetected) { currentEstimate = negativeInfinity; continue; } // Re-estimate weights double expectationSum = 0; for (int j = 0; j < componentCount; ++j) { weights[j] = 0; for (int i = 0; i < data.Length; ++i) { weights[j] += expectations[i, j]; expectationSum += expectations[i, j]; } } for (int j = 0; j < componentCount; ++j) { weights[j] /= expectationSum; } // Compute likelihood estimate currentEstimate = 0; for (int i = 0; i < data.Length; ++i) { for (int j = 0; j < componentCount; ++j) { currentEstimate += expectations[i, j] * (VectorGaussian.GetLogProb(data[i], means[j], covariances[j]) + Math.Log(weights[j])); } } DebugConfiguration.WriteDebugText("L={0:0.000000}", currentEstimate); } while (convergenceDetected || (currentEstimate - lastEstimate > tolerance)); Mixture <VectorGaussian> result = new Mixture <VectorGaussian>(); for (int j = 0; j < componentCount; ++j) { result.Add(VectorGaussian.FromMeanAndVariance(means[j], covariances[j]), weights[j]); } DebugConfiguration.WriteDebugText("GMM successfully fitted."); return(result); }
private SortedSet <EnergyBound> BreadthFirstBranchAndBoundTraverse(ShapeConstraints constraints) { SortedSet <EnergyBound> front = new SortedSet <EnergyBound> { this.CalculateEnergyBound(constraints) }; int currentIteration = 1; DateTime lastOutputTime = startTime; int processedConstraintSets = 0; while (!front.Min.Constraints.CheckIfSatisfied(this.maxCoordFreedom, this.maxWidthFreedom) && !this.IsStopping) { this.WaitIfPaused(); EnergyBound parentLowerBound = front.Min; front.Remove(parentLowerBound); List <ShapeConstraints> expandedConstraints = parentLowerBound.Constraints.SplitMostFree(this.maxCoordFreedom, this.maxWidthFreedom); foreach (ShapeConstraints constraintsSet in expandedConstraints) { EnergyBound lowerBound = this.CalculateEnergyBound(constraintsSet); front.Add(lowerBound); // Uncomment for strong invariants check //ObjectBackgroundTerm[,] lowerBoundShapeTerm = new ObjectBackgroundTerm[this.segmentedImage.Width, this.segmentedImage.Height]; //for (int i = 0; i < this.segmentedImage.Width; ++i) // for (int j = 0; j < this.segmentedImage.Height; ++j) // lowerBoundShapeTerm[i, j] = CpuBranchAndBoundShapeTermsCalculator.CalculateShapeTerm(lowerBound.Constraints, new Point(i, j)); //ObjectBackgroundTerm[,] parentLowerBoundShapeTerm = new ObjectBackgroundTerm[this.segmentedImage.Width, this.segmentedImage.Height]; //for (int i = 0; i < this.segmentedImage.Width; ++i) // for (int j = 0; j < this.segmentedImage.Height; ++j) // parentLowerBoundShapeTerm[i, j] = CpuBranchAndBoundShapeTermsCalculator.CalculateShapeTerm(parentLowerBound.Constraints, new Point(i, j)); //for (int i = 0; i < this.segmentedImage.Width; ++i) // for (int j = 0; j < this.segmentedImage.Height; ++j) // { // Debug.Assert(lowerBoundShapeTerm[i, j].ObjectTerm >= parentLowerBoundShapeTerm[i, j].ObjectTerm - 1e-7); // Debug.Assert(lowerBoundShapeTerm[i, j].BackgroundTerm >= parentLowerBoundShapeTerm[i, j].BackgroundTerm - 1e-7); // //CalculateShapeTerm(lowerBound.Constraints, new Point(0, 67)); // //CalculateShapeTerm(parentLowerBound.Constraints, new Point(0, 67)); // } // Lower bound should not decrease (check always, it's important!) Trace.Assert(lowerBound.SegmentationEnergy >= parentLowerBound.SegmentationEnergy - 1e-6); Trace.Assert(lowerBound.ShapeEnergy >= parentLowerBound.ShapeEnergy - 1e-6); //this.CalculateEnergyBound(lowerBound.Constraints); //this.CalculateEnergyBound(parentLowerBound.Constraints); ++processedConstraintSets; } // Some debug output if (currentIteration % this.ProgressReportRate == 0) { DateTime currentTime = DateTime.Now; EnergyBound currentMin = front.Min; DebugConfiguration.WriteDebugText( "On iteration {0} front contains {1} constraint sets.", currentIteration, front.Count); DebugConfiguration.WriteDebugText( "Current lower bound is {0:0.0000} ({1:0.0000} + {2:0.0000}).", currentMin.Bound, currentMin.SegmentationEnergy, currentMin.ShapeEnergy * this.ShapeEnergyWeight); double processingSpeed = processedConstraintSets / (currentTime - lastOutputTime).TotalSeconds; DebugConfiguration.WriteDebugText("Processing speed is {0:0.000} items per sec", processingSpeed); double maxVertexConstraintsFreedom = currentMin.Constraints.VertexConstraints.Max(c => c.Freedom); double maxEdgeConstraintsFreedom = currentMin.Constraints.EdgeConstraints.Max(c => c.Freedom); DebugConfiguration.WriteDebugText( "Max vertex freedom: {0:0.00}, max edge freedom: {1:0.00}", maxVertexConstraintsFreedom, maxEdgeConstraintsFreedom); DebugConfiguration.WriteDebugText("Elapsed time: {0}", DateTime.Now - this.startTime); DebugConfiguration.WriteDebugText(); this.ReportBranchAndBoundProgress(front); lastOutputTime = currentTime; processedConstraintSets = 0; } currentIteration += 1; } return(front); }