Benchmark
SVCBenchmark ties together the data loader, processors, and model into a single
runnable pipeline.
SVCBenchmark
class SVCBenchmark(Component):
def __init__(
self,
data_loader: RegistrationKey,
model: RegistrationKey,
text_processor: RegistrationKey,
label_processor: RegistrationKey,
):
self.data_loader = data_loader
self.model = model
self.text_processor = text_processor
self.label_processor = label_processor
def run(self):
logging.basicConfig(level=logging.INFO)
data_loader = IMDBLoader.instantiate(self.data_loader)
train_df, val_df, test_df = data_loader.get_splits()
text_processor = TfIdfProcessor.instantiate(self.text_processor)
label_processor = LabelProcessor.instantiate(self.label_processor)
x_train = text_processor.process(data=train_df, is_training_data=True)
y_train = label_processor.process(data=train_df, is_training_data=True)
x_val = text_processor.process(data=val_df)
y_val = label_processor.process(data=val_df)
x_test = text_processor.process(data=test_df)
y_test = label_processor.process(data=test_df)
model = SVCModel.instantiate(self.model)
train_info, val_info = model.fit(
x_train=x_train, y_train=y_train,
x_val=x_val, y_val=y_val
)
test_info = model.evaluate(x=x_test, y=y_test)
logging.info(f'Train info:\n{train_info}')
logging.info(f'Val info:\n{val_info}')
logging.info(f'Test info:\n{test_info}')
Notice that SVCBenchmark.__init__ receives RegistrationKey objects, not built
component instances. Each dependency is built lazily inside run() via
Component.instantiate(key).
This is a deliberate design choice enabled by resolve_automatically=False in the
benchmark’s registration (see below). It means:
The
Registryvalidates that eachRegistrationKeyexists and is resolvable, but does not build the nested components eagerly.Components are constructed only when
run()is called, keeping memory usage low until the pipeline actually starts.Each nested component gets its own fresh instance per run, with no shared state.
SVCBenchmarkConfig
class SVCBenchmarkConfig(Configuration):
data_loader: RegistrationKey = Param(
RegistrationKey(name='data_loader', tags={'imdb'}, namespace='examples'),
description='Data loader'
)
text_processor: RegistrationKey = Param(
RegistrationKey(name='processor', tags={'tf-idf'}, namespace='examples'),
description='Text processor'
)
label_processor: RegistrationKey = Param(
RegistrationKey(name='processor', tags={'label'}, namespace='examples'),
description='Label processor'
)
model: RegistrationKey = Param(
RegistrationKey(name='model', tags={'svc'}, namespace='examples'),
description='Classifier model'
)
@classmethod
@register_method(
name='benchmark',
tags={'svc'},
namespace='examples',
component='examples.components.benchmark.SVCBenchmark',
run_method='run',
resolve_automatically=False # keep RegistrationKey fields unresolved
)
def default(cls) -> 'SVCBenchmarkConfig':
return super().default()
The four RegistrationKey fields point to the other registered components.
resolve_automatically=False tells the Registry not to replace those keys with
Configuration instances during dag_resolution() — they are passed as-is to
SVCBenchmark.__init__, which then resolves them lazily inside run().
The default keys can be swapped by overriding individual fields via model_copy():
# Use a custom model instead of the default SVC
config = SVCBenchmarkConfig.default()
config = config.model_copy(update={
'model': RegistrationKey(name='model', tags={'custom'}, namespace='my_project')
})
Demo script
from pathlib import Path
from cinnamon.registry import Registry
from examples.components.benchmark import SVCBenchmark
if __name__ == '__main__':
directory = Path(__file__).parent.parent.resolve()
Registry.build(directory=directory)
benchmark = SVCBenchmark.instantiate(
name='benchmark', tags={'svc'}, namespace='examples'
)
benchmark.run()
Registry.build() discovers and registers all four component configurations.
SVCBenchmark.instantiate() builds the benchmark with its four RegistrationKey
fields intact. benchmark.run() then builds and runs each nested component in sequence.
Note
The demo is at examples/demos/demo_benchmark.py.
Run it from the examples/ directory so that relative paths in
IMDBLoaderConfig (the datasets/ subfolder) resolve correctly.
Congratulations!
That’s the full pipeline — a customisable, plug-and-play machine-learning experiment
where every stage can be swapped independently via RegistrationKey.
To extend it, you can:
Register a new
modelkey pointing to a different classifier.Register a new
processorkey with different tf-idf parameters.Build a
CustomBenchmarkConfigthat mixes example and custom components.
See the catalog for the full list of registered keys.