// LogL returns the per-instance log-likelihood. Note that the log-likelihood // of some instances might evaluate to NaN. LogL will ignore such cases. func LogL(corpus []*Instance, model *Model) float64 { logl := 0.0 workers := runtime.NumCPU() - 1 aggr := make(chan float64) inst := 0 var wg sync.WaitGroup wg.Add(1) go func() { for l := range aggr { if !math.IsNaN(l) && l > 0 { logl += math.Log(l) inst++ } } wg.Done() }() parallel.For(0, workers, 1, func(worker int) { for i := worker; i < len(corpus); i++ { aggr <- Likelihood(corpus[i], model) } }) close(aggr) wg.Wait() if inst == 0 { log.Fatalf("All instances have log-likelihood evaluated to NaN.") } return logl / float64(inst) }
func Epoch(corpus []*Instance, N, C int, baseline *Model) *Model { estimate := NewModel(N, C) workers := runtime.NumCPU() - 1 aggrγ1 := make(chan []float64) aggrΣγ := make(chan []float64) aggrΣξ := make(chan [][]float64) aggrΣγo := make(chan [][]*Multinomial) // TODO(wyi): Use WaitGroup here. go func() { for γ1 := range aggrγ1 { estimate.updateγ1(γ1) } }() go func() { for Σγ := range aggrΣγ { estimate.updateΣγ(Σγ) } }() go func() { for Σξ := range aggrΣξ { estimate.updateΣξ(Σξ) } }() go func() { for Σγo := range aggrΣγo { estimate.updateΣγo(Σγo) } }() parallel.For(0, workers, 1, func(worker int) { for i := worker; i < len(corpus); i += workers { β := β(corpus[i], baseline) γ1, Σγ, Σξ, Σγo := Inference(corpus[i], baseline, β) aggrγ1 <- γ1 aggrΣγ <- Σγ aggrΣξ <- Σξ aggrΣγo <- Σγo } }) close(aggrγ1) close(aggrΣγ) close(aggrΣξ) close(aggrΣγo) return estimate }