code: func (t *Trainer) crossValidateTrain(epochs int) error {
  	if t.perf != nil {
  		defer func() {
  			close(t.perf)
  			t.perf = nil
  		}()
  	}
  
  	var epochChan chan struct{}
  	if t.cost != nil {
  		defer func() {
  			close(t.cost)
  			t.cost = nil
  		}()
  
  		epochChan = t.handleCosts()
  		if epochChan != nil {
  			defer close(epochChan)
  		}
  	}
  	examples := makeExamples(t.trainingSet, t.nn.NNConfig, t.nn.dict, t.ts, t)
  
  	var best Performance
  	for e := 0; e < epochs; e++ {
  		if err := t.nn.train(examples); err != nil {
  			return err
  		}
  
  		if t.EvalPerIter > 0 && e%t.EvalPerIter == 0 || e == epochs-1 {
  			perf := t.crossValidate(t.crossValSet)
  
  			// if there is a channel to report back the performance, send it down
  			if t.perf != nil {
  				perf.Iter = e
  				t.perf <- perf
  			}
  
  			if perf.UAS > best.UAS {
  				best = perf
  
  				if t.SaveBest != "" {
  					f, err := os.Create(t.SaveBest)
  					if err != nil {
  						err = errors.Wrapf(err, "Unable to open SaveBest file %q", t.SaveBest)
  						return err
  					}
  
  					t.Model.SaveWriter(f)
  				}
  			}
  		}
  
  		if epochChan != nil {
  			epochChan <- struct{}{}
  		}
  
  		shuffleExamples(examples)
  	}
  	return nil
  }
docs: // crossValidateTrain trains the model but also does cross validation to ensure overfitting don't happen.