Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update readme #4

Closed
wants to merge 80 commits into from
Closed
Changes from 5 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
a2caa9e
add fiftyone module availability
ehofesmann May 29, 2021
9e7b38e
add fiftyone datasource
ehofesmann May 29, 2021
2d55c9e
add video classification data source
ehofesmann May 29, 2021
35ef87e
add fiftyone classification serializer
ehofesmann May 29, 2021
2c94a5c
optimizations, rework fo serializer
ehofesmann Jun 2, 2021
c6587ea
support classification, detection, segmentation
ehofesmann Jun 3, 2021
3289ffb
values list, load segmentation dataset in load sample
ehofesmann Jun 3, 2021
3748dbf
FiftyOneLabels test
ehofesmann Jun 3, 2021
7ca3d92
serializer and detection tests
ehofesmann Jun 3, 2021
95690ac
fiftyone classification tests
ehofesmann Jun 3, 2021
5883aae
segmentation and video tests
ehofesmann Jun 3, 2021
ab34980
add detections serializiation test
ehofesmann Jun 3, 2021
036a28b
cleanup
brimoor Jun 3, 2021
1489954
cleanup
brimoor Jun 3, 2021
d4616b1
fix test
ehofesmann Jun 3, 2021
7131cf6
Merge branch 'feature/fiftyone' of github.com:voxel51/lightning-flash…
ehofesmann Jun 3, 2021
51d8046
inherit fiftyonedatasource
ehofesmann Jun 3, 2021
68e1ce3
tweaks
brimoor Jun 3, 2021
6ac7ced
Merge branch 'feature/fiftyone' of https://github.com/voxel51/lightni…
brimoor Jun 3, 2021
78e033a
fix class index
ehofesmann Jun 3, 2021
00cb79d
Merge branch 'feature/fiftyone' of github.com:voxel51/lightning-flash…
ehofesmann Jun 3, 2021
073ce6d
adding helper functions for common operations
brimoor Jun 3, 2021
e57ca24
updating interface
brimoor Jun 3, 2021
4a64b11
always use a Label class
brimoor Jun 4, 2021
42474d8
exposing base class params
brimoor Jun 4, 2021
31229fd
merge
ehofesmann Jun 4, 2021
5b1b09c
indent
ehofesmann Jun 4, 2021
64163b3
revert segmentation optimization
ehofesmann Jun 4, 2021
3763262
revert to mutli
ehofesmann Jun 4, 2021
30f0ec3
linting
brimoor Jun 4, 2021
9b91ea1
adding support for label thresholding
brimoor Jun 4, 2021
09858af
linting
ehofesmann Jun 4, 2021
62d280f
merge
ehofesmann Jun 4, 2021
0561388
Merge branch 'master' into feature/fiftyone
ehofesmann Jun 4, 2021
0ce6ede
update changelog
ehofesmann Jun 4, 2021
5278af2
resolve some issues, clean API
tchaton Jun 4, 2021
f204bb2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 4, 2021
d282d42
normalize detection labels
ehofesmann Jun 7, 2021
aa2de97
normalize detection labels
ehofesmann Jun 7, 2021
d56e5d3
fiftyone serializer return filepaths, paths data sources store filepaths
ehofesmann Jun 9, 2021
55b11c6
formatting
ehofesmann Jun 9, 2021
8e54021
formatting
ehofesmann Jun 9, 2021
1e1022b
remove fiftyone from dir, rename fiftyone_visualize()
ehofesmann Jun 9, 2021
fd94802
merge master
ehofesmann Jun 11, 2021
7c44cb5
update metadata to contain dictionaries
ehofesmann Jun 11, 2021
080d81a
add fiftyone docs
ehofesmann Jun 11, 2021
f34ab3b
update fiftyone examples
ehofesmann Jun 12, 2021
ba21d61
rename from_fiftyone_datasets to from_fiftyone
ehofesmann Jun 14, 2021
9a67c85
fiftyone_visualize to visualize, update docs
ehofesmann Jun 15, 2021
bfd4051
merge master
ehofesmann Jun 15, 2021
49d63bf
resolve comments
ehofesmann Jun 15, 2021
427d280
resolve test issues
ehofesmann Jun 15, 2021
8fe7d76
formatting
ehofesmann Jun 15, 2021
a908b9d
formatting
ehofesmann Jun 15, 2021
895e0bf
yapf formatting
ehofesmann Jun 15, 2021
45dded6
update for current FO version
ehofesmann Jun 15, 2021
60c3947
resolve metadata batch issue
ehofesmann Jun 15, 2021
1525514
Merge remote-tracking branch 'upstream/master' into feature/fiftyone
ehofesmann Jun 15, 2021
5120209
use current FO release, update test requirements
ehofesmann Jun 15, 2021
bec6461
syntax
ehofesmann Jun 15, 2021
6eef60e
update test
ehofesmann Jun 15, 2021
9c9b321
update tests
ehofesmann Jun 15, 2021
6d6aad3
yapf formatting
ehofesmann Jun 15, 2021
691fc7f
one more test...
ehofesmann Jun 15, 2021
8e02feb
update readme
ehofesmann Jun 15, 2021
f896941
update readme
ehofesmann Jun 15, 2021
5945e47
update readme
ehofesmann Jun 15, 2021
21d8042
Merge branch 'master' into feature/fiftyone-readme
brimoor Jun 15, 2021
0aa9e7e
improving visualize() method docs
brimoor Jun 16, 2021
f377416
making docstrings sphinx-friendly
brimoor Jun 16, 2021
7c4defd
docs tweaks
brimoor Jun 16, 2021
ae8dc1f
fiftyone integration docs update
brimoor Jun 16, 2021
8c9295c
simpler
brimoor Jun 16, 2021
59da1cd
using FiftyOne page title
brimoor Jun 16, 2021
66b5f0c
Merge remote-tracking branch 'upstream/master' into feature/fiftyone-…
ehofesmann Jun 16, 2021
f3ce2a4
update embedder example
ehofesmann Jun 16, 2021
5567ba2
isort
ehofesmann Jun 16, 2021
ed1dac0
yapf formatting
ehofesmann Jun 16, 2021
6ffc0eb
fix docstring
ehofesmann Jun 16, 2021
4438bcc
update docstrings
ehofesmann Jun 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flash/core/classification.py
Original file line number Diff line number Diff line change
@@ -167,7 +167,7 @@ def serialize(self, sample: Any) -> Union[int, List[int], str, List[str]]:


