dmlc-core源码阅读

核心代码

dmlc/data.h

RowBlock:把样本矩阵X转换成一维向量存储。可以结合spmv.h中的矩阵乘法理解。

此外,offset起始可以不为0,这样可以把输入的样本切割为很多个RowBlock

template<typename IndexType>
struct RowBlock {
  /*! \brief batch size */
  size_t size;  // 样本数量
  /*! \brief array[size+1], row pointer to beginning of each rows */
  const size_t *offset;  // 每个样本的偏移位置,搭配index和label使用
  /*! \brief array[size] label of each instance */
  const real_t *label;   // 样本label
  /*! \brief With weight: array[size] label of each instance, otherwise nullptr */
  const real_t *weight;   // 该样本自身权重,一般不设置(adaboost有用?)
  /*! \brief feature index */
  const IndexType *index; // 样本的特征id,是一种稀疏化表示
  /*! \brief feature value, can be NULL, indicating all values are 1 */
  const real_t *value;   // 样本各特征的值,NULL则均为1,比如one-hot之后
  // ....
}

示例:

  • size = 2 该RowBlock包含两个样本,样本类型是Row<IndexType>
  • offset = 4, 7, 8 第一个样本3个特征,第二个样本1个特征,且offset起始为4,说明这不是第一个RowBlock
  • label = 1, 0 第一个样本label:1,第二个样本label:0
  • index = 0, 1, 3, 1 第一个样本包含特征id:0、1、3,第二个样本包含特征id:1
  • value = 1, 0, 0, 1 第一个样本对应特征值:1、0、0,第二个样本对应特征值:1

src/data/row_block.h

RowBlockContainer 搭配RowBlock使用,是实际保存数据的结构。 RowBlock里只是一些指针,指向RowBlockContainer的动态内存。

两个Push()函数,用于填充RowRowBlock。 同时实现了Load()Save()用于序列化。

dmlc/io.h

InputSplit 基类,从各种dataset读取记录。

  • SingleFileSplit stdin
  • LineSplitter text类型,逐行读取
  • RecordIOSplitter recordio类型
  • ThreadedInputSplit 使用c++11编译,支持thread预读取
  • CachedInputSplit uri里带 # 指定cache文件

Create() 工厂方法,根据uri、part index、文件类型(text或者recordio)创建InputSplit实例。

参考

  • https://github.com/dmlc/dmlc-core