Skip to content

Replace the name num_output_group with the number of targets. - #12353

Open
trivialfis wants to merge 4 commits into
dmlc:masterfrom
trivialfis:n-target-names
Open

Replace the name num_output_group with the number of targets.#12353
trivialfis wants to merge 4 commits into
dmlc:masterfrom
trivialfis:n-target-names

Conversation

@trivialfis

@trivialfis trivialfis commented Jul 23, 2026

Copy link
Copy Markdown
Member

After the multi-output implementation, we have concepts for groups and targets, the group was derived from the num_class parameter. In this PR, we unify them under the n_targets name.

In addition, due to historical reasons, the bst_group_t is misused as a target index. This PR uses bst_target_t consistently.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates XGBoost’s multi-output terminology and indexing to consistently use “targets” (n_targets) instead of “output groups” (previously derived from num_class / num_output_group), and replaces historical misuse of bst_group_t as a target index by using bst_target_t consistently across training, prediction, SHAP, C API shape handling, and tests.

Changes:

  • Renames model/output dimension handling from num_output_group / OutputLength() / Groups() to n_targets / NumTargets() (and NumTreeTargets() for vector-leaf trees).
  • Propagates the target-index type (bst_target_t) through GBTree/GBLinear training, predictors (CPU/GPU), and SHAP implementations.
  • Updates C API prediction shape calculation and test utilities/docs to reflect target-based naming and behavior.

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/cpp/tree/test_tree_stat.cc Fixes RegTree ctor arg type for number of features vs targets in tests.
tests/cpp/test_multi_target.cc Updates learner API usage from Groups() to NumTargets() in tests.
tests/cpp/predictor/test_shap.cc Aligns model-param construction and persisted metadata to target-based sizing.
tests/cpp/predictor/test_predictor.h Updates helper to commit model groups using target indices.
tests/cpp/predictor/test_predictor.cc Updates vector-leaf sizing APIs from leaf-length to tree-targets.
tests/cpp/helpers.h Adjusts helper APIs/formatting to use n_targets and updated LearnerModelParam ctor.
src/predictor/predictor.cc Switches output sizing/validation from output-groups to targets.
src/predictor/interpretability/shap.cu Updates GPU SHAP dimensioning and indexing to use target count.
src/predictor/interpretability/shap.cc Updates CPU SHAP dimensioning to use target count.
src/predictor/gpu_predictor.cu Renames kernel params/indexing from groups to targets for prediction output.
src/predictor/gbtree_view.h Stores n_targets in model view from LearnerModelParam::NumTargets().
src/predictor/cpu_predictor.cc Renames and retypes prediction dimensions from groups to targets.
src/objective/regression_obj.cu Renames leaf-update parameter from group index to target index.
src/objective/quantile_obj.cu Renames and applies target-index semantics in quantile leaf update.
src/objective/adaptive.h Updates adaptive objective helpers to take bst_target_t for label/pred indexing.
src/objective/adaptive.cu Updates CUDA adaptive leaf-update indexing to use target index naming/types.
src/objective/adaptive.cc Updates CPU adaptive leaf-update indexing to use target index naming/types.
src/linear/updater_shotgun.cc Renames group loops/indexing to target loops/indexing for linear training.
src/linear/updater_gpu_coordinate.cu Updates GPU coordinate updater loops/sizes from groups to targets.
src/linear/updater_coordinate.cc Updates CPU coordinate updater loops/sizes from groups to targets.
src/linear/coordinate_common.h Renames params/docs and updates indexing math from groups to targets.
src/learner.cc Introduces NumTargets() in legacy params and stores n_targets in model params.
src/gbm/gbtree.h Updates GBTree APIs to use target_idx and TreesOneGroup consistently.
src/gbm/gbtree.cu Updates GPU helper signatures/indexing from group to target semantics.
src/gbm/gbtree.cc Updates boosting/pred-cache plumbing to use NumTargets()/NumTreeTargets().
src/gbm/gbtree_model.h Renames commit API to accept target_idx.
src/gbm/gbtree_model.cc Updates tree-info indptr and commit logic to iterate over targets.
src/gbm/gblinear.cc Updates prediction/contrib loops to iterate over targets.
src/gbm/gblinear_model.h Updates linear model weight layout to be sized/indexed by targets.
src/data/data.cc Renames reshape helper variable from groups to targets for meta matrices.
src/c_api/c_api.cu Updates inplace predict shape calculation to use NumTargets().
src/c_api/c_api.cc Updates predict shape calculation to use NumTargets().
src/c_api/c_api_utils.h Renames CalcPredictShape params/docs and shapes to be target-based.
python-package/xgboost/testing/shared.py Updates predict-leaf test validation naming from classes to targets.
python-package/xgboost/core.py Updates user-facing docstring terminology from groups to targets.
include/xgboost/predictor.h Updates predictor contribution-output doc to use n_targets.
include/xgboost/objective.h Updates objective leaf-update doc/param naming to target_idx.
include/xgboost/learner.h Replaces Groups() with NumTargets() and renames model param fields/APIs.
include/xgboost/gbm.h Updates contribution-output doc to use n_targets.
demo/guide-python/model_parser.py Updates demo parser to derive n_targets from num_class/num_target and improves CLI structure.
Comments suppressed due to low confidence (2)

