{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Preliminaries" ] }, { "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "id": "2", "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "\n", "import holoviews as hv\n", "import hvplot.pandas # noqa\n", "import panel as pn\n", "\n", "hv.extension(\"bokeh\")\n", "pn.extension()\n", "# If in google colab, run hack that allows holoviews to work properly\n", "try:\n", " import google.colab # noqa\n", "\n", " def _render(self, **kwargs):\n", " hv.extension(\"bokeh\")\n", " return hv.Store.render(self)\n", "\n", " hv.core.Dimensioned._repr_mimebundle_ = _render\n", "except ModuleNotFoundError:\n", " pass\n", "\n", "TMP_NOTEBOOK_ROOT = Path(\"/tmp/bridge-ds/tutorials\")" ] }, { "cell_type": "markdown", "id": "3", "metadata": {}, "source": [ "## Loading the dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "4", "metadata": {}, "outputs": [], "source": [ "from bridge.providers.vision import Coco2017Detection\n", "\n", "root_dir = TMP_NOTEBOOK_ROOT / \"coco\"\n", "\n", "provider = Coco2017Detection(root_dir)\n", "ds = provider.build_dataset()\n", "ds" ] }, { "attachments": {}, "cell_type": "markdown", "id": "5", "metadata": {}, "source": [ "# SampleTransforms\n", "\n", "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).\n", "\n", "Bridge utilizes SampleTransforms in two contexts:\n", "\n", "- `new_sample = sample.transform(sample_transform)`\n", "- `new_ds = ds.transform_samples(sample_transform)` - iterate over all samples and transform each one." ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "## An Example\n", "We will use `TorchvisionV2Transform`, a subclass of `SampleTransform` to take a sample from our dataset and flip it:" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "import holoviews as hv\n", "from torchvision.transforms import v2\n", "\n", "from bridge.primitives.sample.transform.vision import TorchvisionV2Transform\n", "\n", "\n", "def flip_sample(sample):\n", " cmp = v2.Compose([v2.RandomHorizontalFlip(p=1)])\n", " transform = TorchvisionV2Transform(cmp)\n", " flipped_sample = sample.transform(transform)\n", " return flipped_sample\n", "\n", "\n", "sample = ds.iget(1)\n", "flipped = flip_sample(sample)\n", "\n", "opts = dict(frame_width=300)\n", "hv.Layout([sample.show(sample_plot_kwargs=opts), flipped.show(sample_plot_kwargs=opts)])" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "We would like to apply this transformation to the entire dataset; how can we do this?\n", "\n", "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.\n", "\n", "Well... not exactly. Observe the following:" ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "print(\"Original Sample:\")\n", "print(sample._element._load_mechanism.url_or_data)\n", "print()\n", "print(\"Flipped Sample:\")\n", "print(flipped._element._load_mechanism.url_or_data)" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "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.\n", "\n", "The default implementation for `sample.transform()` is to save the new data to RAM, but keeping the entire transformed dataset in RAM cannot scale.\n", "\n", "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**." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.13" } }, "nbformat": 4, "nbformat_minor": 5 }