--- tags: Text generation license: unlicense language: ru widget: - text: "- Как тебя зовут? - Джульетта Мао #" - text: "- А живешь где? - В поясе астероидов #" --- ## Задача Incomplete Utterance Restoration Генеративная модель на основе [sberbank-ai/rugpt3large_based_on_gpt2](https://huggingface.co./sberbank-ai/rugpt3large_based_on_gpt2) для восстановления полного текста реплик в диалоге из контекста. Допустим, последние 2 строки диалога имеют вид: ``` - Как тебя зовут? - Джульетта Мао ``` Модель позволяет получить полный текст последней реплики, с раскрытыми анафорами, эллипсисами и т.д.: ``` Меня зовут Джульетта Мао ``` Раскрытая реплика позволяет использовать многие классические инструменты NLP для своей обработки, включая регулярные выражения, классификаторы интентов и т.д. Подробнее о том, какие ситуации и как обрабатываются моделью, смотрите в [конце страницы](#обрабатываемые-ситуации) и в [этом документе](https://huggingface.co./inkoziev/rugpt_interpreter/blob/main/%D0%92%D0%BE%D1%81%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D1%85%20%D1%80%D0%B5%D0%BF%D0%BB%D0%B8%D0%BA%20%D0%B2%20%D0%B4%D0%B8%D0%B0%D0%BB%D0%BE%D0%B3%D0%B5.pdf). ## Пример использования ``` 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': '', 'eos_token': '', 'pad_token': ''}) model = AutoModelForCausalLM.from_pretrained(model_name) model.to(device) model.eval() # На вход модели подаем последние 2-3 реплики диалога. Каждая реплика на отдельной строке, начинается с символа "-" # В конце добавляем символ "#" input_text = """- Как тебя зовут? - Джульетта Мао #""" #input_text = """- Что Предтечи забрали у Предшественников? #- Они узурпировали у них Мантию — защиту всего живого в галактике #""" 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('')] print(text) ``` ## Формат входных данных На вход модели подается результат токенизации для текста, составленного из 2 или 3 последних реплик диалога. Первым токеном должен быть ``````. Каждая реплика должна начинаться префиксом "- ". Реплики разделяются символом перевода строки. К последней реплике, которая будет раскрываться, добавляется подстрока " #". ``` - Как тебя зовут? - Джульетта Мао # ``` ## Обрабатываемые ситуации Модель разрабатывается с прицелом на использование в [чатботе](https://github.com/Koziev/chatbot). Она поддерживает некоторые типичные ситуации в читчате, которые перечислены далее. В примерах после символа ⇒ идет эталонная раскрытая реплика, которую должна сгенерировать модель. [Эллипсисы](https://ru.wikipedia.org/wiki/%D0%AD%D0%BB%D0%BB%D0%B8%D0%BF%D1%81%D0%B8%D1%81): ``` - Как же тебя зовут, а? - Меня – Стас, а тебя? ⇒ Меня зовут Стас. Как тебя зовут? ``` В редких случаях и главное слово в словосочетании может опускаться, модель попытается его восстановить: ``` - Мама, купи мне собаку. - А ты будешь за ней ухаживать? - А ты мне здоровую купи. ⇒ купи мне здоровую собаку ``` [Анафора](https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%B0%D1%84%D0%BE%D1%80%D0%B0_(%D0%BB%D0%B8%D0%BD%D0%B3%D0%B2%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0)): ``` - Ты собак любишь? - Не люблю я их ⇒ я не люблю собак ``` Иногда для раскрытия полной реплики требуется привлечение здравого смысла, модель для этого будет опираться на статистику претрейна: ``` - Мне на голову упала коробка. - А что в ней было? ⇒ что было в коробке|голове? ``` [Гэппинг](https://ru.wikipedia.org/wiki/%D0%AD%D0%BB%D0%BB%D0%B8%D0%BF%D1%81%D0%B8%D1%81#%D0%93%D1%8D%D0%BF%D0%BF%D0%B8%D0%BD%D0%B3_(en:Gapping)): ``` - Ты кошек любишь? - Их – нет ⇒ я не люблю кошек ``` Сложный гэппинг: ``` - В 25 лет вы получаете пенсию? - Не я - отец. ⇒ Я не получаю пенсию. Отец получает пенсию ``` Восстановление необязательного местоименного подлежащего (см. [pro drop](https://en.wikipedia.org/wiki/Pro-drop_language)): ``` - Согласна? - Да ⇒ я согласна ``` Модель пытается "читать между строк" и восстанавливать подразумеваемые части реплики: ``` - Ты разве ещё не ел? - Тебя ждал ⇒ я еще не ел. я ждал тебя. ``` Отрицания в диалоге: ``` - Я не прав? - Нет. (Да.) ⇒ ты не прав ``` Интерпретация не сводится к копированию слов из контекста, иногда модель должна добавить ассоциируемые с ситуацией слова: ``` - Как прошли выходные? - В Простоквашино ездила... ⇒ я на выходных ездила в Простоквашино ``` Все вышесказанное может быть в разных сочетаниях одновременно: ``` - Где твой кот? - Жена к ветеринару повезла. ⇒ жена повезла моего кота к ветеринару - Заболел? ⇒ твой кот заболел? ``` Сложные предложения: ``` - Я сварила суп, иди ешь. - Из чего? ⇒ из чего ты сварила суп? ``` Замена подлежащего производится, если это улучшает понимание реплики: ``` - Как себя чувствует твой попугай? - Бедняга умер... ⇒ мой попугай умер ``` Иногда от реплики остается только наречие, модель будет восстанавливать все остальное: ``` - Девушка, а Вы животных любите? - Очень! ⇒ я очень люблю животных ``` Форма сказуемого иногда может меняться из соображений согласованности: ``` - Рабинович, как думаете, что будет делать правительство, если завтра население разом бросит курить? - Таки, поднимут акцизы на алкоголь... ⇒ правительно поднимет акцизы на алкоголь, если завтра население разом бросит курить ``` Во всех случаях модель не выдает никакой информации, откуда она взяла подстановку для замены или заполнения в выходном тексте. На выходе получается просто текст реплики в том виде, как ее мог бы сказать человек, безо всяких дополнительных отсылок и маркеров: ``` - У тебя брат есть? - Да, есть - Где он работает? ⇒ Где работает твой брат? ``` В данном примере модель никак не сообщит нам, откуда она взяла подстановку “твой брат” для местоимения “он”. Это сильно упрощает ручную разметку обучающего корпуса и не особо мешает диалоговой системе. Во многих случаях модель приводит порядок слов к более-менее каноническому. Точнее говоря, она старается выдать текст с таким порядком слов, который обычно используют носители языка в данном контексте диалога. Если русскоговорящие предпочитают OVS вместо формального SVO, то модель будет выдавать именно OVS: ``` - У тебя штрафы были? - Нет, их никогда не было ⇒ у меня никогда не было штрафов ``` Модель обычно вставляет личные местоимения, даже если форма глагола позволяет обойтись без них: ``` - Жару любишь? - Ненавижу ее ⇒ я ненавижу жару ``` Сложносочиненные ответы разбиваются на отдельные клаузы, чтобы downstream pipeline мог обработать их последовательно: ``` - Тебя как зовут? - Кортана, а тебя как? ⇒ Меня зовут Кортана. Как тебя зовут? ``` В качестве контекста можно подавать последние 2 или 3 реплики. Более длинные отношения весьма редки, чтобы ради них усложнять датасет. Кроме того, во многих случаях достаточно применить модель рекурсивно - подать вместо исходных реплик диалога результат их раскрытия моделью: ``` - Где живешь? - В Шанхае ⇒ я живу в Шанхае - Давно? ⇒ ты давно живешь в Шанхае? - Два года уже ⇒ я уже два года живу в Шанхае - Как там погода? ⇒ как там погода в Шанхае? ``` Последнее, что хочется отметить: модель обучена **только** на диалоговых данных с короткими репликами (читчат). Она практически не способна раскрывать анафоры в художественных текстах, хотя это не ограничение модели, а особенность обучающего датасета. ### 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 } ```