Чому звичайне хешування не підходить для пошуку подібності
Звичайні функції хешування, які використовуються в хеш-таблицях і мапах, оцінюються за тим, наскільки добре вони уникають зіткнень. Якщо два різних ключі хешуються до одного й того ж значення, це розглядається як нещадна випадковість, яка вирішується за допомогою ланцюгового або пробивання, і, в ідеалі, робиться якомога рідше через хорошу поведінку звалу. Ця властивість є точною, що вам потрібна для побудови словника чи кеша, але це протилежність того, що ви хочете для пошуку подібності. Уявіть, що у вас є десять мільйонів векторів зображень, кожен із яких є вектором кількох сотень чисел, і ви хочете знайти невелику кількість, які візуально схожі на нове фото. Порівнюючи запит з усіма десятимильйонними векторами один за одним, підхід, який називається грубим обчисленням або лінійним скануванням, вимагає повного проходження по всьому набору даних для кожного запиту. Коли набір даних зростає до мільярдів елементів, це стає занадто повільним для будь-якого інтерактивного застосунку, будь то зворотний пошук зображень, перевірка плагіату або рекомендації товарів. Дерев'яні структури, такі як kd-дерева, вирішують пов’язану проблему — точний пошук найближчого сусіда — але вони добре працюють лише у низьких розмірах. Коли кількість вимірів зростає до десятків або сотень, що є типовим для вкладень з сучасних моделей машинного навчання, дерев'яні структури страждають від прокляття розмірності: майже кожен гілок дерева повинен бути досліджений, і пошук деградує до тієї ж вартості, що й порівняння з усім. LSH одночасно обходить обидві проблеми. Він відмовляється від гарантії знаходження найближчого сусіда та замість цього знаходить приблизний з ним із високою ймовірністю, і масштабується без проблем до багатовимірних даних великого обсягу завдяки спеціально розробленим хеш-функціям замість гілкуючого дерева.
Випадкове хешування гіперплощини для подібності косинуса
Один із найпростіших способів побудови функції хешування чутливості до місця розташування – випадкове хешування гіперплощин, розроблений для порівняння даних за допомогою подібності косинуса, яка вимірює кут між двома векторами замість їхньої пікової відстані. Ідея полягає у випадковому виборі гіперплощини через початкове положення простору векторів, визначеної випадковим вектором. Для будь-якої точки даних перевіряється, на якому боці від гіперплощини вона знаходиться, що призводить до одного біта, наприклад, 0 або 1. Інтуїтивно, якщо два вектора вказують приблизно в одному напрямку, випадково вибрана гіперплощина малоймовірно розріже їх, тому вони майже завжди опиняться з одного боку та отримають один і той самий біт. Якщо два вектори вказують у дуже різних напрямках, випадкова гіперплощина набагато ймовірніше відокрелить їх, тому вони часто отримують різні біти. Цей біт хешування є слабким сигналом сам по собі, але він має суттєву властивість чутливості до місця розташування: ймовірність того, що два вектори отримають один і той самий біт, безпосередньо пов’язана з кутом між ними, а отже, і з їхньою подібністю косинуса. Щоб перетворити цей слабкий сигнал на корисний хеш-контейнер, кілька випадкових гіперплощин генеруються одночасно, наприклад, шістнадцять або тридцять два з них, і результати бітів об'єднуються в один бінарний код. Дві позиції, які мають цей точний бінарний код, потрапляють у один контейнер. Оскільки кожен окремий біт лише слабо віддає перевагу схожим елементам, використання багатьох бітів разом робить комбіновану підпис набагато більш розрізнюючим, різко зменшуючи ймовірність випадкового спілкування не схожих векторів у одному контейнері, зберігаючи при цьому схожі вектори разом більшість часу. Ця техніка лежить в основі багатьох практичних систем найближчих сусідів для вкладень, які генеруються нейронними мережами, де подібність косинуса є природним поняттям близькості.
MinHash та подлі́кість для наборів
Існує інший смак LSH, який називається MinHash, побудований для даних, представлених у вигляді наборів, а не векторів, і для вимірювання подібності за допомогою подібності Jaccard, яка визначається як розмір перетину двох наборів, розділений на розмір їх об'єднання. Це природне поняття близькості для завдань, таких як виявлення майже дублікатних документів, де кожен документ представлено як набір перекриваючихся послідовностей слів або «шарпів», які з’являються в ньому, або для порівняння наборів елементів, придбаних двома користувачами у системі рекомендацій. Хитрий MinHash працює так: задайте випадкову перестановку всього всесвіту можливих елементів, застосуйте її до набору та запишіть найменший елемент, який з’являється в цьому наборі після перестановки. Це дивовижне твердження полягає в тому, що ймовірність того, що два набори поділяють один і той же мінімальний елемент під випадковою перестановкою, дорівнює їхній подібності Jaccard. Іншими словами, ця одна випадкова статистика є очікуваною ідеальною оцінкою перетину наборів. На практиці обчислення справжньої випадкової перестановки над величезним всесвітом є дорогим, тому реалізації використовують сім’ю незалежних хеш-функцій та для кожної з них записують найменше значення, яке хешується, по всьому набору елементів. Два документи з високою поділистістю Jaccard узгоджуватимуться щодо багатьох цих мінімальних значень, тоді як два дуже різних документи рідко узгоджуватимуться щодо будь-якого з них. Як і при випадковому хешуванні гіперплощин, цей слабкий сигнал на рівні хешування стає сильним диференціатором, коли багато незалежних значень MinHash об'єднують у підпис, дозволяючи системам виявлення майже дублікатних документів, таким як ті, що використовуються для пошуку плагіату або відображень веб-сторінок, порівнювати компактні фіксовані за розміром підписи замість повних оригінальних документів.
И и или: построение AND-OR для точности и полноты
Одиночный хеш-сиг natures, будь то построенный из случайных гиперплоскостей или значений MinHash, дает вам ручку, но не оптимизированную систему. Реальные реализации LSH объединяют множество хеш-функций с использованием многослойной структуры, часто называемой конструкцией AND-OR или banding. Внутри одной таблицы хеши вы объединяете несколько хеш-значений вместе, например, полосу из пяти, и требуете, чтобы все пять соответствовали для двух элементов, чтобы они считались потенциальной парой в этой таблице. Это часть «И»: согласие со всеми пятью хеш-значениями является строгим требованием, которое редко приводит к ложным столкновениям между несхожими элементами, но также делает более вероятным, что два действительно похожих элемента просто едва промахнутся на одном из пяти и будут потеряны. Чтобы восстановить эту упущенную полноту, вы строите несколько независимых таблиц хешей таким образом, каждая с ее собственными случайно выбранными полосами хеш-функций, и объявляете две пары элементов кандидатами, если они сталкиваются в одной из этих таблиц. Это часть «ИЛИ»: необходимость соответствия только в одном столе из многих делает это гораздо более вероятным, что действительно похожая пара будет поймана хотя бы одним столом, даже если она не попадается в большинстве других. Эти две ручки работают друг против друга предсказуемым и математически хорошо понятным образом. Увеличение ширины полосы, количества хеш-функций, объединенных вместе в таблице, увеличивает точность за счет фильтрации большего числа ложных срабатываний, но снижает полноту, поскольку настоящие совпадения с большей вероятностью не будут соответствовать всем пяти. Увеличение количества независимых таблиц, части «ИЛИ», увеличивает полноту за счет предоставления похожим элементам больше возможностей для столкновения в каком-либо столе, но увеличивает как использование памяти, так и стоимость запросов, поскольку каждая таблица должна быть проверена.
Чому це важливо
Цей ефект пояснює, чому LSH (щоб обчислити найближчих сусідів) стає основою інфраструктури для систем, які повинні працювати на рівні інтернету: пошукові системи за зображеннями, які індексують мільярди фотографій; рекомендаційні системи, які порівнюють мільйони профілів користувачів; та конвеєри виявлення майже однакових елементів, які сканують величезний веб-перегляд на предмет копійованого або віддзеркаленого вмісту. Без LSH, пошук найближчих сусідів точки запиту серед набору даних розміром n потребував би порівняння запиту з усіма n елементами, що призвело б до лінійного зростання вартості з розміром набору даних; подвоєння даних, подвоєння часу запиту, що стає непрактичним, коли n досягає мільярдів. З LSH, дорогі порівняння відбуваються лише між невеликою кількістю кандидатів, які потрапляють у один або кілька бачків, після того як хеш-таблиці вже виконають важку роботу з обмеження простору пошуку. Оскільки хеш-функції були спеціально розроблені так, щоб подібні елементи ймовірно зіткнулися, цей невеликий бачок є непропорційно ймовірним для містити справжніх близьких сусідів, навіть якщо він представляє лише невелику частку всього набору даних. Обчислення хешування запиту само по собі займає час, який залежить тільки від кількості використаних хеш-функцій, а не від розміру набору даних, і пошук відповідних бачків у хеш-таблиці є швидкою, приблизно постійною операцією. Результат – вартість запиту, яка залишається близькою до константної або, в кращому випадку, дуже повільно зростає, коли набір даних збільшується, замість того, щоб масштабуватися з кожним елементом у ньому. Це саме тому LSH став основою інфраструктури для систем, які повинні працювати на рівні інтернету: пошукові системи за зображеннями, які індексують мільярди фотографій, рекомендаційні системи, які порівнюють мільйони профілів користувачів, і конвеєри виявлення майже однакових елементів, які сканують величезний веб-перегляд на предмет копійованого або віддзеркаленого вмісту. Користуючись перевагами швидкості, LSH може бути використаний для пошуку найближчих сусідів точки запиту серед набору даних розміром n, що потребує порівняння запиту з усіма n елементами, що призвело б до лінійного зростання вартості з розміром набору даних; подвоєння даних, подвоєння часу запиту, що стає непрактичним, коли n досягає мільярдів. З LSH, дорогі порівняння відбуваються лише між невеликою кількістю кандидатів, які потрапляють у один або кілька бачків, після того як хеш-таблиці вже виконають важку роботу з обмеження простору пошуку. Оскільки хеш-функції були спеціально розроблені так, щоб подібні елементи ймовірно зіткнулися, цей невеликий бачок є непропорційно ймовірним для містити справжніх близьких сусідів, навіть якщо він представляє лише невелику частку всього набору даних.
Часті запитання
Як LSH відрізняється від звичайного хеш-таблиці, що використовується для пошуку?
Звичайна хеш-таблиця розроблена таким чином, щоб мінімізувати зіткнення, щоб кожен ключ відображався в окремому слоті якомога частіше, що забезпечує швидкий та передбачуваний пошук. LSH навмисно робить протилежне: його хеш-функції побудовані таким чином, щоб подібні вхідні дані ймовірно зіткнулися, тобто опинилися в одному контейнері, а невідповідні – навряд чи. Ця перевернута мета робить LSH корисним для пошуку подібності, а не точного пошуку за ключем.
Чи завжди LSH знаходить справжнього найближчого сусіда?
Ні, і це є задумом. LSH – приблизний метод: він знаходить невеликий набір ймовірних кандидатів із високою ймовірністю, а справжній найближчий сусід зазвичай, але не завжди, є серед них. Збільшення кількості хеш-таблиць та налаштування ширини смуги дозволяє задати ймовірність пропуску справжнього найближчого сусіда до нуля, при цьому збільшується споживання пам'яті та обчислювальні витрати на запит.
Коли я б мав використовувати випадкове хешування гіперплощини замість MinHash?
Випадкове хешування гіперплощини підходить для щільних числових векторів, порівнюваних за косинусною подібністю, таких як вкладення, що генеруються моделями машинного навчання для зображень, тексту або аудіо. MinHash підходить для даних, які природно представлені у вигляді множин, таких як слова чи шматки документа, або елементи, з якими взаємодіяли користувачі, порівнювані за подібністю Жаккарда. Правильний вибір залежить повністю від того, яка міра подібності дійсно відповідає вашим даним та вашій задачі.
Чому не просто використовувати kd-дерево для пошуку найближчих сусідів у багатовимірному просторі?
Kd-дерева та подібні древоподібні структури виконують точний пошук найближчого сусіда ефективно лише тоді, коли кількість вимірів невелика. Зі збільшенням розмірності до десятків або сотень, що є типовим для вкладень реального світу, обрізання древоподібних структур перестає працювати ефективно, а вартість запиту наближається до порівняння з усім набором даних. LSH уникає прокляття розмірності, покладаючись на випадкові хеш-функції замість просторового поділу, і приймає приблизні відповіді замість точних, щоб забезпечити масштабованість.
Що відбувається, якщо я використовую занадто мало хеш-таблиць або занадто вузьку смугу?
Використання занадто малої кількості хеш-таблиць зменшує чутливість: багато дійсно подібних елементів не поділяться контейнером в жодній таблиці та просто будуть пропущені пошуком. Занадто вузька смуга, тобто занадто небагато функцій хешування, об'єднаних в одну таблицю, зменшує точність: невідповідні елементи частіше зіткнуться, заповнюючи кандидати контейнерами нерелевантними елементами, які потім потрібно буде відфільтрувати більш дорогим точним порівнянням.
Спробуйте наживо
Усе, що вище, працює прямо у вашому браузері — відкрийте Locality-Sensitive Hashing: Finding Similar Items in Massive Datasets і змінюйте параметри під час роботи. Нічого не встановлюється, нічого не завантажується на сервер, уся модель живе в одній вкладці.
▶ Відкрити симуляцію Locality-Sensitive Hashing: Finding Similar Items in Massive Datasets