silvic-core
silvic-core provides silvic’s parameter handling, binning, objectives, metrics, split search and LightGBM 3.3.5 model text. It grows trees leaf by leaf using quantized integer histograms. Training uses the Backend interface with this crate’s CpuBackend, the Metal and CUDA backends of silvic-gpu, or the AWS Neuron backend of silvic-neuron. Histograms reduce across ranks through a Collective, using LocalCollective in one process or the TCP ring of silvic-net across processes.
let params = Params::from_json(r#"{"objective": "lambdarank", "num_iterations": 100}"#)?;
let train_set = BinnedDataset::construct(&input, ¶ms, &mut LocalCollective)?;
let model = train(¶ms, &train_set, &[], &mut CpuBackend::new(), &mut LocalCollective, &mut |_| Ok(()))?;
std::fs::write("model.txt", model.to_lightgbm_string())?;
Public API
Params::from_json(text)- LightGBM 3.3.5 parameters by name and alias, from a JSON object of numbers, strings, booleans and lists.
BinnedDataset::construct(input, params, collective)- Bins one rank’s rows: a
DenseMatrix(f32 or f64, row- or column-major, borrowed) with labels, weights, query sizes and categorical columns. Bin mappers come from a sample allgathered over every rank, so every rank bins alike; invalid input on any rank fails every rank with the same error. BinnedDataset::construct_with_reference(input, reference, collective)- Bins a validation set with the training set’s mappers.
train(params, train_set, valid, backend, collective, on_iteration)- Grows
num_iterationstrees and returns theModel; every rank returns the same one.on_iterationsees each iteration’s evaluations, andreport.model()the model so far, to checkpoint; an error from it stops training. train_from(params, init_model, train_set, valid, backend, collective, on_iteration)- Adds
num_iterationstrees toinit_model. Its trees are replayed onto the scores in f32 as training added them, and sampling is keyed by the absolute iteration, so resuming a checkpoint on the same rows and bins gives the uninterrupted model, byte for byte. A model binned differently, LightGBM’s included, continues approximately. model.to_lightgbm_string(),Model::from_lightgbm_string(text)- LightGBM 3.3.5 model text, written byte for byte as LightGBM writes it; LightGBM 3.x and 4.x models read back to the same bytes.
model.predict(matrix, raw_score, num_trees)- LightGBM’s predictions bit for bit, NaN, zeros and unseen categories included, in parallel over rows.
CpuBackend::new(),LocalCollective- The CPU backend, parallel over rayon’s pool, and the collectives of a single process.
trait Backend,trait Collective- What
silvic-gpuandsilvic-netimplement.
Also public SilvicError, Result, model.feature_importance(kind), and the modules config, data, objective, metric, quantize, tree and backend; test_util behind the test-util feature.
Parameters
LightGBM 3.3.5’s names and their aliases, scikit-learn’s included: n_estimators, min_child_weight, reg_alpha, subsample, colsample_bytree and the rest.
objectiveregressionregression(L2),binarywithsigmoid, orlambdarankwithlabel_gain,lambdarank_truncation_levelandlambdarank_norm.- Trees
num_leaves,max_depth,min_data_in_leaf,min_sum_hessian_in_leaf,lambda_l1,lambda_l2,min_gain_to_split,learning_rate.- Sampling
bagging_fraction,bagging_freq,feature_fraction, their seeds, andseed, which draws the others as LightGBM does.- Bins and categoricals
max_bin(at most 255),min_data_in_bin,bin_construct_sample_cnt,max_cat_to_onehot,max_cat_threshold,cat_l2,cat_smooth,min_data_per_group.- Metrics
metric:l2,rmse,binary_logloss,auc,ndcgwitheval_at; the objective’s own by default.use_quantized_gradtrue- Trains on integer histograms of gradients rounded to
num_grad_quant_bins(4) levels, withstochastic_rounding. LightGBM defaults to false. quant_train_renew_leaftrue- Leaf values from exact sums of the float gradients. LightGBM defaults to false.
device_typeauto- Read by the Python package, which builds the backend;
gpu_device_idandnum_threadsas in LightGBM.
An unknown key is an error, not a warning, and so is any of LightGBM’s features outside silvic set to other than its default: is_unbalance, scale_pos_weight, early_stopping_round, monotone_constraints, linear_tree, extra_trees, path_smooth, max_delta_step, zero_as_missing, num_class, and boosting other than gbdt. Keys that only tune how LightGBM runs, such as force_row_wise and deterministic, are accepted and change nothing.
Determinism
Each row’s gradient and hessian round to small integers by stochastic rounding, and bagging draws its rows, from a counter-based hash of the seed, the iteration and the row’s global index. The same row rounds the same way on every backend and on whichever rank holds it. Histograms are sums of those integers, exact in any order, so allreducing them across ranks is exact, and leaf values come from fixed-point sums of the float gradients, exact as well. The same data and parameters give the same model on every run, and on any number of ranks when bin_construct_sample_cnt covers every row, so all ranks bin from the same sample.
Against LightGBM
- Bins
- LightGBM 3.3.5’s
FindBin: for the same sample, every threshold LightGBM splits on is a silvic bin boundary, bit for bit.feature_pre_filteris not applied. - Models and metrics
- Model text byte for byte LightGBM 3.3.5’s; metrics equal LightGBM 4.7’s to 1e-12.
- Training
- Quantized by default, with silvic’s own random draws and f32 training scores: models of the same kind and accuracy as LightGBM’s, not the same trees.
- Zero hessians
- A leaf without hessian is never split and an empty child is rejected, so quantized lambdarank trains on queries without a relevant item, where LightGBM 4.7 aborts.
- Queries
- Any size: LightGBM’s 10000-position discount table is extended by its formula.