File size: 21,554 Bytes
07163df
50127aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8933648
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50127aa
8933648
 
 
 
 
 
 
 
50127aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3384511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
994f258
3384511
 
 
 
 
 
 
 
 
 
 
 
 
50127aa
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# Введение
В этом репозитории методы обработки естественного языка (NLP) используются для изучения стиля речи Рейчел из сериала "Друзья", проведения мультиязыкового анализа английского языка и обучения нейронной сети общению в стиле Рейчел.
Перенос стиля очень популярен в НЛП и сейчас используется в самых разных сферах, от образования до персонализации электронных помощников. А с развитием больших моделей-трансформеров, которые демонстрируют выдающиеся способности в понимании естественного языка и имитации самых разных стилей, передача стиля вышла на новый уровень. Сегодня большие языковые модели, такие как GPT3, благодаря своим объемам и миллиардам параметров способны идеально изучить все особенности обучающей выборки (т. е. обучить распределению) и сгенерировать реалистичный текст в определенном стиле.
В этом посте я исследую возможности языковых моделей для генерации текста в стиле Рейчел из знаменитого сериала "Друзья". Для этого используется корпус английских транскриптов сериала, который был собран для поиска чатбота и обучения двуязычных моделей для общения в стиле Рейчел Грин.
Кроме того, я провела анализ стиля, изучила особенности речи Рейчел.
Таким образом, проект можно условно разделить на 3 части:
* Cбор данных
* Стилистический анализ речи персонажей
* Фреймворк для обучения моделей, которые пишут текст в стиле Рейчел.
Весь код можно найти в этом репозитории HF.

# Данные
## Выбор персонажа
Я решил продолжить использовать сериал, на котором остановился в предыдущем проекте, ситком "Друзья", который шел с 1994 по 2004 год. Несмотря на свой возраст, он остается популярным и по сей день. Этот комедийный сериал рассказывает о жизни шести друзей (Росс, Фиби, Моника, Рейчел, Джоуи и Чендлер), которые живут в Нью-Йорке и постоянно попадают в какие-то неприятности и забавные ситуации. Почему мы выбрали именно этот сериал? По трем причинам:

1. Я нашел в открытом доступе расшифровки 236 эпизодов. Это очень много данных, которые я могу использовать для обучения языковой модели.

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

3. Это популярный сериал, который многие из нас смотрели и хорошо знают. Это значит, что я могу сделать предположения о данных (например, Фиби говорит более простыми словами и т. д.) и оценить реалистичность стиля сгенерированного текста, основываясь на своем опыте просмотра.

## Сбор данных
Оригинальные транскрипты, которые я взял из Интернета, были на английском языке. Затем я выполнил следующую предварительную обработку текста:

1. Во-первых, я очистил данные от мелких графемных ошибок, характерных для транскриптов. Например, если персонаж говорил что-то длинное, его слова могли содержать повторы гласных для имитации длинного звука ("nooooooooooooooooooooooooooooooooooooooooooooooooo").  

2. Во-вторых, я заметил, что некоторые слова содержат повторы одного и того же слова для комичности. Я также удалял такие повторы, оставляя только одну копию повторяющегося слова.  

3. В-третьих, поскольку я хотел передать стиль, присущий каждому персонажу, я отбросил общие фразы, используемые всеми 6 главными героями ("Знаете что!", "О Боже!" и т. д.).

Таким образом, я собрал корпус диалогов для 6 персонажей, включающий около 8 тысяч предложений для каждого персонажа. Подробное распределение по количеству предложений для каждого персонажа вы можете увидеть в таблице ниже:
!["Number of replicas for every character"](./images/NumberOfReplicasOverCharacter.png)

### Анализ данных
Количество реплик для всех сезонов показано ниже:
!["Number of replicas for every character"](./images/NumberOfReplicasOverSeason.png)
Как видно, среднее значение количества реплик за все сезоны составляет 6000 при стандартном отклонении около 400.

Количество реплик для всех эпизодов показано ниже:
!["Number of replicas for all seasons"](./images/NumberOfReplicasInEpisode.png)
Как видно, среднее значение количества реплик в эпизоде составляет 265. Стандартное отклонение составляет около 65 реплик. 

Самые частые слова в наборе данных:
!["Number of replicas for episode"](./images/MostFrequentWords.png)

