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. |