Давайте сначала опишем нашу проблему с покупками: идентификация модного предмета на изображении пользователя и поиск его в интернет-магазине. Вы когда-нибудь видели кого-то на улице и думали: «Вау, это красивое платье, интересно, где я могу его достать?» Для меня попробовать методы дистанционного метрического обучения было крутой задачей. Надеюсь, вам тоже будет интересно.
набор данных
Во-первых, нам нужен набор данных. На самом деле я пришел к этой идее, когда узнал, что пользователи на Aliexpress делают много изображений. Я подумал: «Вау, конечно, я могу использовать эти данные для поиска по изображению». Для простоты я решил остановиться на женских топах.
Вот список категорий, которые я использую:
- одеваться
- Рубашки и Рубашки
- Толстовки и свитера
- свитер
- Пальто и Пальто
Я использовал пакет запросов python и пакет BeautifulSoup для сбора данных. Изображение продавца можно получить с домашней страницы продукта, но для изображения пользователя нам нужно просмотреть страницу обратной связи. На странице товара есть что-то под названием «цвет». Цвет может быть просто другим цветом того же стиля предмета, или это может быть совершенно другой предмет. Поэтому мы относимся к разным цветам как к разным товарам.
Вы можете найти код, который я использую для получения всей информации об элементе по следующей ссылке (это даже больше, чем требуется для нашей задачи)
https://github.com/movchan74/streettoshopexperiments/blob/master/getitem_info.py
Все, что нам нужно, это пройти страницу поиска по каждой категории и получить все предметыurl
и используйте функцию выше, чтобы получить информацию для каждого элемента.
Наконец, у нас будет два набора изображений для каждого товара: изображение продавца (каждый элементitem['colors']
полеurl
) и изображение от пользователя (каждый элементitem['feedbacks']
полеimgs
).
Для каждого цвета у нас есть только одно изображение от продавца, но для каждого цвета у нас может быть несколько изображений от пользователя (иногда для цвета вообще нет изображения).
Отлично! Мы получили данные. Однако собранный набор данных зашумлен:
- Присутствуют зашумленные изображения от пользователей (фото коробок, текстур или просто части предмета, неупакованные предметы, неактуальные фото).
Чтобы решить эту проблему, я разделил 5000 изображений на две категории: хорошие изображения и шумные изображения. Вначале я планировал обучить двухклассовый классификатор и использовать его для очистки набора данных. Но потом я решил сохранить эту идею для дальнейшей работы и просто добавить очищенные изображения в тестовые и проверочные наборы.
- Вторая проблема заключается в том, что некоторые товары продаются несколькими продавцами. У продавцов иногда даже есть такие же картинки (или слегка отредактированные). Но как с этим бороться?Самый простой способ — ничего не делать и использовать надежный алгоритм для изучения метрики расстояния. Но это влияет на проверку, потому что мы можем иметь один и тот же элемент в данных проверки и обучения. Это приводит к неправильному. Другой способ — с помощью чего-то найти похожие (даже одинаковые изображения) и объединить их в один предмет. Мы можем использовать перцептивное хеширование для поиска идентичных изображений (например, phash или whash), или мы можем обучить модель на зашумленных данных и применить эту модель для поиска похожих изображений. Я выбрал второй вариант, потому что он позволяет объединить слегка отредактированные изображения.
дистанционное метрическое обучение
Одним из самых популярных методов дистанционного метрического обучения является потеря триплетов:
где max(x, 0) — функция шарнира, d(x, y) — функция расстояния между x и y, F(x) — глубокая нейронная сеть, M — интервал, a — якорь, p — положительный образец, а n - отрицательный образец.
F(a), F(p), F(n) — точки в многомерном пространстве (вложение), создаваемые глубокой нейронной сетью. Стоит отметить, что вложения обычно необходимо нормализовать, чтобы они имели единичную длину, т. е. ||x|| = 1, чтобы они были устойчивыми к изменениям освещения и контрастности и имели стабильность обучения. Якоря и положительные образцы относятся к одному классу, а отрицательные образцы являются образцами другого класса.
Но как выбрать (a, p, n)?Мы можем случайным образом выбирать выборки как тройки, но это приводит к следующим проблемам. Во-первых, троек может быть N³. Это означает, что нам нужно много времени, чтобы изучить все возможные тройки. Но на практике нам этого делать не нужно, потому что после нескольких итераций обучения останется много троек, не нарушающих тройное ограничение (нулевые потери). Это значит, что эти тройки бесполезны для тренировки.
Одним из самых распространенных способов тройной селекции является жесткий негативный майнинг:
На практике выбор самых сложных отрицательных выборок приводит к плохим локальным минимумам в начале обучения. В частности, это может привести к коллапсу модели (т. е. F(x) = 0).
Полужесткие отрицательные выборки находятся дальше от точки привязки, чем положительные выборки, но они все же жесткие (нарушающие ограничения), поскольку лежат в интервале M.
Существует два способа создания полутвердых (и жестких) отрицательных образцов: онлайн и офлайн.
- Онлайн означает, что мы случайным образом выбираем большую партию из обучающего набора данных и выбираем тройки из выборок в нем. Однако нам нужна большая партия. В моем случае это невозможно, так как у меня только GTX 1070 с 8 ГБ ОЗУ.
- В автономном методе нам нужно остановить обучение через некоторое время, предсказать вложения для определенного количества выборок, выбрать триплеты и обучить модель с этими триплетами. Это означает, что нам нужно пройти вперед дважды, но это цена автономного метода.
Хорошо, мы уже можем обучить модель с тройным убытком и полужестким отрицательным майнингом в автономном режиме. Однако нам также нужен трюк, чтобы успешно решить нашу исходную проблему. Наша задача — найти изображение продавца, наиболее близкое к изображению пользователя. Однако обычно изображение продавца более качественное (по освещению, камере, местоположению), чем изображение пользователя, поэтому у нас есть два домена: изображение продавца и изображение пользователя. Чтобы получить эффективную модель, нам нужно сократить разрыв между этими двумя областями. Эта проблема называется адаптацией домена.
Вверху: изображение пользователя, внизу: изображение продавца
Я предлагаю очень простую технику, чтобы закрыть доменный разрыв: давайте выберем анкоры из изображения продавца и положительные и отрицательные образцы из изображения пользователя. это все! Просто и эффективно.
выполнить
Для реализации своих идей и проведения экспериментов я использовал библиотеку Keras с бэкендом Tensorflow.
Я выбрал модель Inception V3 в качестве базовой CNN для модели. Как обычно, я инициализировал CNN с весами ImageNet. После глобального объединения с использованием нормализации L2 в конце сети я добавил два полносвязных слоя. Встроенный размер 128.
def get_model():
no_top_model = InceptionV3(include_top=False, weights='imagenet', pooling='avg')
x = no_top_model.output
x = Dense(512, activation='elu', name='fc1')(x)
x = Dense(128, name='fc2')(x)
x = Lambda(lambda x: K.l2_normalize(x, axis=1), name='l2_norm')(x)
return Model(no_top_model.inputs, x)
Нам также необходимо реализовать функцию тройных потерь. Мы передаем якоря, положительные/отрицательные образцы как один мини-пакет и разбиваем его на 3 тензора внутри функции потерь. Функция расстояния представляет собой квадрат евклидова расстояния.
def margin_triplet_loss(y_true, y_pred, margin, batch_size):
out_a = tf.gather(y_pred, tf.range(0, batch_size, 3))
out_p = tf.gather(y_pred, tf.range(1, batch_size, 3))
out_n = tf.gather(y_pred, tf.range(2, batch_size, 3))
loss = K.maximum(margin
+ K.sum(K.square(out_a-out_p), axis=1)
- K.sum(K.square(out_a-out_n), axis=1),
0.0)
return K.mean(loss)
Скомпилируйте модель:
from functools import partial, update_wrapper
def wrapped_partial(func, *args, **kwargs):
partial_func = partial(func, *args, **kwargs)
update_wrapper(partial_func, func)
return partial_func
opt = keras.optimizers.Adam(lr=0.0001)
model.compile(loss=wrapped_partial(margin_triplet_loss, margin=margin, batch_size=batch_size), optimizer=opt)
Результаты экспериментов
Производительность измеряется скоростью отзыва K (R@K). Давайте посмотрим, как рассчитывается R@K. Набор проверки изображения каждого пользователя. В качестве запроса нам нужно найти соответствующее изображение продавца. Мы берем изображение запроса, вычисляем вектор встраивания и ищем в векторе всех изображений продавцов ближайшего соседа этого вектора. Мы используем не только изображения продавца из проверочного набора, но и изображения из обучающего набора, так как это позволяет добавлять отвлекающие факторы, что усложняет нашу задачу.
У нас есть изображение запроса и список наиболее похожих изображений продавца. Мы возвращаем 1 для этого запроса, если среди K наиболее похожих изображений есть соответствующее изображение продавца, и 0 в противном случае. Теперь нам нужно создать его для каждого пользовательского изображения в проверочном наборе и найти средний балл R@K для каждого запроса.
Как я уже говорил, я очистил небольшое количество пользовательских изображений от зашумленных изображений. Поэтому я измерил производительность модели на двух наборах данных проверки: полном наборе данных проверки и подмножестве только с чистыми изображениями.
Результаты далеки от идеала, предстоит многое сделать:
- Удалите шум с пользовательских изображений. Я сделал свои первые шаги в этом направлении и подчистил небольшую часть.
- Объединяйте элементы более точно (по крайней мере, в проверочном наборе).
- Сокращение доменных пробелов. Я думаю, что этого можно добиться с помощью улучшений, специфичных для предметной области (например, улучшения освещения), и с использованием специализированных методов (например, https://arxiv.org/abs/1409.7495).
- Примените другой метод дистанционного метрического обучения. Я попробовал это https://arxiv.org/abs/1703.07464, но в моем случае это сработало хуже.
- Соберите больше данных.
Демонстрация, код и обученная модель
Я продемонстрировал эту модель. Вы можете проверить это здесь: http://vps389544.ovh.net:5555/
Вы можете загрузить собственное изображение для поиска или использовать случайное изображение из проверочного набора.
Код и обученная модель: http://vps389544.ovh.net:5555/.
Сводная станция блога о технологиях искусственного интеллекта Panchuang: http://docs.panchuang.net/PyTorch, официальная учебная станция на китайском языке: http://pytorch.panchuang.net/OpenCV, официальный китайский документ: http://woshicver.com/