@Override
    protected void doTrain() {
        setInitialValues();
        Random random = new Random();
        for (int iter = 0; iter < params.maxIters; iter++) {
            int k = random.nextInt(dataSeqs.size());
            // now update thetas.
            DataSequence dataSeq = dataSeqs.get(k);
            calculateExpFValuesUsingTheta(dataSeq,ExpF,thetaState[k],thetaTransition[k],false);
            //TODO: need to set etas properly.
            double eta = etas[k];
            for (int i = 0; i < thetaState[k].length; i++) {
                initMDone = computeLogMiTrainMode(featureGenerator, lambda, dataSeq, i, Mi_YY, Ri_Y, false, reuseM, initMDone);
                for (int y = 0; y < numY; y++) {
                    thetaState[k][i][y] -= eta*(thetaState[k][i][y]-params.invSigmaSquare*Ri_Y.get(y));
                    if (i > 0) {
                        for (int yprev = 0; yprev < numY; yprev++) {
                            thetaTransition[k][i][yprev][y] -= eta*(thetaTransition[k][i][yprev][y]-params.invSigmaSquare*Mi_YY.get(yprev,y));
                        }
                    }
                }
            }
            // update lambda..
            for (int f = 0; f < lambda.length; f++) {
                lambda[f] += ExpF[f];
            }
            calculateExpFValuesUsingTheta(dataSeq,ExpF,thetaState[k],thetaTransition[k],false);
            for (int f = 0; f < lambda.length; f++) {
                lambda[f] -= ExpF[f];
            } 
        }
        for (int f = 0; f < lambda.length; f++) {
            lambda[f] *= params.invSigmaSquare;
        }
    }