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++;
-
else
-
wrong++;
-
}
-
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_type
-
FileHandler.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呢?如果不能,就無法分佈或平行計算。理論上來說,雖然是同一模型和演算法,但訓練集不一樣,最終結果也是和樣本集有關係,沒有合併的理論基礎。所以這個思路應該是不行的。
當然如果能夠從理論上解決模型合併,給出數學證明,還是可以嘗試,可能對部分學習方法有效,如決策樹分支可以合併。有興趣的可以一起研究,前期是要對學習演算法有理論掌握,才能自己編寫分散式或並行模型演算法。現有的機器學習庫中,Spark平臺叢集上跑MLib庫的程式是否可以達到這種效果呢?Hadoop叢集的MapReduce我也沒想好怎麼用ML庫跑出分散式效果?這個課題有興趣的可以一起探索。
對於Java機器學習庫ML下步要實戰的三個方向:1)特徵抽取和選擇以及特徵值處理;2)模型引數調優,要求掌握該學習方法理論;3)針對具體應用採用不同的學習方法,還是要求掌握理論,要回答的出為什麼這個學習方法適用於這個任務呢?
--------------------- 作者:fjssharpsword 來源:CSDN 原文:https://blog.csdn.net/fjssharpsword/article/details/73614719?utm_source=copy