Skip to content

Commit 56fe1a7

Browse files
update sphinx pages
and added docstrinsg
1 parent 6cec0e9 commit 56fe1a7

5 files changed

Lines changed: 179 additions & 9117 deletions

File tree

bde/bde.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,40 @@ def __init__(
527527
desired_energy_var_end: float = 0.1,
528528
step_size_init: float | None = None,
529529
):
530+
"""Initialise the regressor with architecture, optimisation, and sampling settings.
531+
532+
Parameters
533+
----------
534+
n_members : int, default=2
535+
Number of deterministic networks in the ensemble.
536+
hidden_layers : list[int] | None, default= None
537+
Hidden layer widths; defaults to ``[4, 4]`` internally when ``None``.
538+
seed : int, default=0
539+
Shared PRNG seed for member initialisation and sampling.
540+
loss : BaseLoss | None
541+
Custom training loss; defaults to :class:`bde.loss.GaussianNLL`.
542+
activation : str, default='relu'
543+
Activation function applied to each hidden layer.
544+
epochs : int, default=20
545+
Maximum training epochs during the deterministic phase.
546+
patience : int | None, optional
547+
Early-stopping patience measured in epochs; ``None`` disables it.
548+
n_samples : int, default=10
549+
Posterior samples retained for each ensemble member.
550+
warmup_steps : int, default=50
551+
Number of warm-up iterations for the MCMC sampler.
552+
lr : float, default=1e-3
553+
Learning rate for the Adam optimiser used in pre-sampling training.
554+
n_thinning : int, default=2
555+
Thinning interval applied to posterior samples.
556+
desired_energy_var_start : float, default=0.5
557+
Target energy variance at the start of warm-up.
558+
desired_energy_var_end : float, default=0.1
559+
Target energy variance at the end of warm-up.
560+
step_size_init : float | None, optional
561+
Override for the sampler's initial step size; falls back to ``lr``.
562+
"""
563+
530564
super().__init__(
531565
n_members=n_members,
532566
hidden_layers=hidden_layers,
@@ -592,6 +626,40 @@ def __init__(
592626
desired_energy_var_end: float = 0.1,
593627
step_size_init: float | None = None,
594628
):
629+
"""Initialise the classifier with architecture, optimisation, and sampling settings.
630+
631+
Parameters
632+
----------
633+
n_members : int, default=2
634+
Number of deterministic networks in the ensemble.
635+
hidden_layers : list[int] | None, default= None
636+
Hidden layer widths; defaults to ``[4, 4]`` internally when ``None``.
637+
seed : int, default=0
638+
Shared PRNG seed for member initialisation and sampling.
639+
loss : BaseLoss | None
640+
Custom training loss; defaults to :class:`bde.loss.GaussianNLL`.
641+
activation : str, default='relu'
642+
Activation function applied to each hidden layer.
643+
epochs : int, default=20
644+
Maximum training epochs during the deterministic phase.
645+
patience : int | None, optional
646+
Early-stopping patience measured in epochs; ``None`` disables it.
647+
n_samples : int, default=10
648+
Posterior samples retained for each ensemble member.
649+
warmup_steps : int, default=50
650+
Number of warm-up iterations for the MCMC sampler.
651+
lr : float, default=1e-3
652+
Learning rate for the Adam optimiser used in pre-sampling training.
653+
n_thinning : int, default=2
654+
Thinning interval applied to posterior samples.
655+
desired_energy_var_start : float, default=0.5
656+
Target energy variance at the start of warm-up.
657+
desired_energy_var_end : float, default=0.1
658+
Target energy variance at the end of warm-up.
659+
step_size_init : float | None, optional
660+
Override for the sampler's initial step size; falls back to ``lr``.
661+
"""
662+
595663
super().__init__(
596664
n_members=n_members,
597665
hidden_layers=hidden_layers,

doc/api.rst

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,3 @@ Estimator
1717

1818
BdeRegressor
1919
BdeClassifier
20-
21-
22-
Predictor
23-
=========
24-
25-
.. autosummary::
26-
:toctree: generated/
27-
:template: class.rst
28-
29-
BdePredictor
30-
31-
32-
Utilities
33-
=========
34-
35-
.. autosummary::
36-
:toctree: generated/
37-
:template: functions.rst
38-
39-
utils.discovery.all_estimators
40-
utils.discovery.all_displays
41-
utils.discovery.all_functions

doc/user_guide.rst

Lines changed: 108 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -6,175 +6,111 @@
66
User Guide
77
==========
88

9-
Estimator
10-
---------
11-
12-
The central piece of transformer, regressor, and classifier is
13-
:class:`sklearn.base.BaseEstimator`. All estimators in scikit-learn are derived
14-
from this class. In more details, this base class enables to set and get
15-
parameters of the estimator. It can be imported as::
16-
17-
>>> from sklearn.base import BaseEstimator
18-
19-
Once imported, you can create a class which inherate from this base class::
20-
21-
>>> class MyOwnEstimator(BaseEstimator):
22-
... pass
23-
24-
Transformer
25-
-----------
26-
27-
Transformers are scikit-learn estimators which implement a ``transform`` method.
28-
The use case is the following:
29-
30-
* at ``fit``, some parameters can be learned from ``X`` and ``y``;
31-
* at ``transform``, `X` will be transformed, using the parameters learned
32-
during ``fit``.
33-
34-
.. _mixin: https://en.wikipedia.org/wiki/Mixin
35-
36-
In addition, scikit-learn provides a
37-
mixin_, i.e. :class:`sklearn.base.TransformerMixin`, which
38-
implement the combination of ``fit`` and ``transform`` called ``fit_transform``.
39-
40-
One can import the mixin class as::
41-
42-
>>> from sklearn.base import TransformerMixin
43-
44-
Therefore, when creating a transformer, you need to create a class which
45-
inherits from both :class:`sklearn.base.BaseEstimator` and
46-
:class:`sklearn.base.TransformerMixin`. The scikit-learn API imposed ``fit`` to
47-
**return ``self``**. The reason is that it allows to pipeline ``fit`` and
48-
``transform`` imposed by the :class:`sklearn.base.TransformerMixin`. The
49-
``fit`` method is expected to have ``X`` and ``y`` as inputs. Note that
50-
``transform`` takes only ``X`` as input and is expected to return the
51-
transformed version of ``X``::
52-
53-
>>> class MyOwnTransformer(TransformerMixin, BaseEstimator):
54-
... def fit(self, X, y=None):
55-
... return self
56-
... def transform(self, X):
57-
... return X
58-
59-
We build a basic example to show that our :class:`MyOwnTransformer` is working
60-
within a scikit-learn ``pipeline``::
61-
62-
>>> from sklearn.datasets import load_iris
63-
>>> from sklearn.pipeline import make_pipeline
64-
>>> from sklearn.linear_model import LogisticRegression
65-
>>> X, y = load_iris(return_X_y=True)
66-
>>> pipe = make_pipeline(MyOwnTransformer(),
67-
... LogisticRegression(random_state=10,
68-
... solver='lbfgs'))
69-
>>> pipe.fit(X, y) # doctest: +ELLIPSIS
70-
Pipeline(...)
71-
>>> pipe.predict(X) # doctest: +ELLIPSIS
72-
array([...])
73-
74-
Predictor
75-
---------
76-
77-
Regressor
78-
~~~~~~~~~
79-
80-
Similarly, regressors are scikit-learn estimators which implement a ``predict``
81-
method. The use case is the following:
82-
83-
* at ``fit``, some parameters can be learned from ``X`` and ``y``;
84-
* at ``predict``, predictions will be computed using ``X`` using the parameters
85-
learned during ``fit``.
86-
87-
In addition, scikit-learn provides a mixin_, i.e.
88-
:class:`sklearn.base.RegressorMixin`, which implements the ``score`` method
89-
which computes the :math:`R^2` score of the predictions.
90-
91-
One can import the mixin as::
92-
93-
>>> from sklearn.base import RegressorMixin
94-
95-
Therefore, we create a regressor, :class:`MyOwnRegressor` which inherits from
96-
both :class:`sklearn.base.BaseEstimator` and
97-
:class:`sklearn.base.RegressorMixin`. The method ``fit`` gets ``X`` and ``y``
98-
as input and should return ``self``. It should implement the ``predict``
99-
function which should output the predictions of your regressor::
100-
101-
>>> import numpy as np
102-
>>> class MyOwnRegressor(RegressorMixin, BaseEstimator):
103-
... def fit(self, X, y):
104-
... return self
105-
... def predict(self, X):
106-
... return np.mean(X, axis=1)
107-
108-
We illustrate that this regressor is working within a scikit-learn pipeline::
109-
110-
>>> from sklearn.datasets import load_diabetes
111-
>>> X, y = load_diabetes(return_X_y=True)
112-
>>> pipe = make_pipeline(MyOwnTransformer(), MyOwnRegressor())
113-
>>> pipe.fit(X, y) # doctest: +ELLIPSIS
114-
Pipeline(...)
115-
>>> pipe.predict(X) # doctest: +ELLIPSIS
116-
array([...])
117-
118-
Since we inherit from the :class:`sklearn.base.RegressorMixin`, we can call
119-
the ``score`` method which will return the :math:`R^2` score::
120-
121-
>>> pipe.score(X, y) # doctest: +ELLIPSIS
122-
-3.9...
123-
124-
Classifier
125-
~~~~~~~~~~
126-
127-
Similarly to regressors, classifiers implement ``predict``. In addition, they
128-
output the probabilities of the prediction using the ``predict_proba`` method:
129-
130-
* at ``fit``, some parameters can be learned from ``X`` and ``y``;
131-
* at ``predict``, predictions will be computed using ``X`` using the parameters
132-
learned during ``fit``. The output corresponds to the predicted class for each sample;
133-
* ``predict_proba`` will give a 2D matrix where each column corresponds to the
134-
class and each entry will be the probability of the associated class.
135-
136-
In addition, scikit-learn provides a mixin, i.e.
137-
:class:`sklearn.base.ClassifierMixin`, which implements the ``score`` method
138-
which computes the accuracy score of the predictions.
139-
140-
One can import this mixin as::
141-
142-
>>> from sklearn.base import ClassifierMixin
143-
144-
Therefore, we create a classifier, :class:`MyOwnClassifier` which inherits
145-
from both :class:`slearn.base.BaseEstimator` and
146-
:class:`sklearn.base.ClassifierMixin`. The method ``fit`` gets ``X`` and ``y``
147-
as input and should return ``self``. It should implement the ``predict``
148-
function which should output the class inferred by the classifier.
149-
``predict_proba`` will output some probabilities instead::
150-
151-
>>> class MyOwnClassifier(ClassifierMixin, BaseEstimator):
152-
... def fit(self, X, y):
153-
... self.classes_ = np.unique(y)
154-
... return self
155-
... def predict(self, X):
156-
... return np.random.randint(0, self.classes_.size,
157-
... size=X.shape[0])
158-
... def predict_proba(self, X):
159-
... pred = np.random.rand(X.shape[0], self.classes_.size)
160-
... return pred / np.sum(pred, axis=1)[:, np.newaxis]
161-
162-
We illustrate that this regressor is working within a scikit-learn pipeline::
163-
164-
>>> X, y = load_iris(return_X_y=True)
165-
>>> pipe = make_pipeline(MyOwnTransformer(), MyOwnClassifier())
166-
>>> pipe.fit(X, y) # doctest: +ELLIPSIS
167-
Pipeline(...)
168-
169-
Then, you can call ``predict`` and ``predict_proba``::
170-
171-
>>> pipe.predict(X) # doctest: +ELLIPSIS
172-
array([...])
173-
>>> pipe.predict_proba(X) # doctest: +ELLIPSIS
174-
array([...])
175-
176-
Since our classifier inherits from :class:`sklearn.base.ClassifierMixin`, we
177-
can compute the accuracy by calling the ``score`` method::
178-
179-
>>> pipe.score(X, y) # doctest: +ELLIPSIS
180-
0...
9+
This guide focuses on the pieces that are specific to ``bde``. If you are new to
10+
scikit-learn's estimator API, refer to the official `developer guide
11+
<https://scikit-learn.org/stable/developers/develop.html>`__ for the foundational
12+
concepts. The sections below assume that background and concentrate on how
13+
``BdeRegressor`` and ``BdeClassifier`` behave, how they integrate with JAX, and how
14+
you should prepare data to get reliable results.
15+
16+
Estimator overview
17+
------------------
18+
19+
``bde`` exposes two scikit-learn compatible estimators:
20+
21+
* :class:`bde.BdeRegressor` for continuous targets.
22+
* :class:`bde.BdeClassifier` for categorical targets.
23+
24+
Both inherit :class:`sklearn.base.BaseEstimator` and the relevant mixins, so they
25+
support the familiar ``fit``/``predict``/``score`` methods, accept keyword
26+
hyperparameters in ``__init__``, and can be dropped into a
27+
:class:`sklearn.pipeline.Pipeline`. Under the hood they train a fully connected
28+
ensemble in JAX and then run an MCMC sampler to draw posterior weight samples. At
29+
prediction time the estimator combines those samples to provide means, standard
30+
deviations, credible intervals, probability vectors, or the raw ensemble outputs.
31+
32+
Data preparation
33+
----------------
34+
35+
Bayesian deep ensembles are sensitive to feature and target scale because the
36+
networks are initialised with zero-mean weights and the prior assumes unit-scale
37+
activations. Large raw targets (for instance the default output of
38+
:func:`sklearn.datasets.make_regression`) can lead to very poor fits if left
39+
unscaled. Always apply basic preprocessing before calling ``fit``:
40+
41+
Understanding the outputs
42+
-------------------------
43+
44+
The estimators expose several prediction modes:
45+
46+
``predict(X)``
47+
Returns the mean prediction (regression) or hard labels (classification).
48+
``predict(X, mean_and_std=True)``
49+
Regression only; returns a tuple ``(mean, std)`` where ``std`` combines
50+
aleatoric and epistemic components.
51+
``predict(X, credible_intervals=[0.9, 0.95])``
52+
Regression only; returns ``(mean, intervals)`` with quantiles over posterior
53+
samples.
54+
``predict(X, raw=True)``
55+
Returns the raw tensor with leading axes ``(ensemble_members, samples, n,
56+
output_dims)``. Useful for custom diagnostics.
57+
``predict_proba(X)``
58+
Classification only; returns class probability vectors.
59+
60+
61+
Key hyperparameters
62+
-------------------
63+
64+
``n_members``
65+
Number of deterministic networks in the ensemble. Increasing members improves
66+
epistemic uncertainty estimation but raises computational cost.
67+
``hidden_layers``
68+
Widths of hidden layers. Defaults internally to ``[4, 4]`` if ``None``.
69+
``epochs`` / ``patience``
70+
Control training duration. ``epochs`` sets the maximum number of epochs,
71+
while ``patience`` enables early stopping. When ``patience`` is ``None``,
72+
training always runs for all epochs.
73+
``lr``
74+
Learning rate for the Adam optimiser during pre-sampling training.
75+
``warmup_steps`` / ``n_samples`` / ``n_thinning``
76+
Control the MCMC sampling stage. ``warmup_steps`` adjusts the step size,
77+
``n_samples`` defines the number of retained posterior draws, and
78+
``n_thinning`` specifies the interval between saved samples.
79+
80+
81+
82+
Sampler and builder internals
83+
-----------------------------
84+
85+
After the deterministic training phase ``BdeRegressor`` and ``BdeClassifier``
86+
construct a :class:`bde.bde_builder.BdeBuilder` instance. This helper manages the
87+
ensemble members, coordinates parallel training across devices, and hands off to
88+
``bde.sampler`` utilities for warmup and sampling. Advanced users can interact
89+
with these pieces directly:
90+
91+
* ``estimator._bde`` references the builder after ``fit`` and exposes the
92+
deterministic members and training history.
93+
* ``estimator.positions_eT_`` stores the weight samples with shape ``(E, T, ...)``.
94+
* Warmup behaviour can be tuned via ``desired_energy_var_start`` and
95+
``desired_energy_var_end``.
96+
97+
Generally you should rely on the high-level estimator API, but the internals are
98+
accessible for custom diagnostics or research experiments.
99+
100+
Accelerators and environment
101+
----------------------------
102+
103+
The estimators run on whatever backend JAX initialises. On CPU-only machines you
104+
must set ``XLA_FLAGS="--xla_force_host_platform_device_count=<n>"`` to allocate
105+
several virtual devices for the ensemble. On GPU- or TPU-enabled hardware JAX
106+
picks up devices automatically; ensure your environment includes the matching
107+
``jaxlib`` build. The repository ships with a ``pixi.toml`` that pins compatible
108+
versions and provides tasks such as ``pixi run test`` and ``pixi run build-doc``.
109+
110+
Where to next
111+
-------------
112+
113+
* The :ref:`quick_start` page shows condensed scripts you can run end to end.
114+
* :ref:`api` documents every public class and helper in the package.
115+
* :ref:`general_examples` renders notebooks and plots that mirror the examples
116+
in the ``examples/`` directory.

0 commit comments

Comments
 (0)