silvic

silvic-python

silvic-python builds the silvic package, which exposes LightGBM’s Python API over silvic-core. Metal and CUDA training use silvic-gpu, while AWS Neuron training uses silvic-neuron. The silvic.ray module trains one model across Ray actors over the TCP ring of silvic-net.

The extension supports CPython 3.10 or newer through abi3 and runs training without the GIL. Ray, pandas and scikit-learn dependencies are available through the silvic[ray], silvic[pandas] and silvic[sklearn] extras.

pip install silvic

Public API

Dataset(data, label=None, reference=None, weight=None, group=None, feature_name="auto", categorical_feature="auto", params=None)
Training or validation rows from numpy or pandas, binned on first use. group holds query sizes, rows sorted by query. pandas category columns become categorical features, and the model stores their levels as LightGBM’s package does. init_score is rejected.
train(params, train_set, num_boost_round=100, valid_sets=None, valid_names=None, init_model=None, callbacks=None)
Trains and returns a Booster. A number of iterations in params, under any alias, wins over num_boost_round, as in LightGBM. evals_result and verbose_eval work as in LightGBM 3.3.5. init_model, a Booster, a path or model text, keeps its trees and adds num_boost_round more; on the rows it was trained on, the result equals training them all in one go.
Booster(model_file=None, model_str=None)
A trained model, from train or from a LightGBM 3.x or 4.x model of a supported objective. Pickles.
booster.predict(data, raw_score=False, num_iteration=None)
LightGBM’s predictions, bit for bit. binary models apply the sigmoid unless raw_score.
booster.model_to_string(), booster.save_model(path)
LightGBM 3.3.5 model text, byte for byte what LightGBM writes. lleaves compiles it.
booster.to_lightgbm()
The same model as a lightgbm.Booster, to pickle, serve or explain with pred_contrib.
log_evaluation(period=1), record_evaluation(result)
LightGBM 4’s callbacks: print every period iterations, or record every evaluation into a dict.
SilvicRanker, SilvicRegressor, SilvicClassifier
LGBMRanker, LGBMRegressor and LGBMClassifier (two classes): the same constructor parameters, fit with group, sample_weight, eval_set and eval_group, and booster_, feature_importances_, evals_result_. scikit-learn is optional.
available_devices()
The runtime devices visible to this process: cpu, and available metal, cuda or neuron accelerators.

Also public booster.num_trees(), booster.feature_name(), booster.feature_importance(importance_type), CallbackEnv, SilvicModel, and the exceptions below.

Devices

device_type in the parameters picks the backend and gpu_device_id the device. At verbosity 1 or more, training prints the device it runs on.

auto default
CUDA, then Metal, then the CPU.
gpu
CUDA, then Metal; an error without either.
cpu, metal, cuda
That backend, or an error when it is absent.
neuron Linux, explicit selection
AWS Neuron through silvic-neuron; gpu_device_id selects a logical NeuronCore. Requires the separate compiler and runtime.

Errors

SilvicError is the base class. ConfigError and DataError are also ValueErrors, as LightGBM raises for bad input; DeviceError, CollectiveError, ModelError and UnsupportedError are also RuntimeErrors. An unknown parameter is a ValueError, as are fobj, feval, learning_rates and early stopping, which silvic does not do. An exception raised in a callback stops training and is raised from train; Ctrl-C raises KeyboardInterrupt.

silvic.ray

import ray
import silvic.ray

booster = silvic.ray.train(
    params,
    ray.data.read_parquet("s3://bucket/train/"),
    label_column="label",
    group_column="query_id",
    num_workers=5,
    use_gpu=True,
    num_boost_round=1500,
)
silvic.ray.train(params, train_dataset, *, label_column, group_column=None, num_workers=1, use_gpu=False, ...)
Trains one model across num_workers actors and returns rank 0’s Booster. Also takes weight_column, feature_columns (every other column by default), categorical_features (integer-coded columns), valid_datasets (a dict of name to dataset), num_boost_round, evals_result and verbose_eval.
resources_per_worker {"CPU": 1}
One placement-group bundle per actor. An explicit CPU count also sets num_threads. use_gpu adds one Ray GPU, which CUDA uses; Metal needs none. Explicit device_type="neuron" instead adds one neuron_cores resource by default; a positive whole-number reservation overrides it. Ray sets NEURON_RT_VISIBLE_CORES. Neuron rejects use_gpu and GPU resources.
placement_strategy "PACK"
The placement group’s strategy.
timeout_s 1800
Bounds placement, the TCP rendezvous, and how long a collective waits for a silent peer.
max_failures 3
How many times a lost worker is replaced and training resumed before the run gives up.
checkpoint_period 25
Iterations between the checkpoints rank 0 sends the driver; a resume repeats at most this many.
min_workers num_workers
The fewest workers a resume may continue on when a lost node is not replaced.
replacement_timeout_s 300
How long a resume waits for every worker’s bundle to be placed, at each worker count it tries.
ordered_partitions(data, num_workers, *, label_column, ...)
Each worker’s rows in training order, to repeat a distributed run in one process.

Rows go to rank hash(group key) % num_workers, so each actor holds whole queries. One task per input block splits it into a piece per worker, and each actor fetches only its own pieces: the dataset is read once and every row moves once. Each actor then sorts its rows by group key, features, label and weight, an order that depends only on the data and num_workers. The model equals silvic.train on the workers’ rows in rank order, when bin_construct_sample_cnt covers every row.

A lost worker, a reclaimed spot node or a lost object does not end the run. The driver kills the actors, places the group again, and every rank re-loads its rows and trains the remaining trees from the last checkpoint. With the same number of workers, rows and bins are the same, so the model equals an uninterrupted run, byte for byte. When the group can’t be placed in replacement_timeout_s and min_workers is lower, it continues on one worker fewer at a time, repartitioned: a valid model, but no longer the uninterrupted one. It never scales back up. Every resume prints a warning naming the node, the error and the iteration it resumes from.

Other failures are raised at once: an actor’s own exception before a dead actor, and either before the collective errors its peers see. After max_failures resumes, the root error is raised.