# Анализ стилей персонажей
Прежде чем обучать языковые шаблоны, я исследовал стилевые особенности Рэйчел. В частности, чтобы определить особенности речи, я сделал следующее:

* Подсчитал описательную статистику: количество слов, среднее количество слов в предложении, индекс читабельности, доля сложных слов и т. д.

* Наиболее частотные слова для персонажей;

* Доля положительных и отрицательных слов.

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

После такого первичного анализа речи я более детально исследовала словарный запас и проанализировала его с точки зрения сложности слов, используемых персонажами. За "трудные" слова мы условно приняли длинные слова, состоящие более чем из 4 слогов. Долю сложных слов для каждого персонажа можно увидеть на графике ниже:

## Самые частые слова Рейчел
Я провел анализ наиболее частотных слов Рейчел, исключив стоп-слова из nltk.stopwords("english"). Результат этого анализа показан ниже.
!["Most frequent Rachel's words"](./images/RachelMostFrequentWords.png)
Или эти данные можно представить в виде изображения
!["Most frequent rachel's words in image"](./images/RachelWords.png)

# Подготовка данных
Итак, мы собрали фразы Рейчел и разделили их на два набора данных: реплики и фразы. Для целей моделирования мы снабдили все реплики дополнительным набором лексем и тегов:

Специальные лексемы <s> и </s>, обозначающие начало и конец примера.

Имя персонажа пишется заглавными буквами.

Специальный псевдоним NOTFRIEND, который являлся маркером реплики другого говорящего в диалоговых парах "реплика НЕФРИЕНДА - ответ ГЕРОЯ". Мы использовали такой псевдоним, чтобы отделить чужие реплики от героя, чьему стилю мы хотим подражать.

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

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

!["raw monologues"](./images/phrases.png)

2. Необработанные диалоги - набор данных, содержащий пары "реплика НЕдруга - ответ ГЕРОя", разделенные символом переноса строки \n.  Набор данных диалогов необходим, потому что мы хотим, чтобы наша модель могла поддерживать разговор с пользователем в стиле Friends, а не просто генерировать текст.

!["raw dialogs"](./images/replicas.png)

# Обучение

## Архитектура модели GPT2
Архитектура модели GPT-2 (Generative Pre-trained Transformer 2) основана на трансформерной архитектуре, предложенной в статье "Attention is All You Need" от Vaswani et al. (2017). Однако, GPT-2 представляет собой усовершенствование и расширение этой базовой архитектуры. Вот основные компоненты архитектуры GPT-2:

1. **Stacked Transformer Decoder Layers**: GPT-2 состоит из нескольких блоков трансформера, где каждый блок представляет собой "слой декодера". Каждый слой декодера включает в себя множество механизмов внимания и нормализацию LayerNorm. 

2. **Multi-Head Self-Attention Mechanism**: Этот механизм позволяет модели сосредотачиваться на различных частях входных данных и извлекать их взаимосвязи. В GPT-2 используется множество "голов" внимания, которые позволяют модели фокусироваться на разных аспектах данных.

3. **Feed-Forward Neural Networks**: Каждый блок трансформера содержит также набор полносвязных слоев (feed-forward networks), которые применяются к выходу из слоев внимания.

4. **Positional Encoding**: Для того чтобы модель могла учитывать порядок слов в последовательности, в GPT-2 используется позиционное кодирование, которое добавляет информацию о позиции каждого слова в последовательности.

5. **Layer Normalization**: Нормализация слоев (LayerNorm) применяется после каждого слоя в трансформере для стабилизации обучения.

6. **Residual Connections**: В GPT-2 используются связи прямого распространения (residual connections), которые позволяют более эффективно передавать градиенты в глубоких нейронных сетях.

7. **Position-wise Feedforward Networks**: Полносвязные сети применяются к каждой позиции в последовательности независимо, что позволяет модели лучше захватывать локальные зависимости.

Архитектура GPT-2 представляет собой стек этих блоков, причем количество блоков и их размер могут варьироваться в зависимости от размера модели. Например, оригинальная модель GPT-2 имеет 12 слоев декодера для маленьких версий и до 48 слоев для самых крупных версий.
Для обучения модели передачи стиля Рейчел чатботу я использовал несколько моделей. Обучение моделей проходит в два этапа. На первом этапе модель пытается уловить личность Рейчел и изучает ее монологи. На втором этапе модель пытается узнать, как Рейчел ведет себя в диалогах, поэтому на этом этапе модель обучается на диалогах.

