<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Voxel51-Brian</title>
    <description>The latest articles on Forem by Voxel51-Brian (@voxel51-brian).</description>
    <link>https://forem.com/voxel51-brian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F895780%2F457b5c48-3d53-4118-a6a3-29931e89c837.jpg</url>
      <title>Forem: Voxel51-Brian</title>
      <link>https://forem.com/voxel51-brian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/voxel51-brian"/>
    <language>en</language>
    <item>
      <title>FiftyOne Computer Vision Tips and Tricks for Adding and Merging Data – Feb 17, 2023</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Sat, 18 Feb 2023 16:30:14 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-for-adding-and-merging-data-feb-17-2023-3kfm</link>
      <guid>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-for-adding-and-merging-data-feb-17-2023-3kfm</guid>
      <description>&lt;p&gt;Welcome to our weekly FiftyOne tips and tricks blog where we give practical pointers for using FiftyOne on topics inspired by discussions in the open source community. This week we’ll cover &lt;a href="https://docs.voxel51.com/recipes/merge_datasets.html" rel="noopener noreferrer"&gt;adding and merging data&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, What’s FiftyOne?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/fiftyone/" rel="noopener noreferrer"&gt;FiftyOne&lt;/a&gt; is an open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqbxalwomx9800o7cgl3m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqbxalwomx9800o7cgl3m.gif" alt=" " width="80" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html" rel="noopener noreferrer"&gt;Get started!&lt;/a&gt; We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s dive into this week’s tips and tricks!&lt;/p&gt;

&lt;h2&gt;
  
  
  A primer on adding and merging
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_datasets.html#using-datasets" rel="noopener noreferrer"&gt;Datasets&lt;/a&gt; are the core data structure in FiftyOne, allowing you to represent your raw data, labels, and associated metadata. &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/basics.html#samples" rel="noopener noreferrer"&gt;Samples&lt;/a&gt; are the atomic elements of a &lt;code&gt;Dataset&lt;/code&gt; that store all the information related to a given piece of data. When you query and manipulate a Dataset object using &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_views.html#using-views" rel="noopener noreferrer"&gt;dataset views&lt;/a&gt;, a &lt;code&gt;DatasetView&lt;/code&gt; object is returned, which represents a filtered view into a subset of the underlying dataset’s contents.&lt;/p&gt;

&lt;p&gt;Many computer vision workflows involve operations that merge data from multiple sources, such as adding new samples to an existing dataset, or merging a model’s predictions into a dataset which contains ground truth labels. In FiftyOne, &lt;code&gt;Dataset&lt;/code&gt; and &lt;code&gt;DatasetView&lt;/code&gt; objects come with a variety of methods that make performing these add and merge operations easy.&lt;/p&gt;

&lt;p&gt;Continue reading for some tips and tricks to help you master adding and merging data in FiftyOne!&lt;/p&gt;

&lt;h2&gt;
  
  
  Encountering a sample multiple times
&lt;/h2&gt;

&lt;p&gt;If you want to add a completely new collection of samples, samples, to a dataset, &lt;code&gt;dataset&lt;/code&gt;, then you can use the &lt;code&gt;add_samples()&lt;/code&gt; and &lt;code&gt;add_collection()&lt;/code&gt; methods for the most part interchangeably. However, if there are samples that appear multiple times in your workflows, due to sources of randomness, for instance, then these two methods have different consequences.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;add_samples()&lt;/code&gt; encounters samples that are already present in the dataset to which the method is applied, it generates a &lt;em&gt;new&lt;/em&gt; sample with a new &lt;code&gt;id&lt;/code&gt;, and adds this to the dataset. On the other hand, &lt;code&gt;add_collection()&lt;/code&gt; ignores the sample and moves on. &lt;/p&gt;

&lt;p&gt;In the code block below, when applied to the Quickstart Dataset with a random collection from the dataset as input, &lt;code&gt;add_collection()&lt;/code&gt; leaves the dataset unchanged, whereas &lt;code&gt;add_samples()&lt;/code&gt; increases the size of the dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
# 200 samples
dataset = foz.load_zoo_dataset("quickstart")
# randomly select 50 samples
samples = dataset.take(50)
# doesn’t change dataset size
dataset.add_collection(samples)
# 200 samples → 250 samples
dataset.add_samples(samples)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.utils.random.html" rel="noopener noreferrer"&gt;FiftyOne’s random utils&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add samples by directory
&lt;/h2&gt;

&lt;p&gt;FiftyOne supports a variety of common computer vision data formats, making it easy to load your data into FiftyOne and accelerating your computer vision workflows. FiftyOne’s &lt;code&gt;DatasetImporter&lt;/code&gt; classes allow you to import data in various formats without needing to write your own loops and I/O scripts. &lt;/p&gt;

