Глубокое погружение в встраивание нейронных сетей

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

Небольшое примечание: для этой статьи потребуются промежуточные знания в области глубокого обучения и нейронных сетей. Если вы еще не совсем там, я рекомендую сначала взглянуть на Ускоренный курс машинного обучения Google. Содержание курса отлично подходит для понимания основ нейронных сетей для CV и NLP.

Краткий обзор

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

% pip install towhee  # pip3
% python              # python3
>>> import towhee 
>>> text_embedding = towhee.dc(['Hello, world!']) \ 
...     .text_embedding.transformers(model_name='distilbert-base-cased') \ 
...     .to_list()[0]
...
>>> embedding # includes punctuation and start & end tokens
array([[ 0.30296388,  0.19200979,  0.10141158, ..., -0.07752968, 0.28487974, -0.06456392],
       [ 0.03644813,  0.03014304,  0.33564508, ...,  0.11048479, 0.51030815, -0.05664057],
       [ 0.29160976,  0.43050566,  0.46974635, ...,  0.22705288, -0.0923526, -0.04366254],
       [ 0.14108554, -0.00599108,  0.34098792, ...,  0.16725197, 0.10088076, -0.06183652],
       [ 0.35695776,  0.30499873,  0.400652  , ...,  0.20334958, 0.37474275, -0.19292705],
       [ 0.6206475 ,  0.50192136,  0.602711  , ..., -0.03119299, 1.1860386 , -0.6167787 ]], dtype=float32)

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

Контролируемые вложения

До сих пор в моих предыдущих статьях использовались встраивания из моделей, обученных с помощью обучения с учителем, т. е. моделей нейронных сетей, которые обучаются на помеченных/аннотированных наборах данных. Набор данных ImageNet, например, содержит тщательно отобранный набор сопоставлений изображений и классов, а наборы данных для ответов на вопросы, такие как SQuAD, обеспечивают сопоставления предложений 1: 1 на разных языках.

Многие известные модели, обученные на размеченных данных, используют кросс-энтропийную потерю или среднеквадратичную ошибку. Поскольку конечная цель контролируемого обучения состоит в том, чтобы более или менее воспроизвести сопоставления 1: 1 между входными данными и аннотациями (например, вывести вероятность токена класса с учетом входного изображения), вложения, созданные из контролируемых моделей, редко используют выходной слой. Стандартная модель ResNet50, обученная на ImageNet-1k, например, выводит вектор с 1000 измерениями, соответствующий вероятностям того, что входное изображение является экземпляром метки класса N.

Вместо этого большинство современных приложений используют в качестве встраивания предпоследний уровень активаций. На изображении выше (LeNet-5) это соответствует активациям между слоями, помеченными FC (10) (10-мерный выходной слой) и FC (84). Этот слой достаточно близок к выходным данным, чтобы точно представлять семантику входных данных, а также имеет достаточно низкую размерность. Я также встречал приложения компьютерного зрения, в которых используются пулы активаций из гораздо более раннего уровня модели. Эти активации захватывают элементы более низкого уровня входного изображения (углы, края, блоги и т. д.), что может привести к повышению производительности для таких задач, как распознавание логотипа.

Энкодеры и самоконтроль

Основным недостатком использования аннотированных наборов данных является то, что они требуют аннотаций (это звучит немного идиотски, но потерпите меня здесь). Создание высококачественных аннотаций для определенного набора входных данных требует сотен, если не тысяч часов работы одного или нескольких человек. Полный набор данных ImageNet, например, содержит около 22 тыс. категорий, и для его курирования требуется армия из 25 000 человек. Еще больше усложняет ситуацию то, что многие помеченные наборы данных часто содержат непреднамеренные неточности, явные ошибки или контент NSFW в тщательно отобранных результатах. По мере увеличения количества таких случаев качество вложений, созданных моделью встраивания, обученной с помощью обучения с учителем, значительно снижается.

С другой стороны, модели, обученные неконтролируемым способом, не требуют меток. Учитывая безумное количество текста, изображений, аудио и видео, генерируемых ежедневно, модели, обученные с использованием этого метода, по сути, имеют доступ к бесконечному количеству обучающих данных. Хитрость здесь заключается в разработке правильного типа моделей и методологий обучения для использования этих данных. Невероятно мощный и все более популярный способ сделать это — использовать автокодировщики (или архитектуры кодировщик/декодер в целом).

Автоэнкодеры обычно состоят из двух основных компонентов. Первый компонент — кодировщик: он принимает на вход некоторый фрагмент данных и преобразует его в вектор фиксированной длины. Второй компонент — декодер: он отображает вектор обратно в исходный фрагмент данных. Это известно как архитектура кодер-декодер:

Синие прямоугольники, соответствующие Encoder и Decoder, представляют собой нейронные сети с прямой связью, а State — желаемое вложение. В обеих этих сетях нет ничего особенного — многие автокодировщики изображений будут использовать стандартный ResNet50 или ViT для сети кодировщика и такую ​​же большую сеть для декодера.

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

В последние годы появилось множество улучшений самоконтроля, выходящих за рамки традиционного автоэнкодера. Для НЛП модели предварительного обучения с контекстом, т. е. когда слово или символ появляются по отношению к другим в том же предложении или фразе, являются обычным явлением и в настоящее время считаются де-факто методом обучения состояниям. -современные модели встраивания текста. Модели встраивания компьютерного зрения с самоконтролем также оживают; Методы контрастного обучения, основанные на дополнении данных, показали отличные результаты при применении к общим задачам компьютерного зрения. SimCLR и data2vec — это два примера нейронных сетей, использующих маскировку и/или другие дополнения для самоконтролируемого обучения.

