Merge branch 'dev' of ssh://github.com/tqchen/xgboost into dev
Conflicts: regrank/xgboost_regrank_data.h
This commit is contained in:
@@ -28,40 +28,41 @@ namespace xgboost{
|
||||
name_obj_ = "reg";
|
||||
}
|
||||
/*!
|
||||
* \brief a regression booter associated with training and evaluating data
|
||||
* \param train pointer to the training data
|
||||
* \param evals array of evaluating data
|
||||
* \param evname name of evaluation data, used print statistics
|
||||
*/
|
||||
RegRankBoostLearner(const DMatrix *train,
|
||||
const std::vector<DMatrix *> &evals,
|
||||
const std::vector<std::string> &evname){
|
||||
* \brief a regression booter associated with training and evaluating data
|
||||
* \param mats array of pointers to matrix whose prediction result need to be cached
|
||||
*/
|
||||
RegRankBoostLearner(const std::vector<const DMatrix *>& mats){
|
||||
silent = 0;
|
||||
this->SetData(train, evals, evname);
|
||||
}
|
||||
|
||||
obj_ = NULL;
|
||||
name_obj_ = "reg";
|
||||
this->SetCacheData(mats);
|
||||
}
|
||||
/*!
|
||||
* \brief associate regression booster with training and evaluating data
|
||||
* \param train pointer to the training data
|
||||
* \param evals array of evaluating data
|
||||
* \param evname name of evaluation data, used print statistics
|
||||
*/
|
||||
inline void SetData(const DMatrix *train,
|
||||
const std::vector<DMatrix *> &evals,
|
||||
const std::vector<std::string> &evname){
|
||||
this->train_ = train;
|
||||
this->evals_ = evals;
|
||||
this->evname_ = evname;
|
||||
* \brief add internal cache space for mat, this can speedup prediction for matrix,
|
||||
* please cache prediction for training and eval data
|
||||
* warning: if the model is loaded from file from some previous training history
|
||||
* set cache data must be called with exactly SAME
|
||||
* data matrices to continue training otherwise it will cause error
|
||||
* \param mats array of pointers to matrix whose prediction result need to be cached
|
||||
*/
|
||||
inline void SetCacheData(const std::vector<const DMatrix *>& mats){
|
||||
// estimate feature bound
|
||||
int num_feature = (int)(train->data.NumCol());
|
||||
int num_feature = 0;
|
||||
// assign buffer index
|
||||
unsigned buffer_size = static_cast<unsigned>(train->Size());
|
||||
|
||||
for (size_t i = 0; i < evals.size(); ++i){
|
||||
buffer_size += static_cast<unsigned>(evals[i]->Size());
|
||||
num_feature = std::max(num_feature, (int)(evals[i]->data.NumCol()));
|
||||
unsigned buffer_size = 0;
|
||||
|
||||
utils::Assert( cache_.size() == 0, "can only call cache data once" );
|
||||
for( size_t i = 0; i < mats.size(); ++i ){
|
||||
bool dupilicate = false;
|
||||
for( size_t j = 0; j < i; ++ j ){
|
||||
if( mats[i] == mats[j] ) dupilicate = true;
|
||||
}
|
||||
if( dupilicate ) continue;
|
||||
cache_.push_back( CacheEntry( mats[i], buffer_size ) );
|
||||
buffer_size += static_cast<unsigned>(mats[i]->Size());
|
||||
num_feature = std::max(num_feature, (int)(mats[i]->data.NumCol()));
|
||||
}
|
||||
|
||||
|
||||
char str_temp[25];
|
||||
if (num_feature > mparam.num_feature){
|
||||
mparam.num_feature = num_feature;
|
||||
@@ -74,19 +75,18 @@ namespace xgboost{
|
||||
if (!silent){
|
||||
printf("buffer_size=%u\n", buffer_size);
|
||||
}
|
||||
|
||||
// set eval_preds tmp sapce
|
||||
this->eval_preds_.resize(evals.size(), std::vector<float>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief set parameters from outside
|
||||
* \param name name of the parameter
|
||||
* \param val value of the parameter
|
||||
*/
|
||||
* \brief set parameters from outside
|
||||
* \param name name of the parameter
|
||||
* \param val value of the parameter
|
||||
*/
|
||||
inline void SetParam(const char *name, const char *val){
|
||||
if (!strcmp(name, "silent")) silent = atoi(val);
|
||||
if (!strcmp(name, "eval_metric")) evaluator_.AddEval(val);
|
||||
if (!strcmp(name, "objective") ) name_obj_ = val;
|
||||
if (!strcmp(name, "num_class") ) base_gbm.SetParam("num_booster_group", val );
|
||||
mparam.SetParam(name, val);
|
||||
base_gbm.SetParam(name, val);
|
||||
cfg_.push_back( std::make_pair( std::string(name), std::string(val) ) );
|
||||
@@ -96,7 +96,13 @@ namespace xgboost{
|
||||
* this function is reserved for solver to allocate necessary space and do other preparation
|
||||
*/
|
||||
inline void InitTrainer(void){
|
||||
base_gbm.InitTrainer();
|
||||
if( mparam.num_class != 0 ){
|
||||
if( name_obj_ != "softmax" ){
|
||||
name_obj_ = "softmax";
|
||||
printf("auto select objective=softmax to support multi-class classification\n" );
|
||||
}
|
||||
}
|
||||
base_gbm.InitTrainer();
|
||||
obj_ = CreateObjFunction( name_obj_.c_str() );
|
||||
for( size_t i = 0; i < cfg_.size(); ++ i ){
|
||||
obj_->SetParam( cfg_[i].first.c_str(), cfg_[i].second.c_str() );
|
||||
@@ -104,16 +110,25 @@ namespace xgboost{
|
||||
evaluator_.AddEval( obj_->DefaultEvalMetric() );
|
||||
}
|
||||
/*!
|
||||
* \brief initialize the current data storage for model, if the model is used first time, call this function
|
||||
*/
|
||||
* \brief initialize the current data storage for model, if the model is used first time, call this function
|
||||
*/
|
||||
inline void InitModel(void){
|
||||
base_gbm.InitModel();
|
||||
mparam.AdjustBase();
|
||||
}
|
||||
/*!
|
||||
* \brief load model from stream
|
||||
* \param fi input stream
|
||||
*/
|
||||
* \brief load model from file
|
||||
* \param fname file name
|
||||
*/
|
||||
inline void LoadModel(const char *fname){
|
||||
utils::FileStream fi(utils::FopenCheck(fname, "rb"));
|
||||
this->LoadModel(fi);
|
||||
fi.Close();
|
||||
}
|
||||
/*!
|
||||
* \brief load model from stream
|
||||
* \param fi input stream
|
||||
*/
|
||||
inline void LoadModel(utils::IStream &fi){
|
||||
base_gbm.LoadModel(fi);
|
||||
utils::Assert(fi.Read(&mparam, sizeof(ModelParam)) != 0);
|
||||
@@ -144,77 +159,91 @@ namespace xgboost{
|
||||
fo.Write(&mparam, sizeof(ModelParam));
|
||||
}
|
||||
/*!
|
||||
* \brief update the model for one iteration
|
||||
* \param iteration iteration number
|
||||
* \brief save model into file
|
||||
* \param fname file name
|
||||
*/
|
||||
inline void UpdateOneIter(int iter){
|
||||
this->PredictBuffer(preds_, *train_, 0);
|
||||
obj_->GetGradient(preds_, train_->info, base_gbm.NumBoosters(), grad_, hess_);
|
||||
std::vector<unsigned> root_index;
|
||||
base_gbm.DoBoost(grad_, hess_, train_->data, root_index);
|
||||
inline void SaveModel(const char *fname) const{
|
||||
utils::FileStream fo(utils::FopenCheck(fname, "wb"));
|
||||
this->SaveModel(fo);
|
||||
fo.Close();
|
||||
}
|
||||
/*!
|
||||
* \brief update the model for one iteration
|
||||
*/
|
||||
inline void UpdateOneIter(const DMatrix &train){
|
||||
this->PredictRaw(preds_, train);
|
||||
obj_->GetGradient(preds_, train.info, base_gbm.NumBoosters(), grad_, hess_);
|
||||
if( grad_.size() == train.Size() ){
|
||||
base_gbm.DoBoost(grad_, hess_, train.data, train.info.root_index);
|
||||
}else{
|
||||
int ngroup = base_gbm.NumBoosterGroup();
|
||||
utils::Assert( grad_.size() == train.Size() * (size_t)ngroup, "BUG: UpdateOneIter: mclass" );
|
||||
std::vector<float> tgrad( train.Size() ), thess( train.Size() );
|
||||
for( int g = 0; g < ngroup; ++ g ){
|
||||
memcpy( &tgrad[0], &grad_[g*tgrad.size()], sizeof(float)*tgrad.size() );
|
||||
memcpy( &thess[0], &hess_[g*tgrad.size()], sizeof(float)*tgrad.size() );
|
||||
base_gbm.DoBoost(tgrad, thess, train.data, train.info.root_index, g );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \brief evaluate the model for specific iteration
|
||||
* \param iter iteration number
|
||||
* \param evals datas i want to evaluate
|
||||
* \param evname name of each dataset
|
||||
* \param fo file to output log
|
||||
*/
|
||||
inline void EvalOneIter(int iter, FILE *fo = stderr){
|
||||
inline void EvalOneIter(int iter,
|
||||
const std::vector<const DMatrix*> &evals,
|
||||
const std::vector<std::string> &evname,
|
||||
FILE *fo=stderr ){
|
||||
fprintf(fo, "[%d]", iter);
|
||||
int buffer_offset = static_cast<int>(train_->Size());
|
||||
|
||||
for (size_t i = 0; i < evals_.size(); ++i){
|
||||
std::vector<float> &preds = this->eval_preds_[i];
|
||||
this->PredictBuffer(preds, *evals_[i], buffer_offset);
|
||||
obj_->PredTransform(preds);
|
||||
evaluator_.Eval(fo, evname_[i].c_str(), preds, evals_[i]->info);
|
||||
buffer_offset += static_cast<int>(evals_[i]->Size());
|
||||
for (size_t i = 0; i < evals.size(); ++i){
|
||||
this->PredictRaw(preds_, *evals[i]);
|
||||
obj_->PredTransform(preds_);
|
||||
evaluator_.Eval(fo, evname[i].c_str(), preds_, evals[i]->info);
|
||||
}
|
||||
fprintf(fo, "\n");
|
||||
fflush(fo);
|
||||
}
|
||||
/*! \brief get prediction, without buffering */
|
||||
inline void Predict(std::vector<float> &preds, const DMatrix &data){
|
||||
preds.resize(data.Size());
|
||||
const unsigned ndata = static_cast<unsigned>(data.Size());
|
||||
#pragma omp parallel for schedule( static )
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
preds[j] = mparam.base_score + base_gbm.Predict(data.data, j, -1);
|
||||
}
|
||||
/*!
|
||||
* \brief get prediction
|
||||
* \param storage to store prediction
|
||||
* \param data input data
|
||||
* \param bst_group booster group we are in
|
||||
*/
|
||||
inline void Predict(std::vector<float> &preds, const DMatrix &data, int bst_group = -1){
|
||||
this->PredictRaw( preds, data, bst_group );
|
||||
obj_->PredTransform( preds );
|
||||
}
|
||||
public:
|
||||
/*!
|
||||
* \brief interactive update
|
||||
* \param action action type
|
||||
* \parma train training data
|
||||
*/
|
||||
inline void UpdateInteract(std::string action){
|
||||
this->InteractPredict(preds_, *train_, 0);
|
||||
|
||||
int buffer_offset = static_cast<int>(train_->Size());
|
||||
for (size_t i = 0; i < evals_.size(); ++i){
|
||||
std::vector<float> &preds = this->eval_preds_[i];
|
||||
this->InteractPredict(preds, *evals_[i], buffer_offset);
|
||||
buffer_offset += static_cast<int>(evals_[i]->Size());
|
||||
inline void UpdateInteract(std::string action, const DMatrix& train){
|
||||
for(size_t i = 0; i < cache_.size(); ++i){
|
||||
this->InteractPredict(preds_, *cache_[i].mat_);
|
||||
}
|
||||
|
||||
if (action == "remove"){
|
||||
base_gbm.DelteBooster(); return;
|
||||
}
|
||||
|
||||
obj_->GetGradient(preds_, train_->info, base_gbm.NumBoosters(), grad_, hess_);
|
||||
obj_->GetGradient(preds_, train.info, base_gbm.NumBoosters(), grad_, hess_);
|
||||
std::vector<unsigned> root_index;
|
||||
base_gbm.DoBoost(grad_, hess_, train_->data, root_index);
|
||||
base_gbm.DoBoost(grad_, hess_, train.data, root_index);
|
||||
|
||||
this->InteractRePredict(*train_, 0);
|
||||
buffer_offset = static_cast<int>(train_->Size());
|
||||
for (size_t i = 0; i < evals_.size(); ++i){
|
||||
this->InteractRePredict(*evals_[i], buffer_offset);
|
||||
buffer_offset += static_cast<int>(evals_[i]->Size());
|
||||
for(size_t i = 0; i < cache_.size(); ++i){
|
||||
this->InteractRePredict(*cache_[i].mat_);
|
||||
}
|
||||
}
|
||||
private:
|
||||
/*! \brief get the transformed predictions, given data */
|
||||
inline void InteractPredict(std::vector<float> &preds, const DMatrix &data, unsigned buffer_offset){
|
||||
inline void InteractPredict(std::vector<float> &preds, const DMatrix &data){
|
||||
int buffer_offset = this->FindBufferOffset(data);
|
||||
utils::Assert( buffer_offset >=0, "interact mode must cache training data" );
|
||||
preds.resize(data.Size());
|
||||
const unsigned ndata = static_cast<unsigned>(data.Size());
|
||||
#pragma omp parallel for schedule( static )
|
||||
@@ -224,21 +253,42 @@ namespace xgboost{
|
||||
obj_->PredTransform( preds );
|
||||
}
|
||||
/*! \brief repredict trial */
|
||||
inline void InteractRePredict(const DMatrix &data, unsigned buffer_offset){
|
||||
inline void InteractRePredict(const DMatrix &data){
|
||||
int buffer_offset = this->FindBufferOffset(data);
|
||||
utils::Assert( buffer_offset >=0, "interact mode must cache training data" );
|
||||
const unsigned ndata = static_cast<unsigned>(data.Size());
|
||||
#pragma omp parallel for schedule( static )
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
base_gbm.InteractRePredict(data.data, j, buffer_offset + j);
|
||||
}
|
||||
}
|
||||
private:
|
||||
/*! \brief get the transformed predictions, given data */
|
||||
inline void PredictBuffer(std::vector<float> &preds, const DMatrix &data, unsigned buffer_offset){
|
||||
preds.resize(data.Size());
|
||||
/*! \brief get un-transformed prediction*/
|
||||
inline void PredictRaw(std::vector<float> &preds, const DMatrix &data, int bst_group = -1 ){
|
||||
int buffer_offset = this->FindBufferOffset(data);
|
||||
if( bst_group < 0 ){
|
||||
int ngroup = base_gbm.NumBoosterGroup();
|
||||
preds.resize( data.Size() * ngroup );
|
||||
for( int g = 0; g < ngroup; ++ g ){
|
||||
this->PredictBuffer(&preds[ data.Size() * g ], data, buffer_offset, g );
|
||||
}
|
||||
}else{
|
||||
preds.resize( data.Size() );
|
||||
this->PredictBuffer(&preds[0], data, buffer_offset, bst_group );
|
||||
}
|
||||
}
|
||||
/*! \brief get the un-transformed predictions, given data */
|
||||
inline void PredictBuffer(float *preds, const DMatrix &data, int buffer_offset, int bst_group ){
|
||||
const unsigned ndata = static_cast<unsigned>(data.Size());
|
||||
#pragma omp parallel for schedule( static )
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
preds[j] = mparam.base_score + base_gbm.Predict(data.data, j, buffer_offset + j);
|
||||
if( buffer_offset >= 0 ){
|
||||
#pragma omp parallel for schedule( static )
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
preds[j] = mparam.base_score + base_gbm.Predict(data.data, j, buffer_offset + j, data.info.GetRoot(j), bst_group );
|
||||
}
|
||||
}else
|
||||
#pragma omp parallel for schedule( static )
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
preds[j] = mparam.base_score + base_gbm.Predict(data.data, j, -1, data.info.GetRoot(j), bst_group );
|
||||
}{
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -249,24 +299,28 @@ namespace xgboost{
|
||||
/* \brief type of loss function */
|
||||
int loss_type;
|
||||
/* \brief number of features */
|
||||
int num_feature;
|
||||
int num_feature;
|
||||
/* \brief number of class, if it is multi-class classification */
|
||||
int num_class;
|
||||
/*! \brief reserved field */
|
||||
int reserved[16];
|
||||
int reserved[15];
|
||||
/*! \brief constructor */
|
||||
ModelParam(void){
|
||||
base_score = 0.5f;
|
||||
loss_type = 0;
|
||||
num_feature = 0;
|
||||
num_class = 0;
|
||||
memset(reserved, 0, sizeof(reserved));
|
||||
}
|
||||
/*!
|
||||
* \brief set parameters from outside
|
||||
* \param name name of the parameter
|
||||
* \param val value of the parameter
|
||||
*/
|
||||
* \brief set parameters from outside
|
||||
* \param name name of the parameter
|
||||
* \param val value of the parameter
|
||||
*/
|
||||
inline void SetParam(const char *name, const char *val){
|
||||
if (!strcmp("base_score", name)) base_score = (float)atof(val);
|
||||
if (!strcmp("loss_type", name)) loss_type = atoi(val);
|
||||
if (!strcmp("num_class", name)) num_class = atoi(val);
|
||||
if (!strcmp("bst:num_feature", name)) num_feature = atoi(val);
|
||||
}
|
||||
/*!
|
||||
@@ -280,22 +334,34 @@ namespace xgboost{
|
||||
}
|
||||
};
|
||||
private:
|
||||
struct CacheEntry{
|
||||
const DMatrix *mat_;
|
||||
int buffer_offset_;
|
||||
CacheEntry(const DMatrix *mat, int buffer_offset)
|
||||
:mat_(mat), buffer_offset_(buffer_offset){}
|
||||
};
|
||||
/*! \brief the entries indicates that we have internal prediction cache */
|
||||
std::vector<CacheEntry> cache_;
|
||||
private:
|
||||
// find internal bufer offset for certain matrix, if not exist, return -1
|
||||
inline int FindBufferOffset(const DMatrix &mat){
|
||||
for(size_t i = 0; i < cache_.size(); ++i){
|
||||
if( cache_[i].mat_ == &mat ) return cache_[i].buffer_offset_;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
protected:
|
||||
int silent;
|
||||
EvalSet evaluator_;
|
||||
booster::GBMBase base_gbm;
|
||||
ModelParam mparam;
|
||||
const DMatrix *train_;
|
||||
std::vector<DMatrix *> evals_;
|
||||
std::vector<std::string> evname_;
|
||||
std::vector<unsigned> buffer_index_;
|
||||
ModelParam mparam;
|
||||
// objective fnction
|
||||
IObjFunction *obj_;
|
||||
// name of objective function
|
||||
std::string name_obj_;
|
||||
std::vector< std::pair<std::string, std::string> > cfg_;
|
||||
private:
|
||||
protected:
|
||||
std::vector<float> grad_, hess_, preds_;
|
||||
std::vector< std::vector<float> > eval_preds_;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -35,11 +35,17 @@ namespace xgboost{
|
||||
std::vector<unsigned> group_ptr;
|
||||
/*! \brief weights of each instance, optional */
|
||||
std::vector<float> weights;
|
||||
/*! \brief specified root index of each instance, can be used for multi task setting*/
|
||||
std::vector<unsigned> root_index;
|
||||
/*! \brief get weight of each instances */
|
||||
inline float GetWeight( size_t i ) const{
|
||||
if( weights.size() != 0 ) return weights[i];
|
||||
if( weights.size() != 0 ) return weights[i];
|
||||
else return 1.0f;
|
||||
}
|
||||
inline float GetRoot( size_t i ) const{
|
||||
if( root_index.size() != 0 ) return root_index[i];
|
||||
else return 0;
|
||||
}
|
||||
};
|
||||
public:
|
||||
/*! \brief feature data content */
|
||||
@@ -113,12 +119,13 @@ namespace xgboost{
|
||||
if( fs.Read(&ngptr, sizeof(unsigned) ) != 0 ){
|
||||
info.group_ptr.resize( ngptr );
|
||||
utils::Assert( fs.Read(&info.group_ptr[0], sizeof(unsigned) * ngptr) != 0, "Load group file");
|
||||
utils::Assert( info.group_ptr.back() == data.NumRow(), "number of group must match number of record" );
|
||||
if( ngptr != 0 ){
|
||||
utils::Assert( fs.Read(&info.group_ptr[0], sizeof(unsigned) * ngptr) != 0, "Load group file");
|
||||
utils::Assert( info.group_ptr.back() == data.NumRow(), "number of group must match number of record" );
|
||||
}
|
||||
}
|
||||
}
|
||||
fs.Close();
|
||||
// initialize column support as well
|
||||
data.InitData();
|
||||
|
||||
if (!silent){
|
||||
printf("%ux%u matrix with %lu entries is loaded from %s\n",
|
||||
@@ -146,7 +153,9 @@ namespace xgboost{
|
||||
{// write out group ptr
|
||||
unsigned ngptr = static_cast<unsigned>( info.group_ptr.size() );
|
||||
fs.Write(&ngptr, sizeof(unsigned) );
|
||||
fs.Write(&info.group_ptr[0], sizeof(unsigned) * ngptr);
|
||||
if( ngptr != 0 ){
|
||||
fs.Write(&info.group_ptr[0], sizeof(unsigned) * ngptr);
|
||||
}
|
||||
}
|
||||
fs.Close();
|
||||
if (!silent){
|
||||
@@ -169,7 +178,11 @@ namespace xgboost{
|
||||
inline void CacheLoad(const char *fname, bool silent = false, bool savebuffer = true){
|
||||
int len = strlen(fname);
|
||||
if (len > 8 && !strcmp(fname + len - 7, ".buffer")){
|
||||
this->LoadBinary(fname, silent); return;
|
||||
if( !this->LoadBinary(fname, silent) ){
|
||||
fprintf(stderr,"can not open file \"%s\"", fname);
|
||||
utils::Error("DMatrix::CacheLoad failed");
|
||||
}
|
||||
return;
|
||||
}
|
||||
char bname[1024];
|
||||
sprintf(bname, "%s.buffer", fname);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "../utils/xgboost_omp.h"
|
||||
#include "../utils/xgboost_random.h"
|
||||
#include "xgboost_regrank_data.h"
|
||||
#include "xgboost_regrank_utils.h"
|
||||
|
||||
namespace xgboost{
|
||||
namespace regrank{
|
||||
@@ -31,17 +32,11 @@ namespace xgboost{
|
||||
virtual ~IEvaluator(void){}
|
||||
};
|
||||
|
||||
inline static bool CmpFirst(const std::pair<float, unsigned> &a, const std::pair<float, unsigned> &b){
|
||||
return a.first > b.first;
|
||||
}
|
||||
inline static bool CmpSecond(const std::pair<float, unsigned> &a, const std::pair<float, unsigned> &b){
|
||||
return a.second > b.second;
|
||||
}
|
||||
|
||||
/*! \brief RMSE */
|
||||
struct EvalRMSE : public IEvaluator{
|
||||
virtual float Eval(const std::vector<float> &preds,
|
||||
const DMatrix::Info &info) const {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
const unsigned ndata = static_cast<unsigned>(preds.size());
|
||||
float sum = 0.0, wsum = 0.0;
|
||||
#pragma omp parallel for reduction(+:sum,wsum) schedule( static )
|
||||
@@ -62,6 +57,7 @@ namespace xgboost{
|
||||
struct EvalLogLoss : public IEvaluator{
|
||||
virtual float Eval(const std::vector<float> &preds,
|
||||
const DMatrix::Info &info) const {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
const unsigned ndata = static_cast<unsigned>(preds.size());
|
||||
float sum = 0.0f, wsum = 0.0f;
|
||||
#pragma omp parallel for reduction(+:sum,wsum) schedule( static )
|
||||
@@ -106,7 +102,8 @@ namespace xgboost{
|
||||
/*! \brief Area under curve, for both classification and rank */
|
||||
struct EvalAuc : public IEvaluator{
|
||||
virtual float Eval(const std::vector<float> &preds,
|
||||
const DMatrix::Info &info) const {
|
||||
const DMatrix::Info &info) const {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
std::vector<unsigned> tgptr(2, 0); tgptr[1] = preds.size();
|
||||
const std::vector<unsigned> &gptr = info.group_ptr.size() == 0 ? tgptr : info.group_ptr;
|
||||
utils::Assert(gptr.back() == preds.size(), "EvalAuc: group structure must match number of prediction");
|
||||
@@ -159,6 +156,7 @@ namespace xgboost{
|
||||
public:
|
||||
virtual float Eval(const std::vector<float> &preds,
|
||||
const DMatrix::Info &info) const {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
const std::vector<unsigned> &gptr = info.group_ptr;
|
||||
utils::Assert(gptr.size() != 0, "must specify group when constructing rank file");
|
||||
utils::Assert( gptr.back() == preds.size(), "EvalRanklist: group structure must match number of prediction");
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace xgboost{
|
||||
if (!strcmp("seed", name)) random::Seed(atoi(val));
|
||||
if (!strcmp("num_round", name)) num_round = atoi(val);
|
||||
if (!strcmp("save_period", name)) save_period = atoi(val);
|
||||
if (!strcmp("eval_train", name)) eval_train = atoi(val);
|
||||
if (!strcmp("task", name)) task = val;
|
||||
if (!strcmp("data", name)) train_path = val;
|
||||
if (!strcmp("test:data", name)) test_path = val;
|
||||
@@ -92,6 +93,7 @@ namespace xgboost{
|
||||
use_buffer = 1;
|
||||
num_round = 10;
|
||||
save_period = 0;
|
||||
eval_train = 0;
|
||||
dump_model_stats = 0;
|
||||
task = "train";
|
||||
model_in = "NULL";
|
||||
@@ -122,9 +124,22 @@ namespace xgboost{
|
||||
for (size_t i = 0; i < eval_data_names.size(); ++i){
|
||||
deval.push_back(new DMatrix());
|
||||
deval.back()->CacheLoad(eval_data_paths[i].c_str(), silent != 0, use_buffer != 0);
|
||||
devalall.push_back(deval.back());
|
||||
}
|
||||
std::vector<const DMatrix *> dcache(1, &data);
|
||||
for( size_t i = 0; i < deval.size(); ++ i){
|
||||
dcache.push_back( deval[i] );
|
||||
}
|
||||
// set cache data to be all training and evaluation data
|
||||
learner.SetCacheData(dcache);
|
||||
|
||||
// add training set to evaluation set if needed
|
||||
if( eval_train != 0 ){
|
||||
devalall.push_back( &data );
|
||||
eval_data_names.push_back( std::string("train") );
|
||||
}
|
||||
|
||||
}
|
||||
learner.SetData(&data, deval, eval_data_names);
|
||||
}
|
||||
inline void InitLearner(void){
|
||||
cfg.BeforeFirst();
|
||||
@@ -148,8 +163,8 @@ namespace xgboost{
|
||||
for (int i = 0; i < num_round; ++i){
|
||||
elapsed = (unsigned long)(time(NULL) - start);
|
||||
if (!silent) printf("boosting round %d, %lu sec elapsed\n", i, elapsed);
|
||||
learner.UpdateOneIter(i);
|
||||
learner.EvalOneIter(i);
|
||||
learner.UpdateOneIter(data);
|
||||
learner.EvalOneIter(i, devalall, eval_data_names);
|
||||
if (save_period != 0 && (i + 1) % save_period == 0){
|
||||
this->SaveModel(i);
|
||||
}
|
||||
@@ -169,7 +184,7 @@ namespace xgboost{
|
||||
}
|
||||
}
|
||||
inline void TaskEval(void){
|
||||
learner.EvalOneIter(0);
|
||||
learner.EvalOneIter(0, devalall, eval_data_names);
|
||||
}
|
||||
inline void TaskInteractive(void){
|
||||
const time_t start = time(NULL);
|
||||
@@ -179,7 +194,7 @@ namespace xgboost{
|
||||
cfg_batch.BeforeFirst();
|
||||
while (cfg_batch.Next()){
|
||||
if (!strcmp(cfg_batch.name(), "run")){
|
||||
learner.UpdateInteract(interact_action);
|
||||
learner.UpdateInteract(interact_action, data);
|
||||
batch_action += 1;
|
||||
}
|
||||
else{
|
||||
@@ -188,7 +203,7 @@ namespace xgboost{
|
||||
}
|
||||
|
||||
if (batch_action == 0){
|
||||
learner.UpdateInteract(interact_action);
|
||||
learner.UpdateInteract(interact_action, data);
|
||||
}
|
||||
utils::Assert(model_out != "NULL", "interactive mode must specify model_out");
|
||||
this->SaveModel(model_out.c_str());
|
||||
@@ -235,6 +250,8 @@ namespace xgboost{
|
||||
int silent;
|
||||
/* \brief whether use auto binary buffer */
|
||||
int use_buffer;
|
||||
/* \brief whether evaluate training statistics */
|
||||
int eval_train;
|
||||
/* \brief number of boosting iterations */
|
||||
int num_round;
|
||||
/* \brief the period to save the model, 0 means only save the final round model */
|
||||
@@ -272,6 +289,7 @@ namespace xgboost{
|
||||
private:
|
||||
DMatrix data;
|
||||
std::vector<DMatrix*> deval;
|
||||
std::vector<const DMatrix*> devalall;
|
||||
utils::FeatMap fmap;
|
||||
RegRankBoostLearner learner;
|
||||
};
|
||||
|
||||
@@ -106,8 +106,9 @@ namespace xgboost{
|
||||
namespace regrank{
|
||||
IObjFunction* CreateObjFunction( const char *name ){
|
||||
if( !strcmp("reg", name ) ) return new RegressionObj();
|
||||
if( !strcmp("rank", name ) ) return new PairwiseRankObj();
|
||||
if( !strcmp("softmax", name ) ) return new SoftmaxObj();
|
||||
if( !strcmp("rank:pairwise", name ) ) return new PairwiseRankObj();
|
||||
if( !strcmp("rank:softmax", name ) ) return new SoftmaxRankObj();
|
||||
if( !strcmp("softmax", name ) ) return new SoftmaxMultiClassObj();
|
||||
utils::Error("unknown objective function type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#ifndef XGBOOST_REGRANK_OBJ_HPP
|
||||
#define XGBOOST_REGRANK_OBJ_HPP
|
||||
/*!
|
||||
* \file xgboost_regrank_obj.h
|
||||
* \file xgboost_regrank_obj.hpp
|
||||
* \brief implementation of objective functions
|
||||
* \author Tianqi Chen, Kailong Chen
|
||||
*/
|
||||
//#include "xgboost_regrank_sample.h"
|
||||
#include <vector>
|
||||
#include "xgboost_regrank_utils.h"
|
||||
|
||||
namespace xgboost{
|
||||
namespace regrank{
|
||||
@@ -24,6 +25,7 @@ namespace xgboost{
|
||||
int iter,
|
||||
std::vector<float> &grad,
|
||||
std::vector<float> &hess ) {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
grad.resize(preds.size()); hess.resize(preds.size());
|
||||
|
||||
const unsigned ndata = static_cast<unsigned>(preds.size());
|
||||
@@ -52,11 +54,11 @@ namespace xgboost{
|
||||
|
||||
namespace regrank{
|
||||
// simple softmax rak
|
||||
class SoftmaxObj : public IObjFunction{
|
||||
class SoftmaxRankObj : public IObjFunction{
|
||||
public:
|
||||
SoftmaxObj(void){
|
||||
SoftmaxRankObj(void){
|
||||
}
|
||||
virtual ~SoftmaxObj(){}
|
||||
virtual ~SoftmaxRankObj(){}
|
||||
virtual void SetParam(const char *name, const char *val){
|
||||
}
|
||||
virtual void GetGradient(const std::vector<float>& preds,
|
||||
@@ -64,6 +66,7 @@ namespace xgboost{
|
||||
int iter,
|
||||
std::vector<float> &grad,
|
||||
std::vector<float> &hess ) {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
grad.resize(preds.size()); hess.resize(preds.size());
|
||||
const std::vector<unsigned> &gptr = info.group_ptr;
|
||||
utils::Assert( gptr.size() != 0 && gptr.back() == preds.size(), "rank loss must have group file" );
|
||||
@@ -96,23 +99,76 @@ namespace xgboost{
|
||||
}
|
||||
virtual const char* DefaultEvalMetric(void) {
|
||||
return "pre@1";
|
||||
}
|
||||
private:
|
||||
inline static void Softmax( std::vector<float>& rec ){
|
||||
float wmax = rec[0];
|
||||
for( size_t i = 1; i < rec.size(); ++ i ){
|
||||
wmax = std::max( rec[i], wmax );
|
||||
}
|
||||
double wsum = 0.0f;
|
||||
for( size_t i = 0; i < rec.size(); ++ i ){
|
||||
rec[i] = expf(rec[i]-wmax);
|
||||
wsum += rec[i];
|
||||
}
|
||||
for( size_t i = 0; i < rec.size(); ++ i ){
|
||||
rec[i] /= wsum;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// simple softmax multi-class classification
|
||||
class SoftmaxMultiClassObj : public IObjFunction{
|
||||
public:
|
||||
SoftmaxMultiClassObj(void){
|
||||
nclass = 0;
|
||||
}
|
||||
virtual ~SoftmaxMultiClassObj(){}
|
||||
virtual void SetParam(const char *name, const char *val){
|
||||
if( !strcmp( "num_class", name ) ) nclass = atoi(val);
|
||||
}
|
||||
virtual void GetGradient(const std::vector<float>& preds,
|
||||
const DMatrix::Info &info,
|
||||
int iter,
|
||||
std::vector<float> &grad,
|
||||
std::vector<float> &hess ) {
|
||||
utils::Assert( nclass != 0, "must set num_class to use softmax" );
|
||||
utils::Assert( preds.size() == (size_t)nclass * info.labels.size(), "SoftmaxMultiClassObj: label size and pred size does not match" );
|
||||
grad.resize(preds.size()); hess.resize(preds.size());
|
||||
|
||||
const unsigned ndata = static_cast<unsigned>(info.labels.size());
|
||||
#pragma omp parallel
|
||||
{
|
||||
std::vector<float> rec(nclass);
|
||||
#pragma for schedule(static)
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
for( int k = 0; k < nclass; ++ k ){
|
||||
rec[k] = preds[j + k * ndata];
|
||||
}
|
||||
Softmax( rec );
|
||||
int label = static_cast<int>(info.labels[j]);
|
||||
utils::Assert( label < nclass, "SoftmaxMultiClassObj: label exceed num_class" );
|
||||
for( int k = 0; k < nclass; ++ k ){
|
||||
float p = rec[ k ];
|
||||
if( label == k ){
|
||||
grad[j+k*ndata] = p - 1.0f;
|
||||
}else{
|
||||
grad[j+k*ndata] = p;
|
||||
}
|
||||
hess[j+k*ndata] = 2.0f * p * ( 1.0f - p );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void PredTransform(std::vector<float> &preds){
|
||||
utils::Assert( nclass != 0, "must set num_class to use softmax" );
|
||||
utils::Assert( preds.size() % nclass == 0, "SoftmaxMultiClassObj: label size and pred size does not match" );
|
||||
const unsigned ndata = static_cast<unsigned>(preds.size()/nclass);
|
||||
#pragma omp parallel
|
||||
{
|
||||
std::vector<float> rec(nclass);
|
||||
#pragma for schedule(static)
|
||||
for (unsigned j = 0; j < ndata; ++j){
|
||||
for( int k = 0; k < nclass; ++ k ){
|
||||
rec[k] = preds[j + k * ndata];
|
||||
}
|
||||
Softmax( rec );
|
||||
preds[j] = FindMaxIndex( rec );
|
||||
}
|
||||
}
|
||||
preds.resize( ndata );
|
||||
}
|
||||
virtual const char* DefaultEvalMetric(void) {
|
||||
return "error";
|
||||
}
|
||||
private:
|
||||
int nclass;
|
||||
};
|
||||
};
|
||||
|
||||
namespace regrank{
|
||||
@@ -133,6 +189,7 @@ namespace xgboost{
|
||||
int iter,
|
||||
std::vector<float> &grad,
|
||||
std::vector<float> &hess ) {
|
||||
utils::Assert( preds.size() == info.labels.size(), "label size predict size not match" );
|
||||
grad.resize(preds.size()); hess.resize(preds.size());
|
||||
const std::vector<unsigned> &gptr = info.group_ptr;
|
||||
utils::Assert( gptr.size() != 0 && gptr.back() == preds.size(), "rank loss must have group file" );
|
||||
|
||||
Reference in New Issue
Block a user