日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

隐马尔科夫模型(HMM)的无监督学习算法java实现(baum-welch迭代求解),包括串行以及并行实现

發布時間:2023/12/29 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 隐马尔科夫模型(HMM)的无监督学习算法java实现(baum-welch迭代求解),包括串行以及并行实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

HMM的原理就不說了,這里主要說算法的實現。

?

實際實現起來并不是很困難,前提是你仔細看過hmm的原理,然后很多實現就照著公式寫出對應的代碼,比如前向算法,后向算法,參數更新都是有明確的公式的,只需要對應寫成代碼,這里需要提到2點技巧。

1,所有概率需要取對數,這是因為有的概率實在是太小了,容易溢出,或者精度不夠。

2.對一個求和的式子取對數概率時需要用到一個技巧。下面直接貼出我寫的關于這個計算技巧的理解。

LogSum計算技巧

如果需要計算下面的式子:

其中α是一個概率,只知道 而不知道 ,此時如果直接計算會溢出,為了解決這個問題就可以用到這個logSum計算技巧。傳入參數是一個數組,每個元素為 ,找到其中的最大值

,根據:

示例代碼:

這是一個java版本實現的無監督HMM,包括學習算法和預測算法,算法沒有錯誤,我已經做過多次測試,但是由于HMM的訓練算法就是EM算法,而EM算法對初值十分敏感,所以訓練時必須給定一些先驗條件,即需要給定HMM中的參數pi,A,B至少其中一個,不然訓練出來的參數將時一樣的,毫無意義。當然無監督的HMM效果依然不如監督學習的HMM,我測試了一下分詞,給定了一個監督學習HMM分詞的參數來訓練無監督的HMM,效果如下:

無監督HMM效果:給定參數pi和B 參數已收斂.... 最終參數: pi:[0.0, -2.1474836360090876E9, -2.147483633470365E9, -2.1474836334854264E9] A: [-2.1474836482889004E9, -2.2141536347013195, -0.115686913295864, -2.147483648337081E9] [-2.1474836479972153E9, -1.0239098431251064, -0.4450188807874582, -2.1474836480612097E9] [-0.7149451174254677, -2.1474836483350754E9, -2.147483648333808E9, -0.6718142750423626] [-0.4322715044602754, -2.1474836481090927E9, -2.1474836481949987E9, -1.0470634684331648] [原標題, :, 日, 媒拍, 到, 了, 現場, 罕見, 一幕, 據, 日本, 新聞, 網, (, N, NN, ), 9月, 8日, 報道, ,, 日前, ,, 日本, 海上, 自衛隊, 現役, 最大, 戰艦, 之一, 的, 直升, 機航, 母, “, 加賀, ”, 號在, 南, 海航, 行時, ,, 遭多, 艘, 中國, 海軍, 戰艦, 抵, 近跟, 蹤, 監視, 。]監督學習HMM: [原, 標題, :, 日媒, 拍到, 了, 現場, 罕見, 一幕, 據, 日本, 新聞網, (, NN, N)9月8日, 報道, ,, 日前, ,, 日本, 海上, 自衛隊, 現役, 最大, 戰艦, 之, 一, 的, 直升, 機航母, “, 加賀, ”, 號, 在, 南海, 航行, 時, ,, 遭多, 艘, 中國, 海軍, 戰艦, 抵近, 跟蹤, 監視, 。]

雖然沒有指定參數A,但是可以看到學習出來的A還是有準確性,比如B轉移到B的概率為0,B轉移到S的概率為0,M轉移到M的概率為0,M轉移到S的概率為0.....這和監督學習的HMM一樣的。

這樣看來這個算法確實有效。

光從結果來看無監督的HMM指定了pi和B參數,整體效果還是差于監督學習的HMM。測試語料只有人民日報1998的分割語料。

由于原代碼比較長,并且本來是寫到我的開源項目中的,所以不簡單是整合到一個類中就是所有代碼,還包含了一些依賴。

