dmlc分布式线性模型编译笔记

阅读更多
1、使用第三方修改后的wormhole工程


原始工程wormhole: https://github.com/dmlc/wormhole
文档: https://media.readthedocs.org/pdf/wormhole/latest/wormhole.pdf
在线文档: https://wormhole.readthedocs.io/en/latest/


下面的这个虽然比较新,但是。。。根本没开发完成!!!
difacto: https://github.com/dmlc/difacto

第三方修改过的:
https://github.com/CNevd/Difacto_DMLC
因为tracker原因,该项目在我自己搭建的hadoop(单机)上没问题,但是公司平台上运行不起来
tracker最终使用的是dmlc core的tracker(直接复制tracker文件夹即可,但是参数名称有变化);

最终使用的修改过tracker后的工程: https://github.com/cherishlc/Difacto_DMLC

2、找不到glog库的问题
注意:也可使用编译选项make USE_GLOG=0 从而不依赖glog
到 https://github.com/google/glog 下载一下,编译
注意:如果./autogen.sh && ./configure && make && make install命令的最后一步安装因权限问题无法解决,可以通过设置LD_LIBRARY_PATH, LIBRARY_PATH 等环境变量解决:
export GLOG_HOME=/home/user/glog

# g++ 引用的头文件路径
export EXTRA_INCLUDES=$GLOG_HOME/src
# g++ 引用的lib文件路径
export LIBRARY_PATH=$LIBRARY_PATH:$GLOG_HOME/.libs
# 运行程序时查找的动态链接库路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GLOG_HOME/.libs



3、编译
以下编译选项打开了HDFS开关,并且不依赖glog
make USE_HDFS=1 USE_GLOG=0 -j8

export MAKEDMLC="make USE_HDFS=1 USE_GLOG=0 -j8"
cd dmlc-core; $MAKEDMLC; cd -
cd ps-lite; $MAKEDMLC; cd -
cd src/linear; $MAKEDMLC


4、yarn任务提交
调用链:
TODO


/Difacto_DMLC/dmlc-core/yarn/src/org/apache/hadoop/yarn/dmlc/Client.java

5、logistic regression代码阅读

#训练数据的内部存储格式; 以稀疏矩阵形式存储
src/solver/minibatch_solver.h:  using Minibatch = dmlc::RowBlock;
dmlc-core/include/dmlc/data.h:  template struct RowBlock {

#index 比如 第0个特征的 FeaID为0
src/linear/async_sgd.h:using FeaID = ps::Key;



#真正执行训练的地方
src/linear/async_sgd.h:  virtual void ProcessMinibatch(const Minibatch& mb, const Workload& wl) {
线性模型的计算是在ProcessMinibatch函数中的loss->Init函数:
src/linear/loss.h: loss->Init(data->GetBlock(), *val, nt_);
void Init(const RowBlock& data,
    const std::vector& w, int nt) {
data_ = data;
Xw_.resize(data_.size);
SpMV::Times(data_, w, &Xw_, nt_); // linear model here
nt_ = nt;
init_ = true;
}

线性部分(不包括sigmoid)的计算是在SpMV::Times函数,其实就是个 乘法+累加的运算
其定义在:
src/base/spmv.h
关键代码: 
if (D.value) {//D为dmlc::RowBlock;  D.value不为空,说明在libsvm 格式的训练文件中, 0 1:0.5 2:1中权重有不为1的情况; 这时,线性模型就会考虑这些权重!!!
  for (size_t j = D.offset[i]; j < D.offset[i+1]; ++j)
    y_i += x[D.index[j]] * D.value[j];
} else {
  for (size_t j = D.offset[i]; j < D.offset[i+1]; ++j)
    y_i += x[D.index[j]];
}



6、关于logistic loss
从下面的代码中可以看到,输入中的label只区分是否大于0,大于0则认为是正样本,否则为负样本
至于logistic regression中标签取0\1和取1,-1的区别(实际上没有区别,只是loss的形式不同,但loss的值是完全一样的),
可以参考博客: https://www.cnblogs.com/bentuwuying/p/6616680.html
定义在src/linear/loss.h: template  class LogitLoss
最终调用的是:src/base/binary_class_evaluation.h:  V LogitObjv()
  V LogitObjv() {
    V objv = 0;
#pragma omp parallel for reduction(+:objv) num_threads(nt_)
    for (size_t i = 0; i < size_; ++i) {
      V y = label_[i] > 0 ? 1 : -1;
      V score = y * predict_[i];
      if (score < -30)
        objv += -score;
      else if (score <= 30)
        objv += log( 1 + exp( - score ));
    }
    return objv;
  }


7、数据读取
0、在工程目录搜索libsvm文件名,可以发现libsvm格式的解析类位于dmlc-core/src/data/libsvm_parser.h中,解析方法为ParseBlock()

但是解析函数是被谁调用的呢?博主按如下方式进行的查找:
1、上文提到,真正执行训练的是src/linear/async_sgd.h中的AsgdWorker类,训练函数为ProcessMinibatch();在其中没有找到数据读取的相关函数
2、AsgdWorker类的父类为solver::MinibatchWorker, 位于src/solver/minibatch_solver.h中
3、ProcessMinibatch()虚函数在solver::MinibatchWorker的Process()方法中被调用,这里可以看到dmlc::data::MinibatchIter reader; 这个reader就是读取数据的类了,该类位于src/base/minibatch_iter.h中。
4、reader传递给ProcessMinibatch()函数的数据为reader.Value()
5、reader.Value()返回reader的成员变量out_blk_;  out_blk_在成员函数Next()的末尾被设为out_blk_ = mb_.GetBlock();
6、继续追溯,mb_在成员函数Next()中通过Push()方法被设置,在Push方法中,mb_通过in_blk_设置;而Next方法中有一句in_blk_ = parser_->Value();

至此,数据流分析完毕
  reader(比如LibSVMParser)
  => solver::MinibatchWorker的 in_blk_ => mb_ => out_blk_
  => AsgdWorker::ProcessMinibatch() mb 通过localize=> data
  => loss->Init(data->GetBlock(), *val, nt_); 声明loss,并将data赋值到其中

因而,如果想修改libsvm数据的解析方式及使用方式,需要修改的地方有:
  数据读取:LibSVMParser类中的ParseBlock()函数
  将读取的数据分片: MinibatchIter类中的Push函数
  数据本地化:Localizer类中的RemapIndex()函数
  计算梯度时使用样本权重:LogitLoss中的CalcGrad函数
 

你可能感兴趣的:(dmlc,线性模型,分布式)