Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: where is the gradient step in the xgboost source code?

Tags:

c++

r

xgboost

Below is the source code for the xgb.train function in the package xgboost.

library(xgboost)
> xgb.train
function (params = list(), data, nrounds, watchlist = list(), 
    obj = NULL, feval = NULL, verbose = 1, print_every_n = 1L, 
    early_stopping_rounds = NULL, maximize = NULL, save_period = NULL, 
    save_name = "xgboost.model", xgb_model = NULL, callbacks = list(), 
    ...) 
{
    check.deprecation(...)
    params <- check.booster.params(params, ...)
    check.custom.obj()
    check.custom.eval()
    dtrain <- data
    if (!inherits(dtrain, "xgb.DMatrix")) 
        stop("second argument dtrain must be xgb.DMatrix")
    if (length(watchlist) > 0) {
        if (typeof(watchlist) != "list" || !all(vapply(watchlist, 
            inherits, logical(1), what = "xgb.DMatrix"))) 
            stop("watchlist must be a list of xgb.DMatrix elements")
        evnames <- names(watchlist)
        if (is.null(evnames) || any(evnames == "")) 
            stop("each element of the watchlist must have a name tag")
    }
    params <- c(params, list(silent = ifelse(verbose > 1, 0, 
        1)))
    print_every_n <- max(as.integer(print_every_n), 1L)
    if (!has.callbacks(callbacks, "cb.print.evaluation") && verbose) {
        callbacks <- add.cb(callbacks, cb.print.evaluation(print_every_n))
    }
    evaluation_log <- list()
    if (!has.callbacks(callbacks, "cb.evaluation.log") && length(watchlist) > 
        0) {
        callbacks <- add.cb(callbacks, cb.evaluation.log())
    }
    if (!is.null(save_period) && !has.callbacks(callbacks, "cb.save.model")) {
        callbacks <- add.cb(callbacks, cb.save.model(save_period, 
            save_name))
    }
    stop_condition <- FALSE
    if (!is.null(early_stopping_rounds) && !has.callbacks(callbacks, 
        "cb.early.stop")) {
        callbacks <- add.cb(callbacks, cb.early.stop(early_stopping_rounds, 
            maximize = maximize, verbose = verbose))
    }
    cb <- categorize.callbacks(callbacks)
    if (!is.null(params[["seed"]])) {
        warning("xgb.train: `seed` is ignored in R package.  Use `set.seed()` instead.")
    }
    is_update <- NVL(params[["process_type"]], ".") == "update"
    handle <- xgb.Booster.handle(params, append(watchlist, dtrain), 
        xgb_model)
    bst <- xgb.handleToBooster(handle)
    num_class <- max(as.numeric(NVL(params[["num_class"]], 1)), 
        1)
    num_parallel_tree <- max(as.numeric(NVL(params[["num_parallel_tree"]], 
        1)), 1)
    niter_init <- 0
    if (!is.null(xgb_model)) {
        niter_init <- as.numeric(xgb.attr(bst, "niter")) + 1
        if (length(niter_init) == 0) {
            niter_init <- xgb.ntree(bst)%/%(num_parallel_tree * 
                num_class)
        }
    }
    if (is_update && nrounds > niter_init) 
        stop("nrounds cannot be larger than ", niter_init, " (nrounds of xgb_model)")
    rank <- 0
    niter_skip <- ifelse(is_update, 0, niter_init)
    begin_iteration <- niter_skip + 1
    end_iteration <- niter_skip + nrounds
    for (iteration in begin_iteration:end_iteration) {
        for (f in cb$pre_iter) f()
        xgb.iter.update(bst$handle, dtrain, iteration - 1, obj)
        bst_evaluation <- numeric(0)
        if (length(watchlist) > 0) 
            bst_evaluation <- xgb.iter.eval(bst$handle, watchlist, 
                iteration - 1, feval)
        xgb.attr(bst$handle, "niter") <- iteration - 1
        for (f in cb$post_iter) f()
        if (stop_condition) 
            break
    }
    for (f in cb$finalize) f(finalize = TRUE)
    bst <- xgb.Booster.complete(bst, saveraw = TRUE)
    bst$niter = end_iteration
    if (length(evaluation_log) > 0 && nrow(evaluation_log) > 
        0) {
        if (inherits(xgb_model, "xgb.Booster") && !is_update && 
            !is.null(xgb_model$evaluation_log) && isTRUE(all.equal(colnames(evaluation_log), 
            colnames(xgb_model$evaluation_log)))) {
            evaluation_log <- rbindlist(list(xgb_model$evaluation_log, 
                evaluation_log))
        }
        bst$evaluation_log <- evaluation_log
    }
    bst$call <- match.call()
    bst$params <- params
    bst$callbacks <- callbacks
    if (!is.null(colnames(dtrain))) 
        bst$feature_names <- colnames(dtrain)
    bst$nfeatures <- ncol(dtrain)
    return(bst)
}

In particular, I am trying to locate where in the source code xgboost is calculating the gradient. I can see that the object handle is defined as handle <- xgb.Booster.handle(params, append(watchlist, dtrain), xgb_model). And I found xgb.Booster.handle here: https://github.com/dmlc/xgboost/blob/master/R-package/R/xgb.Booster.R. This file calls upon several C++ files, one of which is XGBoosterCreate_R, which is defined here: https://github.com/dmlc/xgboost/blob/master/R-package/src/xgboost_R.cc.

However, upon scanning the C++ code, it's unclear to me where exactly the gradient step is being calculated. Can anyone point me to where the gradient is defined in the source code?

like image 542
Adrian Avatar asked Oct 27 '22 23:10

Adrian


1 Answers

There is extensive documentation, see e.g. https://github.com/dmlc/xgboost/blob/master/doc/c.rst which I consider insightful.

This aside, the links you shared are within the R-wrapper (if I may call it like that) of the actual source code, the source code starts with

#include <dmlc/logging.h>
#include <dmlc/omp.h>
#include <xgboost/c_api.h>
#include <vector>
#include <string>
#include <utility>
#include <cstring>
#include <cstdio>
#include <sstream>
#include "./xgboost_R.h"

The 3rd line points to the directory xgboost/ where you find a c_api.h which is the Advanced Programmer Interface for the actual library. The code is amazingly well documented: At first glance, the actual iteration step is probably XGBoosterUpdateOneIter.

like image 156
B--rian Avatar answered Nov 23 '22 04:11

B--rian