Forum Applications Trading Strategies (Algo Quant)
HMM Error for training the model
-
RyuParticipant January 20, 2012 at 7:13 am
Hi,
I am training a HMM with SuanShu but once it got errors in some cases. I tried a few different settings but the errors still occurred. Let me summarize how the error occurs.
Set HMM with 3 states with 5 discrete values in the emission probability at each state. Then I randomized a matrix A of size 3 x 3 and matrix B of size 3 x 5. Now I also get 100 observations, where the first 99 values are between 1 and 4, and the 100th value is 5. Then it runs out an infinite value matrices A and B. I suspect the issue is due to that the training algorithm finds that the value 5 cannot be found from the previous occurrences and cannot determine the probability of the model at value 5 in observation. For more details, you can refer to the following .java.
Is it an algorithmic issue or something would be fixed? Thanks.
Main Program:
<br /> package com.numericalmethod.suanshu.examples;<br /> import com.numericalmethod.suanshu.matrix.doubles.Matrix;<br /> import com.numericalmethod.suanshu.stats.hmm.rabiner.HmmTrainByEM;<br /> import com.numericalmethod.suanshu.stats.hmm.rabiner.HiddenMarkovModel;<br /> import com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix;<br /> import com.numericalmethod.suanshu.vector.doubles.dense.DenseVector;<br /> import org.junit.Test;<br /> import java.io.*;<br /> import java.util.*;<br /> <br /> /**<br /> *<br /> * @author Chan<br /> */<br /> <br /> <br /> public class Test_HMM_20120120 {<br /> public static void main( String args[]) { <br /> org.junit.runner.JUnitCore.main("com.numericalmethod.suanshu.examples.Test_HMM_20120120");<br /> }<br /> @Test<br /> public void test_0010(){<br /> // Initialization<br /> double ThresholdValue = 0.500; //Input 1<br /> int[] ActiveCol = {1, 2, 3}; //Input 2<br /> int number_row_a = 3, number_col_a = number_row_a; //Input 3<br /> int NumberofTotalCol = 5; //Input 4<br /> int number_row_b = number_row_a, number_col_b = ActiveCol.length*2-1;<br /> int WinSize = 100; <br /> int nTraining = 10;<br /> DenseVector PI_0 = new DenseVector(MarkovModel_pre_20120119.GenerateRandomMatrix(1, number_row_a).t()); <br /> DenseMatrix A_0 = new DenseMatrix(MarkovModel_pre_20120119.GenerateRandomMatrix(number_row_a, number_col_a));<br /> DenseMatrix B_0 = new DenseMatrix(MarkovModel_pre_20120119.GenerateRandomMatrix(number_row_b, number_col_b)); <br /> HiddenMarkovModel model_0 = new HiddenMarkovModel(PI_0, A_0, B_0);<br /> <br /> DenseVector Obs = new DenseVector(MarkovModel_pre_20120119.GenerateRandomMatrix(1, WinSize).t());<br /> System.out.print(Obs.toString());<br /> int[] TempArray = new int[WinSize+1];<br /> for (int i = 0; i<winsize ; i++){ <br></winsize> if (Obs.get(i+1)<0.25/WinSize)<br /> TempArray<i> = 1;<br /> else if (Obs.get(i+1)>=0.25/WinSize && Obs.get(i+1)<0.5/WinSize)<br /> TempArray</i><i> = 2;<br /> else if (Obs.get(i+1)>=0.5/WinSize && Obs.get(i+1)<0.75/WinSize)<br /> TempArray</i><i> = 3;<br /> else<br /> TempArray</i><i> = 4;<br /> System.out.println(TempArray</i><i>);<br /> }<br /> <br /> TempArray[WinSize] = 4;<br /> for (int k=0; k<ntraining ; k++) //train nTraining times<br></ntraining> model_0 = new HmmTrainByEM().train(model_0, TempArray);<br /> <br /> System.out.println(model_0.A().toString()); <br /> System.out.println(model_0.B().toString());<br /> }<br /> }<br /> <br /> </i>It depends to another .java with method GenerateRandomMatrix from class MarkovModel_pre_20120119. Just copy it in another .java and use it in the main program. Method GenerateRandomMatrix is to generate random matrices.
<br /> <br /> package com.numericalmethod.suanshu.examples;<br /> <br /> import com.numericalmethod.suanshu.matrix.doubles.Matrix;<br /> import com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix;<br /> import java.util.*;<br /> import java.io.*;<br /> <br /> /**<br /> *<br /> * @author Chan<br /> */<br /> <br /> <br /> public class MarkovModel_pre_20120119 {<br /> public static void main(String args[]) {<br /> // Test out the functions<br /> //Matrix A = new DenseMatrix(GetObservationState(readData("C:\text.txt", 2, 100), 0.005)); <br /> //System.out.println(A.toString()); <br /> }<br /> <br /> <br /> public static DenseMatrix readData(String FilePath, int ColSize, int WinSize, int[] ActiveCol)<br /> {<br /> <br /> // Col1 = Date; Col2 = Closed price; Col3 = Return;<br /> DenseMatrix temp_Data = new DenseMatrix(new double[1000][ActiveCol.length +1]);<br /> // Col1 = Date; Col2 = Closed price; Col3 = Normalized return;<br /> DenseMatrix output_Data = new DenseMatrix(new double [1000][ActiveCol.length +1]);<br /> <br /> <br /> try{<br /> // Open the file that is the first<br /> // command line parameter<br /> FileInputStream fstream = new FileInputStream(FilePath);<br /> <br /> // Get the object of DataInputStream<br /> DataInputStream in = new DataInputStream(fstream);<br /> BufferedReader br = new BufferedReader(new InputStreamReader(in));<br /> String strLine;<br /> //Read File Line By Line<br /> int i =1;<br /> strLine = br.readLine();<br /> while ((strLine = br.readLine()) != null && i < = 1000) { <br /> // Input the first col and second col to date and close price<br /> int colCount = 1;<br /> for (int col = 1; col < = ColSize; col++)<br /> { <br /> for (int ActiveColn = 1; ActiveColn< =ActiveCol.length; ActiveColn++)<br /> if (col == ActiveCol[ActiveColn-1]){ <br /> temp_Data.set(i, colCount++, Double.parseDouble(strLine.split(",")[col-1])) ; <br /> break;<br /> }<br /> }<br /> i++;<br /> }<br /> //Close the input stream<br /> in.close();<br /> }catch (Exception e){//Catch exception if any<br /> System.err.println("Error: " + e.getMessage());<br /> }<br /> <br /> // Calculate the return, the first one return cannot be calculated<br /> for (int i = 1000; i>=2; i--){<br /> if (temp_Data.get(i, 1)>0)<br /> for (int col=ActiveCol.length +1; col >=3 ;col--)<br /> temp_Data.set(i, col, (temp_Data.get(i, col-1)-temp_Data.get(i-1, col-1))/temp_Data.get(i-1, col-1));<br /> }<br /> <br /> // Assign date and price<br /> for (int i = 1000; i>WinSize; i-- ){ <br /> output_Data.set(i-WinSize, 1, temp_Data.get(i, 1));<br /> output_Data.set(i-WinSize, 2, temp_Data.get(i, 2));<br /> }<br /> <br /> // Assign all the observations<br /> for (int col = 3; col< =ActiveCol.length +1; col++)<br /> {<br /> for (int i = 1000; i>WinSize; i-- ){<br /> double mean = 0, variance = 0;<br /> for (int j = 0; i<winsize ; j++)<br></winsize> mean+=temp_Data.get(i-j, 3); <br /> mean = mean/WinSize;<br /> <br /> for (int j = 0; j<winsize ; j++)<br></winsize> variance+=(temp_Data.get(i-j, 3)-mean)*(temp_Data.get(i-j, 3)-mean); <br /> variance = variance/WinSize;<br /> output_Data.set(i-WinSize, col, (temp_Data.get(i,col)-mean)/Math.sqrt(variance));<br /> }<br /> }<br /> return output_Data;<br /> }<br /> <br /> public static DenseMatrix GetObservationState(DenseMatrix Obser, double Threshold)<br /> {<br /> // Find out the size of a non-zero submatrix of Obser<br /> int NonZeroRowSize = 0;<br /> for (int i = 1; i < = Obser.nRows(); i++)<br /> if (Obser.get(i,1)>0) NonZeroRowSize++;<br /> <br /> DenseMatrix output_GetObser = new DenseMatrix (new double[NonZeroRowSize][Obser.nCols()]);<br /> for (int i = 1; i< =NonZeroRowSize; i++)<br /> {<br /> // Assign Date<br /> output_GetObser.set(i, 1, Obser.get(i, 1));<br /> // Assign Price<br /> output_GetObser.set(i, 2, Obser.get(i, 2));<br /> // Assign state<br /> for (int col = 3; col < = Obser.nCols(); col++)<br /> {<br /> if (Obser.get(i, col)< (-1)*Threshold)<br /> output_GetObser.set(i, col, 1);<br /> else if (Obser.get(i, col)> Threshold)<br /> output_GetObser.set(i, col, 3);<br /> else<br /> output_GetObser.set(i, col, 2);<br /> }<br /> <br /> }<br /> <br /> return GenerateObservationValue(output_GetObser);<br /> }<br /> <br /> <br /> // It generate the state by the weighted average of observation state (default factors 1)<br /> // If the observation<i> = {1, 2, 3, 3, 2}, then translate it to {-1, 0, 1, 1, 0}<br /> // Add all those observation value. Max value = Size; Min Value = -Size<br /> public static DenseMatrix GenerateObservationValue(DenseMatrix output_GetObser)<br /> {<br /> DenseMatrix OutMx = new DenseMatrix(new double [output_GetObser.nRows()][3]);<br /> for (int row = 1; row< =output_GetObser.nRows(); row ++)<br /> {<br /> int SumObservation = 0;<br /> for (int col = 3; col < = output_GetObser.nCols(); col++)<br /> SumObservation += output_GetObser.get(row, col);<br /> // Consider there are two observations, min_value = 2 and max_value = 6<br /> // We need to transfer it to observation values from 1 to 5<br /> OutMx.set(row, 1, output_GetObser.get(row, 1));<br /> OutMx.set(row, 2, output_GetObser.get(row, 2));<br /> OutMx.set(row, 3, SumObservation-(output_GetObser.nCols()-3));<br /> } <br /> return OutMx;<br /> }<br /> <br /> // Return a random matrix<br /> public static DenseMatrix GenerateRandomMatrix(int rowsize, int colsize){<br /> Random generator = new Random();<br /> <br /> double r1 = generator.nextDouble();<br /> double r2 = generator.nextDouble();<br /> double sum = r1 + r2;<br /> r1 = r1/sum;<br /> r2 = r2/sum; <br /> double sum_a; <br /> <br /> DenseMatrix ResultMatrix = new DenseMatrix(new double[rowsize][colsize]);<br /> double[] r_a = new double[colsize+1];<br /> <br /> <br /> for ( int j = 1; j< =rowsize;j++){<br /> sum_a =0;<br /> for (int i=1;i< =colsize;i++){<br /> r_a</i><i> = generator.nextDouble();<br /> sum_a = r_a</i><i> + sum_a;<br /> }<br /> for (int i=1;i< =colsize;i++){<br /> r_a</i><i> = r_a</i><i>/sum_a;<br /> }<br /> for ( int k = 1;k< = colsize;k++){<br /> ResultMatrix.set(j, k, r_a[k]);<br /> }<br /> }<br /> return ResultMatrix;<br /> }<br /> }<br /> </i>