pytorch gpt2 text-generation ru transformers Text generation license:unlicense
---
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': '<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>- Как тебя зовут?
- Джульетта Мао #
```


## Обрабатываемые ситуации

Модель разрабатывается с прицелом на использование в [чатботе](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
}
```
