// NewModel creates a new Gaussian mixture model. func NewModel(dim, numComponents int, options ...Option) *Model { gmm := &Model{ ModelName: "GMM", // default name ModelDim: dim, NComponents: numComponents, Diag: true, tmpProbs: make([]float64, numComponents), } gmm.Type = reflect.TypeOf(*gmm).String() // Set options. for _, option := range options { option(gmm) } if len(gmm.PosteriorSum) == 0 { gmm.PosteriorSum = make([]float64, gmm.NComponents) } // Create components if not provided. if len(gmm.Components) == 0 { gmm.Components = make([]*gaussian.Model, numComponents, numComponents) for i := range gmm.Components { cname := componentName(gmm.ModelName, i, gmm.NComponents) gmm.Components[i] = gaussian.NewModel(gmm.ModelDim, gaussian.Name(cname)) } } // Initialize weights. // Caller may pass weight, log(weights), or no weights. switch { case len(gmm.LogWeights) > 0 && len(gmm.Weights) > 0: glog.Fatal("options not allowed: provide only one of LogWeights or Weights") case len(gmm.LogWeights) == 0 && len(gmm.Weights) == 0: gmm.LogWeights = make([]float64, numComponents) logw := -math.Log(float64(gmm.NComponents)) floatx.Apply(floatx.SetValueFunc(logw), gmm.LogWeights, nil) gmm.Weights = make([]float64, gmm.NComponents) floatx.Exp(gmm.Weights, gmm.LogWeights) glog.Infof("init weights with equal values: %.6f", gmm.Weights[0]) case len(gmm.LogWeights) > 0: gmm.Weights = make([]float64, gmm.NComponents) floatx.Exp(gmm.Weights, gmm.LogWeights) case len(gmm.Weights) > 0: gmm.LogWeights = make([]float64, numComponents) floatx.Log(gmm.LogWeights, gmm.Weights) } return gmm }
// Estimate computes model parameters using sufficient statistics. func (gmm *Model) UpdateOne(o model.Obs, w float64) { obs, _, _ := model.ObsToF64(o) maxProb := gmm.logProbInternal(obs, gmm.tmpProbs) gmm.Likelihood += maxProb floatx.Apply(floatx.AddScalarFunc(-maxProb+math.Log(w)), gmm.tmpProbs, nil) // Compute posterior probabilities. floatx.Exp(gmm.tmpProbs, gmm.tmpProbs) // Update posterior sum, needed to compute mixture weights. floats.Add(gmm.PosteriorSum, gmm.tmpProbs) // Update Gaussian components. for i, c := range gmm.Components { c.UpdateOne(o, gmm.tmpProbs[i]) } // Count number of observations. gmm.NSamples += w }