class FiftyOneLabels(ClassificationSerializer):
"""A :class:`.Serializer` which converts the model outputs (assumed to be logits) to FiftyOne classification format.
"""A :class:`.Serializer` which converts the model outputs to FiftyOne classification format.

Args:
labels: A list of labels, assumed to map the class index to the label for that class. If ``labels`` is not
32 changes: 26 additions & 6 deletions flash/core/data/data_source.py
Original file line number Diff line number Diff line change
@@ -44,9 +44,10 @@
from flash.core.utilities.imports import _FIFTYONE_AVAILABLE

if _FIFTYONE_AVAILABLE:
from fiftyone.core.labels import Label
from fiftyone.core.collections import SampleCollection
else:
SampleCollection = None
Label, SampleCollection = None, None


# Credit to the PyTorchVision Team:
@@ -479,17 +480,19 @@ def __init__(self, label_field: str = "ground_truth"):
super().__init__()
self.label_field = label_field

@property
def label_cls(self):
return Label

def load_data(self,
data: SampleCollection,
dataset: Optional[Any] = None) -> Sequence[Mapping[str, Any]]:
self._validate(data)

_, label_path = data._get_label_field_path(self.label_field, "label")
filepaths, targets = data.values(["filepath", label_path])

classes = data.default_classes
if not classes:
classes = data.classes.get(self.label_field, None)
if classes is None:
classes = data.distinct(label_path)
classes = self._get_classes(data)

if dataset is not None:
dataset.num_classes = len(classes)
@@ -508,3 +511,20 @@ def predict_load_data(self,
data: SampleCollection,
dataset: Optional[Any] = None) -> Sequence[Mapping[str, Any]]:
return [{DefaultDataKeys.INPUT: f} for f in data.values("filepath")]

def _validate(self, data):
label_type = data._get_label_field_type(self.label_field)
if not issubclass(label_type, self.label_cls):
raise ValueError("Expected field '%s' to have type %s; found %s" % (self.label_field, self.label_cls, label_type))

def _get_classes(self, data):
classes = data.classes.get(self.label_field, None)

if not classes:
classes = data.default_classes

if not classes:
_, label_path = data._get_label_field_path(self.label_field, "label")
classes = data.distinct(label_path)