Вложения как входные данные для других моделей

Модели встраивания очень уникальны; они не только полезны для разработки общих приложений, но и их результаты часто используются в других моделях машинного обучения. Прекрасным примером тому являются трансформеры Vision. Их популярность резко возросла за последние два года благодаря высокой производительности и большому рецептивному полю, недоступному для традиционных сверточных нейронных сетей. Основная предпосылка преобразователей зрения состоит в том, чтобы разделить изображение на квадратные фрагменты, создать вложения для каждого фрагмента и использовать вложения в качестве входных данных для стандартного преобразователя. Это, как ни странно, очень хорошо работает для распознавания изображений.

Другим прекрасным примером этого является CLIP OpenAI, большая модель нейронной сети, которая обучена сопоставлять изображения с естественным языком. CLIP обучается тому, что составляет практически бесконечные данные из Интернета, например. Фотографии Flickr и соответствующий заголовок фотографии.

Методология CLIP на самом деле довольно проста. Во-первых, CLIP переводит изображения и текст в скрытое состояние (т. е. встраивание); эти скрытые состояния затем обучаются отображать в одно и то же пространство, то есть встраивание текста и встраивание изображения должны быть очень близки друг к другу, если текст может точно описать изображение. Дьявол кроется в деталях, когда дело доходит до машинного обучения, и CLIP на самом деле довольно сложно реализовать на практике без значительного набора данных и некоторой настройки гиперпараметров.

CLIP используется в качестве основного компонента в DALLE (и DALLE-2), механизме преобразования текста в изображение от OpenAI. В последнее время вокруг DALLE-2 было много шума, но все это было бы невозможно без представительской власти CLIP. Хотя результаты CLIP и DALLE были впечатляющими, встраивание изображений все еще имеет значительный потенциал для роста. Определенную семантику более высокого уровня, такую ​​как количество объектов и математические операции, по-прежнему сложно представить во встраивании изображения.

Создание собственных вложений

В прошлом я пару раз указывал на проект с открытым исходным кодом Towhee, показывая, как его можно использовать для создания вложений, а также для разработки приложений, требующих встраивания. Towhee объединяет сотни моделей встраивания и классификации изображений из различных источников (, torchvision и т. д.), обученных с использованием различных методов. У Towhee также есть много моделей NLP, любезно предоставленных библиотекой 🤗 Transformers.

Давайте сделаем шаг назад и посмотрим, как Towhee генерирует эти вложения под капотом.

>>> from towhee import pipeline
>>> p = pipeline('image-embedding')
>>> embedding = p('towhee.jpg')

В Towhee метод по умолчанию для создания вложений из контролируемой модели заключается в простом удалении окончательного слоя классификации или регрессии. Для моделей PyTorch мы можем сделать это с помощью следующего фрагмента кода:

>>> import torch.nn as nn
>>> import torchvision
>>> resnet50 = torchvision.models.resnet50(pretrained=True)
>>> resnet50_emb = nn.Sequential(*(list(resnet50.children())[:-1]))

Последняя строка в приведенном выше фрагменте кода воссоздает сеть прямой связи (nn.Sequential), состоящую из всех слоев в resnet50 (resnet50.children()), за исключением последнего слоя ([:-1]). Промежуточные встраивания также могут быть созданы с помощью того же метода удаления слоев. Этот шаг необязателен для моделей, обученных с потерей контраста/триплета, или в качестве автоэнкодера.

Модели, основанные на (для CV) и transformers (для NLP), также поддерживают свои собственные методы, упрощающие извлечение признаков:

>>> import numpy as np
>>> from PIL import Image
>>> import timm
>>> image = numpy.array(Image.open('towhee.jpg'))
>>> model = timm.models.resnet50(pretrained=True)
>>> embedding = model.forward_features(img)
>>> from transformers import AutoTokenizer, AutoModel
>>> tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
>>> model = AutoModel.from_pretrained('bert-base-uncased')
>>> inputs = tokenizer('Hello, world!', return_tensors='pt')
>>> outputs = model(**inputs)
>>> embedding = outputs.last_hidden_state()

Towhee поддерживает оболочки для timm и transformers:

>>> import towhee
>>> text_embedding = towhee.dc(['Hello, world!']) \
...     .text_embedding.transformers(model_name='distilbert-base-cased') \
...     .to_list()[0] # same as intro example
...
>>> img_embedding = towhee.glob('towhee.jpg') \
...     .image_decode() \
...     .image_embedding.timm(model_name='resnet50') \
...     .to_list()[0]
...

Другие источники

Я составил краткий (и очень неполный) список других замечательных ресурсов по встраиваниям, если вы хотите прочитать больше или подойти к теме с другой точки зрения:

  1. В Документации Milvus представлен обзор встраивания векторов (применительно к хранилищам и векторным базам данных).
  2. OpenAI поддерживает страницу встраивания текста, которую вы можете проверить.
  3. Will Koehrsen дает большой обзор вложений. Это немного устарело (2018 год), но все же отличный ресурс.
  4. Посмотрите, как встраивания используются в Твиттере для рекомендации.
  5. Обратный поиск изображений — одно из многих приложений для встраивания векторов. Этот учебник демонстрирует, как построить его за считанные минуты.

Если этот пост был для вас полезен, подпишитесь на меня в Твиттере. В следующем посте я представлю краткий обзор алгоритмов поиска по сходству и векторного индексирования. Следите за обновлениями!

Первоначально опубликовано на https://frankzliu.com 30 апреля 2022 г.