activereg — An active learning framework for supervised regression problems.
Active learning reduces labeling cost by iteratively selecting the most informative candidates from an unlabeled pool, training on them, and refining the model. This repository provides the full infrastructure: acquisition functions, sampling strategies, ML model backends, evaluation metrics, and benchmark scripts.
- Overview
- Package Structure
- Installation
- Quick Start
- Lab Use
- ML Models
- Acquisition Functions
- Multi-Property Optimization
- Sampling Strategies
- Configuration
- Running Benchmarks
- License
The active learning loop in activereg follows a standard pool-based protocol:
Initial labeled set
│
▼
Train ML model
│
▼
Predict on pool ──► Acquisition landscape
│
▼
Select batch ──► FPS / Voronoi / random
│
▼
Label batch ──► add to training set
│
└──── repeat ◄────────────────────┘
Each iteration expands the training set with the most informative points according to the chosen acquisition function, converging toward an accurate model with fewer labels than random or grid sampling.
activereg/
├── mlmodel/ # ML model backends (subpackage)
│ ├── _base.py # MLModel protocol definition
│ ├── _gpr.py # Gaussian Process Regressor
│ ├── _knn.py # k-Nearest Neighbours regressor
│ ├── _mlp.py # MLP and Anchored Ensemble MLP [extra: nn]
│ ├── _bnn.py # Bayesian Neural Network (PyTorch + Pyro) [extra: nn]
│ ├── _kernels.py # Kernel factory for GPs
│ └── _multi_property.py # Multi-property model wrappers
├── acquisition.py # Acquisition functions and batch selection
├── adaptiveRefinement.py # Adaptive spatial refinement strategies
├── benchmarkFunctions.py # Benchmark test functions (Hartmann, Ackley, …) [extra: benchmarks]
├── beauty.py # Visualization utilities
├── data.py # Dataset generation (LHS, Sobol, random)
├── experiment.py # Experiment setup, model factory, and AL cycle core
├── hyperparams.py # Hyperparameter grids and grid search utilities
├── metrics.py # Evaluation metrics (RMSE, NLL, PICP, MPIW, …)
├── sampling.py # Sampling methods (FPS, Voronoi, random)
├── utils.py # Miscellaneous utilities
└── format.py # Repository path constants
All ML models expose the same three-method protocol (see MLModel in activereg/mlmodel/_base.py):
| Method | Signature | Description |
|---|---|---|
train |
(X, y) → None |
Fit model to labeled data |
predict |
(X) → (ŷ, mean, uncertainty) |
Predict with uncertainty estimate |
__repr__ |
() → str |
Human-readable model description |
- Python 3.10+
The core install depends only on the scientific Python stack (NumPy, pandas, SciPy, scikit-learn, matplotlib, seaborn, joblib, PyYAML, tqdm). PyTorch is not required — the core covers the entire active learning loop: GPR and kNN backends, acquisition functions, batch selection, metrics, and plotting.
git clone https://github.com/AGardinon/ActiveLearningRegressor.git
cd ActiveLearningRegressor
pip install -e .Deep-learning and benchmark-generation dependencies are opt-in:
| Extra | Installs | Needed for |
|---|---|---|
nn |
torch, pyro-ppl |
MLP, AnchoredEnsembleMLP, BayesianNN |
benchmarks |
botorch (pulls in torch) |
synthetic test functions and benchmark dataset generation |
all |
both of the above | everything |
pip install -e '.[nn]' # neural-network backends
pip install -e '.[benchmarks]' # synthetic benchmark functions
pip install -e '.[all]' # everythingOptional components are imported lazily, so a missing extra surfaces only when you actually use it — and says which extra to install:
>>> from activereg.mlmodel import BayesianNN
ImportError: 'BayesianNN' requires the optional 'nn' dependencies.
Install them with: pip install 'activereg[nn]'| Task | Install |
|---|---|
| Run AL with GPR or kNN over an existing pool CSV | core |
| Regenerate figures from stored benchmark results | core |
scripts/run_lab_cycle.py, scripts/insilico_lab_al_simulation.py |
core |
scripts/benchmark_gtlandscape.py — runs against a precomputed ground-truth landscape |
core |
scripts/benchmark_functions.py — generates data from analytic test functions |
benchmarks |
| Neural-network model backends | nn |
Relevant only when installing the nn or benchmarks extras, which pull the CPU-only PyTorch wheel by default. For a CUDA build, install PyTorch separately before installing the extra — follow the official PyTorch install guide.
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from activereg.experiment import (
setup_multi_property_ml_model,
setup_data_pool,
run_single_al_cycle,
)
# --- data ---
# pool_df: search space (features only)
# evidence_df: initial labeled samples (features + targets)
pool_df = pd.read_csv("datasets/my_pool.csv")
evidence_df = pd.read_csv("datasets/my_evidence.csv")
search_vars = ["x1", "x2", "x3"]
target_vars = ["y"]
# --- scaler: fit once on the full pool, reuse every cycle ---
scaler = StandardScaler()
_, scaler = setup_data_pool(df=pool_df, search_var=search_vars, scaler=scaler)
# --- model config ---
config = {
"ml_model": "GPR",
"model_parameters": {"kernel": "MATERN_W", "n_restarts_optimizer": 10, "alpha": 1e-10},
}
acquisition_params = [{"acquisition_mode": "expected_improvement", "n_points": 5, "xi": 0.01}]
# --- active learning cycle ---
for cycle in range(10):
model = setup_multi_property_ml_model(config, target_vars)
result = run_single_al_cycle(
pool_df=pool_df,
evidence_df=evidence_df,
scaler=scaler,
ml_model=model,
search_vars=search_vars,
target_vars=target_vars,
acquisition_params=acquisition_params,
batch_selection_method="highest_landscape",
batch_selection_params={"percentile": 95, "sampling_method": "voronoi"},
)
# next_batch_df contains the selected candidates with NaN targets
# measure them and add to evidence_df for the next cycle
new_points = result["next_batch_df"]
print(f"Cycle {cycle+1}: selected {len(new_points)} candidates")
# evidence_df = pd.concat([evidence_df, measured_points])activereg provides two additional workflows for experiments that cannot be run as a single automated benchmark.
One AL step at a time, with physical measurement between cycles:
Cycle 0: python scripts/run_lab_cycle.py -c config.yaml
→ writes cycle_0/output_sampled.csv
(fill in measured values → cycle_0/validated.csv)
Cycle 1: python scripts/run_lab_cycle.py -c config.yaml
→ reads validated.csv, updates evidence, writes cycle_1/output_sampled.csv
...
Folder layout created automatically on the first run:
lab_al_experiments/{experiment_name}/
dataset/
POOL.csv # immutable: full search space (features only)
EVIDENCE.csv # grows each cycle (features + targets)
CANDIDATES.csv # shrinks each cycle (features only)
scaler.joblib # fit once on POOL
cycle_0/
output_sampled.csv # points to measure (targets = NaN)
predictions.csv # model predictions over pool
landscapes.csv # acquisition landscape per entry
model_snapshot.pkl
log.json
validated.csv # fill in measurements, then re-run
cycle_1/
...
Copy and edit scripts/lab_cycle_config_template.yaml to configure your experiment.
Set ground_truth_file in the config to run the full multi-cycle loop automatically — the script looks up target values from the CSV after each cycle, so no manual measurement step is needed:
ground_truth_file: "ackley3d_10000pts.csv" # in datasets/python scripts/insilico_lab_al_simulation.py -c scripts/insilico_lab_al_simulation_config.yaml| Model | Class | Backend | Uncertainty source | Requires |
|---|---|---|---|---|
| Gaussian Process Regressor | GPR |
scikit-learn | Posterior variance | core |
| k-Nearest Neighbours | kNNRegressorAL |
scikit-learn | Neighbourhood spread | core |
| Multi-Layer Perceptron | MLP |
PyTorch | Dropout / ensemble | nn extra |
| Anchored Ensemble MLP | AnchoredEnsembleMLP |
PyTorch | Ensemble disagreement | nn extra |
| Bayesian Neural Network | BayesianNN |
PyTorch + Pyro | Variational posterior | nn extra |
Models are configured via YAML files in scripts/mlmodel_config/ and instantiated through the factory:
from activereg.experiment import setup_ml_model
model = setup_ml_model(
ml_model_type="GPR",
ml_model_params={"kernel": "matern", "nu": 2.5},
)The KernelFactory in activereg/mlmodel/_kernels.py supports composing standard scikit-learn kernels (RBF, Matérn, WhiteKernel, ConstantKernel). Pre-defined kernel recipes are available in hyperparams.py.
Acquisition functions map the model's predictions over the unlabeled pool to a scalar informativeness score for each candidate point.
Convention: all acquisition functions are defined for maximisation — a higher predicted mean or acquisition score is always better. Minimisation objectives must be negated upstream.
| Mode | Key parameters | Description |
|---|---|---|
upper_confidence_bound |
kappa (default 2.0) |
μ + κ·σ — tunable exploration/exploitation balance |
expected_improvement |
xi (default 0.01) |
Expected improvement over the best observation |
target_expected_improvement |
y_target, and exactly one of dist or epsilon |
Steers toward a target value rather than the maximum |
percentage_target_expected_improvement |
percentage |
As above, with the target set as a percentage of the observed range |
maximum_predicted_value |
— | Pure exploitation: rank by predicted mean |
uncertainty_landscape |
— | Pure exploration: rank by predicted uncertainty |
exploration_mutual_info |
noise variance | Mutual-information exploration; needs a meaningful noise estimate |
Numbered variants. Any mode may carry a numeric suffix — expected_improvement_1, target_expected_improvement_2 — which selects the same formula but lets one acquisition protocol declare the same mode several times with different parameters. The suffix is stripped internally (acquisition.py:291).
from activereg.acquisition import AcquisitionFunction
acq = AcquisitionFunction(
acquisition_mode="upper_confidence_bound",
y_best=float(y_train.max()),
kappa=2.0,
)
landscape = acq.landscape_acquisition(X_candidates, ml_model)Given a landscape, a batch of q points is chosen by one of:
| Strategy | Function | Description |
|---|---|---|
| Highest landscape | batch_highest_landscape |
Draws spatially from the top percentile of the landscape |
| Constant liar | batch_constant_liar |
Imputes a fixed value for pending points, then re-acquires |
| Kriging believer | batch_kriging_believer |
Imputes the model's own prediction for pending points |
| Local penalization | batch_local_penalization |
Suppresses the landscape around already-selected points |
highest_landscape is the strategy in practical use. penalize_landscape_fast applies the Gaussian suppression used for within-batch diversity.
⚠️ Under development — documentation to be added.The implementation is merged and usable, but the API and configuration schema may still change. Treat this section as a pointer, not a spec.
activereg supports active learning campaigns that optimize several target properties jointly, rather than one at a time.
What exists today:
IndependentMultiPropertyModel(activereg/mlmodel/_multi_property.py) — a dict of independent single-property models sharing one interface, pluswrap_single_propertyfor backwards compatibility.- ParEGO-style scalarization in
activereg/acquisition.py—scalarize(),WeightSampler, andcompute_per_property_stats(). Random per-cycle weight sampling turns the multi-property problem into a sequence of scalar ones, tracing out the Pareto front across cycles. augmented_chebyshevscalarization (default) applied in quality space, where each property is normalised so0= worst and1= best, consistent with the maximisation convention above.- Multi-property config variants alongside their single-property counterparts:
scripts/general_config/*_multiprop.yaml.
Not yet documented here: the joint acquisition entry schema, weight-sampling options, per-property vs joint dispatch, and worked examples.
Backwards compatibility is preserved throughout — single-property campaigns are unaffected, and all existing acquisition formulas and batch selectors operate unchanged on the scalarized 1-D landscape.
Once the acquisition landscape is computed, a batch of candidates is drawn using one of three strategies:
| Strategy | Function | Description |
|---|---|---|
| Farthest Point Sampling | fps |
Maximises pairwise distance in feature space |
| Voronoi | voronoi |
Cluster-aware spatial coverage |
| Random | rnd |
Uniform random draw from top percentile |
from activereg.sampling import sample_landscape
# X_top: coordinates of the candidates surviving the landscape filter.
# Returns the indices of the selected points within X_top.
selected_idx = sample_landscape(X_top, n_points=5, sampling_mode="fps")Experiments are controlled by YAML configuration files under scripts/:
scripts/
├── general_config/
│ ├── benchmark_config.yaml # experiment-level settings
│ ├── acquisition_mode_settings.yaml # acquisition function parameters
│ └── target_function_config.yaml # benchmark function / dataset settings
├── mlmodel_config/
│ ├── gpr_config.yaml # Gaussian Process Regressor
│ ├── knnregressor_config.yaml # k-Nearest Neighbours
│ └── mlpanchored_config.yaml # Anchored Ensemble MLP [extra: nn]
└── lab_cycle_config_template.yaml # template for run_lab_cycle.py
Key configuration fields shared across benchmark and lab scripts:
ml_model: "GPR"
model_parameters:
kernel: "MATERN_W" # kernel recipe; see hyperparams.py
n_restarts_optimizer: 20
alpha: 1.0e-10
normalize_y: true
batch_selection_method: "highest_landscape" # highest_landscape | constant_liar | …
batch_selection_params:
percentile: 95
sampling_method: "voronoi" # voronoi | fps | random
acquisition_parameters:
- acquisition_mode: "expected_improvement"
n_points: 5
xi: 0.01Benchmark experiments compare acquisition strategies on synthetic test functions (Hartmann3, Hartmann6, Ackley, Styblinski-Tang) across dimensions. Two entry points are available:
benchmark_functions.py — evaluates the analytic test function directly to generate the pool and label points. Requires the benchmarks extra (botorch).
bash scripts/run_benchmark_funcs.sh
# Or directly with Python
python scripts/benchmark_functions.py \
-bc scripts/general_config/benchmark_config.yaml \
-mc scripts/mlmodel_config/gpr_config.yaml \
-acqmodes scripts/general_config/acquisition_mode_settings.yaml \
-tfc scripts/general_config/target_function_config.yaml \
-r 5benchmark_gtlandscape.py — runs against a precomputed ground-truth landscape CSV named by ground_truth_file in the benchmark config, so no analytic function is evaluated. Runs on the core install (no -tfc argument, since the target function is already baked into the ground-truth file).
bash scripts/run_benchmark_gtlandsc.sh
python scripts/benchmark_gtlandscape.py \
-bc scripts/general_config/benchmark_config.yaml \
-mc scripts/mlmodel_config/gpr_config.yaml \
-acqmodes scripts/general_config/acquisition_mode_settings.yaml \
-r 5Both accept --rerun to overwrite an existing benchmark folder. Results (training CSVs, metric logs, per-run config/ snapshots) are written to benchmarks/.
MIT License. See LICENSE for details.