我遇到的场景是:样本集有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 来源:优快云 原文:https://blog.youkuaiyun.com/fjssharpsword/article/details/73614719?utm_source=copy
1080

被折叠的 条评论
为什么被折叠?



