Migration Guide

Any breaking API changes that will need to be accounted for/will likely require updates to your experiment code will be documented here with explanations of how to do so.

0.14.0 - 0.15.0

The naming scheme for “args”/parameters has been cleaned up and “args” is no longer a concept in curifactory. The args module has been renamed to params, and the base parameter class ExperimentArgs has been renamed to ExperimentParameters.

The following changes will need to be made in any previous experiments:

Change any Record.args references to Record.params

This will likely effect every stage that uses parameters, e.g.

@stage(...)
def train_model(record: cf.Record):
    model = LogisticRegression(random_state=record.args.seed_args)

Should now become:

@stage(...)
def train_model(record: cf.Record):
    model = LogisticRegression(random_state=record.params.seed_args)

Classes subclassing curifactory.args.ExperimentArgs should subclass curifactory.params.ExperimentParameters

The args module has been renamed to params, so any imports that explicitly reference curifactory.args will need to be changed to curifactory.params. Similarly, the base parameter class that you extend for custom parameters will need to be changed from ExperimentArgs to ExperimentParameters:

from curifactory import ExperimentParameters

@dataclass
class MyParams(ExperimentParameters):
    ...

Both of the above changes are currently optional, Record.args and curifactory.args.ExperimentArgs exist with deprecation warnings. These will likely be fully removed in version 0.16.0.

0.13.0 - 0.14.0

Aggregate stages should now specify inputs in the decorator

Along with the addition of DAG-based stage execution, @aggregate stages now have an inputs attribute in the decorator, which similarly to the @stage decorator should include the string names of all artifacts in all aggregated records that will be needed in the aggregate stage code.

Specifying inputs is required for the DAG to map the experiment correctly, not doing so will likely cause any stages before the aggregate (that it would otherwise rely on) to never execute.

Similar to @stage, any listed input strings need a corresponding argument of the same name in the function definition. Each of these arguments will be populated with a dictionary where each key is a record, and the value is the corresponding artifact of that name from that record’s state. This allows simplifying aggregate stage code, as you no longer need to directly access the state from each record.

An example to demonstrate required/suggested changes follows, assume that this stage is trying to take all of the results from previous records and put them into a single dictionary, where the keys are the names of the parameter sets that generated the associated result metric:

A previous aggregate stage would have been:

@aggregate(outputs=["final_results"])
def combine_results(record: Record, records: list[Record]):
    final_results = {}
    for r in records:
        if "results" in r.state:
            final_results[r.args.name] = r.state["results"]
    return final_results

This code could now be changed to:

@aggregate(inputs=["results"], outputs=["final_results"])
def combine_results(record: Record, records: list[Record], results: dict[Record, float]):
    final_results = {}
    for r, result in results.items():
        final_results[r.args.name] = result
    return final_results

Note that the minimum amount of changes to still function would simply involve adding the inputs and the corresponding function definition argument, the inner stage code itself doesn’t need to change.

@aggregate(inputs=["results"], outputs=["final_results"])
def combine_results(record: Record, records: list[Record], results: dict[Record, float]):
    final_results = {}
    for r in records:
        if "results" in r.state:
            final_results[r.args.name] = r.state["results"]
    return final_results

Any specified inputs that don’t appear in one or more of the passed records’ states will print a warning but will not error. The associated argument’s dictionary will simply not contain that record.

Note

To temporarily retain previous v0.13.x behavior for aggregate stages that you do not yet specify inputs for, you can run the experiment with the --no-dag CLI flag.