Adapters¶
Adapters bridge the gap between ml-labs' unified interface and each ML framework's specific fit() parameter conventions (e.g., eval_set, validation_data, callbacks).
Adapter Interface¶
All adapters extend ModelAdapter and may implement three members:
get_params(params, logger)¶
Adjusts or filters constructor parameters before the model is instantiated. The default implementation returns params unchanged.
LightGBM example — strips early_stopping and eval_metric from constructor params (they belong in fit()):
def get_params(self, params, logger=None):
return {k: v for k, v in params.items() if k not in ['early_stopping', 'eval_metric']}
get_fit_params(data_dict, params, logger)¶
Builds the keyword arguments passed to model.fit(). Receives a data_dict with (train, train_v) tuples per key.
Behaviour is controlled by two constructor parameters shared by all adapters:
| Parameter | Values | Effect |
|---|---|---|
eval_mode |
'none'/None |
No eval set |
'valid' |
Pass inner-validation fold only | |
'both' |
Pass both train and inner-validation fold | |
verbose |
0 |
Silent |
0 < v < 1 |
Progress every v*100% of estimators |
|
v >= 1 |
Every v iterations (framework-native) |
result_objs¶
A class-level dict of extractable model attributes used by ModelAttrCollector:
result_objs = {
'feature_importances': (get_importance_fn, True), # (callable, mergeable)
'trees': (get_trees_fn, False),
}
mergeable=True means the result is a pd.Series or pd.DataFrame that can be aggregated across folds by get_attrs_agg().
Built-in Adapters¶
Adapters are registered by model class name and resolved automatically via get_adapter(). The default eval_mode='both', verbose=0.1.
DefaultAdapter¶
Used for any model not in the registry. Passes no extra fit parameters — suitable for standard sklearn transformers and estimators.
sklearn Adapters¶
| Adapter | Models | result_objs |
|---|---|---|
LMAdapter |
LinearRegression, LogisticRegression |
coef |
PCAAdapter |
PCA |
explained_variance, explained_variance_ratio, components |
LDAAdapter |
LinearDiscriminantAnalysis |
coef, intercept, scalings, explained_variance_ratio |
DecisionTreeAdapter |
DecisionTreeClassifier/Regressor |
feature_importances✓, tree✗, plot_tree✗ |
✓ mergeable, ✗ not mergeable
LightGBMAdapter¶
Passes eval_set to fit(). Supports early_stopping and eval_metric as node params (they are moved from constructor to fit()).
early_stopping accepts either a lgb.early_stopping callback instance or a plain dict of lgb.early_stopping constructor kwargs:
exp.set_node('lgbm', grp='lgbm_grp', params={
'n_estimators': 1000,
# callback instance
'early_stopping': early_stopping(50, verbose=False),
# or equivalently as a dict (preferred — avoids false rebuild detection)
'early_stopping': {'stopping_rounds': 50, 'verbose': False},
'eval_metric': 'auc',
})
Using a dict is recommended: _params_equal compares plain dicts correctly, so changing other params won't trigger spurious rebuilds caused by callback object identity.
result_objs: feature_importances✓, evals_result✓, trees✗
XGBoostAdapter¶
Passes eval_set to fit(). Progress callback is added via get_params().
result_objs: feature_importances✓, evals_result✓, trees✗
CatBoostAdapter¶
Passes eval_set to fit(). verbose=0<v<1 falls back to silent (CatBoost callback API is complex).
result_objs: feature_importances_pvc✓, feature_importances_interaction✓, evals_result✓, trees✗
KerasAdapter¶
Uses validation_data=(X_val, y_val) instead of eval_set. Both 'valid' and 'both' eval modes behave identically (Keras only accepts a single validation set).
result_objs: none
NNAdapter¶
For NNClassifier and NNRegressor. Passes the inner-validation fold as eval_set=[(X_val, y_val)] to fit(). Progress is reported via a Keras callback (_ProgressCallback) injected into the callbacks argument of fit().
result_objs: evals_result✓
Custom Adapter¶
from mllabs.adapter import ModelAdapter, register_adapter
class MyAdapter(ModelAdapter):
def get_fit_params(self, data_dict, params=None, logger=None):
train_X, train_v_X = data_dict['X']
train_y, train_v_y = data_dict['y']
return {
'eval_set': [(train_v_X.values, train_v_y.values)],
}
register_adapter('MyModel', MyAdapter(eval_mode='valid', verbose=0))
After registration, MyAdapter is resolved automatically whenever a node uses MyModel as its processor.
To use an adapter on a specific node or group without registering it globally: