<table class="fo-notebook-links" align="left">
    <td>
        <a target="_blank" href="https://colab.research.google.com/github/voxel51/fiftyone/blob/main/docs/source/recipes/custom_parser.ipynb">
            <img src="https://cdn.voxel51.com/colab-logo-256px.png"> &nbsp; Run in Google Colab
        </a>
    </td>
    <td>
        <a target="_blank" href="https://github.com/voxel51/fiftyone/blob/main/docs/source/recipes/custom_parser.ipynb">
            <img src="https://cdn.voxel51.com/github-logo-256px.png"> &nbsp; View source on GitHub
        </a>
    </td>
    <td>
        <a target="_blank" href="https://raw.githubusercontent.com/voxel51/fiftyone/main/docs/source/recipes/custom_parser.ipynb" download>
            <img src="https://cdn.voxel51.com/cloud-icon-256px.png"> &nbsp; Download notebook
        </a>
    </td>
</table>

# Writing Custom Sample Parsers

This recipe demonstrates how to write a [custom SampleParser](https://voxel51.com/docs/fiftyone/user_guide/sample_parsers.html#writing-a-custom-sampleparser) and use it to add samples in your custom format to a FiftyOne Dataset.

## Setup

If you haven’t already, install FiftyOne:

In this receipe we’ll use the [TorchVision Datasets](https://pytorch.org/vision/stable/datasets.html) library to download the [CIFAR-10 dataset](https://www.cs.toronto.edu/~kriz/cifar.html) to use as sample data to feed our custom parser.

You can install the necessary packages, if necessary, as follows:

## Writing a SampleParser

FiftyOne provides a [SampleParser](https://voxel51.com/docs/fiftyone/api/fiftyone.utils.data.html#fiftyone.utils.data.parsers.SampleParser) interface that defines how it parses provided samples when methods such as [Dataset.add_labeled_images()](https://voxel51.com/docs/fiftyone/api/fiftyone.core.html#fiftyone.core.dataset.Dataset.add_labeled_images) and
[Dataset.ingest_labeled_images()](https://voxel51.com/docs/fiftyone/api/fiftyone.core.html#fiftyone.core.dataset.Dataset.ingest_labeled_images) are used.

`SampleParser` itself is an abstract interface; the concrete interface that you should implement is determined by the type of samples that you are importing. See [writing a custom SampleParser](https://voxel51.com/docs/fiftyone/user_guide/sample_parsers.html#writing-a-custom-sampleparser) for full details.

In this recipe, we’ll write a custom [LabeledImageSampleParser](https://voxel51.com/docs/fiftyone/api/fiftyone.utils.data.html#fiftyone.utils.data.parsers.LabeledImageSampleParser) that can parse labeled images from a [PyTorch Dataset](https://pytorch.org/docs/stable/data.html).

Here’s the complete definition of the `SampleParser`:

Note that `PyTorchClassificationDatasetSampleParser` specifies `has_image_path == False` and `has_image_metadata == False`, because the PyTorch dataset directly provides the in-memory image, not its path on disk.

## Ingesting samples into a dataset

In order to use `PyTorchClassificationDatasetSampleParser`, we need a PyTorch Dataset from which to feed it samples.

Let’s use the [CIFAR-10 dataset](https://www.cs.toronto.edu/~kriz/cifar.html) from the [TorchVision Datasets](https://pytorch.org/docs/stable/torchvision/datasets.html) library:

Now we can load the samples into the dataset. Since our custom sample parser declares `has_image_path == False`, we must use the [Dataset.ingest_labeled_images()](https://voxel51.com/docs/fiftyone/api/fiftyone.core.html#fiftyone.core.dataset.Dataset.ingest_labeled_images) method to load the samples into a FiftyOne dataset, which will write the individual images to disk as they are ingested so that FiftyOne can access them.

Let’s inspect the contents of the dataset to verify that the samples were loaded as expected:

We can also verify that the ingested images were written to disk as expected:

## Adding samples to a dataset

If our `LabeledImageSampleParser` declared `has_image_path == True`, then we could use [Dataset.add_labeled_images()](https://voxel51.com/docs/fiftyone/api/fiftyone.core.html#fiftyone.core.dataset.Dataset.add_labeled_images) to add samples to FiftyOne datasets without creating a copy of the source images on disk.

However, our sample parser does not provide image paths, so an informative error message is raised if we try to use it in an unsupported way:

## Cleanup

You can cleanup the files generated by this recipe by running:
