InstanceEngine

InstanceEngine(
    spec,
    *,
    device=None,
    num_workers=0,
    strict_data=True,
    check_objects=True,
)

Many instance models, one spec. What platypus_fit(spec) will call for this task.

Methods

Name Description
best_model Which model scored best, by one column of evaluate.
dataset One split as (image, instance target) pairs.
evaluate One row per model and decoding: the comparison this task is for.
evaluate_cases One row per case instead of one row per model, for one decoding.
export_weights Write one trained model’s weights, with the sidecar that says what they are for.
fit Train every model the spec asks for, in order.
loader A torch DataLoader over one split, wrapping dataset.
predict The model’s own channels, channels-last, one array per source image, stacked.
predict_instances One label map per source image: objects numbered from 1.

best_model

InstanceEngine.best_model(key='average_precision', split='validation')

Which model scored best, by one column of evaluate.

The name alone, because a (model, decoding) pair is not a model: the rows are searched over both axes and the winning row’s model is returned, so a model that wins only through connected_components is reported as the winner it is - which is the result this dataset actually produced.

dataset

InstanceEngine.dataset(model, split, *, augmented=False, only_images=None)

One split as (image, instance target) pairs.

Parameters

Name Type Description Default
model InstanceModel Which model’s settings to read - the input size, the tiling, the separation the target is built for and that target’s own parameters. required
split str Which data. required
augmented bool Apply the model’s augmentation. Training only. False
only_images bool | None Read images alone. Defaults to what the split actually has. None

Returns

Name Type Description
InstanceDataset An InstanceDataset. inspect_objects() on it is what fit calls to refuse a
InstanceDataset split whose objects have all vanished in the resize.

evaluate

InstanceEngine.evaluate(split='validation')

One row per model and decoding: the comparison this task is for.

A decoding costs a hundredth of an epoch, so the table gains an axis for nearly nothing.

This paragraph used to say connected_components is in every model’s rows whether it was asked for or not, and it is not. It is in the pair decode derives to when a model stayed silent, which is the signal’s own decoding plus the yardstick; a model that writes a decode list gets the list it wrote and nothing added. That is the right behaviour - the engine does not put a row in somebody’s table that they did not ask for - and the claim was wrong rather than the code: the only test on it covered the derived case, and examples/compare_instance_separations.py keeps the yardstick in its own --decode handling precisely because nothing below does it. test_a_written_decode_list_is_what_you_get is the half that was missing.

The reason the yardstick belongs in a comparison is unchanged and is why the derivation includes it: it ignores the separation signal, so it is the row the signal’s row has to be read against.

Parameters

Name Type Description Default
split str Which data to score on. 'validation'

Returns

Name Type Description
list[dict[str, Any]] One row per (model, decoding): what the model is, what it was trained on, the
list[dict[str, Any]] mask’s own numbers, and the instance average precision with the object counts
list[dict[str, Any]] that explain it. average_precision is the mean over images, which is what the
list[dict[str, Any]] Data Science Bowl ranked on.
list[dict[str, Any]] **foreground_dice is the mask column to read across models and dice is
list[dict[str, Any]] not.** The first is a binary overlap of anything the model called an object
list[dict[str, Any]] against anything that is one, computed identically whatever the separation
list[dict[str, Any]] signal is, unsmoothed and averaged over images - the same pooling as the
list[dict[str, Any]] average_precision beside it. The second is the training metric, a mean over
list[dict[str, Any]] the class channels that model’s head has, so it is read down one model’s rows
list[dict[str, Any]] and never across two. Both are the same for every decoding of one model.
list[dict[str, Any]] pyplatypus#222 has the measurement that separates them: 0.09 apart in the
list[dict[str, Any]] class column where the masks are 0.0062 apart, and in the other direction.

Raises

Name Type Description
EngineError If nothing has been trained, or the split carries no masks.

evaluate_cases

InstanceEngine.evaluate_cases(
    model_name=None,
    split='validation',
    *,
    decode=None,
    group_by=None,
)

One row per case instead of one row per model, for one decoding.

One decoding rather than all of them, so a row stays one case and summarise_cases keeps meaning what it means. The table across decodings is evaluate’s job; this one answers “on which case does it fail”, and the object counts beside each score are what say whether a case was mislabelled or shattered.

Parameters

Name Type Description Default
model_name str | None Which model, by name. Defaults to the first. None
split str Which data to score on. 'validation'
decode str | None Which decoding, by name. Defaults to the model’s first, which is the separation’s own rather than the yardstick. None
group_by str | None A pattern picking a group out of each case’s name, pooling a group’s objects into one score the way a volume’s slices would be. None

Returns

Name Type Description
list[dict[str, Any]] One row per case, or per group.

export_weights

InstanceEngine.export_weights(model_name, path, **extra)

Write one trained model’s weights, with the sidecar that says what they are for.

Parameters

Name Type Description Default
model_name str Which model’s weights to write. required
path str | Path Where to write. The sidecar goes beside it. required
**extra Anything else to record - the dataset and its licence belong here. {}

Returns

Name Type Description
Path The path written.

fit

InstanceEngine.fit(verbose=False)

Train every model the spec asks for, in order.

Parameters

Name Type Description Default
verbose bool Print each model’s name and its per-epoch numbers as they arrive. False

Returns

Name Type Description
dict[str, History] One History per model, by name. The same objects stay on the engine, so
dict[str, History] evaluate, predict and export_weights work afterwards.

Raises

Name Type Description
EngineError If a split a model needs is missing, carries no per-object masks, or carries objects that have all vanished at this input size - which check_objects is what looks for.

loader

InstanceEngine.loader(
    model,
    split,
    *,
    augmented=False,
    shuffle=False,
    only_images=False,
    for_loss=True,
)

A torch DataLoader over one split, wrapping dataset.

A flows run’s batches carry a third item, the foreground the regression term is averaged over, and the paths that only score or predict do not pay for it - for_loss=False is how they say so. rim never needs one: its channels are all classes and its loss is an ordinary overlap.

predict

InstanceEngine.predict(model_name=None, split='test')

The model’s own channels, channels-last, one array per source image, stacked.

The class channels are probabilities and the vector channels are raw, which is the one place this differs from the semantic engine’s predict: a softmax across a flow component and a class would return a number and mean nothing.

predict_instances is the form most callers want - this is what it decodes.

predict_instances

InstanceEngine.predict_instances(model_name=None, split='test', *, decode=None)

One label map per source image: objects numbered from 1.

A list rather than a stacked array even when every image is the same size, because what a caller does with these is read one case at a time - count the objects, measure them, draw them with overlay_instances.

Parameters

Name Type Description Default
model_name str | None Which model, by name. Defaults to the first. None
split str Which data to predict on. 'test'
decode str | None Which decoding, by name. Defaults to the model’s first. None

Returns

Name Type Description
list[np.ndarray] One (H, W) int32 label map per sample, in the split’s own order.