Java机器学习库ML之六关于模型迭代训练的思考
我遇到的場景是:樣本集有5000萬條,接近5個G,那么這樣的樣本集一次導入訓練,我放著一天一夜都沒跑出結果,機器性能還特別好,是64位linux有128G內存。
針對這樣的情況,我想到的是兩種思路:
1)將樣本集分割然后來迭代訓練模型,這個對模型結果理論上是沒有影響的,一次導入樣本集訓練,和多次導入樣本多次訓練同一個模型,最終模型結果應該是一致的;模型保存的針對訓練集所訓練出來的參數,如y=ax+b的a和b,樣本集分割后,一個子集訓練出的a和b經過下一個子集訓練就會變化,最終朝向整體樣本集要訓練的值。
這個方法,參考代碼如下:
package com.vip;import java.io.File;import be.abeel.util.Pair; import net.sf.javaml.classification.Classifier; import net.sf.javaml.classification.KNearestNeighbors; import net.sf.javaml.core.Dataset; import net.sf.javaml.core.DefaultDataset; import net.sf.javaml.core.DenseInstance; import net.sf.javaml.core.Instance; import net.sf.javaml.sampling.Sampling; import net.sf.javaml.tools.data.FileHandler;public class VIPClassifer {public static void main(String[] args)throws Exception {if (args.length != 2) {System.err.println("Usage: 輸入訓練集和測試集路徑");System.exit(2);} Sampling s = Sampling.SubSampling;//Contruct a KNN classifier that uses 5 neighbors to make a decision.Classifier knn = new KNearestNeighbors(5);Dataset ds_validate=new DefaultDataset();for(int i=0;i<12;i++){//5000萬提交記錄,分成10份各500萬條String filePath=args[0]+"/lim_"+String.format("%02d", i);/* Load a data set 前面13列是訓練特征,最后1列標記*/Dataset ori_data = FileHandler.loadDataset(new File(filePath), 13, "\\s+");//抽樣訓練集和驗證集 Pair<Dataset, Dataset> sam_data = s.sample(ori_data, (int) (ori_data.size() * 0.9)); knn.buildClassifier(sam_data.x());//多樣本集追加訓練for(Instance inst:sam_data.y()){//加入驗證集ds_validate.add(inst);}System.out.println("訓練完成第"+String.valueOf(i)+"份樣本集");} //驗證集int correct = 0, wrong = 0;/* Classify all instances and check with the correct class values */for (Instance inst : ds_validate) {Object predictedClassValue = knn.classify(inst);Object realClassValue = inst.classValue();if (predictedClassValue.equals(realClassValue))correct++;elsewrong++;}System.out.println("Correct predictions " + correct);System.out.println("Wrong predictions " + wrong);//模型預測/* Load a data set 前面13列是訓練特征,最后2列是uid和spuid聯合標識*/Dataset pre_data = FileHandler.loadDataset(new File(args[1]),"\\s+");System.out.println(pre_data.instance(0));Dataset out_data = new DefaultDataset();for(Instance inst:pre_data){double[] values = new double[13]; for(int i=0;i<13;i++) values[i]=inst.value(i);Instance pre_inst = new DenseInstance(values); //無標記,13列特征參與訓練Object pre_classvalue = knn.classify(pre_inst);//預測結果//pre_inst.setClassValue(pre_classvalue);//標注預測結果double[] u_spu_id=new double[]{inst.value(13),inst.value(14)};Instance out_inst = new DenseInstance(u_spu_id,pre_classvalue); //帶標記out_data.add(out_inst);}//輸出u_Id+spu_id+action_typeFileHandler.exportDataset(out_data, new File("/data1/DataFountain/fangjs/output.txt"));} } //java -XX:-UseGCOverheadLimit -Xmx10240m -Xms10240m -jar fangjs/vip.jar fangjs/data test_features_new.txt //優化方向:樣本類別不均衡,特征抽取和特征值處理,模型調參或模型更換通過這個方法是否會和最終結果有差距,到時和python執行結果比較。
2)第二個思路我想的是模型合并,或者可以說是并行計算或分布計算,就是將樣本集分布到不同機子上然后用同一個算法訓練,最后合并模型。這個和模型集成有差別的,模型集成指的是對同一個訓練集采用不同模型訓練;而模型合并指的是對不同訓練集(同一樣本集分割出來)采用同一模型訓練。
模型合并的思路 ,我暫時沒想到怎么去試驗,因為對模型結果如何合并我還沒想到怎么處理。還是拿y=ax+b來說,分割出來的樣本子集用同一個模型訓練,一定是有不同的a和b,那用什么來合并a和b呢?如果不能,就無法分布或并行計算。理論上來說,雖然是同一模型和算法,但訓練集不一樣,最終結果也是和樣本集有關系,沒有合并的理論基礎。所以這個思路應該是不行的。
當然如果能夠從理論上解決模型合并,給出數學證明,還是可以嘗試,可能對部分學習方法有效,如決策樹分支可以合并。有興趣的可以一起研究,前期是要對學習算法有理論掌握,才能自己編寫分布式或并行模型算法?,F有的機器學習庫中,Spark平臺集群上跑MLib庫的程序是否可以達到這種效果呢?Hadoop集群的MapReduce我也沒想好怎么用ML庫跑出分布式效果?這個課題有興趣的可以一起探索。
對于Java機器學習庫ML下步要實戰的三個方向:1)特征抽取和選擇以及特征值處理;2)模型參數調優,要求掌握該學習方法理論;3)針對具體應用采用不同的學習方法,還是要求掌握理論,要回答的出為什么這個學習方法適用于這個任務呢?
總結
以上是生活随笔為你收集整理的Java机器学习库ML之六关于模型迭代训练的思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java机器学习库ML之五样本不均衡
- 下一篇: 【正一专栏】故意豪宅纵火的保姆会判死刑吗