Поиск вкраплений ближайших соседей с помощью Qdrant и FiftyOne

Вкрапления нейронных сетей — это низкоразмерное представление входных данных, которое находит разнообразные применения. Эмбеддинги обладают некоторыми интересными возможностями, поскольку они способны улавливать семантику точек данных. Это особенно полезно для неструктурированных данных, таких как изображения и видео, так как можно закодировать не только сходство пикселей, но и некоторые более сложные взаимосвязи.

Вкрапления из набора данных BDD100K, визуализированные с помощью FiftyOne и Plotly

Выполнение поиска по этим эмбеддингам дает множество вариантов использования, таких как классификация, построение рекомендательных систем или даже обнаружение аномалий. Одним из основных преимуществ выполнения поиска ближайших соседей по вкраплениям для решения этих задач является то, что нет необходимости создавать собственную сеть для каждой новой задачи, часто можно просто использовать предварительно обученные модели. Фактически, можно использовать вкрапления, сгенерированные некоторыми общедоступными моделями, без какой-либо дополнительной настройки.

Несмотря на то, что существует множество мощных вариантов использования вкраплений, в рабочих процессах, выполняющих поиск по вкраплениям, есть ряд проблем. В частности, выполнение поиска ближайших соседей в большом наборе данных, а затем возможность эффективно действовать на основе результатов поиска, например, выполнять такие рабочие процессы, как автоматическая маркировка данных, является как технической, так и инструментальной задачей. С этой целью Qdrant и FiftyOne могут помочь сделать эти рабочие процессы легкими.

Qdrant — это векторная база данных с открытым исходным кодом, предназначенная для выполнения приблизительного поиска ближайших соседей (ANN) на плотных нейронных вкраплениях, что необходимо для любой готовой к производству системы, которая должна масштабироваться на большие объемы данных.

FiftyOne — это инструмент для курации наборов данных и оценки моделей с открытым исходным кодом, который позволяет эффективно управлять и визуализировать набор данных, генерировать вкрапления и улучшать результаты моделирования.

В этой статье мы загрузим набор данных MNIST в FiftyOne и выполним классификацию на основе ANN, то есть точки данных будут классифицированы путем выбора наиболее распространенной метки истинности среди K ближайших точек из нашего обучающего набора данных. Другими словами, для каждого тестового примера мы выберем K ближайших соседей, используя выбранную функцию расстояния, а затем просто выберем лучшую метку путем голосования. Весь этот поиск в векторном пространстве будет выполняться с помощью Qdrant, чтобы ускорить процесс. Затем мы оценим результаты этой классификации в FiftyOne.

Установка

Если вы хотите начать использовать семантический поиск с Qdrant, вам нужно запустить его экземпляр, поскольку этот инструмент работает по принципу клиент-сервер. Самый простой способ сделать это — использовать официальный образ Docker и запустить Qdrant с помощью всего одной команды:

docker run -p “6333:6333” -p “6334:6334” -d qdrant/qdrant

После выполнения команды у нас будет запущен сервер Qdrant с HTTP API на порту 6333 и gRPC-интерфейсом на порту 6334.

Нам также потребуется установить несколько пакетов Python. Мы будем использовать FiftyOne для визуализации данных вместе с их истинными метками и метками, предсказанными нашей моделью сходства вкраплений. Вкрапления будут созданы с помощью MobileNet v2, доступного в torchvision. Конечно, нам нужно как-то общаться с сервером Qdrant, и поскольку мы будем использовать Python, qdrant_client является предпочтительным способом сделать это.

pip install fiftyone
pip install torchvision
pip install qdrant_client

Конвейер обработки

  • Загрузка набора данных
  • Генерация вкраплений
  • Загрузка вкраплений в Qdrant
  • Классификация по ближайшим соседям
  • Оценка в FiftyOne

Загрузка набора данных

Есть несколько шагов, которые мы должны сделать, чтобы все прошло гладко. Прежде всего, нам нужно загрузить набор данных MNIST и извлечь из него обучающие примеры, так как мы будем использовать их в наших поисковых операциях. Чтобы сделать все еще быстрее, мы будем использовать не все примеры, а только 2500. Мы можем использовать FiftyOne Dataset Zoo для загрузки нужного нам подмножества MNIST всего одной строкой кода.

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"])
Вход в полноэкранный режим Выход из полноэкранного режима

Для начала давайте посмотрим на набор данных в приложении FiftyOne.

# Visualize the dataset in FiftyOne
session = fo.launch_app(train_view)
Вход в полноэкранный режим Выход из полноэкранного режима

Генерация вкраплений

Следующим шагом будет генерация вкраплений для образцов из набора данных. Это всегда можно сделать за пределами FiftyOne, используя собственные модели. Однако FiftyOne также предоставляет различные модели в FiftyOne Model Zoo, которые можно использовать прямо из коробки для генерации вкраплений.

В этом примере мы используем MobileNetv2, обученную на ImageNet, для вычисления вкрапления для каждого изображения.

# Compute embeddings
model = foz.load_zoo_model("mobilenet-v2-imagenet-torch")

train_embeddings = train_view.compute_embeddings(model)
Вход в полноэкранный режим Выход из полноэкранного режима

Загрузка вкраплений в Qdrant

Qdrant позволяет хранить не только векторы, но и некоторые соответствующие атрибуты — каждая точка данных имеет связанный с ней вектор и, по желанию, полезную нагрузку в формате JSON. Мы хотим использовать это, чтобы передать метку истинности, чтобы убедиться, что мы можем сделать наше предсказание позже.

ground_truth_labels = train_view.values("ground_truth.label")
train_payload = [
    {"ground_truth": gt} for gt in ground_truth_labels
]
Войти в полноэкранный режим Выход из полноэкранного режима