&lt;p&gt;If you have VOC-style data stored in a single directory on disk, for instance, you can create a dataset from this data using the &lt;code&gt;from_dir()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
name = "my-dataset"
data_path = "/path/to/images"
labels_path = "/path/to/voc-labels"
# Import dataset by explicitly providing paths to the source media and labels
dataset = fo.Dataset.from_dir(
    dataset_type=fo.types.VOCDetectionDataset,
    data_path=data_path,
    labels_path=labels_path,
    name=name,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;add_dir()&lt;/code&gt; method, you can extend the logic of any existing DatasetImporter to data that is stored in multiple directories. To add &lt;code&gt;train&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt; data in YOLOv5 format to a single dataset, you can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
name = "my-dataset"
dataset_dir = "/path/to/yolov5-dataset"
# The splits to load
splits = ["train", "val"]
# Load the dataset, using tags to mark the samples in each split
dataset = fo.Dataset(name)
for split in splits:
    dataset.add_dir(
        dataset_dir=dataset_dir,
        dataset_type=fo.types.YOLOv5Dataset,
        split=split,
        tags=split,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to add the contents of each directory directly to the final dataset without having to instantiate temporary datasets. The &lt;code&gt;merge_dir()&lt;/code&gt; can also be similarly useful!&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/dataset_creation/index.html" rel="noopener noreferrer"&gt;loading data into FiftyOne&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add from archive
&lt;/h2&gt;

&lt;p&gt;On a related note, if you have data in a common archived format, such as &lt;code&gt;.zip&lt;/code&gt;, &lt;code&gt;.tar&lt;/code&gt;, or &lt;code&gt;.tar.gz&lt;/code&gt; stored on disk, you can use the &lt;code&gt;add_dir()&lt;/code&gt; or &lt;code&gt;merge_dir()&lt;/code&gt; methods to add this data to your dataset. If the archived data has not been unpacked yet, FiftyOne will handle this extraction for you!&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.dataset.html#fiftyone.core.dataset.Dataset.from_archive" rel="noopener noreferrer"&gt;from_archive()&lt;/a&gt;, &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.dataset.html#fiftyone.core.dataset.Dataset.add_archive" rel="noopener noreferrer"&gt;add_archive()&lt;/a&gt;, and &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.dataset.html#fiftyone.core.dataset.Dataset.merge_archive" rel="noopener noreferrer"&gt;merge_archive()&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add model predictions
&lt;/h2&gt;

&lt;p&gt;In machine learning workflows, it is common practice to withhold ground truth information at inference time. To accomplish this, it is often beneficial to separate the various fields of your dataset so that only certain subsets of information are available at different steps. &lt;/p&gt;

&lt;p&gt;When it comes to evaluating model performance at the end of the day, however, we would like to merge ground truth labels and predictions into a common dataset. In FiftyOne, this is possible with the &lt;code&gt;merge_samples()&lt;/code&gt; method. If we have a &lt;code&gt;predictions_view&lt;/code&gt; only containing predictions, and a &lt;code&gt;dataset&lt;/code&gt; with all other information, we can merge the predictions into our base dataset as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
# Create a dataset containing only ground truth objects
dataset = foz.load_zoo_dataset("quickstart")
dataset = dataset.exclude_fields("predictions").clone()
# Example predictions view
predictions_view = dataset1.select_fields("predictions")
# Merge the predictions
dataset.merge_samples(predictions_view)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.collections.html#fiftyone.core.collections.SampleCollection.select_fields" rel="noopener noreferrer"&gt;selecting&lt;/a&gt; and &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.collections.html#fiftyone.core.collections.SampleCollection.exclude_fields" rel="noopener noreferrer"&gt;excluding&lt;/a&gt; fields in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Export multiple labels with merge_labels()
&lt;/h2&gt;

&lt;p&gt;If you have multiple &lt;code&gt;Label&lt;/code&gt; fields and you want to export your data using a common format, you can use the &lt;code&gt;merge_labels()&lt;/code&gt; method to merge all of these label fields into one field for export. &lt;/p&gt;

&lt;p&gt;For instance, if you have three labels, &lt;code&gt;ground_truth&lt;/code&gt;, &lt;code&gt;model1_predictions&lt;/code&gt;, and &lt;code&gt;model2_predictions&lt;/code&gt;, you can merge all of these labels as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset = fo.load_dataset(...)
## clone label fields into temporary fields
dataset.clone_sample_field("ground_truth", "tmp")
dataset.clone_sample_field("model1_predictions", "tmp1")
dataset.clone_sample_field("model2_predictions", "tmp2")
## merge model1 predictions into ground_truth
dataset.merge_labels("tmp1", "tmp")
## merge model2 predictions into ground_truth
dataset.merge_labels("tmp2", "tmp")
## export the merged labels field
dataset.export(..., label_field="tmp")
## clean up
dataset.delete_sample_fields(["tmp", "tmp1", "tmp2"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to export the data just so that you can import it at a later time, however, then you can avoid all of this and instead make your dataset persistent!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataset.persistent = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about labels and dataset persistence in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the FiftyOne community!
&lt;/h2&gt;

&lt;p&gt;Join the thousands of engineers and data scientists already using FiftyOne to solve some of the most challenging problems in computer vision today!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,350+ &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack members&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2,500+ &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;stars on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;3,100+ &lt;a href="https://www.meetup.com/pro/computer-vision-meetups/" rel="noopener noreferrer"&gt;Meetup members&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/voxel51/fiftyone/network/dependents?package_id=UGFja2FnZS0xNzAxODM0MjUx" rel="noopener noreferrer"&gt;Used by&lt;/a&gt; 246+ repositories&lt;/li&gt;
&lt;li&gt;56+ &lt;a href="https://github.com/voxel51/fiftyone/graphs/contributors" rel="noopener noreferrer"&gt;contributors&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html" rel="noopener noreferrer"&gt;Get started!&lt;/a&gt; We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the FiftyOne &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>top7</category>
    </item>
    <item>
      <title>Announcing FiftyOne 0.19 with Spaces, In-App Embeddings Visualization, Saved Views, and More!</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Fri, 17 Feb 2023 04:23:02 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/announcing-fiftyone-019-with-spaces-in-app-embeddings-visualization-saved-views-and-more-5eb3</link>
      <guid>https://forem.com/voxel51-brian/announcing-fiftyone-019-with-spaces-in-app-embeddings-visualization-saved-views-and-more-5eb3</guid>
      <description>&lt;p&gt;Voxel51 in conjunction with the FiftyOne community is excited to announce the general availability of &lt;a href="https://docs.voxel51.com/release-notes.html#fiftyone-0-19-0" rel="noopener noreferrer"&gt;FiftyOne 0.19&lt;/a&gt;. This release is packed with new features that make it even easier and faster to visualize your computer vision datasets and boost the performance of your machine learning models. How? Read on!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what’s FiftyOne?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/fiftyone/" rel="noopener noreferrer"&gt;FiftyOne&lt;/a&gt; is the open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm32n9gdz7w957tng174e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm32n9gdz7w957tng174e.gif" alt="FiftyOne in action" width="80" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/" rel="noopener noreferrer"&gt;Get started!&lt;/a&gt; We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s dive into the release.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl;dr: What’s new in FiftyOne 0.19?
&lt;/h2&gt;

&lt;p&gt;This release includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spaces&lt;/strong&gt;: an all-new customizable framework for organizing interactive information panels within the FiftyOne App, allowing you to visualize and query your datasets in powerful new ways through a convenient interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-App embeddings visualization&lt;/strong&gt;: you can now interactively explore embeddings visualizations natively in the App by opening an embeddings panel with one click&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saved views&lt;/strong&gt;: you can now save views into your datasets and switch between them natively in the App&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-disk segmentations&lt;/strong&gt;: you can now store your semantic segmentation masks and heatmaps on disk, rather than in the database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New UI filtering options&lt;/strong&gt;: the App’s sidebar now contains upgraded options for filtering datasets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FiftyOne Teams documentation&lt;/strong&gt;: documentation for &lt;a href="https://docs.voxel51.com/teams/index.html#fiftyone-teams" rel="noopener noreferrer"&gt;FiftyOne Teams&lt;/a&gt; is now publicly available!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the &lt;a href="https://docs.voxel51.com/release-notes.html#fiftyone-0-19-0" rel="noopener noreferrer"&gt;release notes&lt;/a&gt; for a full rundown of additional enhancements and bug fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live demo &amp;amp; AMA on Feb. 28 @ 10 AM PT
&lt;/h2&gt;

&lt;p&gt;You can see all of the new features in action in a live webinar and AMA on February 28, 2023 at 10 AM Pacific Time. I’ll be demoing all of the new features in FiftyOne 0.19, followed by an open Q&amp;amp;A where you can get answers to any questions you might have. &lt;a href="https://voxel51.com/computer-vision-events/whats-new-in-fiftyone-0-19/?utm_source=blog" rel="noopener noreferrer"&gt;Register here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, here’s a quick overview of some of the new features we packed into this release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spaces
&lt;/h2&gt;

&lt;p&gt;FiftyOne 0.19 debuts Spaces, a customizable framework for organizing interactive information Panels in the App.&lt;/p&gt;

&lt;p&gt;As of FiftyOne 0.19, the following Panel types are included natively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/user_guide/app.html#app-samples-panel" rel="noopener noreferrer"&gt;Samples Panel&lt;/a&gt;: the media grid that loads by default when you launch the App&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/user_guide/app.html#app-histograms-panel" rel="noopener noreferrer"&gt;Histograms Panel&lt;/a&gt;: a dashboard of histograms for the fields of your dataset&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(New!)&lt;/strong&gt; &lt;a href="https://docs.voxel51.com/user_guide/app.html#app-embeddings-panel" rel="noopener noreferrer"&gt;Embeddings Panel&lt;/a&gt;: a canvas for working with embeddings visualizations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/user_guide/app.html#app-map-panel" rel="noopener noreferrer"&gt;Map Panel&lt;/a&gt;: visualizes the geolocation data of datasets that have a GeoLocation field&lt;/li&gt;
&lt;li&gt;You can also configure &lt;a href="https://docs.voxel51.com/plugins/index.html#fiftyone-plugins" rel="noopener noreferrer"&gt;custom Panels via plugins&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the screenshot below, for example, we’ve added the Embeddings and Map Panels to the default Samples Panel so we can visualize all three together seamlessly in the App.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feva2ghp1qs6xcl8oeoki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feva2ghp1qs6xcl8oeoki.png" alt="Viewing three panels in FiftyOne, customized through the new Spaces feature" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can configure Spaces visually in the App in a variety of ways described below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the + icon in any Space to add a new Panel:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faddob5jg3f9v7hu9ksee.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faddob5jg3f9v7hu9ksee.gif" alt="Add a new panel in the FiftyOne App" width="760" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you have multiple Panels open in a Space, you can use the divider buttons to split the Space either horizontally or vertically:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fask3e5ttnwsh7sax46f3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fask3e5ttnwsh7sax46f3.gif" alt="Split Spaces and Panels in the FiftyOne App horizontally or vertically" width="1171" height="831"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can rearrange Panels at any time by dragging their tabs between Spaces, or close a Panel by clicking on its x icon:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd98a5cy7l0pb29p61fq4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd98a5cy7l0pb29p61fq4.gif" alt="Easily rearrange Panels in the FiftyOne App" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also programmatically configure your Spaces layout from Python!&lt;/p&gt;

&lt;p&gt;The code sample below shows an end-to-end example of loading a dataset, generating an embeddings visualization &lt;a href="https://docs.voxel51.com/user_guide/brain.html" rel="noopener noreferrer"&gt;via the FiftyOne Brain&lt;/a&gt;, and launching the App with a customized Spaces layout that includes the Samples Panel, Histograms Panel, and Embeddings Panel with the Brain result already loaded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
fob.compute_visualization(dataset, brain_key="img_viz")
samples_panel = fo.Panel(
    type="Samples",
    pinned=True,  # don’t allow closing
)
histograms_panel = fo.Panel(
    type="Histograms",
    state=dict(plot="Labels"),  # open label fields by default
)
# Open the visualization we generated above by default
embeddings_panel = fo.Panel(
    type="Embeddings",
    state=dict(brainResult="img_viz", colorByField="metadata.size_bytes"),
)
spaces = fo.Space(
    children=[
        fo.Space(
            children=[
                fo.Space(children=[samples_panel]),
                fo.Space(children=[histograms_panel]),
            ],
            orientation="horizontal",
        ),
        fo.Space(children=[embeddings_panel]),
    ],
    orientation="vertical",
)
session = fo.launch_app(dataset, spaces=spaces)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://docs.voxel51.com/user_guide/app.html#spaces" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; for more information about using and configuring Spaces layouts.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-App embeddings visualization
&lt;/h2&gt;

&lt;p&gt;New in FiftyOne 0.19 (and enabled by the Spaces feature above), when you load a dataset in the App that contains an &lt;a href="https://docs.voxel51.com/user_guide/brain.html#brain-embeddings-visualization" rel="noopener noreferrer"&gt;embeddings visualization&lt;/a&gt;, you can open the &lt;a href="https://docs.voxel51.com/user_guide/app.html#embeddings-panel" rel="noopener noreferrer"&gt;Embeddings Panel&lt;/a&gt; to visualize and interactively explore a scatterplot of the embeddings in the App.&lt;/p&gt;

&lt;p&gt;For example, try running the code below to download a dataset, generate two embeddings visualizations on it, and launch the App:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
# Image embeddings
fob.compute_visualization(dataset, brain_key="img_viz")
# Object patch embeddings
fob.compute_visualization(
    dataset, patches_field="ground_truth", brain_key="gt_viz"
)
session = fo.launch_app(dataset)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then click on the + icon next to the Samples tab to open the Embeddings Panel and use the two menus in the upper-left corner of the Panel to configure your plot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brain key&lt;/strong&gt;: the Brain key associated with the &lt;a href="https://docs.voxel51.com/user_guide/brain.html#visualizing-embeddings" rel="noopener noreferrer"&gt;compute_visualization()&lt;/a&gt; run to display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color by&lt;/strong&gt;: an optional sample field (or label attribute, for patches embeddings) to color the points by&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there you can lasso points in the plot to show only the corresponding samples/patches in the Samples Panel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjuvw38b7fhtogruc3km.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjuvw38b7fhtogruc3km.gif" alt="FiftyOne App, In-App Embeddings Visualization" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Embeddings Panel also provides a number of additional controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press the &lt;strong&gt;pan&lt;/strong&gt; icon in the menu (or type g) to switch to pan mode, in which you can click and drag to change your current field of view&lt;/li&gt;
&lt;li&gt;Press the &lt;strong&gt;lasso&lt;/strong&gt; icon (or type s) to switch back to lasso mode&lt;/li&gt;
&lt;li&gt;Press the &lt;strong&gt;locate&lt;/strong&gt; icon to reset the plot’s viewport to a tight crop of the current view’s embeddings&lt;/li&gt;
&lt;li&gt;Press the &lt;strong&gt;x&lt;/strong&gt; icon (or double click anywhere in the plot) to clear the current selection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When coloring points by categorical fields (strings and integers) with fewer than 100 unique classes, you can also use the legend to toggle the visibility of each class of points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single click on a legend trace to show/hide that class in the plot&lt;/li&gt;
&lt;li&gt;Double click on a legend trace to show/hide all other classes in the plot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepfcesg22opt0dyy8giw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepfcesg22opt0dyy8giw.gif" alt="Embeddings Panel in FiftyOne - New Controls Available" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As demonstrated in the previous section, the Embeddings Panel can also be programmatically configured via Python.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://docs.voxel51.com/user_guide/app.html#embeddings-panel" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; for more information about working with embeddings visualizations in the App.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saved views
&lt;/h2&gt;

&lt;p&gt;In FiftyOne 0.19 you can use a new menu in the upper-left of the App to record the current state of the App’s view bar and filters sidebar as a &lt;strong&gt;saved view&lt;/strong&gt; into your dataset:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpehwij4n7t7lzon8rzhl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpehwij4n7t7lzon8rzhl.gif" alt="Save a dataset view in FiftyOne App" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Saved views are persisted on your dataset under a name of your choice so that you can quickly load them in a future session via the UI or Python.&lt;/p&gt;

&lt;p&gt;Saved views are a convenient way to record semantically relevant subsets of a dataset, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Samples in a particular state, e.g. with certain tag(s)&lt;/li&gt;
&lt;li&gt;A subset of a dataset that was used for a task, e.g. training a model&lt;/li&gt;
&lt;li&gt;Samples that contain content of interest, e.g. object types or image characteristics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that saved views only store the rules used to extract content from the underlying dataset, not the actual content itself. You can save hundreds of views into a dataset if desired without worrying about storage space.&lt;/p&gt;

&lt;p&gt;You can load a saved view at any time by selecting it from the saved view menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbqo8ka6jixtmpmt7h13.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmbqo8ka6jixtmpmt7h13.gif" alt="Load a saved view in the FiftyOne App" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also edit or delete saved views by clicking on their pencil icon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9el7u22ibqinwqw54cf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9el7u22ibqinwqw54cf.gif" alt="Editing a Saved View in the FiftyOne App" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also programmatically create saved views &lt;a href="https://docs.voxel51.com/user_guide/using_views.html#saving-views" rel="noopener noreferrer"&gt;via Python&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
from fiftyone import ViewField as F
dataset = foz.load_zoo_dataset("quickstart")
dataset.persistent = True
# Create a view
cats_view = (
    dataset
    .select_fields("ground_truth")
    .filter_labels("ground_truth", F("label") == "cat")
    .sort_by(F("ground_truth.detections").length(), reverse=True)
)
# Save the view
dataset.save_view("cats-view", cats_view)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And load them in future sessions (including saved views created via the App):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset = fo.load_dataset("quickstart")
# Retrieve a saved view
cats_view = dataset.load_saved_view("cats-view")
print(cats_view)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://docs.voxel51.com/user_guide/app.html#saving-views" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; for more information about using saved views in the App and Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-disk segmentations
&lt;/h2&gt;

&lt;p&gt;In prior FiftyOne versions, &lt;a href="https://docs.voxel51.com/user_guide/using_datasets.html#semantic-segmentation" rel="noopener noreferrer"&gt;semantic segmentations&lt;/a&gt; and &lt;a href="https://docs.voxel51.com/user_guide/using_datasets.html#heatmaps" rel="noopener noreferrer"&gt;heatmaps&lt;/a&gt; could only be stored as compressed bytes directly in the database.&lt;/p&gt;

&lt;p&gt;Now in FiftyOne 0.19, you can store segmentations and heatmaps as images on disk and store (only) their paths on your FiftyOne datasets, just like you do for the primary media of each sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import cv2
import numpy as np
import fiftyone as fo
# Example segmentation mask
mask_path = "/tmp/segmentation.png"
mask = np.random.randint(10, size=(128, 128), dtype=np.uint8)
cv2.imwrite(mask_path, mask)
sample = fo.Sample(filepath="/path/to/image.png")
sample["segmentation"] = fo.Segmentation(mask_path=mask_path)
print(sample)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segmentation masks can be stored in either of these formats on disk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2D 8-bit or 16-bit images&lt;/li&gt;
&lt;li&gt;3D 8-bit RGB images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you load datasets with segmentation fields containing 2D masks in the App, each pixel value is rendered as a different color from the App’s color pool so that you can visually distinguish the classes. When you view RGB segmentation masks in the App, the mask colors are always used.&lt;/p&gt;

&lt;p&gt;You can also &lt;a href="https://docs.voxel51.com/user_guide/using_datasets.html#storing-mask-targets" rel="noopener noreferrer"&gt;store semantic labels&lt;/a&gt; for your segmentation fields on your dataset. Then, when you view the dataset in the App, label strings will appear in the App’s tooltip when you hover over pixels.&lt;/p&gt;

&lt;p&gt;If you are working with 2D segmentation masks, specify target keys as integers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset = fo.Dataset()
dataset.default_mask_targets = {1: "cat", 2: "dog"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you are working with RGB segmentation masks, specify target keys as RGB hex strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset = fo.Dataset()
dataset.default_mask_targets = {"#499CEF": "cat", "#6D04FF": "dog"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire FiftyOne API was upgraded to support on-disk and/or RGB segmentations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evaluation via &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#semantic-segmentations" rel="noopener noreferrer"&gt;evaluate_segmentations()&lt;/a&gt; natively supports on-disk and/or RGB segmentations&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://docs.voxel51.com/api/fiftyone.core.collections.html#fiftyone.core.collections.SampleCollection.apply_model" rel="noopener noreferrer"&gt;apply_model()&lt;/a&gt; method now has an optional output_dir argument specifying where to store semantic segmentation inferences as images on disk &lt;/li&gt;
&lt;li&gt;There’s a new &lt;a href="https://docs.voxel51.com/api/fiftyone.utils.labels.html#fiftyone.utils.labels.export_segmentations" rel="noopener noreferrer"&gt;export_segmentations()&lt;/a&gt; utility for conveniently exporting in-database segmentations to on-disk images&lt;/li&gt;
&lt;li&gt;Other new utilities like &lt;a href="https://docs.voxel51.com/api/fiftyone.utils.labels.html#fiftyone.utils.labels.transform_segmentations" rel="noopener noreferrer"&gt;transform_segmentations()&lt;/a&gt; are now available for manipulating segmentations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out &lt;a href="https://docs.voxel51.com/user_guide/using_datasets.html#semantic-segmentation" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; for more information about adding on-disk segmentations to your FiftyOne datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  New UI filtering options
&lt;/h2&gt;

&lt;p&gt;We’re constantly improving and extending the filtering options available natively in the App to provide more powerful and intuitive ways to query datasets. In FiftyOne 0.19, we added a new selector that allows you to fine-tune your filters in the sidebar.&lt;/p&gt;

&lt;p&gt;For example, when filtering by the label attribute of a Detections field, you can choose between the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(default): Filter to only show objects with the specified labels (omitting samples with no matching objects)&lt;/li&gt;
&lt;li&gt;Exclude objects with the specified labels&lt;/li&gt;
&lt;li&gt;Show samples that contain the specified labels (without filtering)&lt;/li&gt;
&lt;li&gt;Omit samples that contain the specific labels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All applicable filtering options are available from both the grid view and the &lt;a href="https://docs.voxel51.com/user_guide/app.html#viewing-a-sample" rel="noopener noreferrer"&gt;sample modal&lt;/a&gt;, and for all field types, including top-level fields and &lt;a href="https://docs.voxel51.com/user_guide/using_datasets.html#dynamic-attributes" rel="noopener noreferrer"&gt;dynamic label attributes&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6un2cat43pmcz9xj9mnu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6un2cat43pmcz9xj9mnu.gif" alt="New UI Filtering Options in the FiftyOne App" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FiftyOne Teams documentation
&lt;/h2&gt;

&lt;p&gt;Exciting news! Documentation for FiftyOne Teams is now publicly available at &lt;a href="https://docs.voxel51.com/teams" rel="noopener noreferrer"&gt;https://docs.voxel51.com/teams/index.html&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;FiftyOne Teams enables multiple users to securely collaborate on the same datasets and models, either on-premises or in the cloud, all built on top of the open source FiftyOne workflows that you’re already relying on. Look interesting? &lt;a href="https://voxel51.com/get-fiftyone-teams/" rel="noopener noreferrer"&gt;Schedule a demo&lt;/a&gt; to get started with FiftyOne Teams yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community contributions
&lt;/h2&gt;

&lt;p&gt;Shoutout to the following community members who contributed to this release!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kalpit-S" rel="noopener noreferrer"&gt;kalpit-S&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2354" rel="noopener noreferrer"&gt;#2354 – added help link for Mapbox configuration in App&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/flakeice" rel="noopener noreferrer"&gt;flakeice&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2359" rel="noopener noreferrer"&gt;#2359 – fix bug when loading datasets in VOC format&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Rusteam" rel="noopener noreferrer"&gt;Rustem Galiullin&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2353" rel="noopener noreferrer"&gt;#2353 – add support for custom CVAT task names&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Rusteam" rel="noopener noreferrer"&gt;Rustem Galiullin&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2373" rel="noopener noreferrer"&gt;#2373 – exact frame count support&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/oguz-hanoglu" rel="noopener noreferrer"&gt;Oguz-hanoglu&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2297" rel="noopener noreferrer"&gt;#2297 – improved explanation of sidebar modes in the App&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jwertherUM" rel="noopener noreferrer"&gt;Jamie Werther&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2427" rel="noopener noreferrer"&gt;#2427 – show only supported eval keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/nmanovic" rel="noopener noreferrer"&gt;Nikita Manovich&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2478" rel="noopener noreferrer"&gt;#2478 – Fix several CVAT links&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shortcipher3" rel="noopener noreferrer"&gt;Chris Hall&lt;/a&gt; contributed &lt;a href="https://github.com/voxel51/fiftyone/pull/2561" rel="noopener noreferrer"&gt;#2561 – updated CVAT links&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FiftyOne community updates
&lt;/h2&gt;

&lt;p&gt;The FiftyOne community continues to grow!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,300+ &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack&lt;/a&gt; members&lt;/li&gt;
&lt;li&gt;2,500+ stars on &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;3,000+ &lt;a href="https://www.meetup.com/pro/computer-vision-meetups/" rel="noopener noreferrer"&gt;Meetup members&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/voxel51/fiftyone/network/dependents?package_id=UGFja2FnZS0xNzAxODM0MjUx" rel="noopener noreferrer"&gt;Used by&lt;/a&gt; 245+ repositories&lt;/li&gt;
&lt;li&gt;56+ &lt;a href="https://github.com/voxel51/fiftyone/graphs/contributors" rel="noopener noreferrer"&gt;contributors&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html" rel="noopener noreferrer"&gt;Get started!&lt;/a&gt; We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the FiftyOne &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gratitude</category>
      <category>writing</category>
      <category>career</category>
    </item>
    <item>
      <title>FiftyOne Computer Vision Tips and Tricks – Feb 10, 2023</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Sat, 11 Feb 2023 16:29:04 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-feb-10-2023-52m6</link>
      <guid>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-feb-10-2023-52m6</guid>
      <description>&lt;p&gt;Welcome to our weekly FiftyOne tips and tricks blog where we recap interesting questions and answers that have recently popped up on &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ"&gt;Slack&lt;/a&gt;, &lt;a href="https://github.com/voxel51/fiftyone"&gt;GitHub&lt;/a&gt;, Stack Overflow, and Reddit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what’s FiftyOne?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/fiftyone/"&gt;FiftyOne&lt;/a&gt; is an open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V9vrOSta--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyqflcy6j7jhhjsmdiuv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V9vrOSta--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyqflcy6j7jhhjsmdiuv.gif" alt="open source FiftyOne in action" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html"&gt;Get started&lt;/a&gt;! We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s dive into this week’s tips and tricks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolating spurious or missing objects
&lt;/h2&gt;

&lt;p&gt;Community Slack member George Pearse asked,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Is there a way to just get bounding boxes around the possibly missing and possibly spurious objects in my dataset?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here, George is asking about how to isolate potential mistakes in ground truth labels on a dataset. When working with a new dataset, it is always important to validate the quality of the ground truth annotations. Even highly regarded and well-cited datasets &lt;a href="https://deepomatic.com/how-we-improved-computer-vision-metrics-by-more-than-5-percent-only-by-cleaning-labelling-errors"&gt;can contain a plethora of errors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two such common types of errors in object detection labels are: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A ground truth label was &lt;em&gt;spuriously&lt;/em&gt; added to the data, and does not correspond to an object in the allowed object classes&lt;/li&gt;
&lt;li&gt;An object is not annotated, so the ground truth detection is &lt;em&gt;missing&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fortunately, the &lt;a href="https://docs.voxel51.com/user_guide/brain.html"&gt;FiftyOne Brain&lt;/a&gt; provides a built-in method that identifies possible spurious and missing detections. These are stored at both the sample level and the detection level.&lt;/p&gt;

&lt;p&gt;With FiftyOne’s filtering capabilities, it is easy to create a view containing only the detections that are possibly spurious, or possibly missing, or both. In these cases, you might also find it helpful to convert the filtered view to a &lt;a href="https://docs.voxel51.com/api/fiftyone.core.patches.html#fiftyone.core.patches.PatchView"&gt;PatchView&lt;/a&gt; so you can view each potential error on its own. Here is some code to get you started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
from fiftyone import ViewField as F

## load example dataset
dataset = foz.load_zoo_dataset("quickstart")

## find possible mistakes
fob.compute_mistakenness(dataset, "predictions")

## create a view containing only objects whose
## ground truth detections are possibly missing
pred_field = "predictions"
missing_view = dataset.filter_labels(
    pred_field, 
    F("possible_missing") &amp;gt; 0, 
    only_matches=True
).to_patches(pred_field)

## create a view containing only objects whose
## ground truth detections are possibly spurious
gt_field = "ground_truth"
spurious_view = dataset.filter_labels(
    gt_field, 
    F("possible_spurious") &amp;gt; 0, 
    only_matches=True
).to_patches(gt_field)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then view these in the &lt;a href="https://docs.voxel51.com/user_guide/app.html"&gt;FiftyOne App&lt;/a&gt;. Inspect the possibly spurious detection patches, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session = fo.launch_app(spurious_view)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZDed8Cq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb7zh61kk22id7npw6cs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZDed8Cq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb7zh61kk22id7npw6cs.png" alt="View containing object patches of potentially spurious ground truth detection labels in the FiftyOne Quickstart Dataset, a subset of MS COCO.&amp;lt;br&amp;gt;
" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/tutorials/detection_mistakes.html"&gt;identifying detection mistakes&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Filtering by ID
&lt;/h2&gt;

&lt;p&gt;Community Slack member Sylvia Schmitt asked,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I am storing related sample IDs as &lt;code&gt;StringField&lt;/code&gt; objects in a separate field on my data and I want to use them to match sample IDs that are stored as &lt;code&gt;ObjectIdField&lt;/code&gt; objects. How do I do this?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you were comparing the values in two &lt;code&gt;StringFields&lt;/code&gt;, you could use the &lt;a href="https://docs.voxel51.com/api/fiftyone.core.expressions.html#fiftyone.core.expressions.ViewField"&gt;ViewField&lt;/a&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
from fiftyone import ViewField as F
dataset = fo.Dataset(..)
dataset.match(F('field_a') == F('field_b'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, sample IDs are represented as &lt;code&gt;ObjectIdField&lt;/code&gt; objects. They are stored under an &lt;code&gt;_id&lt;/code&gt; key in the underlying database, and need to be referenced with this same syntax, prepending an underscore. Additionally, the object needs to be converted to a string for the comparison.&lt;/p&gt;

&lt;p&gt;Here is what such a matching operation might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
from fiftyone import ViewField as F

dataset = foz.load_zoo_dataset("quickstart")

# Add a `str_id` field that matches `id` on 10 samples
view = dataset.take(10)
view.set_values("str_id", view.values("id"))

matching_view = dataset.match(
    F("str_id") == F("_id").to_string()
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/basics.html#fields"&gt;fields&lt;/a&gt; and &lt;a href="https://docs.voxel51.com/user_guide/using_views.html#filtering"&gt;filtering&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merging datasets with shared media files
&lt;/h2&gt;

&lt;p&gt;Community Slack member Joy Timmermans asked,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I have three datasets, and some of my samples are in multiple datasets. I’d like to combine all of these datasets into one dataset for export, retaining each copy of each of the samples. How do I do this?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your datasets were created independently, even if there are samples that have the same media files (located at the same file paths), these samples will have different sample IDs. In this case, you can create a combined dataset with the &lt;code&gt;add_collection()&lt;/code&gt; method without passing in any optional arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz

dataset = foz.load_zoo_dataset("quickstart")
ds1 = dataset[:100].clone()
ds2 = dataset[100:].clone()

## create temporary dataset for combining
tmp = ds1.clone()
## add ds2 samples
tmp.add_collection(ds2)

## export
tmp.export(..)
## delete temporary dataset
tmp.delete()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If, on the other hand, your datasets have samples with the same sample IDs, then applying the &lt;code&gt;add_collection()&lt;/code&gt; method without options will only lead to the “combined” dataset having a single copy of each media file. &lt;/p&gt;

&lt;p&gt;Fortunately, you can bypass this by passing in &lt;code&gt;new_ids = True&lt;/code&gt; to &lt;code&gt;add_collection()&lt;/code&gt;. In your case, combining three datasets would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
## start with dataset1, dataset2, dataset3
tmp = dataset1.clone()
tmp.add_collection(dataset2, new_ids = True)
tmp.add_collection(dataset3, new_ids = True)
tmp.export(..)
tmp.delete()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/recipes/merge_datasets.html"&gt;merging datasets&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting GeoJSON annotations
&lt;/h2&gt;

&lt;p&gt;Community Slack member Kais Bedioui asked,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“I am logging some of my production data in GeoJSON format, and I want to save it in the database in that same format. Is there a way to include the &lt;code&gt;ground_truth&lt;/code&gt; label in the &lt;code&gt;labels.json&lt;/code&gt; file so that when I reload the GeoJSON dataset, it comes with its annotations?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To do this, you can use the optional &lt;code&gt;property_makers&lt;/code&gt; argument of the GeoJSON exporter to include additional properties directly in GeoJSON format. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart-geo")
dataset.export(
    labels_path="/tmp/labels.json",
    dataset_type=fo.types.GeoJSONDataset,
    property_makers={"ground_truth": lambda d: len(d.detections)},
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if you want to save the annotations but do &lt;em&gt;not&lt;/em&gt; need to save everything in GeoJSON format, you can export it as a FiftyOne &lt;code&gt;Dataset&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset.export(
    export_dir="/tmp/all",
    dataset_type=fo.types.FiftyOneDataset,
    export_media=False,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you take this approach, all you have to do to load the dataset back in is use FiftyOne’s &lt;code&gt;from_dir()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
dataset = fo.Dataset.from_dir(
    dataset_dir="/tmp/all",
    dataset_type=fo.types.FiftyOneDataset,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/dataset_creation/datasets.html#basic-recipe"&gt;from_dir()&lt;/a&gt;, and &lt;a href="https://docs.voxel51.com/user_guide/dataset_creation/datasets.html#loading-datasets-from-disk"&gt;importing&lt;/a&gt; and &lt;a href="https://docs.voxel51.com/user_guide/export_datasets.html"&gt;exporting data&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking random frames from videos
&lt;/h2&gt;

&lt;p&gt;Community Slack member Joy Timmermans asked,&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Is there an equivalent of &lt;code&gt;take()&lt;/code&gt; for frames in a video dataset so that I can randomly select a subset of frames for each sample?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One way to accomplish this would be to use a Python library for random sampling in conjunction with the &lt;code&gt;select_frames()&lt;/code&gt; method. First, you can use random sampling without replacement to pick a set of frame numbers for each video. Then, you can get the frame &lt;code&gt;id&lt;/code&gt; for each of these frames. Finally, you can pass this list of &lt;code&gt;id&lt;/code&gt;s into &lt;code&gt;select_frames()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s one implementation using numpy’s random choice method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from numpy.random import choice as nrc
import fiftyone as fo
import fiftyone.zoo as foz
from fiftyone import ViewField as F
dataset = foz.load_zoo_dataset("quickstart-video")
## get nested list of frame ids for each sample
frame_ids = dataset.values("frames.id")
## number of frames for each sample
nframes = dataset.values(F("frames").length())
## number of samples in dataset
nsample = len(dataset)
sample_frames = [nrc(nframe, 10, replace=False) for nframe in nframes]
keep_frame_ids = []
for i in range(nsample):
    curr_frame_ids = frame_ids[i]
    for s in sample_frames[i]:
        keep_frame_ids.append(curr_frame_ids[s])
kept_view = dataset.select_frames(keep_frame_ids)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’d like, at this point you can also convert the videos to frames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kept_frames_view = kept_view.to_frames()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/using_views.html#video-views"&gt;video views&lt;/a&gt; and &lt;a href="https://docs.voxel51.com/user_guide/using_views.html#frame-views"&gt;frame views&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the FiftyOne community!
&lt;/h2&gt;

&lt;p&gt;Join the thousands of engineers and data scientists already using FiftyOne to solve some of the most challenging problems in computer vision today!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,300+ &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ"&gt;FiftyOne Slack&lt;/a&gt; members&lt;/li&gt;
&lt;li&gt;2,500+ stars on &lt;a href="https://github.com/voxel51/fiftyone"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;3,000+ &lt;a href="https://www.meetup.com/pro/computer-vision-meetups/"&gt;Meetup members&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/voxel51/fiftyone/network/dependents?package_id=UGFja2FnZS0xNzAxODM0MjUx"&gt;Used by&lt;/a&gt; 241+ repositories&lt;/li&gt;
&lt;li&gt;55+ &lt;a href="https://github.com/voxel51/fiftyone/graphs/contributors"&gt;contributors&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html"&gt;Get started!&lt;/a&gt; We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computervision</category>
      <category>machinelearning</category>
      <category>ai</category>
      <category>datascience</category>
    </item>
    <item>
      <title>FiftyOne Computer Vision Model Evaluation Tips and Tricks – Feb 03, 2023</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Fri, 03 Feb 2023 18:40:54 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/fiftyone-computer-vision-model-evaluation-tips-and-tricks-feb-03-2023-41ne</link>
      <guid>https://forem.com/voxel51-brian/fiftyone-computer-vision-model-evaluation-tips-and-tricks-feb-03-2023-41ne</guid>
      <description>&lt;p&gt;Welcome to our weekly &lt;a href="https://voxel51.com/blog/category/tips-tricks/" rel="noopener noreferrer"&gt;FiftyOne tips and tricks blog&lt;/a&gt; where we give practical pointers for using FiftyOne on topics inspired by discussions in the open source community. This week we’ll cover &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html" rel="noopener noreferrer"&gt;model evaluation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what’s FiftyOne?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/fiftyone/" rel="noopener noreferrer"&gt;FiftyOne&lt;/a&gt; is an open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeoxjznijsbr5v1np6bf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeoxjznijsbr5v1np6bf.gif" alt="Short gif showing key features of open source FiftyOne" width="8" height="4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/" rel="noopener noreferrer"&gt;Get started&lt;/a&gt;! We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s dive into this week’s tips and tricks!&lt;/p&gt;

&lt;h2&gt;
  
  
  A primer on model evaluations
&lt;/h2&gt;

&lt;p&gt;FiftyOne provides a variety of builtin methods for evaluating your model predictions, including regressions, classifications, detections, polygons, instance and semantic segmentations, on both image and video datasets.&lt;/p&gt;

&lt;p&gt;When you evaluate a model in FiftyOne, you get access to the standard &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#aggregate-metrics" rel="noopener noreferrer"&gt;aggregate metrics&lt;/a&gt; such as classification reports, &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#id11" rel="noopener noreferrer"&gt;confusion matrices&lt;/a&gt;, and &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#map-and-pr-curves" rel="noopener noreferrer"&gt;PR curves&lt;/a&gt; for your model. In addition, FiftyOne can also record fine-grained statistics like accuracy and false positive counts at the sample-level, which you can leverage via dataset views and the FiftyOne App to interactively explore the strengths and weaknesses of your models on individual data samples.&lt;/p&gt;

&lt;p&gt;FiftyOne’s model evaluation methods are conveniently exposed as methods on all &lt;code&gt;Dataset&lt;/code&gt; and &lt;code&gt;DatasetView&lt;/code&gt; objects, which means that you can evaluate entire datasets or specific views into them via the same syntax.&lt;/p&gt;

&lt;p&gt;Continue reading for some tips and tricks to help you master evaluations in FiftyOne!&lt;/p&gt;

&lt;h2&gt;
  
  
  Task-specific evaluation methods
&lt;/h2&gt;

&lt;p&gt;In FiftyOne, the Evaluation API supports common computer vision tasks like object detection and classification with default evaluation methods that implement some of the standard routines in the field. For standard object detection, for instance, the default evaluation style is MS COCO. In most other cases, the default evaluation style is denoted &lt;code&gt;"simple"&lt;/code&gt;. If the default style for a given task is what you are looking for, then there is no need to specify the &lt;code&gt;method&lt;/code&gt; argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
results = dataset.evaluate_detections(
    "predictions", 
    gt_field = "ground_truth"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can explicitly specify a method to use for model evaluation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataset.evaluate_detections(
    "predictions", 
    gt_field = "ground_truth", 
    method = "open-images"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each evaluation method has an associated evaluation config, which specifies what arguments can be passed into the evaluation routine when using that style of evaluation. For &lt;a href="https://docs.voxel51.com/api/fiftyone.utils.eval.activitynet.html#fiftyone.utils.eval.activitynet.ActivityNetEvaluationConfig" rel="noopener noreferrer"&gt;ActivityNet style evaluation&lt;/a&gt;, for example, you can pass in an &lt;code&gt;iou&lt;/code&gt; argument specifying the IoU threshold to use, and you can pass in &lt;code&gt;compute_mAP = True&lt;/code&gt; to tell the method to compute the mean average precision. &lt;/p&gt;

&lt;p&gt;To see which label types are available for a dataset, check out the section detailing that dataset in the FiftyOne Dataset Zoo documentation.&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/tutorials/evaluate_detections.html" rel="noopener noreferrer"&gt;evaluating object detections&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluations on views
&lt;/h2&gt;

&lt;p&gt;All methods in FiftyOne’s Evaluation API that are applicable to &lt;code&gt;Dataset&lt;/code&gt; instances are also exposed to &lt;code&gt;DatasetView&lt;/code&gt;. This means that you can compute evaluations on subsets of your dataset obtained through filtering, matching, and chaining together any number of view stages. &lt;/p&gt;

&lt;p&gt;As an example, we can evaluate detections only on samples that are highly &lt;a href="https://docs.voxel51.com/tutorials/uniqueness.html" rel="noopener noreferrer"&gt;unique&lt;/a&gt; in our dataset, and which have fewer than 10 predicted detections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.brain as fob
import fiftyone.zoo as foz
from fiftyone import ViewField as F
## compute uniqueness of each sample
fob.compute_uniqueness(dataset)
dataset = foz.load_zoo_dataset("quickstart")
## create DatasetView with 50 most unique images
unique_view = dataset.sort_by(
    "uniqueness", 
    reverse=True
).limit(50)
## get only the unique images with fewer than 10 predicted detections
few_pred_unique_view = unique_view.match(
    F("predictions.detections").length() &amp;lt; 10
)
## evaluate detections for this view
few_pred_unique_view.evaluate_detections(
    "predictions", 
    gt_field="ground_truth",
    eval_key="eval_few_unique"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about the &lt;a href="https://docs.voxel51.com/user_guide/brain.html" rel="noopener noreferrer"&gt;FiftyOne Brain&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plotting interactive confusion matrices
&lt;/h2&gt;

&lt;p&gt;For classification and detection evaluations, FiftyOne’s evaluation routines generate &lt;a href="https://en.wikipedia.org/wiki/Confusion_matrix" rel="noopener noreferrer"&gt;confusion matrices&lt;/a&gt;. You can plot these confusion matrices in FiftyOne with the &lt;code&gt;plot_confusion_matrix()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
## generate evaluation results
results = dataset.evaluate_detections(
    "predictions", 
    gt_field = "ground_truth"
)
## plot confusion matrix
classes = ["person", "kite", "car", "bird"]
plot = results.plot_confusion_matrix(classes=classes)
plot.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the confusion matrix is implemented in &lt;a href="https://plotly.com/python/" rel="noopener noreferrer"&gt;plotly&lt;/a&gt;, it is interactive! To interact visually with your data via the confusion matrix, attach the plot to a session launched with the dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## create a session and attach plot
session = fo.launch_app(dataset)
session.plots.attach(plot)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clicking into a cell in the confusion matrix then changes which samples appear in the sample grid in the &lt;a href="https://docs.voxel51.com/user_guide/app.html" rel="noopener noreferrer"&gt;FiftyOne App&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ljcm01swcsvib01ym56.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ljcm01swcsvib01ym56.gif" alt="confusion matrix in FiftyOne App" width="1536" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/plots.html" rel="noopener noreferrer"&gt;interactive plotting&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating frames of a video
&lt;/h2&gt;

&lt;p&gt;All of the evaluation methods in FiftyOne’s Evaluation API can be applied to frame-level labels in addition to sample-level labels. This means that you can evaluate video samples without needing to convert the frames of a video sample to standalone image samples. &lt;/p&gt;

&lt;p&gt;Applying FiftyOne evaluation methods to video frames also has the added benefit that useful statistics are computed at both the frame and sample levels. For instance, the following code populates the fields &lt;code&gt;eval_tp&lt;/code&gt;, &lt;code&gt;eval_fp&lt;/code&gt;, and &lt;code&gt;eval_fn&lt;/code&gt; as summary statistics on the sample level, containing the total number of true positives, false positives, and false negatives across all frames in the sample. Additionally, on each frame, the evaluation populates an &lt;code&gt;eval&lt;/code&gt; field for each detection with a value of either &lt;code&gt;tp&lt;/code&gt;, &lt;code&gt;fp&lt;/code&gt;, or &lt;code&gt;fn&lt;/code&gt;, as well as an &lt;code&gt;eval_iou&lt;/code&gt; field where appropriate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset(
    "quickstart-video", 
    dataset_name="video-eval-demo"
)
## Create some test predictions 
classes = dataset.distinct("frames.detections.detections.label")
def jitter(val):
    if random.random() &amp;lt; 0.10:
        return random.choice(classes)
    return val
predictions = []
for sample_gts in dataset.values("frames.detections"):
    sample_predictions = []
    for frame_gts in sample_gts:
        sample_predictions.append(
            fo.Detections(
                detections=[
                    fo.Detection(
                        label=jitter(gt.label),
                        bounding_box=gt.bounding_box,
                        confidence=random.random(),
                    )
                    for gt in frame_gts.detections
                ]
            )
        )
    predictions.append(sample_predictions)
dataset.set_values("frames.predictions", predictions)
dataset.evaluate_detections(
    "frames.predictions",
    gt_field="frames.detections",
    eval_key="eval",
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the only difference in practice is the prefix “frames” used to specify the predictions field and the ground truth field.  &lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/using_views.html#video-views" rel="noopener noreferrer"&gt;video views&lt;/a&gt; and &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#evaluating-videos" rel="noopener noreferrer"&gt;evaluating videos&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing multiple evaluations
&lt;/h2&gt;

&lt;p&gt;With all of the flexibility the Evaluation API provides, you’d be well within reason to wonder what evaluation you should perform. Fortunately, FiftyOne makes it easy to perform, manage, and store the results from multiple evaluations!&lt;/p&gt;

&lt;p&gt;The results from each evaluation can be stored and accessed via an evaluation key, specified by the &lt;code&gt;eval_key&lt;/code&gt; argument. This allows you to compare different evaluation methods on the same data,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz
dataset = foz.load_zoo_dataset("quickstart")
dataset.evaluate_detections(
    "predictions", 
    gt_field = "ground_truth", 
    method = "coco", 
    eval_key = "coco_eval"
)
dataset.evaluate_detections(
    "predictions", 
    gt_field = "ground_truth", 
    method = "open-images", 
    eval_key = "oi_eval"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;evaluate predictions generated by multiple models,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataset.evaluate_detections(
    "model1_predictions", 
    gt_field = "ground_truth", 
    eval_key = "model1_eval"
)
dataset.evaluate_detections(
    "model2_predictions", 
    gt_field = "ground_truth", 
    eval_key = "model2_eval"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or compare evaluations on different subsets or views of your data, such as a view with only small bounding boxes and a view with only large bounding boxes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fiftyone import ViewField as F
bbox_area = (
    F("bounding_box")[2] *
    F("bounding_box")[3]
)
large_boxes = bbox_area &amp;gt; 0.7
small_boxes = bbox_area &amp;lt; 0.3
# Create a view that contains only small-sized objects
small_view = (
    dataset
    .filter_labels(
        "ground_truth", 
        small_boxes
    )
)
# Create a view that contains only large-sized objects
large_view = (
    dataset
    .filter_labels(
        "ground_truth", 
        large_boxes
    )
)
small_view.evaluate_detections(
    "predictions",
    gt_field="ground_truth",
    eval_key="eval_small",
)
large_view.evaluate_detections(
    "predictions",
    gt_field="ground_truth",
    eval_key="eval_large",
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about &lt;a href="https://docs.voxel51.com/user_guide/evaluation.html#managing-evaluations" rel="noopener noreferrer"&gt;managing model evaluations&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Join the FiftyOne community!
&lt;/h2&gt;

&lt;p&gt;Join the thousands of engineers and data scientists already using FiftyOne to solve some of the most challenging problems in computer vision today!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,300+ &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack&lt;/a&gt; members&lt;/li&gt;
&lt;li&gt;2,500+ stars on &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2,900+ &lt;a href="https://www.meetup.com/pro/computer-vision-meetups/" rel="noopener noreferrer"&gt;Meetup members&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/voxel51/fiftyone/network/dependents?package_id=UGFja2FnZS0xNzAxODM0MjUx" rel="noopener noreferrer"&gt;Used by&lt;/a&gt; 241+ repositories&lt;/li&gt;
&lt;li&gt;55+ &lt;a href="https://github.com/voxel51/fiftyone/graphs/contributors" rel="noopener noreferrer"&gt;contributors&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, give the &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;FiftyOne project a star&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.voxel51.com/" rel="noopener noreferrer"&gt;Get started with FiftyOne&lt;/a&gt;! We’ve made it easy to get up and running in a few minutes.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;FiftyOne Slack community&lt;/a&gt;, we’re always happy to help.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>ethereum</category>
      <category>web3</category>
      <category>crypto</category>
    </item>
    <item>
      <title>FiftyOne Computer Vision Tips and Tricks - Sept 30, 2022</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Fri, 30 Sep 2022 15:07:04 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-sept-30-2022-1b49</link>
      <guid>https://forem.com/voxel51-brian/fiftyone-computer-vision-tips-and-tricks-sept-30-2022-1b49</guid>
      <description>&lt;p&gt;Welcome to our weekly FiftyOne tips and tricks blog where we recap interesting questions and answers that have recently popped up on &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;Slack&lt;/a&gt;, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, Stack Overflow, and Reddit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what’s FiftyOne?
&lt;/h2&gt;

&lt;p&gt;FiftyOne is an open source machine learning toolset that enables data science teams to improve the performance of their computer vision models by helping them curate high quality datasets, evaluate models, find mistakes, visualize embeddings, and get to production faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnro7iicvktx25rqcjpr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnro7iicvktx25rqcjpr.gif" alt="fiftyone in action gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html" rel="noopener noreferrer"&gt;Get started&lt;/a&gt;: we’ve made it easy to get up and running in a few minutes&lt;/li&gt;
&lt;li&gt;Join the FiftyOne &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;, we’re always happy to help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let’s dive into this week’s tips and tricks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom plugins for the FiftyOne App
&lt;/h2&gt;

&lt;p&gt;Community Slack member Gerard Corrigan asked,&lt;/p&gt;

&lt;p&gt;“I’d like to integrate FiftyOne with another app. How can I do that?”&lt;/p&gt;

&lt;p&gt;With the latest &lt;a href="https://medium.com/voxel51/announcing-fiftyone-0-17-0-with-grouped-datasets-3d-geolocation-and-custom-plugins-339600ab73a1" rel="noopener noreferrer"&gt;FiftyOne 0.17.0&lt;/a&gt; release you can now customize and extend the FiftyOne App’s behavior. For example, if you need a unique way to visualize individual samples, plot entire datasets, or fetch FiftyOne data, a custom plugin just might be the ticket!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcq055du81xssi3ml8vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcq055du81xssi3ml8vl.png" alt="custom plugin in FiftyOne"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Learn more about &lt;a href="https://github.com/voxel51/fiftyone/blob/develop/app/packages/plugins/README.md" rel="noopener noreferrer"&gt;how to develop custom plugins&lt;/a&gt; for the FiftyOne App on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exporting visualization options from the FiftyOne App
&lt;/h2&gt;

&lt;p&gt;Community Slack member Murat Aksoy asked,&lt;/p&gt;

&lt;p&gt;“Is there a way to export videos from the FiftyOne App? Specifically after an end-user makes adjustments to visualization options such as which labels to show, opacity, etc?”&lt;/p&gt;

&lt;p&gt;The best workflow to accomplish this would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactively select/filter in the FiftyOne App in IPython/notebook&lt;/li&gt;
&lt;li&gt;Press the “bookmark” icon to save your current filters into the view bar&lt;/li&gt;
&lt;li&gt;Render the labels for the current view from Python via:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;session.view.draw_labels(...)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;drawlabels()&lt;/code&gt; method provides a bunch of options for configuring the look-and-feel of the exported labels, including font sizes, transparency, etc.&lt;/p&gt;

&lt;p&gt;In a nutshell, you can use the FiftyOne App to visually filter, but you must use &lt;code&gt;drawlabels()&lt;/code&gt; in Python to trigger the rendering and provide any look-and-feel customizations you want, like transparency.&lt;/p&gt;

&lt;p&gt;Learn more about the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/draw_labels.html" rel="noopener noreferrer"&gt;&lt;code&gt;drawlabels()&lt;/code&gt; method&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving aggregations per video
&lt;/h2&gt;

&lt;p&gt;Community Slack member Tadej Svetina asked,&lt;/p&gt;

&lt;p&gt;“I have a video dataset and I am interested in getting some aggregations (let’s say count of detections) per video. How do I do that?”&lt;/p&gt;

&lt;p&gt;You can actually use the values() aggregation for this along with some pretty advanced view expression usage. Specifically, you can reduce the frames in each video to a single value based on the length of the detections in a field of each video. For example, here’s a way to get the number of detections in every video of the dataset.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Or you can modify this code slightly to get a dictionary mapping of video IDs to the number of objects in each video:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;id_num_objects_map = dict(zip(*dataset.values(["id", num_objects])))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Learn more about how to use &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.expressions.html#fiftyone.core.expressions.ViewExpression.reduce" rel="noopener noreferrer"&gt;&lt;code&gt;reduce()&lt;/code&gt;&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with polylines and labels using the CVAT integration
&lt;/h2&gt;

&lt;p&gt;Community Slack member Guillaume Dumont asked,&lt;/p&gt;

&lt;p&gt;“I am using the CVAT integration with a local CVAT server and somehow, in the cases where the polylines have the same &lt;code&gt;label_id&lt;/code&gt;, the last one would override the previous one when downloading annotations. This ended up leaving a single polyline where I expected there to be many. Any ideas what’s going on here?”&lt;/p&gt;

&lt;p&gt;When calling &lt;code&gt;to_polylines()&lt;/code&gt; you want to make sure to use the &lt;code&gt;mask_types="thing"&lt;/code&gt; rather than the default &lt;code&gt;mask_types="stuff"&lt;/code&gt; which will give each segment a unique ID. You can also directly annotate semantic segmentation masks and let FiftyOne manage the conversion to polylines for you.&lt;/p&gt;

&lt;p&gt;Here’s the relevant snippet from &lt;a href="https://voxel51.com/docs/fiftyone/api/fiftyone.core.labels.html?highlight=mask#fiftyone.core.labels.Segmentation.to_detections" rel="noopener noreferrer"&gt;the Docs&lt;/a&gt; in regards to mask_types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`mask_types`(“stuff”) — whether the classes are “stuff” (amorphous regions of pixels) or “thing” (connected regions, each representing an instance of the thing).

Can be any of the following:

- “stuff” if all classes are stuff classes

- “thing” if all classes are thing classes

- a dict mapping pixel values to “stuff” or “thing” for each class
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Learn more about the &lt;a href="https://voxel51.com/docs/fiftyone/integrations/cvat.html?highlight=cvat" rel="noopener noreferrer"&gt;CVAT integration&lt;/a&gt; and &lt;code&gt;to_polylines()&lt;/code&gt; and &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_datasets.html#semantic-segmentation" rel="noopener noreferrer"&gt;semantic segmentation&lt;/a&gt; in the FiftyOne Docs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exporting only landscape orientation images
&lt;/h2&gt;

&lt;p&gt;Community Slack member Stan asked,&lt;/p&gt;

&lt;p&gt;“How would I go about exporting only images in a certain orientation, for example landscape vs portrait? I have a script to tag images as landscape by checking if width is greater than height and then removing all images and annotations for the images that are not in the landscape orientation. What would be the FiftyOne approach for this?”&lt;/p&gt;

&lt;p&gt;Here’s a way to isolate landscape image samples, and then remove all other samples, using for example the quickstart dataset:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Learn more about the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/index.html" rel="noopener noreferrer"&gt;FiftyOne Dataset Zoo&lt;/a&gt; quickstart dataset in the FiftyOne Docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you like what you see on GitHub, &lt;a href="https://github.com/voxel51/fiftyone" rel="noopener noreferrer"&gt;give the project a star&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://voxel51.com/docs/fiftyone/index.html" rel="noopener noreferrer"&gt;Get started&lt;/a&gt;: we’ve made it easy to get up and running in a few minutes&lt;/li&gt;
&lt;li&gt;Join the FiftyOne &lt;a href="https://join.slack.com/t/fiftyone-users/shared_invite/zt-s6936w7b-2R5eVPJoUw008wP7miJmPQ" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;, we’re always happy to help&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computervision</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>ai</category>
    </item>
    <item>
      <title>Announcing Our $12.5M Series A Funding to Bring Transparency and Clarity to the World’s Data</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Fri, 23 Sep 2022 17:28:48 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/announcing-our-125m-series-a-funding-to-bring-transparency-and-clarity-to-the-worlds-data-2joj</link>
      <guid>https://forem.com/voxel51-brian/announcing-our-125m-series-a-funding-to-bring-transparency-and-clarity-to-the-worlds-data-2joj</guid>
      <description>&lt;p&gt;We're delighted to announce that we raised $12.5 million in Series A funding from new investors Drive Capital, Top Harvest Capital, and Shasta Ventures as well as existing investors eLab Ventures and ID Ventures. This financing allows us to accelerate the next phase of our growth in bringing data-centric machine learning to the world.&lt;/p&gt;

&lt;p&gt;Since we started &lt;a href="https://voxel51.com/"&gt;Voxel51&lt;/a&gt; in October 2018, we’ve been building open source and commercial software that enables developers, scientists, and organizations to build high-quality datasets and computer vision models that are powering some of today’s most remarkable machine learning and artificial intelligence. Our software provides the infrastructure for these users to analyze and modulate their datasets allowing them to address critical issues like data bias.&lt;/p&gt;

&lt;p&gt;One of our first big milestones was in August 2020 with the launch of the &lt;a href="https://github.com/voxel51/fiftyone"&gt;open source FiftyOne project&lt;/a&gt;. Since then, FiftyOne has seen incredible growth and adoption. Today FiftyOne is used by tens of thousands of engineers and scientists and has reached 150,000+ monthly active machines, 1900+ GitHub stars, and 1000+ members in our Slack community. We’re grateful for everyone in the enthusiastic and growing FiftyOne community — for your support, contributions, and for being a part of this journey with us!&lt;/p&gt;

&lt;p&gt;Late last year, we began working with dozens of startups and Fortune 500 enterprises as early adopters of FiftyOne Teams, our commercial product that enables teams to securely collaborate on their datasets and models. Our early adopters span a variety of industries — automotive, robotics, security, retail, healthcare, and more — including large organizations, which are typically risk averse; a testament to the utility and value that FiftyOne Teams provides! By providing us with real-world usage, input, and feedback, our early adopters helped us shape and harden the &lt;a href="https://voxel51.com/fiftyone-teams/"&gt;FiftyOne Teams&lt;/a&gt; solution that we’re publicly announcing today. (You can find the full press release &lt;a href="https://www.prnewswire.com/news-releases/voxel51-raises-12-5m-series-a-to-bring-transparency-and-clarity-to-computer-vision-data-301629679.html"&gt;here&lt;/a&gt;.) A huge shoutout and thank you to all of our early adopters for making FiftyOne Teams ready for the broader ML/AI community to enjoy!&lt;/p&gt;

&lt;p&gt;So… what’s next for Voxel51? It’s no secret that there has been an explosion of visual data. For example, there are an estimated &lt;a href="https://www.ldv.co/blog/2017/8/8/45-billion-cameras-by-2022-fuel-business-opportunities"&gt;45 billion cameras&lt;/a&gt; in the world today, and the growth will continue to accelerate for decades. This creates a tremendous opportunity for computer vision applications, but only if the data can be properly organized, indexed, and labeled.&lt;/p&gt;

&lt;p&gt;As Voxel51 enters its next phase of growth, we’re doubling down on our commitment to build FiftyOne alongside the community so that it remains the leading open source tool for building high-quality datasets and computer vision models. We’re also accelerating the development of FiftyOne Teams as critical and trusted infrastructure for managing organization’s visual data, enabling them to build machine learning systems based on high quality, transparent data that brings their ML-powered products to market faster.&lt;/p&gt;

&lt;p&gt;We’re going to need many more exceptional and diverse people to achieve our mission of bringing transparency and clarity to the world’s data. If our mission excites you, check out our &lt;a href="https://voxel51.com/jobs/"&gt;open positions across product, engineering, community, and more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you to everyone who has supported Voxel51 over the years — our amazing team, investors, customers, partners, and open source community. Today is a significant milestone on our journey and I’m excited for many more to come!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>computervision</category>
      <category>ai</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Nearest Neighbor Embeddings Search with Qdrant and FiftyOne</title>
      <dc:creator>Voxel51-Brian</dc:creator>
      <pubDate>Thu, 21 Jul 2022 18:52:49 +0000</pubDate>
      <link>https://forem.com/voxel51-brian/nearest-neighbor-embeddings-search-with-qdrant-and-fiftyone-32ef</link>
      <guid>https://forem.com/voxel51-brian/nearest-neighbor-embeddings-search-with-qdrant-and-fiftyone-32ef</guid>
      <description>&lt;p&gt;Neural network embeddings are a low-dimensional representation of input data that give rise to a variety of applications. Embeddings have some interesting capabilities, as they are able to capture the semantics of the data points. This is especially useful for unstructured data like images and videos, so you can not only encode pixel similarities but also some more complex relationships.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ywh46j7dhc0q9drfbr1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ywh46j7dhc0q9drfbr1.png" alt="Embeddings from the [BDD100K dataset](https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/datasets.html?highlight=bdd100k#dataset-zoo-bdd100k) visualized using [FiftyOne](https://voxel51.com/docs/fiftyone/) and [Plotly](https://voxel51.com/docs/fiftyone/user_guide/plots.html)"&gt;&lt;/a&gt;&lt;em&gt;Embeddings from the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/datasets.html?highlight=bdd100k#dataset-zoo-bdd100k" rel="noopener noreferrer"&gt;BDD100K dataset&lt;/a&gt; visualized using &lt;a href="https://voxel51.com/docs/fiftyone/" rel="noopener noreferrer"&gt;FiftyOne&lt;/a&gt; and &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/plots.html" rel="noopener noreferrer"&gt;Plotly&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Performing searches over these embeddings gives rise to a lot of use cases like classification, building up the recommendation systems, or even anomaly detection. One of the primary benefits of performing a nearest neighbor search on embeddings to accomplish these tasks is that there is no need to create a custom network for every new problem, you can often just use pre-trained models. In fact, it is possible to use the embeddings generated by some publicly available models without any further finetuning.&lt;/p&gt;

&lt;p&gt;While there are a lot of powerful use cases that involve embeddings, there are a number of challenges in workflows performing searches over embeddings. Specifically, performing a nearest neighbor search on a large dataset and then being able to effectively act on the results of the search, for example performing workflows like auto-labeling of data, are both technical and tooling challenges. To that end, Qdrant and FiftyOne can help make these workflows effortless.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt; is an open-source vector database designed to perform an approximate nearest neighbor search (ANN) on dense neural embeddings which is necessary for any production-ready system that is expected to scale to large amounts of data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://voxel51.com/docs/fiftyone/" rel="noopener noreferrer"&gt;FiftyOne&lt;/a&gt; is an open-source dataset curation and model evaluation tool that allows you to effectively manage and visualize your dataset, generate embeddings, and improve your model results.&lt;/p&gt;

&lt;p&gt;In this article, we’re going to load the MNIST dataset into FiftyOne and perform the classification based on ANN, so the data points will be classified by selecting the most common ground truth label among the K nearest points from our training dataset. In other words, for each test example, we’re going to select its K nearest neighbors, using a chosen distance function, and then just select the best label by voting. All that search in the vector space will be done with Qdrant, to speed things up. We will then evaluate the results of this classification in FiftyOne.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;If you want to start using the semantic search with Qdrant, you need to run an instance of it, as this tool works in a client-server manner. The easiest way to do this is to use an official Docker image and start Qdrant with just a single command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -p “6333:6333” -p “6334:6334” -d qdrant/qdrant&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After running the command we’ll have the Qdrant server running, with HTTP API exposed at port 6333 and gRPC interface at 6334.&lt;/p&gt;

&lt;p&gt;We will also need to install a few Python packages. We’re going to use FiftyOne to visualize the data, along with their ground truth labels and the ones predicted by our embeddings similarity model. The embeddings will be created by MobileNet v2, available in torchvision. Of course, we need to communicate to Qdrant server somehow as well, and since we’re going to use Python, qdrant_client is a preferred way of doing that.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install fiftyone&lt;br&gt;
pip install torchvision&lt;br&gt;
pip install qdrant_client&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Processing pipeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Loading the dataset&lt;/li&gt;
&lt;li&gt;Generating embeddings&lt;/li&gt;
&lt;li&gt;Loading embeddings into Qdrant&lt;/li&gt;
&lt;li&gt;Nearest neighbor classification&lt;/li&gt;
&lt;li&gt;Evaluation in FiftyOne&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Loading the dataset
&lt;/h3&gt;

&lt;p&gt;There are several steps we need to take to get things running smoothly. First of all, we need to load the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/datasets.html#mnist" rel="noopener noreferrer"&gt;MNIST dataset&lt;/a&gt; and extract the train examples from it, as we’re going to use them in our search operations. To make everything even faster, we’re not going to use all the examples, but just 2500 samples. We can use the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/dataset_zoo/index.html" rel="noopener noreferrer"&gt;FiftyOne Dataset Zoo&lt;/a&gt; to load the subset of MNIST we want in just one line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fiftyone as fo
import fiftyone.zoo as foz

# Load the data
dataset = foz.load_zoo_dataset("mnist", max_samples=2500)

# Get all training samples
train_view = dataset.match_tags(tags=["train"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s start by taking a look at the dataset in the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/app.html" rel="noopener noreferrer"&gt;FiftyOne App&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Visualize the dataset in FiftyOne
session = fo.launch_app(train_view)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03zy78sdep0i1809mv0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03zy78sdep0i1809mv0r.png" alt="subset of MNIST data visualized"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating embeddings
&lt;/h3&gt;

&lt;p&gt;The next step is to generate embeddings on the samples in the dataset. This can always be done outside of FiftyOne, with your own custom models. However, FiftyOne also provides various different models in the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/model_zoo/index.html" rel="noopener noreferrer"&gt;FiftyOne Model Zoo&lt;/a&gt; that can be used right out of the box to generate embeddings.&lt;/p&gt;

&lt;p&gt;In this example, we use &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/model_zoo/models.html#mobilenet-v2-imagenet-torch" rel="noopener noreferrer"&gt;MobileNetv2&lt;/a&gt; trained on ImageNet to compute an embedding for each image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Compute embeddings
model = foz.load_zoo_model("mobilenet-v2-imagenet-torch")

train_embeddings = train_view.compute_embeddings(model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loading embeddings into Qdrant
&lt;/h3&gt;

&lt;p&gt;Qdrant allows storing not only vectors but also some corresponding attributes — each data point has a related vector and optionally a JSON payload attached to it. We want to use this to pass in the ground truth label to make sure we can make our prediction later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ground_truth_labels = train_view.values("ground_truth.label")
train_payload = [
    {"ground_truth": gt} for gt in ground_truth_labels
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having the embedding created, we can simply start communicating with the Qdrant server. An instance of &lt;code&gt;QdrantClient&lt;/code&gt; is then helpful, as it encloses all the required methods. Let’s connect and create a collection of points, simply called &lt;code&gt;“mnist”&lt;/code&gt;. The vector size is dependent on the model output, so if we want to experiment with a different model another day, then we will just need to import a different one, but the rest will be kept the same. Eventually, after making sure the collection exists, we can send all the vectors along with their payloads containing their true labels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import qdrant_client as qc
from qdrant_client.http.models import Distance

# Load the train embeddings into Qdrant
def create_and_upload_collection(
    embeddings, payload, collection_name="mnist"
):
    client = qc.QdrantClient(host="localhost")
    client.recreate_collection(
        collection_name=collection_name,
        vector_size=embeddings.shape[1],
        distance=Distance.COSINE,
    )
    client.upload_collection(
        collection_name=collection_name,
        vectors=embeddings,
        payload=payload,
    )
    return client

client = create_and_upload_collection(train_embeddings, train_payload)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nearest neighbor classification
&lt;/h3&gt;

&lt;p&gt;Now to perform inference on the dataset. We can create the embeddings for our test dataset, but just ignore the ground truth and try to find it out using ANN, then compare if both match. Let’s take one step at a time and start with creating the embeddings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Assign the labels to test embeddings by selecting
# the most common label among the neighbours of each sample
test_view = dataset.match_tags(tags=["test"])
test_embeddings = test_view.compute_embeddings(model)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Time for some magic. Let’s simply iterate through the test dataset’s samples and their corresponding embeddings, and use the search operation to find the 15 closest embeddings from the training set. We’ll also need to select the payloads, as they contain the ground truth labels which are required to find the most common label in the neighborhood of a particular point. Python’s &lt;code&gt;Counter&lt;/code&gt; class will be helpful to avoid any boilerplate code. The most common label will be stored as an &lt;code&gt;“ann_prediction”&lt;/code&gt; on each test sample in FiftyOne.&lt;/p&gt;

&lt;p&gt;This is encompassed in the function below which takes an embedding vector as input, uses the Qdrant search capability to find the nearest neighbors to the test embedding, generates a class prediction, and returns a FiftyOne &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_datasets.html#classification" rel="noopener noreferrer"&gt;Classification&lt;/a&gt; object that we can store in our &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_datasets.html" rel="noopener noreferrer"&gt;FiftyOne dataset&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import collections
from tqdm import tqdm

def generate_fiftyone_classification(
    embedding, collection_name="mnist"
):
    search_results = client.search(
        collection_name=collection_name,
        query_vector=embedding,
        with_payload=True,
        top=15,
    )
    # Count the occurrences of each class and select the most common label
    # with the confidence estimated as the number of occurrences of 
    # the most common label divided by a total number of results.
    counter = collections.Counter(
        [point.payload["ground_truth"] for point in search_results]
    )
    predicted_class, occurences_num = counter.most_common(1)[0]
    confidence = occurences_num / sum(counter.values())
    prediction = fo.Classification(
        label=predicted_class, confidence=confidence
    )
    return prediction

predictions = []

# Call Qdrant to find the closest data points
for embedding in tqdm(test_embeddings):
    prediction = generate_fiftyone_classification(embedding)
    predictions.append(prediction)

test_view.set_values("ann_prediction", predictions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, we estimated the confidence by calculating the fraction of samples belonging to the most common label. That gives us an intuition of how sure we were while predicting the label for each case and can be used in FiftyOne to easily spot confusing examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluation in FiftyOne
&lt;/h3&gt;

&lt;p&gt;It’s high time for some results! Let’s start by visualizing how this classifier has performed. We can easily launch the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/app.html" rel="noopener noreferrer"&gt;FiftyOne App&lt;/a&gt; to view the ground truth, predictions, and images themselves.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;session = fo.launch_app(test_view)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uecwota1yfcxx86vbjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uecwota1yfcxx86vbjb.png" alt="Viewing ground truth, predictions, and images in FiftyOne"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FiftyOne provides a variety of built-in &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/evaluation.html" rel="noopener noreferrer"&gt;methods for evaluating your model&lt;/a&gt; predictions, including regressions, classifications, detections, polygons, instance and semantic segmentations, on both image and video datasets. In two lines of code, we can compute and print an evaluation report of our &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/evaluation.html#classifications" rel="noopener noreferrer"&gt;classifier&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Evaluate the ANN predictions, with respect to the values in ground_truth
results = test_view.evaluate_classifications(
    "ann_prediction", gt_field="ground_truth", eval_key="eval_simple"
)

# Display the classification metrics
results.print_report()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;precision    recall  f1-score   support

    0 - zero       0.87      0.98      0.92       219
     1 - one       0.94      0.98      0.96       287
     2 - two       0.87      0.72      0.79       276
   3 - three       0.81      0.87      0.84       254
    4 - four       0.84      0.92      0.88       275
    5 - five       0.76      0.77      0.77       221
     6 - six       0.94      0.91      0.93       225
   7 - seven       0.83      0.81      0.82       257
   8 - eight       0.95      0.91      0.93       242
    9 - nine       0.94      0.87      0.90       244

    accuracy                           0.87      2500
   macro avg       0.88      0.87      0.87      2500
weighted avg       0.88      0.87      0.87      2500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After performing the evaluation in FiftyOne, we can use the results object to generate an &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/plots.html#confusion-matrices" rel="noopener noreferrer"&gt;interactive confusion matrix&lt;/a&gt; allowing us to click on cells and automatically update the App to show the corresponding samples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plot = results.plot_confusion_matrix()
plot.show()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn70ah4m9byhi7f962s26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn70ah4m9byhi7f962s26.png" alt="confusion matrix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s dig in a bit further. We can use the &lt;a href="https://voxel51.com/docs/fiftyone/user_guide/using_views.html#filtering" rel="noopener noreferrer"&gt;sophisticated query language&lt;/a&gt; of FiftyOne to easily find all predictions that did not match the ground truth, yet were predicted with high confidence. These will generally be the most confusing samples for the dataset and the ones from which we can gather the most insight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from fiftyone import ViewField as F

# Display FiftyOne app, but include only the wrong predictions that 
# were predicted with high confidence
false_view = (
    test_view
    .match(F("eval_simple") == False)
    .filter_labels("ann_prediction", F("confidence") &amp;gt; 0.7)
)
session.view = false_view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh57du0rjzq6sz389id9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh57du0rjzq6sz389id9.png" alt="view updated mnist data sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the most confusing samples for the model and, as you can see, they are fairly irregular compared to other images in the dataset. A next step we could take to improve the performance of the model could be to use FiftyOne to curate additional samples similar to these. From there, those samples can then be annotated through the integrations between FiftyOne and tools like &lt;a href="https://voxel51.com/docs/fiftyone/integrations/cvat.html" rel="noopener noreferrer"&gt;CVAT&lt;/a&gt; and &lt;a href="https://voxel51.com/docs/fiftyone/integrations/labelbox.html" rel="noopener noreferrer"&gt;Labelbox&lt;/a&gt;. Additionally, we could use some more vectors for training or just perform a fine-tuning of the model with similarity learning, for example using the triplet loss. But right now this example of using FiftyOne and Qdrant for vector similarity classification is working pretty well already.&lt;/p&gt;

&lt;p&gt;And that’s it! As simple as that, we created an ANN classification model using FiftyOne with Qdrant as an embeddings backend, so finding the similarity between vectors can stop being a bottleneck as it would in the case of a traditional k-NN.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://colab.research.google.com/github/voxel51/fiftyone-examples/blob/feature/qdrant-recipe/examples/Qdrant_FiftyOne_Recipe.ipynb" rel="noopener noreferrer"&gt;Click here for the notebook&lt;/a&gt; containing the source code of what you saw in this. Additionally, it includes a realistic use case of this process to perform pre-annotation of night and day attributes on the BDD100K road-scene dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;FiftyOne and Qdrant can be used together to efficiently perform a nearest neighbor search on embeddings and act on the results on your image and video datasets. The beauty of this process lies in its flexibility and repeatability. You can easily load additional ground truth labels for new fields into both FiftyOne and Qdrant and repeat this pre-annotation process using the existing embeddings. This can quickly cut down on annotation costs and result in higher-quality datasets, faster.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This blog post was made in collaboration between the teams at &lt;a href="https://qdrant.tech/" rel="noopener noreferrer"&gt;Qdrant&lt;/a&gt; and &lt;a href="https://voxel51.com/" rel="noopener noreferrer"&gt;Voxel51&lt;/a&gt; and is co-authored by &lt;a href="https://www.linkedin.com/in/kacperlukawski/" rel="noopener noreferrer"&gt;Kacper Łukawski&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/eric-hofesmann/" rel="noopener noreferrer"&gt;Eric Hofesmann&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>computervision</category>
      <category>datascience</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
