Pull to refresh
577.52
Яндекс
Как мы делаем Яндекс

«Душа молчит, хоть слышит всё вокруг»: как мы отучаем генеративные модели галлюцинировать

Level of difficultyMedium
Reading time7 min
Views8.8K

Вот так когда-то отвечала языковая модель, когда её просили привести пример стихотворения Бальмонта. Стихотворение с таким названием действительно есть, но начинается оно совсем не так: 

Есть в русской природе усталая нежность,

Безмолвная боль затаенной печали,

Безвыходность горя, безгласность, безбрежность,

Холодная высь, уходящие дали.

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

Мы, Александр Кайгородов и Светлана Маргасова, обучаем генеративные модели в Яндексе. В этой статье мы расскажем, как заставить генеративные модели перестать придумывать несуществующие факты и как научиться находить эти ошибки, если они всё же случаются. Вы узнаете о том, как использовать внешнюю информацию, опираясь на которую мы можем выполнять как обусловленную генерацию (Retrieval Augmented Generation), так и фактологическую оценку имеющихся генераций (Fact-Check). 

Зачем нам внешняя информация для генерации

Первая и самая главная причина — для борьбы с галлюцинированием. Но есть ещё несколько проблем, которые мы попутно решаем с помощью внешней информации (этот подход называется RAG — Retrieval Augmented Generation): 

  1. Расширяем ограниченное представление о мире, которое модель получила в ходе претрейна. Например, знакомим модель с последними новостями и событиями, которые на момент её обучения ещё просто не произошли.

  2. Узнаём, какой источник данных модель использовала для ответа.

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

Теория
Теория
Практика
Практика

Под каждую задачу мы собираем базу знаний из материалов, которые потенциально полезны для генерации. Наполнение базы зависит от форматов, с которыми умеет работать генеративная модель (тексты, таблицы, картинки), и от задачи. Например, для задач общей тематики мы можем положить туда тексты из интернета или снапшоты из «Википедии». А если хотим встраивать модель в поддержку какого-нибудь сервиса — положим тексты документации. 

Для обучения нужны размеченные запросы и ответы — классические данные для SFT (supervised fine-tuning). При этом релевантных документов для конкретного запроса у нас нет. Чтобы найти их в базе знаний, мы используем модель Retriever. Она строит эмбеддинг запроса и всех документов в базе и находит ближайшие по определённой метрике близости, например по косинусному расстоянию. Для построения эмбеддингов можно использовать модели на основе BERT или GPT, предобученные на парах близких текстов.

Схема работы модели Retriever
Схема работы модели Retriever

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

Модель Generator — это классическая GPT-подобная языковая модель. Но если обычно на вход поступает только запрос, то здесь мы подаём ещё и документ — как правило, просто конкатенируем его с запросом.

Схема работы модели Generator
Схема работы модели Generator

Модели мы обучаем вместе. Во время обучения мы извлекаем k релевантных документов из базы. 

top_{k}(< emb(query), emb(doc_{i})>)

Лосс модели Generator — это обычная кросс-энтропия на каждой тройке «запрос — ответ — документ». 

\Sigma_{i} Cross Entropy Loss (answer|query, doc_{i})

А чтобы обучать Retriever, нам нужно выдавать тексты, которые будут полезнее для генерации. Для этого мы можем сближать распределение релевантности документов относительно запроса, которое выдаёт Retriever, с распределением правдоподобия ответа при условии каждого из документов, которое выдаёт Generator. 

Для сближения мы минимизируем KL-дивергенцию. 

KL – divergence (p_{retriver}, p_{generator})
Схема обучения модели Retriever
Схема обучения модели Retriever

Казалось бы, всё понятно и просто, но в процессе реализации этой схемы мы столкнулись с рядом проблем.

С какими проблемами мы столкнулись и как их решали

Проблема 1. Эмбеддинги документов устаревают. Если база знаний большая, то перестраивать эмбеддинги при каждой итерации сложно. Вместо этого мы их замораживаем. Ещё можно обновлять базу раз в несколько итераций (а не каждую итерацию) или использовать модель-переаранжировщик, которая обучает эмбеддинги документов и выдаёт из большой выдачи нужные k документов. 

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

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

  • На обучении можно подсматривать в ответ и доставать релевантные документы на основании не только запроса, но и ответа. А во время инференса дистиллировать такую модель Embedder в классический Embedder, который видит только запрос. 

  • Также помогает подливка supervised-данных, когда есть разметка на запросы и ответы и релевантные для ответа документы. 

  • Можно смотреть на retrieval utility — профит от каждого документа, который находится как разница лосса Generator без документа и с документом. То есть из лосса Generator, при котором он вообще не видит никакой документ, мы вычитаем лосс, когда он видит документ. А если документы не нужны и Generator и так выдаёт хороший ответ, то мы штрафуем такие примеры и взвешиваем лосс пропорционально профиту.