return classes
2 changes: 1 addition & 1 deletion flash/image/classification/data.py
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ def __init__(
test_transform: Optional[Dict[str, Callable]] = None,
predict_transform: Optional[Dict[str, Callable]] = None,
image_size: Tuple[int, int] = (196, 196),
**data_source_kwargs,
**data_source_kwargs: Any,
):
self.image_size = image_size

28 changes: 17 additions & 11 deletions flash/image/detection/data.py
Original file line number Diff line number Diff line change
@@ -16,19 +16,20 @@

from flash.core.data.callback import BaseDataFetcher
from flash.core.data.data_module import DataModule
from flash.core.data.data_source import DataSource, DefaultDataKeys, DefaultDataSources
from flash.core.data.data_source import DataSource, DefaultDataKeys, DefaultDataSources, FiftyOneDataSource
from flash.core.data.process import Preprocess, Serializer
from flash.core.utilities.imports import _COCO_AVAILABLE, _FIFTYONE_AVAILABLE, _TORCHVISION_AVAILABLE
from flash.image.data import ImagePathsDataSource, ImageFiftyOneDataSource
from flash.image.data import ImagePathsDataSource
from flash.image.detection.transforms import default_transforms

if _COCO_AVAILABLE:
from pycocotools.coco import COCO

if _FIFTYONE_AVAILABLE:
from fiftyone.core.labels import Detections
from fiftyone.core.collections import SampleCollection
else:
SampleCollection = None
Detections, SampleCollection = None, None

if _TORCHVISION_AVAILABLE:
from torchvision.datasets.folder import default_loader
@@ -95,15 +96,21 @@ def load_sample(self, sample: Dict[str, Any]) -> Dict[str, Any]:
return sample


class ObjectDetectionFiftyOneDataSource(ImageFiftyOneDataSource):
class ObjectDetectionFiftyOneDataSource(FiftyOneDataSource):

def __init__(self, label_field: str = "ground_truth", iscrowd: str = "iscrowd"):
super().__init__(label_field=label_field)
self.iscrowd = iscrowd

@property
def label_cls(self):
return Detections

def load_data(self,
data: SampleCollection,
dataset: Optional[Any] = None) -> Sequence[Dict[str, Any]]:
self._validate(data)

data.compute_metadata()

filepaths, widths, heights, labels, bboxes, iscrowds = data.values(
@@ -117,12 +124,7 @@ def load_data(self,
]
)

classes = data.default_classes
if classes is None:
classes = data.classes.get(self.label_field, None)
if classes is None:
classes = data.distinct(self.label_field + ".detections.label")