Создав встраивание, мы можем просто начать взаимодействие с сервером Qdrant. Для этого пригодится экземпляр QdrantClient, поскольку он содержит все необходимые методы. Давайте подключимся и создадим коллекцию точек, называемую просто "mnist". Размер вектора зависит от выходной модели, поэтому если в другой день мы захотим поэкспериментировать с другой моделью, то нам просто нужно будет импортировать другую модель, а все остальное останется прежним. В конце концов, убедившись, что коллекция существует, мы можем отправить все векторы вместе с их полезной нагрузкой, содержащей их истинные метки.

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)
Вход в полноэкранный режим Выход из полноэкранного режима

Классификация по ближайшим соседям

Теперь необходимо выполнить вывод на наборе данных. Мы можем создать вкрапления для нашего тестового набора данных, но просто проигнорировать базовую истину и попытаться выяснить ее с помощью ANN, а затем сравнить, если оба совпадают. Давайте сделаем один шаг за раз и начнем с создания вкраплений.

# 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)
Войдите в полноэкранный режим Выход из полноэкранного режима

Пришло время немного поколдовать. Давайте просто пройдемся итерациями по образцам тестового набора данных и соответствующим им вкраплениям и воспользуемся операцией поиска, чтобы найти 15 ближайших вкраплений из обучающего набора. Нам также нужно будет выбрать вложения, поскольку они содержат метки, необходимые для нахождения наиболее распространенной метки в окрестности конкретной точки. Класс Python Counter будет полезен, чтобы избежать шаблонизированного кода. Наиболее распространенная метка будет храниться как "ann_prediction" для каждого тестового образца в FiftyOne.

Это охватывается приведенной ниже функцией, которая принимает вектор вкраплений в качестве входных данных, использует возможность поиска Qdrant для нахождения ближайших соседей тестового вкрапления, генерирует предсказание класса и возвращает объект FiftyOne Classification, который мы можем хранить в нашем наборе данных FiftyOne.

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)
Вход в полноэкранный режим Выход из полноэкранного режима

Кстати, мы оценили доверие, вычислив долю образцов, принадлежащих наиболее распространенной метке. Это дает нам представление о том, насколько мы были уверены, предсказывая метку для каждого случая, и может быть использовано в FiftyOne для легкого выявления запутанных примеров.

Оценка в FiftyOne

Пришло время получить результаты! Давайте начнем с визуализации результатов работы классификатора. Мы можем легко запустить приложение FiftyOne, чтобы просмотреть исходные данные, прогнозы и сами изображения.

session = fo.launch_app(test_view)

FiftyOne предоставляет множество встроенных методов для оценки прогнозов вашей модели, включая регрессии, классификации, обнаружения, полигоны, экземпляры и семантические сегментации, как на наборах данных изображений, так и на видео. С помощью двух строк кода мы можем вычислить и распечатать отчет об оценке нашего классификатора.

# 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()
Вход в полноэкранный режим Выход из полноэкранного режима
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
Войти в полноэкранный режим Выход из полноэкранного режима

После выполнения оценки в FiftyOne мы можем использовать объект результатов для создания интерактивной матрицы путаницы, позволяющей нам щелкать по ячейкам и автоматически обновлять App, чтобы показать соответствующие образцы.

plot = results.plot_confusion_matrix()
plot.show()
Вход в полноэкранный режим Выход из полноэкранного режима

Давайте углубимся немного дальше. Мы можем использовать сложный язык запросов FiftyOne, чтобы легко найти все предсказания, которые не совпали с базовой истиной, но были предсказаны с высокой степенью достоверности. Как правило, это самые запутанные образцы в наборе данных и те, из которых мы можем извлечь наибольшую пользу.

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") > 0.7)
)
session.view = false_view
Войти в полноэкранный режим Выход из полноэкранного режима

Это самые запутанные образцы для модели, и, как вы можете видеть, они довольно нерегулярны по сравнению с другими изображениями в наборе данных. Следующим шагом для улучшения работы модели может быть использование FiftyOne для создания дополнительных образцов, похожих на эти. Затем эти образцы можно аннотировать с помощью интеграции между FiftyOne и такими инструментами, как CVAT и Labelbox. Кроме того, мы можем использовать еще несколько векторов для обучения или просто выполнить тонкую настройку модели с помощью обучения сходству, например, используя триплетные потери. Но уже сейчас этот пример использования FiftyOne и Qdrant для классификации по сходству векторов работает довольно хорошо.

И это все! Вот так просто мы создали модель классификации ANN, используя FiftyOne с Qdrant в качестве бэкенда для вкраплений, так что поиск сходства между векторами может перестать быть узким местом, как это было бы в случае традиционного k-NN.

Попробуйте сами!

Нажмите здесь, чтобы получить блокнот, содержащий исходный код того, что вы видели в этой статье. Кроме того, он включает в себя реалистичный пример использования этого процесса для выполнения предварительной аннотации атрибутов ночи и дня на наборе данных BDD100K дорожных сцен.

Резюме

FiftyOne и Qdrant можно использовать вместе, чтобы эффективно выполнять поиск ближайших соседей по вкраплениям и действовать в соответствии с результатами на ваших наборах данных изображений и видео. Красота этого процесса заключается в его гибкости и повторяемости. Вы можете легко загрузить дополнительные метки для новых полей в FiftyOne и Qdrant и повторить процесс предварительного аннотирования с использованием существующих вкраплений. Это позволяет быстро сократить расходы на аннотирование и быстрее получить наборы данных более высокого качества.

Эта статья в блоге была написана в сотрудничестве между командами Qdrant и Voxel51 в соавторстве с Кацпером Лукавски и Эриком Хофесманном.

Оцените статью
devanswers.ru
Добавить комментарий