這里我整理出了串行版本的只包好2個依賴的代碼,供學習使用,由于訓練中很多步驟都可以并行實現,所以我并行了一些消耗時間的步驟,要比串行的快得多。過幾天我會更新到github上,完整的源碼請參考我的開源項目:GitHub - colin0000007/CONLP: 一個自然語言處理初學者可以參考的庫,包含分詞,詞性標注,命名實體識別,依存句法分析大多模型和算法都是自己實現 。a natural language processing library for beginners

代碼中需要用到語料以及HMM的參數A和B:

語料以及參數A和B.rar_免費高速下載|百度網盤-分享無限制

下面是串行版本的代碼,:

package com.outsider.test;import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; /*** * 無監督學習的HMM實現* 少量數據建議串行* 大量數據,幾十萬,百萬甚至更高的數據強烈建議并行訓練,性能是串行的好4倍以上* @author outsider*/ public class UnsupervisedFirstOrderGeneralHMM{private double precision = 1e-7;/*** 訓練數據長度*/private int sequenceLen;public Logger logger = Logger.getLogger(UnsupervisedFirstOrderGeneralHMM.class.getName());/**初始狀態概率**/protected double[] pi;/**轉移概率**/protected double[][] transferProbability1;/**發射概率**/protected double[][] emissionProbability;/**定義無窮大**/public static final double INFINITY = (double) -Math.pow(2, 31);/**狀態值集合的大小**/protected int stateNum;/**觀測值集合的大小**/protected int observationNum;public UnsupervisedFirstOrderGeneralHMM() {super();}public UnsupervisedFirstOrderGeneralHMM(int stateNum, int observationNum, double[] pi,double[][] transferProbability1, double[][] emissionProbability) {this.stateNum = stateNum;this.observationNum = observationNum;this.pi = pi;this.transferProbability1 = transferProbability1;this.emissionProbability = emissionProbability;}public UnsupervisedFirstOrderGeneralHMM(int stateNum, int observationNum) {this.stateNum = stateNum;this.observationNum = observationNum;initParameters();}/*** λ是HMM參數的總稱*//*** 訓練方法* @param x 訓練序列數據* @param maxIter 最大迭代次數* @param precision 精度*/public void train(int[] x, int maxIter, double precision) {this.sequenceLen = x.length;baumWelch(x, maxIter, precision);}public void train(int[] x) {this.sequenceLen = x.length;//不做概率歸一化}/*** baumWelch算法迭代求解* 迭代時存在這樣的現象:新參數和上一次的參數差反而會變大,但是到后面這個誤差值幾乎會收斂* 所以迭代終止的條件有2個:* 1.達到最大迭代次數* 2.參數A,B,pi中的值相比上一次的最大誤差小于某個精度值則認為收斂* 3.若1中給的精度值太大,則可能導致無法收斂,所以增加了一個條件,如果當前迭代的誤差和上一次迭代的誤差小于某個值(這里給定1e-7),* 可以認為收斂了。* @param x 觀測序列* @param maxIter 最大迭代次數,如果傳入<=0的數則默認為Integer.MAX_VALUE,相當于不收斂就不跳出循環* @param precision 參數誤差的精度小于precision就認為收斂*/protected void baumWelch(int[] x, int maxIter, double precision) {int iter = 0;double oldMaxError = 0;if(maxIter <= 0) {maxIter = Integer.MAX_VALUE;}//初始化各種參數double[][] alpha = new double[sequenceLen][stateNum];double[][] beta = new double[sequenceLen][stateNum];double[][] gamma = new double[sequenceLen][stateNum];double[][][] ksi = new double[sequenceLen][stateNum][stateNum];while(iter < maxIter) {logger.info("\niter"+iter+"...");long start = System.currentTimeMillis();//計算各種參數,為更新模型參數做準備,對應EM中的E步calcAlpha(x, alpha);calcBeta(x, beta);calcGamma(x, alpha, beta, gamma);calcKsi(x, alpha, beta, ksi);//更新參數,對應EM中的M步double[][] oldA = generateOldA();//double[][] oldB = generateOldB();//double[] oldPi = pi.clone();updateLambda(x, gamma, ksi);//double maxError = calcError(oldA, oldPi, oldB);double maxError = calcError(oldA, null, null);logger.info("max_error:"+maxError);if(maxError < precision || (Math.abs(maxError-oldMaxError)) < this.precision) {logger.info("參數已收斂....");break;}oldMaxError = maxError;iter++;long end = System.currentTimeMillis();logger.info("本次迭代結束,耗時:"+(end - start)+"毫秒");}logger.info("最終參數:");logger.info("pi:"+Arrays.toString(pi));logger.info("A:");for(int i = 0; i < transferProbability1.length; i++) {logger.info(Arrays.toString(transferProbability1[i]));}}/*** 保存舊的參數A* @return*/protected double[][] generateOldA() {double[][] oldA = new double[stateNum][stateNum];for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {oldA[i][j] = transferProbability1[i][j];}}return oldA;}/*** 保存舊的參數B* @return*/protected double[][] generateOldB() {double[][] oldB = new double[stateNum][observationNum];for(int i = 0; i < stateNum; i++) {for(int j = 0; j < observationNum; j++) {oldB[i][j] = emissionProbability[i][j];}}return oldB;}/*** 暫時只計算參數A的誤差* 發現計算B和pi會發現參數誤差越來越大的現象,基本不能收斂* @param old* @return*/protected double calcError(double[][] oldA, double[] oldPi, double[][] oldB) {double maxError = 0;for(int i =0 ; i < stateNum; i++) {/*double tmp1 = Math.abs(pi[i] - oldPi[i]);maxError = tmp1 > maxError ? tmp1 : maxError;*/for(int j =0; j < stateNum; j++) {double tmp = Math.abs(oldA[i][j] - transferProbability1[i][j]);maxError = tmp > maxError ? tmp : maxError;}/*for(int k =0; k < observationNum; k++) {double tmp2 = Math.abs(emissionProbability[i][k] - oldB[i][k]);maxError = tmp2 > maxError ? tmp2 : maxError;}*/}return maxError;}/*** 概率初始化為0*/public void initParameters() {//初始概率隨機初始化pi = new double[stateNum];transferProbability1 = new double[stateNum][stateNum];emissionProbability = new double[stateNum][observationNum];//概率初始化為0for(int i = 0; i < stateNum; i++) {pi[i] = INFINITY;for(int j = 0; j < stateNum; j++) {transferProbability1[i][j] = INFINITY;}for(int k = 0; k < observationNum; k++) {emissionProbability[i][k] = INFINITY;}}}/*** 數組求和* @param arr* @return*/public static double sum(double[] arr) {double sum = 0;for(int i = 0; i < arr.length;i++) {sum += arr[i];}return sum;}/*** 隨機初始化參數PI*/public void randomInitPi() {for(int i = 0; i < stateNum; i++) {pi[i] = Math.random() * 100;}//log歸一化double sum = Math.log(sum(pi));for(int i =0; i < stateNum; i++) {if(pi[i] == 0) {pi[i] = INFINITY;continue;}pi[i] = Math.log(pi[i]) - sum;}}/*** 隨機初始化參數A*/public void randomInitA() {for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {transferProbability1[i][j] = Math.random()*100;;}double sum = Math.log(sum(transferProbability1[i]));for(int k = 0; k < stateNum; k++) {if(transferProbability1[i][k] == 0) {transferProbability1[i][k] = INFINITY;continue;}transferProbability1[i][k] = Math.log(transferProbability1[i][k]) - sum;}}}/*** 隨機初始化參數B*/public void randomInitB() {for(int i = 0; i < stateNum; i++) {for(int j = 0; j < observationNum; j++) {emissionProbability[i][j] = Math.random()*100;;}double sum = Math.log(sum(emissionProbability[i]));for(int k = 0; k < observationNum; k++) {if(emissionProbability[i][k] == 0) {emissionProbability[i][k] = INFINITY;continue;}emissionProbability[i][k] = Math.log(emissionProbability[i][k]) - sum;}}}/*** 隨機初始化所有參數*/public void randomInitAllParameters() {randomInitA();randomInitB();randomInitPi();}/*** 前向算法,根據當前參數λ計算α* α是一個序列長度*狀態長度的矩陣* 已檢測,應該沒有問題*/protected void calcAlpha(int[] x, double[][] alpha) {logger.info("計算alpha...");long start = System.currentTimeMillis();//double[][] alpha = new double[sequenceLen][stateNum];//alpha t=0初始值for(int i = 0; i < stateNum; i++) {alpha[0][i] = pi[i] + emissionProbability[i][x[0]];}double[] logProbaArr = new double[stateNum];for(int t = 1; t < sequenceLen; t++) {for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {logProbaArr[j] = (alpha[t -1][j] + transferProbability1[j][i]);}alpha[t][i] = logSum(logProbaArr) + emissionProbability[i][x[t]];}}long end = System.currentTimeMillis();logger.info("計算結束...耗時:"+ (end - start) +"毫秒");//return alpha;}/*** 后向算法,根據當前參數λ計算β* * @param x*/protected void calcBeta(int[] x, double[][] beta) {logger.info("計算beta...");long start = System.currentTimeMillis();//double[][] beta = new double[sequenceLen][stateNum];//初始概率beta[T][i] = 1for(int i = 0; i < stateNum; i++) {beta[sequenceLen-1][i] = 1;}double[] logProbaArr = new double[stateNum];for(int t = sequenceLen -2; t >= 0; t--) {for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {logProbaArr[j] = transferProbability1[i][j] + emissionProbability[j][x[t+1]] +beta[t + 1][j];}beta[t][i] = logSum(logProbaArr);}}long end = System.currentTimeMillis();logger.info("計算結束...耗時:"+ (end - start) +"毫秒");//return beta;}/*** 根據當前參數λ計算ξ* @param x 觀測結點* @param alpha 前向概率* @param beta 后向概率*/protected void calcKsi(int[] x, double[][] alpha, double[][] beta, double[][][] ksi) {logger.info("計算ksi...");long start = System.currentTimeMillis();//double[][][] ksi = new double[sequenceLen][stateNum][stateNum];double[] logProbaArr = new double[stateNum * stateNum];for(int t = 0; t < sequenceLen -1; t++) {int k = 0;for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {ksi[t][i][j] = alpha[t][i] + transferProbability1[i][j] +emissionProbability[j][x[t+1]]+beta[t+1][j];logProbaArr[k++] = ksi[t][i][j];}}double logSum = logSum(logProbaArr);//分母for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {ksi[t][i][j] -= logSum;//分子除分母}}}long end = System.currentTimeMillis();logger.info("計算結束...耗時:"+ (end - start) +"毫秒");//return ksi;}/*** 根據當前參數λ,計算γ* @param x*/protected void calcGamma(int[] x, double[][] alpha, double[][] beta, double[][] gamma) {logger.info("計算gamma...");long start = System.currentTimeMillis();//double[][] gamma = new double[sequenceLen][stateNum];for(int t = 0; t < sequenceLen; t++) {//分母需要求LogSumfor(int i = 0; i < stateNum; i++) {gamma[t][i] = alpha[t][i] + beta[t][i];}double logSum = logSum(gamma[t]);//分母部分for(int j = 0; j < stateNum; j++) {gamma[t][j] = gamma[t][j] - logSum;}}long end = System.currentTimeMillis();logger.info("計算結束...耗時:"+ (end - start) +"毫秒");//return gamma;}/*** 更新參數*/protected void updateLambda(int[] x ,double[][] gamma, double[][][] ksi) {//順序可以顛倒updatePi(gamma);updateA(ksi, gamma);updateB(x, gamma);}/*** 更新參數pi* @param gamma*/public void updatePi(double[][] gamma) {//更新HMM中的參數pifor(int i = 0; i < stateNum; i++) {pi[i] = gamma[0][i];}}/*** 更新參數A* @param ksi* @param gamma*/protected void updateA(double[][][] ksi, double[][] gamma) {logger.info("更新參數轉移概率A...");由于在更新A都要用到對不同狀態的前T-1的gamma值求和,所以這里先算double[] gammaSum = new double[stateNum];double[] tmp = new double[sequenceLen -1];for(int i = 0; i < stateNum; i++) {for(int t = 0; t < sequenceLen -1; t++) {tmp[t] = gamma[t][i];}gammaSum[i] = logSum(tmp);}long start1 = System.currentTimeMillis();//更新HMM中的參數Adouble[] ksiLogProbArr = new double[sequenceLen - 1];for(int i = 0; i < stateNum; i++) {for(int j = 0; j < stateNum; j++) {for(int t = 0; t < sequenceLen -1; t++) {ksiLogProbArr[t] = ksi[t][i][j];}transferProbability1[i][j] = logSum(ksiLogProbArr) - gammaSum[i];}}long end1 = System.currentTimeMillis();logger.info("更新完畢...耗時:"+(end1 - start1)+"毫秒");}/*** 更新參數B* @param x* @param gamma*/protected void updateB(int[] x, double[][] gamma) {//下面需要用到gamma求和為了減少重復計算,這里直接先計算//由于在更新B時都要用到對不同狀態的所有gamma值求和,所以這里先算double[] gammaSum2 = new double[stateNum];double[] tmp2 = new double[sequenceLen];for(int i = 0; i < stateNum; i++) {for(int t = 0; t < sequenceLen; t++) {tmp2[t] = gamma[t][i];}gammaSum2[i] = logSum(tmp2);}logger.info("更新狀態下分布概率B...");long start2 = System.currentTimeMillis();ArrayList<Double> valid = new ArrayList<Double>();for(int i = 0; i < stateNum; i++) {for(int k = 0; k < observationNum; k++) {valid.clear();//由于這里沒有初始化造成了計算出錯的問題for(int t = 0; t < sequenceLen; t++) {if(x[t] == k) {valid.add(gamma[t][i]);}}//B[i][k],i狀態下k的分布為概率0,if(valid.size() == 0) {emissionProbability[i][k] = INFINITY;continue;}//對分子求logSumdouble[] validArr = new double[valid.size()];for(int q = 0; q < valid.size(); q++) {validArr[q] = valid.get(q);}double validSum = logSum(validArr);//分母的logSum已經在上面做了emissionProbability[i][k] = validSum - gammaSum2[i];}}long end2 = System.currentTimeMillis();logger.info("更新完畢...耗時:"+(end2 - start2)+"毫秒");}/*** logSum計算技巧* @param tmp* @return*/public double logSum(double[] logProbaArr) {if(logProbaArr.length == 0) {return INFINITY;}double max = max(logProbaArr);double result = 0;for(int i = 0; i < logProbaArr.length; i++) {result += Math.exp(logProbaArr[i] - max);}return max + Math.log(result);}/*** 設置先驗概率pi* 必須傳入取對數后的概率* @param pi*/public void setPriorPi(double[] pi){this.pi = pi;}/*** 設置先驗轉移概率A* 必須傳入取對數的概率* @param trtransferProbability1*/public void setPriorTransferProbability1(double[][] trtransferProbability1){this.transferProbability1 = trtransferProbability1;}/*** 設置先驗狀態下的觀測分布概率,B* 必須傳入取對數的概率* @param emissionProbability*/public void setPriorEmissionProbability(double[][] emissionProbability) {this.emissionProbability = emissionProbability;}public static double max(double[] arr) {double max = arr[0];for(int i = 1; i < arr.length;i++) {max = arr[i] > max ? arr[i] : max;}return max;}/*** 維特比解碼* @param O 觀測序列,輸入的是經過編碼處理的,而不是原始數據,* 比如,如果序列是字符串,那么輸入必須是一系列的字符的編碼而不是字符本身* @return 返回預測結果,*/public int[] verterbi(int[] O) {double[][] deltas = new double[O.length][this.stateNum];//保存deltas[t][i]的值是由上一個哪個狀態產生的int[][] states = new int[O.length][this.stateNum];//初始化deltas[0][]for(int i = 0;i < this.stateNum; i++) {deltas[0][i] = pi[i] + emissionProbability[i][O[0]];}//計算deltasfor(int t = 1; t < O.length; t++) {for(int i = 0; i < this.stateNum; i++) {deltas[t][i] = deltas[t-1][0]+transferProbability1[0][i];for(int j = 1; j < this.stateNum; j++) {double tmp = deltas[t-1][j]+transferProbability1[j][i];if (tmp > deltas[t][i]) {deltas[t][i] = tmp;states[t][i] = j;}}deltas[t][i] += emissionProbability[i][O[t]];}}//回溯找到最優路徑int[] predict = new int[O.length];double max = deltas[O.length-1][0];for(int i = 1; i < this.stateNum; i++) {if(deltas[O.length-1][i] > max) {max = deltas[O.length-1][i];predict[O.length-1] = i; }}for(int i = O.length-2;i >= 0;i-- ) {predict[i] = states[i+1][predict[i+1]];}return predict;}//測試public static void main(String[] args) {UnsupervisedFirstOrderGeneralHMM hmm = new UnsupervisedFirstOrderGeneralHMM(4, 65536);//關閉日志打印//CONLPLogger.closeLogger(hmm.logger);//由于是監督學習的語料所以這里需要去掉其中的分隔符String path = "src/pku_training.splitBy2space.utf8";String data = IOUtils.readText(path, "utf-8");String[] d2 = data.split(" ");StringBuilder sb = new StringBuilder();for(String word : d2) {sb.append(word);}data = sb.toString();//訓練數據int[] x = SegmentationUtils.str2int(data);//由于串行很慢,可以只取訓練數據的前10000個來訓練int[] minX = new int[10000];System.arraycopy(x, 0, minX, 0, 10000);//訓練之前設置先驗概率,必須設置,EM對初始值敏感,如果不設置默認為都為0,所有參數都將一樣,沒有意義//如果只給了其中一些參數的先驗值,可以隨機初始化其他參數,例如//hmm.randomInitA();//hmm.randomInitB();//hmm.randomInitPi();//hmm.randomInitAllParameters();//設置先驗信息至少設置參數pi,A,B中的一個hmm.setPriorPi(new double[] {-1.138130826175848, -2.632826946498266, -1.138130826175848, -1.2472622308278396});hmm.setPriorTransferProbability1((double[][]) IOUtils.readObject("src/A"));hmm.setPriorEmissionProbability((double[][]) IOUtils.readObject("src/B"));//開始訓練hmm.train(minX, -1, 0.5);String str = "原標題:日媒拍到了現場罕見一幕" + "據日本新聞網(NNN)9月8日報道,日前,日本海上自衛隊現役最大戰艦之一的直升機航母“加賀”號在南海航行時,遭多艘中國海軍戰艦抵近跟蹤監視。" ; //將詞轉換為對應的Unicode碼int[] O = SegmentationUtils.str2int(str);int[] predict = hmm.verterbi(O);System.out.println(Arrays.toString(predict));String[] res = SegmentationUtils.decode(predict, str);System.out.println(Arrays.toString(res));} }

依賴IoUtils:

package com.outsider.test;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List;public class IOUtils {public static String readTextWithLineCheckBreak(String path, String encoding) {return readText(path, encoding, "\n");}/*** 讀取文本文件,返回整個字符串,不包括換行符號* @param path 文件路徑* @param encoding 編碼,傳入null或者空串使用默認編碼* @return*/public static String readText(String path, String encoding) {return readText(path, encoding, null);}/*** 讀取文本,指定每一行末尾符號* @param path* @param encoding* @param lineEndStr* @return*/public static String readText(String path, String encoding, String lineEndStr) {try {if(lineEndStr == null) {lineEndStr = "";}BufferedReader reader = null;if((!encoding.trim().equals(""))&&encoding!=null) {reader = new BufferedReader(new InputStreamReader(new FileInputStream(path),encoding));} else {reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));}String s="";StringBuilder sb = new StringBuilder();while((s=reader.readLine())!=null) {sb.append(s+lineEndStr);}reader.close();return sb.toString();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}/*** 讀取文本文件,返回整個字符串,不包括換行符號* @param path 文件路徑* @param encoding 編碼,傳入null或者空串使用默認編碼* @param addNewLine 是否加換行符* @return*/public static List<String> readTextAndReturnLinesCheckLineBreak(String path, String encoding, boolean addNewLine) {try {String lineBreak;if(addNewLine) {lineBreak = "\n";} else {lineBreak = "";}BufferedReader reader = null;if((!encoding.trim().equals(""))&&encoding!=null) {reader = new BufferedReader(new InputStreamReader(new FileInputStream(path),encoding));} else {reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));}String s="";List<String> list = new ArrayList<>();while((s=reader.readLine())!=null) {list.add(s+lineBreak);}reader.close();return list;} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}public static List<String> readTextAndReturnLines(String path, String encoding){return readTextAndReturnLinesCheckLineBreak(path, encoding, false);}/*** 讀取文本的每一行* 并且返回數組形式* @param path* @param encoding* @return*/public static String[] readTextAndReturnLinesOfArray(String path, String encoding){List<String> lines = readTextAndReturnLines(path, encoding);String[] arr = new String[lines.size()];lines.toArray(arr);return arr;}/*** 寫入文本文件* @param data* @param path* @param encoding*/public static void writeTextData2File(String data,String path,String encoding) {try {BufferedWriter writer = null;if((!encoding.trim().equals(""))&&encoding!=null) {writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path),encoding));} else {writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));}writer.write(data);writer.close();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** 把對象寫入文件* @param path* @param object*/public static void writeObject2File(String path, Object object) {try {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path));out.writeObject(object);out.close();} catch (Exception e) {e.printStackTrace();} }/*** 讀取對象* @param path* @return*/public static Object readObject(String path) {try {ObjectInputStream in = new ObjectInputStream(new FileInputStream(path));return in.readObject();} catch (Exception e) {e.printStackTrace();}return null; }}

