Skip to content

Commit

Permalink
Merge pull request #1864 from voxel51/feature/label-dict-imports
Browse files Browse the repository at this point in the history
Adding support for label field dicts when importing labeled datasets
  • Loading branch information
brimoor authored Jun 17, 2022
2 parents d3491d5 + eaf653e commit 5cd9186
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 106 deletions.
27 changes: 19 additions & 8 deletions docs/source/user_guide/dataset_creation/datasets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5164,14 +5164,20 @@ should implement is determined by the type of dataset that you are importing.
importer = CustomLabeledImageDatasetImporter(...)
label_field = ...
if isinstance(label_field, dict):
label_key = lambda k: label_field.get(k, k)
elif label_field is not None:
label_key = lambda k: label_field + "_" + k
else:
label_field = "ground_truth"
label_key = lambda k: k
with importer:
for image_path, image_metadata, label in importer:
sample = fo.Sample(filepath=image_path, metadata=image_metadata)
if isinstance(label, dict):
sample.update_fields(
{label_field + "_" + k: v for k, v in label.items()}
)
sample.update_fields({label_key(k): v for k, v in label.items()})
elif label is not None:
sample[label_field] = label
Expand Down Expand Up @@ -5566,14 +5572,20 @@ should implement is determined by the type of dataset that you are importing.
importer = CustomLabeledVideoDatasetImporter(...)
label_field = ...
if isinstance(label_field, dict):
label_key = lambda k: label_field.get(k, k)
elif label_field is not None:
label_key = lambda k: label_field + "_" + k
else:
label_field = "ground_truth"
label_key = lambda k: k
with importer:
for video_path, video_metadata, label, frames in importer:
sample = fo.Sample(filepath=video_path, metadata=video_metadata)
if isinstance(label, dict):
sample.update_fields(
{label_field + "_" + k: v for k, v in label.items()}
)
sample.update_fields({label_key(k): v for k, v in label.items()})
elif label is not None:
sample[label_field] = label
Expand All @@ -5583,8 +5595,7 @@ should implement is determined by the type of dataset that you are importing.
for frame_number, _label in frames.items():
if isinstance(_label, dict):
frame_labels[frame_number] = {
label_field + "_" + field_name: label
for field_name, label in _label.items()
label_key(k): v for k, v in _label.items()
}
elif _label is not None:
frame_labels[frame_number] = {label_field: _label}
Expand Down
27 changes: 19 additions & 8 deletions docs/source/user_guide/dataset_creation/samples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,14 @@ classification or object detections) associated with the image.
sample_parser = CustomLabeledImageSampleParser(...)
label_field = ...
if isinstance(label_field, dict):
label_key = lambda k: label_field.get(k, k)
elif label_field is not None:
label_key = lambda k: label_field + "_" + k
else:
label_field = "ground_truth"
label_key = lambda k: k
for sample in samples:
sample_parser.with_sample(sample)
Expand All @@ -947,9 +955,7 @@ classification or object detections) associated with the image.
sample = fo.Sample(filepath=image_path, metadata=metadata)
if isinstance(label, dict):
sample.update_fields(
{label_field + "_" + k: v for k, v in label.items()}
)
sample.update_fields({label_key(k): v for k, v in label.items()})
elif label is not None:
sample[label_field] = label
Expand Down Expand Up @@ -1191,6 +1197,14 @@ classification or object detections) associated with the image.
sample_parser = CustomLabeledVideoSampleParser(...)
label_field = ...
if isinstance(label_field, dict):
label_key = lambda k: label_field.get(k, k)
elif label_field is not None:
label_key = lambda k: label_field + "_" + k
else:
label_field = "ground_truth"
label_key = lambda k: k
for sample in samples:
sample_parser.with_sample(sample)
Expand All @@ -1207,9 +1221,7 @@ classification or object detections) associated with the image.
sample = fo.Sample(filepath=video_path, metadata=metadata)
if isinstance(label, dict):
sample.update_fields(
{label_field + "_" + k: v for k, v in label.items()}
)
sample.update_fields({label_key(k): v for k, v in label.items()})
elif label is not None:
sample[label_field] = label
Expand All @@ -1219,8 +1231,7 @@ classification or object detections) associated with the image.
for frame_number, _label in frames.items():
if isinstance(_label, dict):
frame_labels[frame_number] = {
label_field + "_" + field_name: label
for field_name, label in _label.items()
label_key(k): v for k, v in _label.items()
}
elif _label is not None:
frame_labels[frame_number] = {label_field: _label}
Expand Down
28 changes: 19 additions & 9 deletions docs/source/user_guide/model_zoo/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ All models in the FiftyOne Model Zoo are instances of the |Model| class, which
defines a common interface for loading models and generating predictions with
defined input and output data formats.

.. note:
.. note::

The following sections describe the interface that all models in the Model
Zoo implement. If you write a wrapper for your custom model that implements
Expand Down Expand Up @@ -357,7 +357,7 @@ and the output ``labels`` can be any of the following:
# Multiple sample-level labels
for key, value in labels.items():
sample[label_field + "_" + key] = value
sample[label_key(key)] = value
- A dict mapping frame numbers to |Label| instances. In this case, the
provided labels are interpreted as frame-level labels that should be added
Expand All @@ -384,27 +384,37 @@ and the output ``labels`` can be any of the following:
# Multiple per-frame labels
sample.frames.merge(
{
frame_number: {
label_field + "_" + name: label
for name, label in frame_dict.items()
}
frame_number: {label_key(k): v for k, v in frame_dict.items()}
for frame_number, frame_dict in labels.items()
}
)
In the above snippets, the ``label_key`` function maps label dict keys to field
names, and is defined from ``label_field`` as follows::

.. code-block:: python
:linenos:
if isinstance(label_field, dict):
label_key = lambda k: label_field.get(k, k)
elif label_field is not None:
label_key = lambda k: label_field + "_" + k
else:
label_key = lambda k: k
For models that support batching, the |Model| interface also provides a
:meth:`predict_all() <fiftyone.core.models.Model.predict_all>` method that can
provide an efficient implementation of predicting on a batch of data.

.. note:
.. note::

Builtin methods like
:meth:`apply_model() <fiftyone.core.collections.SampleCollection.apply_model>`
provide a ``batch_size`` parameter that can be used to control the batch
size used when performing inference with models that support efficient
batching.

.. note:
.. note::

PyTorch models can implement the |TorchModelMixin| mixin, in which case
`DataLoaders <https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader>`_
Expand Down Expand Up @@ -440,7 +450,7 @@ By convention,
:meth:`Model.embed() <fiftyone.core.models.EmbeddingsMixin.embed>` should
return a numpy array containing the embedding.

.. note:
.. note::

Sample embeddings are typically 1D vectors, but this is not strictly
required.
Expand Down
Loading

0 comments on commit 5cd9186

Please sign in to comment.