// UpdateOne updates model using a single weighted sample. func (m *Model) UpdateOne(o model.Obs, w float64) { m.updateCount++ // We create a chain of hmms to update stats for an obs sequence. // The chain is released once the update is done. // The assigner has the logic for mapping labels to a chain of models. chain, err := m.Set.chainFromAssigner(o, m.assigner) if err != nil { glog.Warningf("skipping, failed to update hmm model stats, oid:%s, error: %s", o.ID(), err) return } // Use the forward-backward algorithm to compute counts. if m.useAlignments { err = chain.updateFromAlignments() if err != nil { m.updateFailCount++ if glog.V(6) { glog.Fatal(err) } glog.Warning(err) return } } else { err = chain.update() if err != nil { m.updateFailCount++ if glog.V(6) { glog.Fatal(err) } glog.Warning(err) return } // Print log(prob(O/model))\ p := chain.beta.At(0, 0, 0) m.logProb += p glog.V(1).Infof("update hmm stats, oid:%s, logProb:%.2f total:%.2f", o.ID(), p, m.logProb) } }
// Use the label to create a chain of hmms. // If model set only has one hmm, no need to use labels, simply assign the only hmm. func (ms *Set) chainFromAssigner(obs model.Obs, assigner Assigner) (*chain, error) { var hmms []*Net var fos model.FloatObsSequence switch o := obs.(type) { case model.FloatObsSequence: fos = o case *model.FloatObsSequence: fos = *o default: return nil, fmt.Errorf("obs must be of type model.FloatObsSequence, found type %s which is not supported", reflect.TypeOf(obs)) } if len(fos.ValueAsSlice()) == 0 { return nil, fmt.Errorf("obs sequence has no data") } if assigner == nil && ms.size() == 1 { hmms = append(hmms, ms.Nets[0]) if glog.V(3) { glog.Warningf("assigner missing but model set has only one hmm network - assigning model [%s] to chain", ms.Nets[0].Name) } } else if assigner == nil { return nil, fmt.Errorf("need assigner to create hmm chain if model set is greater than one") } else { // Get the labeler and check that it is of type SimpleLabeler // otherwise return error. labeler, ok := obs.Label().(model.SimpleLabel) if !ok { return nil, fmt.Errorf("labeler must be of type model.SimpleLabel, found type %s which is not supported", reflect.TypeOf(obs.Label())) } // Now we need to assign hmms to the chain. // We will use the sequence of labels to lookup the models by name. labels := strings.Split(labeler.String(), ",") if len(labels) == 1 && len(labels[0]) == 0 { return nil, fmt.Errorf("no label found, can't assign models") } modelNames := assigner.Assign(labels) glog.V(5).Infof("obsid:%s, labels:%v", obs.ID(), labels) glog.V(5).Infof("obsid:%s, models:%v", obs.ID(), modelNames) for _, name := range modelNames { h, ok := ms.net(name) if !ok { return nil, fmt.Errorf("can't find model for name [%s] in set - assignment failed", name) } hmms = append(hmms, h) } } nq := len(hmms) if nq == 0 { return nil, fmt.Errorf("the assigner returned no models") } ch := &chain{ hmms: hmms, nq: nq, ns: make([]int, nq, nq), obs: obs, vectors: fos.Value().([][]float64), nobs: len(fos.Value().([][]float64)), ms: ms, } for k, hmm := range hmms { if hmm.A.Shape[0] > ch.maxNS { ch.maxNS = hmm.A.Shape[0] } ch.ns[k] = hmm.A.Shape[0] } ch.alpha = narray.New(ch.nq, ch.maxNS, ch.nobs) ch.beta = narray.New(ch.nq, ch.maxNS, ch.nobs) ch.computeLikelihoods() // Validate. // Can't have models with transitions from entry to exit states // at the beginning or end of a chain. if isTeeModel(hmms[0]) { return nil, fmt.Errorf("the first model in the chain can't have a transition from entry to exit states - model name is [%s] with id [%d]", hmms[0].Name, hmms[0].id) } if isTeeModel(hmms[nq-1]) { return nil, fmt.Errorf("the last model in the chain can't have a transition from entry to exit states - model name is [%s] with id [%d]", hmms[nq-1].Name, hmms[nq-1].id) } return ch, nil }