Sample Transform#

Download this notebook from GitHub

Open In Colab

Preliminaries#

Imports#

[1]:
from pathlib import Path

import holoviews as hv
import hvplot.pandas  # noqa
import panel as pn

hv.extension("bokeh")
pn.extension()
# If in google colab, run hack that allows holoviews to work properly
try:
    import google.colab  # noqa

    def _render(self, **kwargs):
        hv.extension("bokeh")
        return hv.Store.render(self)

    hv.core.Dimensioned._repr_mimebundle_ = _render
except ModuleNotFoundError:
    pass

TMP_NOTEBOOK_ROOT = Path("/tmp/bridge-ds/tutorials")
%opts magic unavailable (pyparsing cannot be imported)
%compositor magic unavailable (pyparsing cannot be imported)

Loading the dataset#

[2]:
from bridge.providers.vision import Coco2017Detection

root_dir = TMP_NOTEBOOK_ROOT / "coco"

provider = Coco2017Detection(root_dir)
ds = provider.build_dataset()
ds
Annotations file /tmp/bridge-ds/tutorials/coco/annotations/instances_train2017.json already exists, skipping download.
loading annotations into memory...
Done (t=14.37s)
creating index...
index created!
[2]:
Dataset: {'n_samples': 118287, 'n_bbox': 860001, 'n_image': 118287}

SampleTransforms#

Manipulating data in Bridge is done through SampleTransforms. If you recall, data is stored in Bridge Elements rather than Samples, but in many cases we want to transform all Elements in a Sample together (for example, crop an image and remove all bboxes outside of the crop).

Bridge utilizes SampleTransforms in two contexts:

  • new_sample = sample.transform(sample_transform)

  • new_ds = ds.transform_samples(sample_transform) - iterate over all samples and transform each one.

An Example#

We will use TorchvisionV2Transform, a subclass of SampleTransform to take a sample from our dataset and flip it:

[3]:
import holoviews as hv
from torchvision.transforms import v2

from bridge.primitives.sample.transform.vision import TorchvisionV2Transform


def flip_sample(sample):
    cmp = v2.Compose([v2.RandomHorizontalFlip(p=1)])
    transform = TorchvisionV2Transform(cmp)
    flipped_sample = sample.transform(transform)
    return flipped_sample


sample = ds.iget(1)
flipped = flip_sample(sample)

opts = dict(frame_width=300)
hv.Layout([sample.show(sample_plot_kwargs=opts), flipped.show(sample_plot_kwargs=opts)])
[3]:

We would like to apply this transformation to the entire dataset; how can we do this?

At first glance, this may seem rather straightforward: Perform sample.transform() iteratively (i.e. call ds.transform_data()) over the entire dataset, and we’ve successfully transformed our dataset.

Well… not exactly. Observe the following:

[4]:
print("Original Sample:")
print(sample._element._load_mechanism.url_or_data)
print()
print("Flipped Sample:")
print(flipped._element._load_mechanism.url_or_data)
Original Sample:
http://images.cocodataset.org/train2017/000000000025.jpg

Flipped Sample:
[[[ 71  69  80]
  [ 58  57  65]
  [ 59  60  64]
  ...
  [  7   8   3]
  [  8   9   4]
  [  8   9   4]]

 [[150 149 157]
  [148 147 153]
  [151 150 155]
  ...
  [  7   8   3]
  [  8   9   4]
  [  8   9   4]]

 [[172 171 176]
  [180 179 184]
  [187 187 189]
  ...
  [  7   8   3]
  [  7   8   3]
  [  8   9   4]]

 ...

 [[133 100  69]
  [140 106  78]
  [154 120  93]
  ...
  [148 132  44]
  [174 166  68]
  [191 189  86]]

 [[139 109  83]
  [145 115  91]
  [126  96  72]
  ...
  [137 134  39]
  [154 159  69]
  [192 186  92]]

 [[139 109  83]
  [145 115  91]
  [127  97  73]
  ...
  [120 117  24]
  [119 123  36]
  [136 129  38]]]

See how url_or_data has changed for the flipped sample? Consider that the LoadMechanism for the original sample is just configured to just load an image from a URL; when we apply an augmentation, our new image is not the same as the source. To keep the new image we need to store it somewhere, detached from the original source.

The default implementation for sample.transform() is to save the new data to RAM, but keeping the entire transformed dataset in RAM cannot scale.

To understand how we can solve this issue, and how did the url_or_data property change to begin with, proceed to the next tutorial where we talk about CacheMechanisms.