Retrieval Utility(doc)=Loss_{generator}(answer|query)-Loss_{generator}(answer|query,doc)

Проблема 4. Embedder-коллапс — это ситуация, когда модель начинает выдавать одни и те же документы на любые запросы. С этим тоже помогает retrieval utility. Мы не обучаем Embedder на примерах, где нет пользы ни от одного документа, потому что там не нужно сближать релевантности. 

Retrieval Utility(doc)< 0

Ещё при Embedder-коллапсе помогают штрафы за выдачу для повторяющихся документов. 

Какие результаты мы получили 

Чтобы проверить, насколько наши решения повышают точность, у нас есть разные срезы в инструкциях. Один из них — срез Open QA. Это особый тип запросов к модели, которые требуют от неё демонстрации знаний о внешнем мире и глубокого понимания связей между этими знаниями. Например, когда и где родился архитектор Константин Мельников. Baseline-модель (то есть модель, работающая без предоставления внешней информации в контексте генерации) может придумать город и год, но RAG-модель посмотрит сниппет из «Википедии» и ответит правильно. 

Асессорская разметка показывает, что в таких случаях RAG выигрывает по SbS 60% на 40% против baseline. А вот с общими вопросами всё сложнее, потому что разница не настолько большая: 55% побед у RAG против 45% у baseline (это значит, что только в 10% случаев ответы одной модели лучше другой). В целом у нас сокращается количество логических и фактических ошибок, к тому же бонусом у нас уменьшается сложность текста. Но, к сожалению, некоторые пункты у нас растут: сомнительная информация, неполный ответ и вредность. С этим всем мы боремся.

Если резюмировать, то при применении RAG уменьшается количество фактических и логических ошибок, а также повышается понятность генерации. Но при этом инференс становится дольше (нужно потратить время на retrieval, и к тому же контекст увеличивается на длину документа) и повышаются затраты на хранение базы данных.

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

Фактчек: как проверять ошибки моделью, а не людьми

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

Примеры возможных ошибок
Примеры возможных ошибок

На первом этапе мы выделяем факты — логические сегменты, которые будем проверять. Давайте попробуем это сделать на примере праздников в Италии. В данном случае разбили генерацию ответа по пунктуации.

Далее переходим к работе с внешней информацией: проверим, действительно ли Рождество в Италии празднуют в эти даты. 

Для проверки сгенерированных фактов необходимы документы. Для поиска документов необходимо сформировать запрос в Яндекс Поиск. На данный момент мы используем модель YandexGPT в режиме Zero-Shot , но ищем способы повышения качества генерации вопросов через Few-Shot или SFT. Для генерации вопроса мы подавали изначальный запрос, выделенный факт и генерацию-ответ. То есть мы подали полный контекст того, на что обращает внимание человек, когда пытается проверить факт. 

Далее — поиск. Мы можем задавать несколько вопросов для проверки одного факта. По каждому из них мы получаем группу из топ-k (в наших экспериментах чаще всего k = 9) релевантных им документов. Так мы получаем опорные документы, которые подтверждают или опровергают факт генерации. В данном случае опорный документ позволяет ответить на вопрос, реальный это факт или ложный.

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

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

Здесь score_{k,n} – это вектор вероятностей каждого класса
Здесь score_{k,n} – это вектор вероятностей каждого класса

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

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

Разметка и оценка качества

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

В разметке для обучения модели мультимногоклассовой классификации мы разделяем на семь классов: 

  1. Правда.

  2. Полуправда.

  3. Мнения разделяются.

  4. Факт не требует подтверждения.

  5. Факт не подтверждается внешними источниками.

  6. Ложь.

  7. Абсурд.

Теперь мы можем тренировать модели пайплайна и проводить его итоговую оценку, используя полученную разметку фактов генерации. Оценку можно проводить как на уровне всей генерации, так и на уровне фактов.

В качестве baseline-решения мы попросили модель самостоятельно проводить фактчек внутри её же генерации, но без использования документа. ROC-AUC-метрика показывает, что, используя внешние источники информации для осуществления проверки фактов генерации, мы повышаем качество классификации на 20%.

Вместо выводов

Итак, мы можем использовать внешнюю информацию для двух задач: генерации и фактчека. Причём при фактчеке мы, по сути, делаем то же самое, но в обратном порядке. 

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

Tags:
Hubs:
Total votes 28: ↑28 and ↓0+28
Comments33

Articles

Information

Website
www.ya.ru
Registered
Founded
Employees
over 10,000 employees
Location
Россия