В данной работе было обучено 3 модели из четырёх: GPT-2-small, GPT-2-medium, GPT-2-large
!["gpt2-models"](https://jalammar.github.io/images/gpt2/gpt2-sizes.png)

Архитектура GPT-2 в зависимости от размера модели представленна на рисунке ниже:
!["gpt2-models"](https://jalammar.github.io/images/gpt2/gpt2-sizes-hyperparameters-3.png)


1. Первый этап - GPT2. Для наборов данных я использовал TextDataset от PyTorch и библиотеку трансформаторов от huggingface.
   Результаты показаны на изображении ниже
   !["gpt2-results"](./images/gpt2-results.png)

2. Вторая модель - GPT2-medium. Результаты обучения на монологах показаны ниже
   !["gpt2-medium-mono-train"](./images/gpt2-medium-mono-train.png)
   Обучение диалогам показано на следующем изображении
   !["gpt2-medium-mono-train"](./images/gpt2-medium-replics-train.png)
   Результат обучения показан ниже
   !["gpt2-medium-results"](./images/gpt2-medium-results.png)

2. Последняя модель - GPT2-large. Обучение на монологах показано ниже
   !["gpt2-large-mono-train"](./images/gpt2-large-mono-train.png)
   Обучение диалогам показано на следующем изображении
   !["gpt2-large-mono-train"](./images/gpt2-large-replics-train.png)
   Результат обучения показан ниже
   !["gpt2-large-results"](./images/gpt2-large-results.png)

### Генерация текста

После обучения, модель собирается в pipeline

```python
chef = pipeline('text-generation', model="./models/en_gpt2-large_rachel_replics", tokenizer=model_type)
```

Для генерации текста используется следующая команда
```python
out = model.generate(inpt.cuda(),
                    max_length=50,
                    repetition_penalty=5.0,
                    do_sample=True,
                    top_k=5,
                    top_p=0.95,
                    temperature=1)
```
,где
1. **max_length=50**: Этот параметр задает максимальную длину генерируемого вывода. В данном случае он равен 50 лексемам.

2. **repetition_penalty=5.0**: Этот параметр наказывает модель за повторение одного и того же токена в выводе. Более высокое значение увеличивает наказание за повторение лексем, что потенциально может привести к более разнообразным выводам.

3. **do_sample=True**: Этот параметр указывает, использовать ли выборку при генерации. Если `True`, модель будет делать выборку из своего выходного распределения для генерации текста, что приведет к более разнообразным результатам.

4. **top_k=5**: Этот параметр определяет количество лексем, которые будут рассматриваться для выборки на основе их вероятностей. Он ограничивает выборку k лексемами с наибольшей вероятностью.

5. **top_p=0.95**: Этот параметр, также известный как выборка по ядрам, управляет порогом кумулятивной вероятности для выборки по ядрам. Он ограничивает выборку подмножеством лексем, чья кумулятивная вероятность превышает этот порог.

6. **temperature=1**: Этот параметр масштабирует логиты перед применением softmax во время выборки. Более высокая температура приводит к большей случайности в генерируемом тексте.
Overall, this code snippet generates text using a GPT-2 model with the specified input prompt and generation parameters, producing diverse and contextually relevant outputs.

# Архитектура

- PrepareData.ipynb <- Парсер данных из Интернета, очистка, токенизация и подготовка к набору данных
- train_data <- папка datasets с монологами и диалогами
- Training_gpt2_medium.ipynb <- обучение gpt2-medium
- en_gpt2-medium_rachel_replics <- модель gpt2-medium
- Training_gpt2_large.ipynb <- тренировка gpt2-large
- en_gpt2-large_rachel_replics <- gpt2-large модель
- images <- изображения для README.md
- app.py <- основной файл
- requirements.txt <- необходимые библиотеки
# Заключение и планы на будущее
Итак, я использовал методы обработки естественного языка для изучения стиля речи Рейчел из известного сериала "Друзья", провел мультиязычный анализ для английского языка и обучил языковые модели на основе GPT говорить в стиле Рейчел.
В будущем я хочу поэкспериментировать с еще более крупными моделями. Например, с LLama, а также с методами генерации управляемого текста для них.