Scikit-learn Integration
PyTorch-BSF provides a high-level wrapper compatible with the Scikit-learn estimator API. This allows you to integrate Bézier simplex fitting into standard machine learning workflows, including pipelines and cross-validation tools.
The BezierSimploidRegressor
The BezierSimploidRegressor class inherits from sklearn.base.BaseEstimator and sklearn.base.RegressorMixin. It supports the standard fit(), predict(), and score() methods, and fits the model with torch_bsf.fit().
import numpy as np
from torch_bsf.sklearn import BezierSimploidRegressor
# Your data (parameters must be on a simplex)
X = np.array([[1.0, 0.0], [0.5, 0.5], [0.0, 1.0]])
y = np.array([[1.0], [0.75], [0.0]])
# Initialize and fit
reg = BezierSimploidRegressor(degree=2)
reg.fit(X, y)
# Predict
y_pred = reg.predict(X)
By default, each row of X is a point on a simplex with n_features vertices, and a Bézier simplex is fitted (a single feature gives a constant model). The fitted model is available as reg.model_.
Choosing a solver
The solver parameter selects how the control points are computed:
solver="lstsq"(default)Since a Bézier simplex is linear in its control points, the squared error is minimized exactly by linear least squares on the Bernstein basis, solved in double precision. This is fast and accurate, especially for high-dimensional outputs (e.g., hundreds of values per sample), where training may stop far from the optimum. The optional
ridgeparameter adds the Tikhonov penalty \(\mathrm{ridge}\,\|P\|^2\) on the control points \(P\); without it, under-determined problems (fewer samples than control points) get the minimum-norm solution. The fitted model keeps the floating dtype ofy(float64forfloat64or integer targets).solver="trainer"Trains the control points by gradient-based optimization with
lightning.pytorch.Trainerfor up tomax_epochsepochs in single precision. Use it for minibatches and accelerators (batch_size,max_epochs,accelerator,devices,precisionandtrainer_kwargs).
import numpy as np
from torch_bsf.sklearn import BezierSimploidRegressor
rng = np.random.default_rng(0)
raw = rng.random((41, 2))
X = raw / raw.sum(axis=1, keepdims=True) # 41 points on a segment
y = np.sin(np.outer(X[:, 0], np.linspace(1, 6, 256))) # 256-dimensional values
reg = BezierSimploidRegressor(degree=10, ridge=1e-12)
reg.fit(X, y)
print(reg.predict(X).shape)
print(reg.score(X, y) > 0.999)
(41, 256)
True
init, freeze, smoothness_weight and normalize work with both solvers; the predictions
are in the scale of y whatever normalize is. With solver="lstsq", the trainer-only options
listed above are ignored, and a nonzero ridge with solver="trainer" raises ValueError.
All parameters work with get_params(), set_params() and clone(), so they can be searched by
GridSearchCV like any other hyperparameter (e.g., {"ridge": [0.0, 1e-6, 1e-3]}).
Bézier simploids
To fit a Bézier simploid, i.e., a tensor product of Bézier simplices (see Simploidal Sets), pass its
type as simploid_type. Each row of X is then the concatenation of the barycentric coordinates of
every factor, and degree is the degree of every factor or one degree per factor. For example, on a
prism (a triangle times a segment):
import numpy as np
from torch_bsf.simploidal import sample_simploid
from torch_bsf.sklearn import BezierSimploidRegressor
X = sample_simploid((2, 1), 40, seed=0).double().numpy() # 3 + 2 columns
y = X[:, :1] ** 2 * X[:, 3:4]
reg = BezierSimploidRegressor(degree=(2, 1), simploid_type=(2, 1)).fit(X, y)
print(reg.simploid_type_, reg.model_.degree)
print(np.allclose(reg.predict(X), y, atol=1e-6))
(2, 1) (2, 1)
True
Integration with Pipelines
You can include BezierSimploidRegressor in a Scikit-learn Pipeline. This is particularly useful if you need to perform data preprocessing (though note that Bézier simplex fitting usually expects parameters to be on a simplex).
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
pipe = Pipeline([
('scaler', StandardScaler()),
('bsf', BezierSimploidRegressor(degree=3))
])
pipe.fit(X, y)
Using GridSearchCV
Since it’s a standard estimator, you can use GridSearchCV to find the optimal hyperparameters, such as the degree or smoothness weight.
from sklearn.model_selection import GridSearchCV
param_grid = {
'degree': [2, 3, 4, 5],
'smoothness_weight': [0.0, 0.01, 0.1]
}
grid = GridSearchCV(BezierSimploidRegressor(), param_grid, cv=5)
grid.fit(X, y)
print(f"Best parameters: {grid.best_params_}")
API Reference
See the API Documentation for a full list of supported parameters.