src/predictor/interpretability/shap.cc:482

  • Same shadowing issue as above: the inner n_targets hides the model-level n_targets, so CHECK_EQ(n_targets, n_targets) is always true and does not validate that each multi-target tree matches the model target count.
    src/gbm/gblinear.cc:260
  • In prediction, the per-target margin falls back to base_score(0) for all targets. This should use the current target_idx so multi-target models with distinct base scores behave correctly.
        // Loop over targets.
        for (bst_target_t target_idx = 0; target_idx < n_targets; ++target_idx) {
          float margin = (base_margin.Size() != 0) ? base_margin(ridx, target_idx) : base_score(0);
          this->Pred(batch[i], &preds[ridx * n_targets], target_idx, margin);
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/predictor/interpretability/shap.cc
Comment thread src/gbm/gblinear.cc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 41 out of 41 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/predictor/interpretability/shap.cc:482

  • In the multi-target tree path, this check is now a tautology (CHECK_EQ(n_targets, n_targets)), so it will never detect a mismatch between the tree’s target count and the model’s declared target count. This looks like a rename oversight from n_groups -> n_targets.

Comment thread include/xgboost/learner.h
@RAMitchell

Copy link
Copy Markdown
Member

As a suggestion, could we establish the vocabulary first along these lines?

Name Meaning
num_outputs Number of columns in a raw-margin prediction
leaf_output_size Number of output values stored in each leaf
num_output_blocks num_outputs / leaf_output_size
num_parallel_tree Number of trees built for each output block
// K-output scalar-leaf model
NumOutputs()      == K;
LeafOutputSize()  == 1;
NumOutputBlocks() == K;

// K-output vector-leaf model
NumOutputs()      == K;
LeafOutputSize()  == K;
NumOutputBlocks() == 1;

// Single-output model
NumOutputs()      == 1;
LeafOutputSize()  == 1;
NumOutputBlocks() == 1;

Here, NumOutputBlocks() is derived rather than stored:

NumOutputBlocks() == NumOutputs() / LeafOutputSize();

NumTreesPerIteration() ==
    NumOutputBlocks() * num_parallel_tree;

With this vocabulary, branches such as the one in DoBoost() could basically collapse into:

auto const n_outputs = mparam.NumOutputs();
auto const leaf_output_size = mparam.LeafOutputSize();
auto const n_output_blocks = mparam.NumOutputBlocks();

CHECK_EQ(n_outputs, n_output_blocks * leaf_output_size);

for (output_block = 0; output_block < n_output_blocks; ++output_block) {
  auto output_begin = output_block * leaf_output_size;
  auto output_end = output_begin + leaf_output_size;

  gradients = CopyGradients(all_gradients, output_begin, output_end);

  for (parallel_tree = 0; parallel_tree < num_parallel_tree; ++parallel_tree) {
    tree = BoostNewTree(gradients, leaf_output_size);
    new_trees[output_block].push_back(tree);
  }
}

The scalar-leaf case naturally loops over K output blocks, while the vector-leaf case loops over one. num_parallel_tree remains a separate dimension within each output block. This assumes equal-sized, contiguous output blocks, which matches the strategies currently supported.

@RAMitchell

Copy link
Copy Markdown
Member

Some areas that might be worth looking into after establishing the naming:

  • In MakeIndptr(), max(tree_info) + 1 is called n_targets, but this is really the number of output blocks: K for scalar leaves and one for vector leaves.
  • NumTreeTargets() controls the size of the leaf vector, so this could become LeafOutputSize().
  • In tree_info, zero means output zero for a scalar tree, but effectively all outputs for a vector tree. Treating this as an output-block index would make both cases consistent.
  • TreesOneGroup is really the collection of num_parallel_tree trees built for one output block.
  • CalcPredictShape(kLeaf) uses the number of outputs as a physical-tree axis. This looks suspicious for vector leaves, where one tree covers K outputs but still produces one leaf index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants