Pruners
A pruner stops an unpromising trial early, before it wastes a full training budget. During a trial
you report intermediate values (a validation loss per epoch, say); the pruner compares the trial's
trajectory against the others seen so far and decides whether to abandon it. OptunaSharp ports
optuna.pruners into OptunaSharp.Pruners.
Single-objective only. Like Optuna, pruning is defined only for single-objective studies. In a multi-objective study
trial.ReportthrowsNotImplementedException(matching Optuna, whosetrial.reportraises there), soShouldPruneis never reached and a pruner never runs.
The pruning loop
Pruning is a contract between your objective and the pruner: you Report and then check
ShouldPrune.
using OptunaSharp;
var study = Optuna.CreateStudy(pruner: new MedianPruner(nStartupTrials: 5, nWarmupSteps: 10));
study.Optimize(trial =>
{
for (int epoch = 0; epoch < 100; epoch++)
{
double loss = TrainOneEpoch(trial, epoch);
trial.Report(loss, epoch);
if (trial.ShouldPrune())
throw new TrialPruned();
}
return Validate(trial);
}, nTrials: 50);
Optimize catches TrialPruned and records the trial with state Pruned. The default pruner (when
you pass none) is MedianPruner, matching Optuna.
The pruners
| Pruner | Strategy | Constructor |
|---|---|---|
MedianPruner |
Prune if worse than the median of past trials at this step | (nStartupTrials: 5, nWarmupSteps: 0, intervalSteps: 1, nMinTrials: 1) |
PercentilePruner |
Prune below a chosen percentile | (double percentile, nStartupTrials: 5, nWarmupSteps: 0, intervalSteps: 1, nMinTrials: 1) |
SuccessiveHalvingPruner |
Asynchronous Successive Halving (ASHA) | (minResource: null, reductionFactor: 4, minEarlyStoppingRate: 0, bootstrapCount: 0) |
HyperbandPruner |
Hyperband over ASHA brackets | (minResource: 1, maxResource: null, reductionFactor: 3, bootstrapCount: 0) |
ThresholdPruner |
Prune outside a fixed value range | (lower: null, upper: null, nWarmupSteps: 0, intervalSteps: 1) |
PatientPruner |
Delay another pruner until patience runs out | (BasePruner? wrappedPruner, int patience, double minDelta = 0.0) |
WilcoxonPruner |
Wilcoxon signed-rank test over per-instance scores | (pThreshold: 0.1, nStartupSteps: 2) |
NopPruner |
Never prunes | () |
Notes on the main pruners
MedianPruneris a special case ofPercentilePrunerat the 50th percentile — the sensible default.nStartupTrialsskips pruning until enough trials exist to compare against;nWarmupStepsprotects the noisy early steps of each trial;intervalStepslimits how often the check runs.SuccessiveHalvingPruner(ASHA) promotes only the top1/reductionFactorof trials to the next resource rung, so most trials stop cheaply. Good when you can express training progress as a resource budget.HyperbandPrunerruns several ASHA brackets with different starting resources and routes trials between them, trading off aggressive vs. conservative early stopping automatically. It typically outperforms a single ASHA configuration.ThresholdPruneris unconditional: prune as soon as a reported value falls belowloweror aboveupper. Useful for hard feasibility limits (e.g. loss that diverged to NaN/∞).PatientPrunerwraps another pruner and suppresses its verdict until the trial has failed to improve forpatiencesteps — a guard against pruning on transient dips.WilcoxonPrunercompares a trial against the best using a statistical test over per-instance results; report the per-instance scores through the trial's intermediate values.
Setting or disabling pruning
var aggressive = Optuna.CreateStudy(pruner: new SuccessiveHalvingPruner(reductionFactor: 3));
var never = Optuna.CreateStudy(pruner: new NopPruner()); // disable pruning entirely
Writing a custom pruner
Derive from BasePruner and implement one method:
public abstract bool Prune(Study study, FrozenTrial trial); // true -> the trial should stop
trial.IntermediateValues gives you the reported trajectory; study.GetTrials(...) gives the history
to compare against.
Relationship to Optuna
| Optuna (Python) | OptunaSharp |
|---|---|
MedianPruner(n_startup_trials=5, n_warmup_steps=10) |
new MedianPruner(nStartupTrials: 5, nWarmupSteps: 10) |
SuccessiveHalvingPruner(reduction_factor=3) |
new SuccessiveHalvingPruner(reductionFactor: 3) |
HyperbandPruner(min_resource=1, max_resource=81) |
new HyperbandPruner(minResource: 1, maxResource: 81) |
trial.report(loss, step) / trial.should_prune() |
trial.Report(loss, step) / trial.ShouldPrune() |
See also
Study and Trials · Samplers · Terminators · the API reference.