language: ru
license: unlicense
tags:
- PyTorch
- Transformers
- gpt2
datasets: inkoziev/incomplete_utterance_restoration
pipeline_tag: text-generation
widget:
- text: '- Как тебя зовут? - Джульетта Мао #'
- text: '- А живешь где? - В поясе астероидов #'
Задача Incomplete Utterance Restoration
Генеративная модель на основе sberbank-ai/rugpt3large_based_on_gpt2 для восстановления полного текста реплик в диалоге из контекста.
Допустим, последние 2 строки диалога имеют вид:
- Как тебя зовут?
- Джульетта Мао
Модель позволяет получить полный текст последней реплики, с раскрытыми анафорами, эллипсисами и т.д.:
Меня зовут Джульетта Мао
Раскрытая реплика позволяет использовать многие классические инструменты NLP для своей обработки, включая регулярные выражения, классификаторы интентов и т.д.
Подробнее о том, какие ситуации и как обрабатываются моделью, смотрите в конце страницы и в этом документе.
Пример использования
Данная модель работает в прототипе диалоговой системы. Она не требует для работы никакой "обвязки", пре- или постпроцессинга, помимо стандартных для моделей семейства GPT, поэтому использовать ее очень просто:
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
device = "cuda" if torch.cuda.is_available() else "cpu"
model_name = "inkoziev/rugpt_interpreter"
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.add_special_tokens({'bos_token': '<s>', 'eos_token': '</s>', 'pad_token': '<pad>'})
model = AutoModelForCausalLM.from_pretrained(model_name)
model.to(device)
model.eval()
# На вход модели подаем последние 2-3 реплики диалога. Каждая реплика на отдельной строке, начинается с символа "-"
# В конце добавляем символ "#"
input_text = """<s>- Как тебя зовут?
- Джульетта Мао #"""
#input_text = """<s>- Что Предтечи забрали у Предшественников?
#- Они узурпировали у них Мантию — защиту всего живого в галактике #"""
encoded_prompt = tokenizer.encode(input_text, add_special_tokens=False, return_tensors="pt").to(device)
output_sequences = model.generate(input_ids=encoded_prompt, max_length=100, num_return_sequences=1, pad_token_id=tokenizer.pad_token_id)
text = tokenizer.decode(output_sequences[0].tolist(), clean_up_tokenization_spaces=True)[len(input_text)+1:]
text = text[: text.find('</s>')]
print(text)
Формат входных данных
На вход модели подается результат токенизации для текста, составленного из 2 или 3 последних реплик диалога.
Первым токеном должен быть <s>
.
Каждая реплика должна начинаться префиксом "- ".
Реплики разделяются символом перевода строки.
К последней реплике, которая будет раскрываться, добавляется подстрока " #".
<s>- Как тебя зовут?
- Джульетта Мао #
Обрабатываемые ситуации
Модель разрабатывается с прицелом на использование в чатботе. Она поддерживает некоторые типичные ситуации в читчате, которые перечислены далее.
В примерах после символа ⇒ идет эталонная раскрытая реплика, которую должна сгенерировать модель.
- Как же тебя зовут, а?
- Меня – Стас, а тебя? ⇒ Меня зовут Стас. Как тебя зовут?
В редких случаях и главное слово в словосочетании может опускаться, модель попытается его восстановить:
- Мама, купи мне собаку.
- А ты будешь за ней ухаживать?
- А ты мне здоровую купи. ⇒ купи мне здоровую собаку
- Ты собак любишь?
- Не люблю я их ⇒ я не люблю собак
Иногда для раскрытия полной реплики требуется привлечение здравого смысла, модель для этого будет опираться на статистику претрейна:
- Мне на голову упала коробка.
- А что в ней было? ⇒ что было в коробке|голове?
- Ты кошек любишь?
- Их – нет ⇒ я не люблю кошек
Сложный гэппинг:
- В 25 лет вы получаете пенсию?
- Не я - отец. ⇒ Я не получаю пенсию. Отец получает пенсию
Восстановление необязательного местоименного подлежащего (см. pro drop):
- Согласна?
- Да ⇒ я согласна
Модель пытается "читать между строк" и восстанавливать подразумеваемые части реплики:
- Ты разве ещё не ел?
- Тебя ждал ⇒ я еще не ел. я ждал тебя.
Отрицания в диалоге:
- Я не прав?
- Нет. (Да.) ⇒ ты не прав
Интерпретация не сводится к копированию слов из контекста, иногда модель должна добавить ассоциируемые с ситуацией слова:
- Как прошли выходные?
- В Простоквашино ездила... ⇒ я на выходных ездила в Простоквашино
Все вышесказанное может быть в разных сочетаниях одновременно:
- Где твой кот?
- Жена к ветеринару повезла. ⇒ жена повезла моего кота к ветеринару
- Заболел? ⇒ твой кот заболел?
Сложные предложения:
- Я сварила суп, иди ешь.
- Из чего? ⇒ из чего ты сварила суп?
Замена подлежащего производится, если это улучшает понимание реплики:
- Как себя чувствует твой попугай?
- Бедняга умер... ⇒ мой попугай умер
Иногда от реплики остается только наречие, модель будет восстанавливать все остальное:
- Девушка, а Вы животных любите?
- Очень! ⇒ я очень люблю животных
Форма сказуемого иногда может меняться из соображений согласованности:
- Рабинович, как думаете, что будет делать правительство, если завтра население разом бросит курить?
- Таки, поднимут акцизы на алкоголь... ⇒ правительно поднимет акцизы на алкоголь, если завтра население разом бросит курить
Во всех случаях модель не выдает никакой информации, откуда она взяла подстановку для замены или заполнения в выходном тексте. На выходе получается просто текст реплики в том виде, как ее мог бы сказать человек, безо всяких дополнительных отсылок и маркеров:
- У тебя брат есть?
- Да, есть
- Где он работает? ⇒ Где работает твой брат?
В данном примере модель никак не сообщит нам, откуда она взяла подстановку “твой брат” для местоимения “он”. Это сильно упрощает ручную разметку обучающего корпуса и не особо мешает диалоговой системе.
Во многих случаях модель приводит порядок слов к более-менее каноническому. Точнее говоря, она старается выдать текст с таким порядком слов, который обычно используют носители языка в данном контексте диалога. Если русскоговорящие предпочитают OVS вместо формального SVO, то модель будет выдавать именно OVS:
- У тебя штрафы были?
- Нет, их никогда не было ⇒ у меня никогда не было штрафов
Модель обычно вставляет личные местоимения, даже если форма глагола позволяет обойтись без них:
- Жару любишь?
- Ненавижу ее ⇒ я ненавижу жару
Сложносочиненные ответы разбиваются на отдельные клаузы, чтобы downstream pipeline мог обработать их последовательно:
- Тебя как зовут?
- Кортана, а тебя как? ⇒ Меня зовут Кортана. Как тебя зовут?
В качестве контекста можно подавать последние 2 или 3 реплики. Более длинные отношения весьма редки, чтобы ради них усложнять датасет. Кроме того, во многих случаях достаточно применить модель рекурсивно - подать вместо исходных реплик диалога результат их раскрытия моделью:
- Где живешь?
- В Шанхае ⇒ я живу в Шанхае
- Давно? ⇒ ты давно живешь в Шанхае?
- Два года уже ⇒ я уже два года живу в Шанхае
- Как там погода? ⇒ как там погода в Шанхае?
Последнее, что хочется отметить: модель обучена только на диалоговых данных с короткими репликами (читчат). Она практически не способна раскрывать анафоры в художественных текстах, хотя это не ограничение модели, а особенность обучающего датасета.
Пример работы в чате
Первый столбец содержит реплики диалога модели читчата с собой, второй столбец - результат раскрытия реплик моделью интерпретатора:
- Добрый вечер, бро! |
- Чё, будем общаться? | Мы будем общаться?
- Ага, а как же | Мы будем общаться
- О чем хочешь говорить? | О чем ты хочешь говорить?
- Давай о чем-нибудь хорошем | Я хочу говорить о чем-нибудь хорошем
- Мне нравится обсуждать компьютерные игры | Мне нравится обсуждать компьютерные игры
- О, компьютерные игры меня тоже интересуют | Меня тоже интересуют компьютерные игры
- Ты играл в Minecraft? | Ты играл в Minecraft?
- Неа, но хотел бы | Я не играл в игру Minecraft. Я хочу поиграть в игру Minecraft.
Датасет
Обучающие данные без аугментации: inkoziev/incomplete_utterance_restoration.
Контакты
Если у Вас есть какие-то вопросы по использованию этой модели, или предложения по ее улучшению - пишите мне [email protected]
Citation:
@MISC{rugpt_interpreter,
author = {Ilya Koziev},
title = {Incomplete Utterance Restoration in Russian Chit-Chat conversations},
url = {https://huggingface.co/inkoziev/rugpt_interpreter},
year = 2022
}