<!-- # hard line break macro for HTML -->

<a id="fiftyone-brain"></a>

# FiftyOne Brain

The [FiftyOne Brain](https://github.com/voxel51/fiftyone-brain) provides
powerful machine learning techniques that are designed to transform how you
curate your data from an art into a measurable science.

#### NOTE
Did you know? You can execute Brain methods from the FiftyOne App by
installing the
[@voxel51/brain](https://github.com/voxel51/fiftyone-plugins/tree/main/plugins/brain)
plugin!

<div style="margin:0; display:inline-block;">
    <a href="../labs/index.html" class="sd-btn sd-btn-primary book-a-demo" rel="noopener noreferrer" data-cta-dynamic="true">
        <div class="arrow">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="size-3">
            <path stroke="currentColor" stroke-width="1.5"
                    d="M1.458 11.995h20.125M11.52 22.063 21.584 12 11.521 1.937"
                    vector-effect="non-scaling-stroke"></path>
            </svg>  
        </div>
        <div class="text">Try experimental Brain features in FiftyOne Labs</div>
    </a>
</div>

The FiftyOne Brain methods are useful across the stages of the machine learning
workflow:

* [Visualizing embeddings](#brain-embeddings-visualization):
  Tired of combing through individual images/videos
  and staring at aggregate performance metrics trying to figure out how to
  improve the performance of your model? Using FiftyOne to visualize your
  dataset in a *low-dimensional embedding space* can reveal patterns and
  clusters in your data that can help you answer many important questions about
  your data, from identifying the most critical failure modes of your model, to
  isolating examples of critical scenarios, to recommending new samples to add
  to your training dataset, and more!
* [Similarity](../user_guide/similarity.md#brain-similarity): When constructing a dataset or training
  a model, have you ever wanted to find similar examples to an image or object
  of interest? For example, you may have found a failure case of your model and
  now want to search for similar scenarios in your evaluation set to diagnose
  the issue, or you want to mine your data lake to augment your training set to
  fix the issue. Use the FiftyOne Brain to index your data by *similarity* and
  you can easily query and sort your datasets to find similar examples, both
  programmatically and via point-and-click in the App.
* [Leaky splits](#brain-leaky-splits):
  Often when sourcing data en masse, duplicates and near duplicates can slip
  through the cracks. The FiftyOne Brain offers a *leaky splits analysis* that
  can be used to find potential leaks between dataset splits. Such leaks can
  be misleading when evaluating a model, giving an overly optimistic measure
  for the quality of training.
* [Near duplicates](#brain-near-duplicates):
  When curating massive datasets, you may inadvertently add near duplicate data
  to your datasets, which can bias or otherwise confuse your models. The
  FiftyOne Brain offers a *near duplicate detection* algorithm that
  automatically surfaces such data quality issues and prompts you to take
  action to resolve them.
* [Exact duplicates](#brain-exact-duplicates):
  Despite your best efforts, you may accidentally add duplicate data to a
  dataset. The FiftyOne Brain provides an *exact duplicate detection* method
  that scans your data and alerts you if a dataset contains duplicate samples,
  either under the same or different filenames.
* [Uniqueness](#brain-image-uniqueness):
  During the training loop for a model, the best results will
  be seen when training on unique data. The FiftyOne Brain provides a
  *uniqueness measure* for images that compare the content of every image in a
  dataset with all other images. Uniqueness operates on raw images and does not
  require any prior annotation on the data. It is hence very useful in the
  early stages of the machine learning workflow when you are likely asking
  “What data should I select to annotate?”
* [Mistakenness](#brain-label-mistakes):
  Annotations mistakes create an artificial ceiling on the performance of your
  models. However, finding these mistakes by hand is at least as arduous as the
  original annotation was, especially in cases of larger datasets. The FiftyOne
  Brain provides a quantitative *mistakenness measure* to identify possible
  label mistakes. Mistakenness operates on labeled images and requires the
  logit-output of your model predictions in order to provide maximum efficacy.
  It also works on detection datasets to find missed objects, incorrect
  annotations, and localization issues.
* [Hardness](#brain-sample-hardness):
  While a model is training, it will learn to understand attributes of certain
  samples faster than others. The FiftyOne Brain provides a *hardness measure*
  that calculates how easy or difficult it is for your model to understand any
  given sample. Mining hard samples is a tried and true measure of mature
  machine learning processes. Use your current model instance to compute
  predictions on unlabeled samples to determine which are the most valuable to
  have annotated and fed back into the system as training samples, for example.
* [Representativeness](#brain-image-representativeness):
  When working with large datasets, it can be hard to determine what samples
  within it are outliers and which are more typical. The FiftyOne Brain offers
  a *representativeness measure* that can be used to find the most common
  types of images in your dataset. This is especially helpful to find easy
  examples to train on in your data and for visualizing common modes of the
  data.

#### NOTE
Check out the [tutorials page](../tutorials/index.md#tutorials) for detailed examples
demonstrating the use of many Brain capabilities.

<a id="brain-embeddings-visualization"></a>

## Visualizing embeddings


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-0-8-0">FiftyOne 0.8.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-1-0">FiftyOne Enterprise 1.0</a></span>
    </div>
    
</div>

The FiftyOne Brain provides a powerful
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization) method
that you can use to generate low-dimensional representations of the samples
and/or individual objects in your datasets.

These representations can be visualized natively in the App’s
[Embeddings panel](../user_guide/app.md#app-embeddings-panel), where you can interactively
select points of interest and view the corresponding samples/labels of interest
in the [Samples panel](../user_guide/app.md#app-samples-panel), and vice versa.

![mnist](images/brain/brain-mnist.png)

There are two primary components to an embedding visualization: the method used
to generate the embeddings, and the dimensionality reduction method used to
compute a low-dimensional representation of the embeddings.

### Embedding methods

The `embeddings` and `model` parameters of
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization)
support a variety of ways to generate embeddings for your data:

- Provide nothing, in which case a default general purpose model is used to
  embed your data
- Provide a [`Model`](../api/fiftyone.core.models.md#fiftyone.core.models.Model) instance or the name of any model from the
  [Model Zoo](../model_zoo/index.md#model-zoo) that supports embeddings
- Provide your own precomputed embeddings in array form
- Provide the name of a [`VectorField`](../api/fiftyone.core.fields.md#fiftyone.core.fields.VectorField) or [`ArrayField`](../api/fiftyone.core.fields.md#fiftyone.core.fields.ArrayField) of your dataset in
  which precomputed embeddings are stored

### Dimensionality reduction methods

The `method` parameter of
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization) allows
you to specify the dimensionality reduction method to use. The supported
methods are:

- **umap** (*default*): Uniform Manifold Approximation and Projection
  ([UMAP](https://github.com/lmcinnes/umap))
- **tsne**: t-distributed Stochastic Neighbor Embedding
  ([t-SNE](https://lvdmaaten.github.io/tsne))
- **pca**: Principal Component Analysis
  ([PCA](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html))
- **manual**: provide a manually computed low-dimensional representation

```python
import fiftyone.brain as fob

results = fob.compute_visualization(
    dataset,
    method="umap",  # "umap", "tsne", "pca", etc
    brain_key="...",
    ...
)
```

#### NOTE
When you use the default [UMAP](https://github.com/lmcinnes/umap) method
for the first time, you will be prompted to install the
[umap-learn](https://github.com/lmcinnes/umap) package.

#### NOTE
Refer to [this section](#brain-visualization-api) for more information
about creating visualization runs.

### Applications

How can embedding-based visualization of your data be used in practice? These
visualizations often uncover hidden structure in you data that has important
semantic meaning depending on the data you use to color/size the points.

Here are a few of the many possible applications:

- Identifying anomalous and/or visually similar examples
- Uncovering patterns in incorrect/spurious predictions
- Finding examples of target scenarios in your data lake
- Mining hard examples for your evaluation pipeline
- Recommending samples from your data lake for classes that need additional
  training data
- Unsupervised pre-annotation of training data

The best part about embedding visualizations is that you will likely discover
more applications specific to your use case when you try it out on your data!

#### NOTE
Check out the
[image embeddings tutorial](../tutorials/image_embeddings.md) to see
example uses of the Brain’s embeddings-powered visualization methods to
uncover hidden structure in datasets.

### Image embeddings example

The following example gives a taste of the powers of visual embeddings in
FiftyOne using the [BDD100K dataset](../dataset_zoo/datasets/bdd100k.md#dataset-zoo-bdd100k) from the
dataset zoo, embeddings generated by a
[mobilenet model](../model_zoo/models/mobilenet_v2_imagenet_torch.md#model-zoo-mobilenet-v2-imagenet-torch) from the model
zoo, and the default [UMAP](https://github.com/lmcinnes/umap) dimensionality
reduction method.

In this setup, the scatterpoints in the
[Embeddings panel](../user_guide/app.md#app-embeddings-panel) correspond to images in the
validation split colored by the `time of day` labels provided by the BDD100K
dataset. When points are lasso-ed in the plot, the corresponding samples are
automatically selected in the [Samples panel](../user_guide/app.md#app-samples-panel):

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz

# The BDD dataset must be manually downloaded. See the zoo docs for details
source_dir = "/path/to/dir-with-bdd100k-files"

dataset = foz.load_zoo_dataset(
    "bdd100k", split="validation", source_dir=source_dir,
)

# Compute embeddings
# You will likely want to run this on a machine with GPU, as this requires
# running inference on 10,000 images
model = foz.load_zoo_model("mobilenet-v2-imagenet-torch")
embeddings = dataset.compute_embeddings(model)

# Compute visualization
results = fob.compute_visualization(
    dataset, embeddings=embeddings, seed=51, brain_key="img_viz"
)

session = fo.launch_app(dataset)
```

#### NOTE
Did you know? You can [programmatically configure](../user_guide/app.md#app-spaces-python)
your Spaces layout!

![image-visualization](images/brain/brain-image-visualization.gif)

The GIF shows the variety of insights that are revealed by running this simple
protocol:

- The first cluster of points selected reveals a set of samples whose field
  of view is corrupted by hardware gradients at the top and bottom of the
  image
- The second cluster of points reveals a set of images in rainy conditions
  with water droplets on the windshield
- Hiding the primary cluster of `daytime` points and selecting the
  remaining `night` points reveals that the `night` points have incorrect
  labels

### Object embeddings example

The following example demonstrates how embeddings can be used to visualize the
ground truth objects in the [quickstart dataset](../dataset_zoo/datasets/quickstart.md#dataset-zoo-quickstart)
using the
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization) method’s
default embeddings model and dimensionality method.

In this setup, we generate a visualization for all ground truth objects, but
then we create a [view](../user_guide/using_views.md#view-filtering) that restricts the visualization
to only objects in a subset of the classes. The scatterpoints in the
[Embeddings panel](../user_guide/app.md#app-embeddings-panel) correspond to objects, colored
by their `label`. When points are lasso-ed in the plot, the corresponding
object patches are automatically selected in the
[Samples panel](../user_guide/app.md#app-samples-panel):

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
from fiftyone import ViewField as F

dataset = foz.load_zoo_dataset("quickstart")

# Generate visualization for `ground_truth` objects
results = fob.compute_visualization(
    dataset, patches_field="ground_truth", brain_key="gt_viz"
)

# Restrict to the 10 most common classes
counts = dataset.count_values("ground_truth.detections.label")
classes = sorted(counts, key=counts.get, reverse=True)[:10]
view = dataset.filter_labels("ground_truth", F("label").is_in(classes))

session = fo.launch_app(view)
```

#### NOTE
Did you know? You can [programmatically configure](../user_guide/app.md#app-spaces-python)
your Spaces layout!

![object-visualization](images/brain/brain-object-visualization.gif)

As you can see, the coloring of the scatterpoints allows you to discover
natural clusters of objects, such as visually similar carrots or kites in the
air.

<a id="brain-visualization-api"></a>

### Visualization API

This section describes how to setup, create, and manage visualizations in
detail.

#### Changing your visualization method


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-0-23-4">FiftyOne 0.23.4</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-1-5-5">FiftyOne Enterprise 1.5.5</a></span>
    </div>
    
</div>

You can use a specific dimensionality reduction method for a particular
visualization run by passing the `method` parameter to
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization):

```python
results = fob.compute_visualization(..., method="<method>", ...)
```

Alternatively, you can change your default dimensionality reduction method for
an entire session by setting the `FIFTYONE_BRAIN_DEFAULT_VISUALIZATION_METHOD`
environment variable:

```shell
export FIFTYONE_BRAIN_DEFAULT_VISUALIZATION_METHOD=<method>
```

Finally, you can permanently change your default dimensionality reduction
method by updating the `default_visualization_method` key of your
[brain config](#brain-config) at `~/.fiftyone/brain_config.json`:

```text
{
    "default_visualization_method": "<method>",
    "visualization_methods": {
        "<method>": {...},
        ...
    }
}
```

#### Configuring your visualization method

Dimensionality reduction methods may be configured in a variety of
method-specific ways, which you can see by inspecting the parameters of a
method’s associated [`VisualizationConfig`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.VisualizationConfig) class.

The relevant classes for the builtin dimensionality reduction methods are:

- **umap**: [`fiftyone.brain.visualization.UMAPVisualizationConfig`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.UMAPVisualizationConfig)
- **tsne**: [`fiftyone.brain.visualization.TSNEVisualizationConfig`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.TSNEVisualizationConfig)
- **pca**: [`fiftyone.brain.visualization.PCAVisualizationConfig`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.PCAVisualizationConfig)
- **manual**: [`fiftyone.brain.visualization.ManualVisualizationConfig`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.ManualVisualizationConfig)

You can configure a dimensionality reduction method’s parameters for a specific
run by simply passing supported config parameters as keyword arguments each
time you call
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization):

```python
results = fob.compute_visualization(
    ...
    method="umap",
    min_dist=0.2,
)
```

Alternatively, you can more permanently configure your dimensionality reduction
method(s) via your [brain config](#brain-config).

<a id="brain-optimizing-lassoing-performance"></a>

#### Optimizing lassoing performance


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-1-4-0">FiftyOne 1.4.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-2-7-0">FiftyOne Enterprise 2.7.0</a></span>
    </div>
    
</div>

You can pass `create_index=True` to
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization) to store
a spatial index of the computed points in a field of your dataset’s samples.

This is highly recommended for large datasets as it enables efficient querying
when lassoing points in the [Embeddings panel](../user_guide/app.md#app-embeddings-panel).

Image embeddings

Object embeddings

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")

# Generate a visualization with a spatial index
results = fob.compute_visualization(
    dataset,
    brain_key="img_viz",
    create_index=True,
)
```

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")

# Generate a patch visualization with a spatial index
results = fob.compute_visualization(
    dataset,
    patches_field="ground_truth",
    brain_key="gt_viz",
    create_index=True,
)
```

#### NOTE
By default, spatial indexes are created in a field/attribute with name
`brain_key`, but you can customize this by passing the `points_field`
parameter to
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization).

You can check whether an existing visualization result has a spatial index
via
[`has_spatial_index`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.VisualizationResults.has_spatial_index),
and you can add or remove spatial indexes via
[`index_points()`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.VisualizationResults.index_points) and
[`remove_index()`](../api/fiftyone.brain.visualization.md#fiftyone.brain.visualization.VisualizationResults.remove_index):

```python
print(results.has_spatial_index)
# True/False

# Add a spatial index to existing visualization results
results.index_points()

# Remove the spatial index from existing visualization results
results.remove_index()
```

<a id="brain-leaky-splits"></a>

## Leaky splits


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-1-1-0">FiftyOne 1.1.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-2-2-0">FiftyOne Enterprise 2.2.0</a></span>
    </div>
    
</div>

Despite our best efforts, duplicates and other forms of non-IID samples
show up in our data. When these samples end up in different splits, this
can have consequences when evaluating a model. It can often be easy to
overestimate model capability due to this issue. The FiftyOne Brain offers a
way to identify such cases in dataset splits.

The leaks of a dataset can be computed directly without the need for the
predictions of a pre-trained model via the
[`compute_leaky_splits()`](../api/fiftyone.brain.md#fiftyone.brain.compute_leaky_splits) method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

# Splits defined via tags
split_tags = ["train", "test"]
index = fob.compute_leaky_splits(dataset, splits=split_tags)
leaks = index.leaks_view()

# Splits defined via field
split_field = "split"  # holds split values e.g. 'train' or 'test'
index = fob.compute_leaky_splits(dataset, splits=split_field)
leaks = index.leaks_view()

# Splits defined via views
split_views = {"train": train_view, "test": test_view}
index = fob.compute_leaky_splits(dataset, splits=split_views)
leaks = index.leaks_view()
```

Notice how the splits of the dataset can be defined in three ways: through
sample tags, through a string field that assigns each split a unique value in
the field, or by directly providing views that define the splits.

**Input**: A [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset) or [`DatasetView`](../api/fiftyone.core.view.md#fiftyone.core.view.DatasetView), and a definition of splits through one
of tags, a field, or views.

**Output**: An index that will allow you to look through your leaks with
[`leaks_view()`](../api/fiftyone.brain.internal.core.leaky_splits.md#fiftyone.brain.internal.core.leaky_splits.LeakySplitsIndex.leaks_view)
and also provides some useful actions once they are discovered such as
automatically cleaning the dataset with
[`no_leaks_view()`](../api/fiftyone.brain.internal.core.leaky_splits.md#fiftyone.brain.internal.core.leaky_splits.LeakySplitsIndex.no_leaks_view)
or tagging the leaks for the future action with
[`tag_leaks()`](../api/fiftyone.brain.internal.core.leaky_splits.md#fiftyone.brain.internal.core.leaky_splits.LeakySplitsIndex.tag_leaks).

**What to expect**: Leaky splits works by embedding samples with a powerful
model and finding very close samples in different splits in this space. Large,
powerful models that were *not* trained on a dataset can provide insight into
visual and semantic similarity between images, without creating further leaks
in the process.

**Similarity index**: Under the hood, leaky splits leverages the brain’s
[`SimilarityIndex`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.SimilarityIndex) to detect
leaks. Any [similarity backend](../user_guide/similarity.md#brain-similarity-backends) that
implements the
[`DuplicatesMixin`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin) can be
used to compute leaky splits. You can either pass an existing similarity index
by passing its brain key to the argument `similarity_index`, or have the
method create one on the fly for you.

**Embeddings**: You can customize the model used to compute embeddings via the
`model` argument of
[`compute_leaky_splits()`](../api/fiftyone.brain.md#fiftyone.brain.compute_leaky_splits). You can
also precompute embeddings and tell leaky splits to use them by passing them
via the `embeddings` argument.

**Thresholds**: Leaky splits uses a threshold to decide what samples are
too close and thus mark them as potential leaks. This threshold can be
customized either by passing a value to the `threshold` argument of
[`compute_leaky_splits()`](../api/fiftyone.brain.md#fiftyone.brain.compute_leaky_splits). The best
value for your use case may vary depending on your dataset, as well as the
embeddings used. A threshold that’s too big may have a lot of false positives,
while a threshold that’s too small may have a lot of false negatives.

The example code below runs leaky splits analysis on the
[COCO dataset](https://cocodataset.org/#home). Try it for yourself and see
what you find!

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
import fiftyone.utils.random as four

# Load some COCO data
dataset = foz.load_zoo_dataset("coco-2017", split="test")

# Set up splits via tags
dataset.untag_samples(dataset.distinct("tags"))
four.random_split(dataset, {"train": 0.7, "test": 0.3})

# Find leaks
index = fob.compute_leaky_splits(dataset, splits=["train", "test"])
leaks = index.leaks_view()
```

The
[`leaks_view()`](../api/fiftyone.brain.internal.core.leaky_splits.md#fiftyone.brain.internal.core.leaky_splits.LeakySplitsIndex.leaks_view)
method returns a view that contains only the leaks in the input splits. Once
you have these leaks, it is wise to look through them. You may gain some
insight into the source of the leaks:

```python
session = fo.launch_app(leaks)
```

Before evaluating your model on your test set, consider getting a version of it
with the leaks removed. This can be easily done via
[`no_leaks_view()`](../api/fiftyone.brain.internal.core.leaky_splits.md#fiftyone.brain.internal.core.leaky_splits.LeakySplitsIndex.no_leaks_view):

```python
# The original test split
test_set = index.split_views["test"]

# The test set with leaks removed
test_set_no_leaks = index.no_leaks_view(test_set)

session.view = test_set_no_leaks
```

Performance on the clean test set will can be closer to the performance of the
model in the wild. If you found some leaks in your dataset, consider comparing
performance on the base test set against the clean test set.

![leaky-splits](images/brain/brain-leaky-splits.png)

<a id="brain-near-duplicates"></a>

## Near duplicates


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-0-13-0">FiftyOne 0.13.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-1-0">FiftyOne Enterprise 1.0</a></span>
    </div>
    
</div>

When curating massive datasets, you may inadvertently add near duplicate data
to your datasets, which can bias or otherwise confuse your models.

The [`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates)
method leverages embeddings to automatically surface near-duplicate samples in
your dataset:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

index = fob.compute_near_duplicates(dataset)
print(index.duplicate_ids)

dups_view = index.duplicates_view()
session = fo.launch_app(dups_view)
```

**Input**: An unlabeled (or labeled) dataset. There are
[recipes](../recipes/index.md#recipes) for building datasets from a wide variety of image
formats, ranging from a simple directory of images to complicated dataset
structures like [COCO](https://cocodataset.org/#home).

**Output**: A [`SimilarityIndex`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.SimilarityIndex) object that provides powerful methods such as
[`duplicate_ids`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.duplicate_ids),
[`neighbors_map`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.neighbors_map)
and
[`duplicates_view()`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.duplicates_view)
to analyze potential near duplicates as demonstrated below

**What to expect**: Near duplicates analysis leverages embeddings to identify
samples  that are too close to their nearest neighbors. You can provide
pre-computed embeddings, specify a [zoo model](../model_zoo/index.md#model-zoo) of your choice
to use to compute embeddings, or provide nothing and rely on the method’s
default model to generate embeddings.

**Thresholds**: When using custom embeddings/models, you may need to adjust the
distance threshold used to detect potential duplicates. You can do this by
passing a value to the `threshold` argument of
[`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates). The
best value for your use case may vary depending on your dataset, as well as the
embeddings used. A threshold that’s too big may have a lot of false positives,
while a threshold that’s too small may have a lot of false negatives.

The following example demonstrates how to use
[`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates) to
detect near duplicate images on the
[CIFAR-10 dataset](../dataset_zoo/datasets/cifar10.md#dataset-zoo-cifar10):

```python
import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("cifar10", split="test")
```

To proceed, we first need some suitable image embeddings for the dataset.
Although the [`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates)
method is equipped with a default general-purpose model to generate embeddings
if none are provided, you’ll typically find higher-quality insights when a
domain-specific model is used to generate embeddings.

In this case, we’ll use a classifier that has been fine-tuned on CIFAR-10 to
pre-compute embeddings and them feed them to
[`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates):

```python
import fiftyone.brain as fob
import fiftyone.brain.internal.models as fbm

# Compute embeddings via a pre-trained CIFAR-10 classifier
model = fbm.load_model("simple-resnet-cifar10")
embeddings = dataset.compute_embeddings(model, batch_size=16)

# Scan for near-duplicates
index = fob.compute_near_duplicates(
    dataset,
    embeddings=embeddings,
    thresh=0.02,
)
```

### Finding near-duplicate samples

The
[`neighbors_map`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.neighbors_map)
property of the index provides a data structure that summarizes the findings.
The keys of the dictionary are the sample IDs of each non-duplicate sample, and
the values are lists of `(id, distance)` tuples listing the sample IDs of the
duplicate samples for each reference sample together with the embedding
distance between the two samples:

```python
print(index.neighbors_map)
```

```text
{
    '61143408db40df926c571a6b': [
        ('61143409db40df926c573075', 5.667297674385298),
        ('61143408db40df926c572ab6', 6.231051661334058)
    ],
    '6114340cdb40df926c577f2a': [
        ('61143408db40df926c572b54', 6.042934361555487)
    ],
    '61143408db40df926c572aa3': [
        ('6114340bdb40df926c5772e9', 5.88984758067434),
        ('61143408db40df926c572b64', 6.063986454046798),
        ('61143409db40df926c574571', 6.10303338363576),
        ('6114340adb40df926c5749a2', 6.161749290179865)
    ],
    ...
}
```

We can conveniently visualize this information in the App via the
[`duplicates_view()`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.duplicates_view)
method of the index, which constructs a view with the duplicate samples
arranged directly after their corresponding reference sample, with optional
additional fields recording the type and nearest reference sample ID/distance:

```python
duplicates_view = index.duplicates_view(
    type_field="dup_type",
    id_field="dup_id",
    dist_field="dup_dist",
)

session = fo.launch_app(duplicates_view)
```

![cifar10-duplicate-view](images/brain/brain-cifar10-duplicate-view.png)

#### NOTE
You can also use the
[`find_duplicates()`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.find_duplicates)
method of the index to rerun the duplicate detection with a different
`threshold` without calling
[`compute_near_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_near_duplicates)
again.

### Finding maximally unique samples

You can also use the
[`find_unique()`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.find_unique)
method of the index to identify a set of samples of any desired size that are
maximally unique with respect to each other:

```python
# Use the similarity index to identify 500 maximally unique samples
index.find_unique(500)
print(index.unique_ids[:5])
```

We can also conveniently visualize the results of this operation via the
[`visualize_unique()`](../api/fiftyone.brain.similarity.md#fiftyone.brain.similarity.DuplicatesMixin.visualize_unique)
method of the index, which generates a scatterplot with the unique samples
colored separately:

```python
# Generate a 2D visualization
viz_results = fob.compute_visualization(dataset, embeddings=embeddings)

# Visualize the unique samples in embeddings space
plot = index.visualize_unique(viz_results)
plot.show(height=800, yaxis_scaleanchor="x")
```

![cifar10-unique-viz](images/brain/brain-cifar10-unique-viz.png)

And of course we can load a view containing the unique samples in the App to
explore the results in detail:

```python
# Visualize the unique images in the App
unique_view = dataset.select(index.unique_ids)
session = fo.launch_app(view=unique_view)
```

![cifar10-unique-view](images/brain/brain-cifar10-unique-view.png)

<a id="brain-exact-duplicates"></a>

## Exact duplicates


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-0-13-0">FiftyOne 0.13.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-1-0">FiftyOne Enterprise 1.0</a></span>
    </div>
    
</div>

Despite your best efforts, you may accidentally add duplicate data to a
dataset. Left unmitigated, such quality issues can bias your models and
confound your analysis.

The [`compute_exact_duplicates()`](../api/fiftyone.brain.md#fiftyone.brain.compute_exact_duplicates)
method scans your dataset and determines if you have duplicate data either
under the same or different filenames:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

duplicates_map = fob.compute_exact_duplicates(dataset)
print(duplicates_map)
```

**Input**: An unlabeled (or labeled) dataset. There are
[recipes](../recipes/index.md#recipes) for building datasets from a wide variety of image
formats, ranging from a simple directory of images to complicated dataset
structures like [COCO](https://cocodataset.org/#home).

**Output**: A dictionary mapping IDs of samples with exact duplicates to lists
of IDs of the duplicates for the corresponding sample

**What to expect**: Exact duplicates analysis uses filehashes to identify
duplicate data, regardless of whether they are stored under the same or
different filepaths in your dataset.

<a id="brain-image-uniqueness"></a>

## Image uniqueness

The FiftyOne Brain allows for the computation of the uniqueness of an image,
in comparison with other images in a dataset; it does so without requiring
any model from you. One good use of uniqueness is in the early stages of the
machine learning workflow when you are deciding what subset of data with which
to bootstrap your models. Unique samples are vital in creating training
batches that help your model learn as efficiently and effectively as possible.

The uniqueness of a [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset) can be computed directly without need the
predictions of a pre-trained model via the
[`compute_uniqueness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_uniqueness) method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

fob.compute_uniqueness(dataset)
```

**Input**: An unlabeled (or labeled) image dataset. There are
[recipes](../recipes/index.md#recipes) for building datasets from a wide variety of image
formats, ranging from a simple directory of images to complicated dataset
structures like [COCO](https://cocodataset.org/#home).

#### NOTE
Did you know? Instead of using FiftyOne’s default model to generate
embeddings, you can provide your own embeddings or specify a model from the
[Model Zoo](../model_zoo/index.md#model-zoo) to use to generate embeddings via the optional
`embeddings` and `model` argument to
[`compute_uniqueness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_uniqueness).

**Output**: A scalar-valued `uniqueness` field is populated on each sample
that ranks the uniqueness of that sample (higher value means more unique).
The uniqueness values for a dataset are normalized to `[0, 1]`, with the most
unique sample in the collection having a uniqueness value of `1`.

You can customize the name of this field by passing the optional
`uniqueness_field` argument to
[`compute_uniqueness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_uniqueness).

**What to expect**: Uniqueness uses a tuned algorithm that measures the
distribution of each [`Sample`](../api/fiftyone.core.sample.md#fiftyone.core.sample.Sample) in the [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset). Using this distribution, it
ranks each sample based on its relative *similarity* to other samples. Those
that are close to other samples are not unique whereas those that are far from
most other samples are more unique.

#### NOTE
Did you know? You can specify a region of interest within each image to use
to compute uniqueness by providing the optional `roi_field` argument to
[`compute_uniqueness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_uniqueness), which
contains [`Detections`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Detections) or [`Polylines`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Polylines) that define the ROI for each sample.

#### NOTE
Check out the [uniqueness tutorial](../tutorials/uniqueness.md) to see
an example use case of the Brain’s uniqueness method to detect
near-duplicate images in a dataset.

![uniqueness](images/brain/brain-uniqueness.gif)

<a id="brain-label-mistakes"></a>

## Label mistakes

Label mistakes can be calculated for both classification and detection
datasets.

Classification

Detection

Correct annotations are crucial in developing high performing models.
Using the FiftyOne Brain and the predictions of a pre-trained model,
you can identify possible labels mistakes in [`Classification`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Classification) fields
of your dataset via the
[`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness)
method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

fob.compute_mistakenness(
    dataset, "predictions", label_field="ground_truth"
)
```

**Input**: Label mistakes operate on samples for which there are both
human annotations (`"ground_truth"` above) and model predictions
(`"predictions"` above).

**Output**: A float `mistakenness` field is populated on each sample
that ranks the chance that the human annotation is mistaken. You can
customize the name of this field by passing the optional
`mistakenness_field` argument to
[`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness).

**What to expect**: Finding mistakes in human annotations is
non-trivial (if it could be done perfectly then the approach would
sufficiently replace your prediction model!) The FiftyOne Brain uses a
proprietary scoring model that ranks samples for which your prediction
model is highly confident but wrong (according to the human annotation
label) as a high chance of being a mistake.

#### NOTE
Check out the
[label mistakes tutorial](../tutorials/classification_mistakes.md)
to see an example use case of the Brain’s mistakenness method on
a classification dataset.

Correct annotations are crucial in developing high performing models.
Using the FiftyOne Brain and the predictions of a pre-trained model,
you can identify possible labels mistakes in [`Detections`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Detections) fields of
your dataset via the
[`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness)
method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

fob.compute_mistakenness(
    dataset, "predictions", label_field="ground_truth"
)
```

**Input**: You can compute label mistakes on samples for which there
are both human annotations (`"ground_truth"` above) and model
predictions (`"predictions"` above).

**Output**: New fields on both the detections in `label_field` and the
samples will be populated:

Detection-level fields:

* `mistakenness` (float): Objects in `label_field` that matched with a
  prediction have their `mistakenness` field populated with a measure
  of the likelihood that the ground truth annotation is a mistake.
* `mistakenness_loc` (float): Objects in `label_field` that matched
  with a prediction have their `mistakenness_loc` field populated with
  a measure of the mistakenness in the localization (bounding box) of
  the ground truth annotation.
* `possible_missing` (bool): If there are predicted objects with no
  matches in `label_field` but which are deemed to be likely correct
  annotations, these objects will have their `possible_missing`
  attribute set to True. In addition, if you pass the optional
  `copy_missing=True` flag to
  [`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness),
  then these objects will be copied into `label_field`.
* `possible_spurious` (bool): Objects in `label_field` that were not
  matched with a prediction and deemed to be likely spurious
  annotations will have their `possible_spurious` field set to True.

Sample-level fields:

* `mistakenness` (float): The maximum mistakenness of an object in the
  `label_field` of the sample.
* `possible_missing` (int): The number of objects that were added to
  the `label_field` of the sample and marked as likely missing
  annotations.
* `possible_spurious` (int): The number of objects in the `label_field`
  of the sample that were deemed to be likely spurious annotations.

You can customize the names of these fields by passing optional
arguments to
[`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness).

**What to expect**: Finding mistakes in human annotations is
non-trivial (if it could be done perfectly then the approach would
sufficiently replace your prediction model!) The FiftyOne Brain uses a
proprietary scoring model that ranks detections for which your
prediction model is highly confident but wrong (according to the human
annotation label) as a high chance of being a mistake.

#### NOTE
Check out the
[detection mistakes tutorials](../tutorials/detection_mistakes.md)
to see an example use case of the Brain’s mistakenness method on a
detection dataset.

![mistakenness](images/brain/brain-mistakenness.png)

<a id="brain-sample-hardness"></a>

## Sample hardness

During training, it is useful to identify samples that are more difficult for a
model to learn so that training can be more focused around these hard samples.
These hard samples are also useful as seeds when considering what other new
samples to add to a training dataset.

In order to compute hardness, all you need to do is add your model predictions
and their logits to your FiftyOne [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset) and then run the
[`compute_hardness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_hardness) method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

fob.compute_hardness(dataset, "predictions")
```

**Input**: A [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset) or [`DatasetView`](../api/fiftyone.core.view.md#fiftyone.core.view.DatasetView) on which predictions have been
computed and are stored in the `"predictions"` argument. Ground truth
annotations are not required for hardness.

**Output**: A scalar-valued `hardness` field is populated on each sample that
ranks the hardness of the sample. You can customize the name of this field via
the `hardness_field` argument of
[`compute_hardness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_hardness).

**What to expect**: Hardness is computed in the context of a prediction model.
The FiftyOne Brain hardness measure defines hard samples as those for which the
prediction model is unsure about what label to assign. This measure
incorporates prediction confidence and logits in a tuned model that has
demonstrated empirical value in many model training exercises.

#### NOTE
Check out the
[classification evaluation tutorial](../tutorials/evaluate_classifications.md)
to see example uses of the Brain’s hardness method to uncover annotation
mistakes in a dataset.

![hardness](images/brain/brain-hardness.png)

<a id="brain-image-representativeness"></a>

## Image representativeness


<div class="available-in">
    <div class="available-in-row">
        <span class="available-in-label">Available in:</span>
        <span class="available-in-pill available-in-pill--oss">Open Source</span><span class="available-in-pill available-in-pill--enterprise">Enterprise</span>
    </div>
    <div class="available-in-row">
        <span class="available-in-versions">Introduced in <a href="../release-notes.html#fiftyone-0-25-0">FiftyOne 0.25.0</a> &middot; <a href="../release-notes.html#fiftyone-enterprise-2-0-0">FiftyOne Enterprise 2.0.0</a></span>
    </div>
    
</div>

During the early stages of the ML workflow it can be useful to find
prototypical samples in your data that accurately describe all the different
aspects of your data. FiftyOne Brain provides a representativeness method that
finds samples which are very similar to large clusters of your data. Highly
representative samples are great for finding modes or easy examples in your
dataset.

The representativeness of a [`Dataset`](../api/fiftyone.core.dataset.md#fiftyone.core.dataset.Dataset) can be computed directly without the need
for the predictions of a pre-trained model via the
[`compute_representativeness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_representativeness)
method:

```python
import fiftyone as fo
import fiftyone.brain as fob

dataset = fo.load_dataset(...)

fob.compute_representativeness(dataset)
```

**Input**: An unlabeled (or labeled) image dataset. There are
[recipes](../recipes/index.md#recipes) for building datasets from a wide variety of image
formats, ranging from a simple directory of images to complicated dataset
structures like [COCO](https://cocodataset.org/#home).

**Output**: A scalar-valued `representativeness` field is populated for each
sample that ranks the representativeness of that sample (higher value means
more representative). The representativeness values for a dataset are
normalized to `[0, 1]`, with the most representative samples in the collection
having a representativeness value of `1`.

You can customize the name of this field by passing the optional
`representativeness_field` argument to
[`compute_representativeness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_representativeness)
.

**What to expect**: Representativeness uses a clustering algorithm to find
similar looking groups of samples. The representativeness is then computed
based on each sample’s proximity to the computed cluster centers, farther
samples being less representative and closer samples being more representative.

#### NOTE
Did you know? You can specify a region of interest within each image to use
to compute representativeness by providing the optional `roi_field`
argument to
[`compute_representativeness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_representativeness),
which contains [`Detections`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Detections) or [`Polylines`](../api/fiftyone.core.labels.md#fiftyone.core.labels.Polylines) that define the ROI for each
sample.

![representativeness](images/brain/brain-representativeness.png)

<a id="brain-managing-runs"></a>

## Managing brain runs

When you run a brain method with a `brain_key` argument, the run is recorded
on the dataset and you can retrieve information about it later, rename it,
delete it (along with any modifications to your dataset that were performed by
it), and even retrieve the view that you computed on using the following
methods on your dataset:

- [`list_brain_runs()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.list_brain_runs)
- [`get_brain_info()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.get_brain_info)
- [`load_brain_results()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.load_brain_results)
- [`load_brain_view()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.load_brain_view)
- [`rename_brain_run()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.rename_brain_run)
- [`delete_brain_run()`](../api/fiftyone.core.collections.md#fiftyone.core.collections.SampleCollection.delete_brain_run)

Visualizations

Similarity

Uniqueness

Mistakenness

Hardness

Representativeness

The
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization)
method accepts an optional `brain_key` parameter that specifies the
brain key under which to store the results of the visualization.

The
[`compute_similarity()`](../api/fiftyone.brain.md#fiftyone.brain.compute_similarity)
method accepts an optional `brain_key` parameter that specifies the
brain key under which to store the similarity index.

The brain key of uniqueness runs is the value of the
`uniqueness_field` passed to
[`compute_uniqueness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_uniqueness).

The brain key of mistakenness runs is the value of the
`mistakenness_field` passed to
[`compute_mistakenness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_mistakenness).

The brain key of hardness runs is the value of the `hardness_field`
passed to [`compute_hardness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_hardness).

The brain key of representativeness runs is the value of the
`representativeness_field` passed to
[`compute_representativeness()`](../api/fiftyone.brain.md#fiftyone.brain.compute_representativeness).

The example below demonstrates the basic interface:

```python
import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")

view = dataset.take(100)

# Run a brain method that returns results
results = fob.compute_visualization(view, brain_key="visualization")

# Run a brain method that populates a new sample field on the dataset
fob.compute_uniqueness(view)

# List the brain methods that have been run
print(dataset.list_brain_runs())
# ['visualization', 'uniqueness']

# Print information about a brain run
print(dataset.get_brain_info("visualization"))

# Load the results of a previous brain run
also_results = dataset.load_brain_results("visualization")

# Load the view on which a brain run was performed
same_view = dataset.load_brain_view("visualization")

# Rename a brain run
dataset.rename_brain_run("visualization", "still_visualization")

# Delete brain runs
# This will delete any stored results and fields that were populated
dataset.delete_brain_run("still_visualization")
dataset.delete_brain_run("uniqueness")
```

<a id="brain-config"></a>

## Brain config

FiftyOne provides a brain config that you can use to either temporarily
or permanently configure the behavior of brain methods.

### Viewing your config

You can print your current brain config at any time via the Python library
and the CLI:

Python

CLI

```python
import fiftyone.brain as fob

# Print your current brain config
print(fob.brain_config)
```

```text
{
    "default_similarity_backend": "sklearn",
    "similarity_backends": {
        "milvus": {
            "config_cls": "fiftyone.brain.internal.core.milvus.MilvusSimilarityConfig"
        },
        "pinecone": {
            "config_cls": "fiftyone.brain.internal.core.pinecone.PineconeSimilarityConfig"
        },
        "qdrant": {
            "config_cls": "fiftyone.brain.internal.core.qdrant.QdrantSimilarityConfig"
        },
        "redis": {
            "config_cls": "fiftyone.brain.internal.core.redis.RedisSimilarityConfig"
        },
        "sklearn": {
            "config_cls": "fiftyone.brain.internal.core.sklearn.SklearnSimilarityConfig"
        },
        "mongodb": {
            "config_cls": "fiftyone.brain.internal.core.mongodb.MongoDBSimilarityConfig"
        },
        "elasticsearch": {
            "config_cls": "fiftyone.brain.internal.core.elasticsearch.ElasticsearchSimilarityConfig"
        },
        "pgvector": {
            "config_cls": "fiftyone.brain.internal.core.pgvector.PgVectorSimilarityConfig"
        },
        "mosaic": {
            "config_cls": "fiftyone.brain.internal.core.mosaic.MosaicSimilarityConfig"
        },
        "lancedb": {
            "config_cls": "fiftyone.brain.internal.core.lancedb.LanceDBSimilarityConfig"
        }
    },
    "default_visualization_method": "umap",
    "visualization_methods": {
        "umap": {
            "config_cls": "fiftyone.brain.visualization.UMAPVisualizationConfig"
        },
        "tsne": {
            "config_cls": "fiftyone.brain.visualization.TSNEVisualizationConfig"
        },
        "pca": {
            "config_cls": "fiftyone.brain.visualization.PCAVisualizationConfig"
        },
        "manual": {
            "config_cls": "fiftyone.brain.visualization.ManualVisualizationConfig"
        }
    }
}
```

```shell
# Print your current brain config
fiftyone brain config
```

```text
{
    "default_similarity_backend": "sklearn",
    "similarity_backends": {
        "milvus": {
            "config_cls": "fiftyone.brain.internal.core.milvus.MilvusSimilarityConfig"
        },
        "pinecone": {
            "config_cls": "fiftyone.brain.internal.core.pinecone.PineconeSimilarityConfig"
        },
        "qdrant": {
            "config_cls": "fiftyone.brain.internal.core.qdrant.QdrantSimilarityConfig"
        },
        "redis": {
            "config_cls": "fiftyone.brain.internal.core.redis.RedisSimilarityConfig"
        },
        "sklearn": {
            "config_cls": "fiftyone.brain.internal.core.sklearn.SklearnSimilarityConfig"
        },
        "mongodb": {
            "config_cls": "fiftyone.brain.internal.core.mongodb.MongoDBSimilarityConfig"
        },
        "elasticsearch": {
            "config_cls": "fiftyone.brain.internal.core.elasticsearch.ElasticsearchSimilarityConfig"
        },
        "lancedb": {
            "config_cls": "fiftyone.brain.internal.core.lancedb.LanceDBSimilarityConfig"
        }
    },
    "default_visualization_method": "umap",
    "visualization_methods": {
        "umap": {
            "config_cls": "fiftyone.brain.visualization.UMAPVisualizationConfig"
        },
        "tsne": {
            "config_cls": "fiftyone.brain.visualization.TSNEVisualizationConfig"
        },
        "pca": {
            "config_cls": "fiftyone.brain.visualization.PCAVisualizationConfig"
        },
        "manual": {
            "config_cls": "fiftyone.brain.visualization.ManualVisualizationConfig"
        }
    }
}
```

#### NOTE
If you have customized your brain config via any of the methods described
below, printing your config is a convenient way to ensure that the changes
you made have taken effect as you expected.

### Modifying your config

You can modify your brain config in a variety of ways. The following sections
describe these options in detail.

#### Order of precedence

The following order of precedence is used to assign values to your brain
config settings as runtime:

1. Config settings applied at runtime by directly editing
   `fiftyone.brain.brain_config`
2. `FIFTYONE_BRAIN_XXX` environment variables
3. Settings in your JSON config (`~/.fiftyone/brain_config.json`)
4. The default config values

#### Editing your JSON config

You can permanently customize your brain config by creating a
`~/.fiftyone/brain_config.json` file on your machine. The JSON file may contain
any desired subset of config fields that you wish to customize.

For example, the following config JSON file customizes the URL of your
[Qdrant server](../integrations/qdrant.md#qdrant-integration) without changing any other default
config settings:

```json
{
    "similarity_backends": {
        "qdrant": {
            "url": "http://localhost:8080"
        }
    }
}
```

When `fiftyone.brain` is imported, any options from your JSON config are merged
into the default config, as per the order of precedence described above.

#### NOTE
You can customize the location from which your JSON config is read by
setting the `FIFTYONE_BRAIN_CONFIG_PATH` environment variable.

#### Setting environment variables

Brain config settings may be customized on a per-session basis by setting the
`FIFTYONE_BRAIN_XXX` environment variable(s) for the desired config settings.

The `FIFTYONE_BRAIN_DEFAULT_SIMILARITY_BACKEND` environment variable allows you
to configure your default similarity backend:

```shell
export FIFTYONE_BRAIN_DEFAULT_SIMILARITY_BACKEND=qdrant
```

**Similarity backends**

You can declare parameters for specific similarity backends by setting
environment variables of the form
`FIFTYONE_BRAIN_SIMILARITY_<BACKEND>_<PARAMETER>`. Any settings that you
declare in this way will be passed as keyword arguments to methods like
[`compute_similarity()`](../api/fiftyone.brain.md#fiftyone.brain.compute_similarity) whenever the
corresponding backend is in use. For example, you can configure the URL of your
[Qdrant server](../integrations/qdrant.md#qdrant-integration) as follows:

```shell
export FIFTYONE_BRAIN_SIMILARITY_QDRANT_URL=http://localhost:8080
```

The `FIFTYONE_BRAIN_SIMILARITY_BACKENDS` environment variable can be set to a
`list,of,backends` that you want to expose in your session, which may exclude
native backends and/or declare additional custom backends whose parameters are
defined via additional config modifications of any kind:

```shell
export FIFTYONE_BRAIN_SIMILARITY_BACKENDS=custom,sklearn,qdrant
```

When declaring new backends, you can include `*` to append new backend(s)
without omitting or explicitly enumerating the builtin backends. For example,
you can add a `custom` similarity backend as follows:

```shell
export FIFTYONE_BRAIN_SIMILARITY_BACKENDS=*,custom
export FIFTYONE_BRAIN_SIMILARITY_CUSTOM_CONFIG_CLS=your.custom.SimilarityConfig
```

**Visualization methods**

You can declare parameters for specific visualization methods by setting
environment variables of the form
`FIFTYONE_BRAIN_VISUALIZATION_<METHOD>_<PARAMETER>`. Any settings that you
declare in this way will be passed as keyword arguments to methods like
[`compute_visualization()`](../api/fiftyone.brain.md#fiftyone.brain.compute_visualization) whenever
the corresponding method is in use. For example, you can suppress logging
messages for the UMAP method as follows:

```shell
export FIFTYONE_BRAIN_VISUALIZATION_UMAP_VERBOSE=false
```

The `FIFTYONE_BRAIN_VISUALIZATION_METHODS` environment variable can be set to a
`list,of,methods` that you want to expose in your session, which may exclude
native methods and/or declare additional custom methods whose parameters are
defined via additional config modifications of any kind:

```shell
export FIFTYONE_BRAIN_VISUALIZATION_METHODS=custom,umap,tsne
```

When declaring new methods, you can include `*` to append new method(s)
without omitting or explicitly enumerating the builtin methods. For example,
you can add a `custom` visualization method as follows:

```shell
export FIFTYONE_BRAIN_VISUALIZATION_METHODS=*,custom
export FIFTYONE_BRAIN_VISUALIZATION_CUSTOM_CONFIG_CLS=your.custom.VisualzationConfig
```

#### Modifying your config in code

You can dynamically modify your brain config at runtime by directly
editing the `fiftyone.brain.brain_config` object.

Any changes to your brain config applied via this manner will immediately
take effect in all subsequent calls to `fiftyone.brain.brain_config` during
your current session.

```python
import fiftyone.brain as fob

fob.brain_config.default_similarity_backend = "qdrant"
fob.brain_config.default_visualization_method = "tsne"
```