依賴的SegmentationUtils:

package com.outsider.test;import java.util.ArrayList; import java.util.List;public class SegmentationUtils {/*** 將字符串數組的每一個字符串中的字符直接轉換為Unicode碼* @param strs 字符串數組* @return Unicode值*/public static List<int[]> strs2int(String[] strs) {List<int[]> res = new ArrayList<>(strs.length);for(int i = 0; i < strs.length;i++) {int[] O = new int[strs[i].length()];for(int j = 0; j < strs[i].length();j++) {O[j] = strs[i].charAt(j);}res.add(O);}return res;}public static int[] str2int(String str) {return strs2int(new String[] {str}).get(0);}/*** 根據預測結果解碼* BEMS 0123* @param predict 預測結果* @param sentence 句子* @return*/public static String[] decode(int[] predict, String sentence) {List<String> res = new ArrayList<>();char[] chars = sentence.toCharArray();for(int i = 0; i < predict.length;i++) {if(predict[i] == 0 || predict[i] == 1) {int a = i;while(predict[i] != 2) {i++;if(i == predict.length) {break;}}int b = i;if(b == predict.length) {b--;}res.add(new String(chars,a,b-a+1));} else {res.add(new String(chars,i,1));}}String[] s = new String[res.size()];return res.toArray(s);} }

總結

以上是生活随笔為你收集整理的隐马尔科夫模型(HMM)的无监督学习算法java实现(baum-welch迭代求解),包括串行以及并行实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。