classes = self._get_classes(data)
class_to_idx = {cls_name: i for i, cls_name in enumerate(classes)}
if dataset is not None:
dataset.num_classes = len(classes)
@@ -160,6 +162,10 @@ def load_data(self,

return output_data

def load_sample(self, sample: Dict[str, Any], dataset: Optional[Any] = None) -> Dict[str, Any]:
sample[DefaultDataKeys.INPUT] = default_loader(sample[DefaultDataKeys.INPUT])
return sample

def _reformat_bbox(self, xmin, ymin, box_w, box_h, img_w, img_h):
xmin *= img_w
ymin *= img_h
@@ -179,7 +185,7 @@ def __init__(
val_transform: Optional[Dict[str, Callable]] = None,
test_transform: Optional[Dict[str, Callable]] = None,
predict_transform: Optional[Dict[str, Callable]] = None,
**data_source_kwargs,
**data_source_kwargs: Any,
):
super().__init__(
train_transform=train_transform,
7 changes: 6 additions & 1 deletion flash/image/detection/serialization.py
Original file line number Diff line number Diff line change
@@ -26,12 +26,17 @@


class FiftyOneDetectionLabels(Serializer):
"""A :class:`.Serializer` which converts the model outputs to FiftyOne detection format.
"""A :class:`.Serializer` which converts model outputs to FiftyOne detection format.

Args:
labels: A list of labels, assumed to map the class index to the label for that class. If ``labels`` is not
provided, will attempt to get them from the :class:`.LabelsState`.
"""

def __init__(self, labels: Optional[List[str]] = None):
if not _FIFTYONE_AVAILABLE:
raise ModuleNotFoundError("Please, run `pip install fiftyone`.")

super().__init__()
self._labels = labels

12 changes: 9 additions & 3 deletions flash/image/segmentation/data.py
Original file line number Diff line number Diff line change
@@ -42,10 +42,10 @@
from flash.image.segmentation.transforms import default_transforms, train_default_transforms

if _FIFTYONE_AVAILABLE:
import fiftyone as fo
from fiftyone.core.labels import Segmentation
from fiftyone.core.collections import SampleCollection
else:
fo, SampleCollection = None, None
Segmentation, SampleCollection = None, None

if _MATPLOTLIB_AVAILABLE:
import matplotlib.pyplot as plt
@@ -167,9 +167,15 @@ def __init__(self, label_field: str = "ground_truth"):
self._fo_dataset = None
self._fo_dataset_name = None

@property
def label_cls(self):
return Segmentation

def load_data(self,
data: SampleCollection,
dataset: Optional[Any] = None) -> Sequence[Mapping[str, Any]]:
self._validate(data)

self._fo_dataset_name = data.name
return [{DefaultDataKeys.INPUT: f} for f in data.values("filepath")]

@@ -208,7 +214,7 @@ def __init__(
image_size: Tuple[int, int] = (196, 196),
num_classes: int = None,
labels_map: Dict[int, Tuple[int, int, int]] = None,
**data_source_kwargs,
**data_source_kwargs: Any,
) -> None:
"""Preprocess pipeline for semantic segmentation tasks.

18 changes: 14 additions & 4 deletions flash/image/segmentation/serialization.py
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ def __init__(self, labels_map: Optional[Dict[int, Tuple[int, int, int]]] = None,

Args:
labels_map: A dictionary that map the labels ids to pixel intensities.
visualise: Wether to visualise the image labels.
visualize: Wether to visualize the image labels.
"""
super().__init__()
self.labels_map = labels_map
@@ -89,8 +89,18 @@ def serialize(self, sample: Dict[str, torch.Tensor]) -> torch.Tensor:

class FiftyOneSegmentationLabels(SegmentationLabels):

def __init__(self, labels_map: Optional[Dict[int, Tuple[int, int, int]]] = None, visualize: bool = False):
"""A :class:`.Serializer` which converts the model outputs to FiftyOne segmentation format.

Args:
labels_map: A dictionary that map the labels ids to pixel intensities.
visualize: Wether to visualize the image labels.
"""
if not _FIFTYONE_AVAILABLE:
raise ModuleNotFoundError("Please, run `pip install fiftyone`.")

super().__init__(labels_map=labels_map, visualize=visualize)

def serialize(self, sample: Dict[str, torch.Tensor]) -> Segmentation:
preds = sample[DefaultDataKeys.PREDS]
assert len(preds.shape) == 3, preds.shape
labels = torch.argmax(preds, dim=-3).numpy() # HxW
labels = super().serialize(sample)
return Segmentation(mask=labels)
16 changes: 12 additions & 4 deletions flash/video/classification/data.py
Original file line number Diff line number Diff line change
@@ -36,9 +36,10 @@
)

if _FIFTYONE_AVAILABLE:
from fiftyone.core.labels import Classification
from fiftyone.core.collections import SampleCollection
else:
SampleCollection = None
Classification, SampleCollection = None, None

if _KORNIA_AVAILABLE:
import kornia.augmentation as K
@@ -164,8 +165,15 @@ def __init__(
decoder=decoder,
)

@property
def label_cls(self):
return Classification

def load_data(self, data: SampleCollection, dataset: Optional[Any] = None) -> 'EncodededVideoDataset':
label_to_class_mapping = dict(enumerate(data.default_classes))
self._validate(data)

classes = self._get_classes(data)
label_to_class_mapping = dict(enumerate(classes))
class_to_label_mapping = {c: l for l, c in label_to_class_mapping.items()}

filepaths, labels = data.values(["filepath", self.label_field + ".label"])
@@ -182,7 +190,7 @@ def load_data(self, data: SampleCollection, dataset: Optional[Any] = None) -> 'E
)
if self.training:
self.set_state(LabelsState(label_to_class_mapping))
dataset.num_classes = len(class_to_label_mapping)
dataset.num_classes = len(classes)
return ds

def predict_load_sample(self, sample: Dict[str, Any]) -> Dict[str, Any]:
@@ -203,7 +211,7 @@ def __init__(
video_sampler: Type[Sampler] = torch.utils.data.RandomSampler,
decode_audio: bool = True,
decoder: str = "pyav",
**data_source_kwargs,
**data_source_kwargs: Any,
):
self.clip_sampler = clip_sampler
self.clip_duration = clip_duration