Следующий этап тестирования ― рекуррентные LSTM-сети.
Как и ранее, в последних экспериментах с сетями прямого распространения, словарь создаётся инструментом Word2Vec с равномерным распределением слов в векторном пространстве. Каждое слово представляется вектором длины .
Подготовка для генерации последовательностей
Кодирование предложений
Рекуррентные сети могут генерировать последовательности, поэтому применим соответствующий способ кодирования. Попросим сеть по предложению-вопросу пословно генерировать предложение-ответ.
В текстовом виде база обучения хранится как набор предложений «Вопрос = Ответ», например:
1 ПРИВЕТ = ПРИВЕТ (2 слова) 2 ДАВНО НЕ ВИДЕЛИСЬ = ЗДРАВСТВУЙ ДРУГ (5 слов) 3 ХОРОШИЙ ДЕНЬ = ОТЛИЧНЫЙ ДЕНЬ (4 слова) 4 КАКОЙ СЕГОДНЯ ДЕНЬ = СЕГОДНЯ ОТЛИЧНЫЙ ДЕНЬ (6 слов) 5 ДАВАЙ ДРУЖИТЬ = ДАВАЙ БУДЕМ ДРУЗЬЯМИ (5 слов) 6 БУДЕШЬ МОИМ ДРУГОМ = ХОРОШО КОГДА МНОГО ДРУЗЕЙ (7 слов) 7 ДО ВСТРЕЧИ = ДО СВИДАНИЯ (4 слова)
Для управления генерацией последовательностей используются следующие служебные теги, которые закодированы с помощью Word2Vec вместе с другими словами:
- #GEN# ― конец предложения-вопроса, можно начинать генерировать ответ;
- #BOS# ― начало генерации ответа;
- #EOS# ― остановить генерацию ответа.
Для обучения нейронной сети формируются две матрицы TrainX и TrainY следующим образом. Каждая матрица имеет размер , где ― число предложений в базе ( в этом примере); ― наибольшее количество слов в предложении + 3 (для #GEN#, #BOS#, #EOS#), в данном примере ; ― длина вектора слова (50).
Все последовательности приводятся к самой длинной по числу слов. В данном примере самой длинной является последовательность №6, значит все предложения дополняются до семи слов, пустые места в конце заполняются #EOS#:
t=0 t=1 t=2 t=3 t=4 t=5 t=6 t=7 t=8 t=9 TrainX[0][t] = ПРИВЕТ #GEN# #BOS# ПРИВЕТ #EOS# #EOS# #EOS# #EOS# #EOS# #EOS# TrainY[0][t] = NULL #BOS# ПРИВЕТ #EOS# #EOS# #EOS# #EOS# #EOS# #EOS# #EOS# t=0 t=1 t=2 t=3 t=4 t=5 t=6 t=7 t=8 t=9 t=10 TrainX[1][t] = ДАВНО НЕ ВИДЕЛИСЬ #BOS# ЗДРАВСТВУЙ ДРУГ #EOS# #EOS# #EOS# #EOS# #EOS# TrainY[1][t] = NULL NULL NULL ЗДРАВСТВУЙ ДРУГ #EOS# #EOS# #EOS# #EOS# #EOS# #EOS#
NULL ― ответ сети значения не имеет, при кодировании слов заполняется нулями.
Генерирование ответа сетью
После обучения на вход нейронной сети пословно подаются все слова вопроса и тег #GEN#. После этого просим сеть предсказывать следующее слово по переданным ранее предыдущим, пока не встретится тег #EOS#. Исключая из ответа служебные теги, получаем ответ.
Тестирование архитектур
Теперь для экспериментов использую язык Python и библиотеку Keras.
Вариант 1. Одна ячейка LSTM, 65 450 параметров
В эксперименте участвуют:
- Слой 1: LSTM с D нейронами на входе и 2D на выходе;
- Слой 2: Слой прямого распространения с D нейронами.
После обучения и запоминания 109 предложений можно получить вот такие ответы.
― ПРИВЕТ ― ПРИВЕТ ― ТЕБЯ КАК ЗОВУТ? ― МЕНЯ ЗОВУТ СЕТЬ ― ПРИВЕТ СЕТЬ ― ПРИВЕТ ― ПРИВЕТ, ТЫ МЕНЯ ЗНАЕШЬ? ― Я ТОЛЬКО УЧУСЬ ― ТЕБЯ ЗОВУТ ОЛЕГ? ― ПРИЯТНО ПОЗНАКОМИТЬСЯ ― ТЕБЯ ЗОВУТ СЕТЬ? ― МЕНЯ ЗОВУТ СЕТЬ ― ТЫ ХОРОШАЯ? ― Я ДУМАЮ ТЕБЕ ― ТЕБЕ ЧТО-НИБУДЬ НРАВИТСЯ? ― МНЕ НРАВИТСЯ СЛУШАТЬ ― ХОЧЕШЬ ПОГОВОРИТЬ? ― БУДУ РАДА ИНТЕРЕСНОЙ БЕСЕДЕ ― О ЧЁМ? ― ДАВАЙ ПОГОВОРИМ О
Вариант 2. Две ячейки LSTM, 93 150 параметров
В эксперименте участвуют:
- Слой 1: LSTM с D нейронами на входе и 2D на выходе;
- Слой 2: LSTM с 2D нейронами на входе и D на выходе;
Задаём те же самые вопросы:
― ПРИВЕТ ― ПРИВЕТ ― КАК ТЕБЯ ЗОВУТ? ― МЕНЯ ЗОВУТ СЕТЬ ― ПРИВЕТ, СЕТЬ ― ЭТО ДРУГ ― ПРИВЕТ, ТЫ МЕНЯ ЗНАЕШЬ? ― Я ТОЛЬКО УЧУСЬ ― ТЕБЯ ЗОВУТ ОЛЕГ? ― МЕНЯ ЗОВУТ ― ТЕБЯ ЗОВУТ СЕТЬ? ― МЕНЯ ЗОВУТ СЕТЬ ― ТЫ ХОРОШАЯ? ― Я ДУМАЮ УЧУСЬ ― ТЕБЕ ЧТО-НИБУДЬ НРАВИТСЯ? ― МНЕ НРАВИТСЯ СЛУШАТЬ МУЗЫКУ ― ХОЧЕШЬ ПОГОВОРИТЬ? ― БУДУ РАДА ИНТЕРЕСНОЙ БЕСЕДЕ ― О ЧЁМ? ― ДАВАЙ ПОГОВОРИМ О
Вариант 3. Три ячейки LSTM, 63 150 параметров
В эксперименте участвуют:
- Слой 1: LSTM с D нейронами на входе и D на выходе;
- Слой 2: LSTM с D нейронами на входе и D на выходе;
- Слой 3: LSTM с D нейронами на входе и D на выходе.
И такой диалог:
― привет ― ПРИВЕТ ― ТЕБЯ КАК ЗОВУТ? ― МЕНЯ ЗОВУТ СЕТЬ ― ПРИВЕТ, СЕТЬ ― ЭТО ТЕБЕ ― ПРИВЕТ, ТЫ МЕНЯ ЗНАЕШЬ? ― Я ТОЛЬКО УЧУСЬ ― ТЕБЯ ЗОВУТ ОЛЕГ? ― МЕНЯ ПОЗНАКОМИТЬСЯ ― ТЕБЯ ЗОВУТ CЕТЬ? ― МЕНЯ ЗОВУТ СЕТЬ ― ТЫ ХОРОШАЯ? ― Я ДУМАЮ В ― ТЕБЕ ЧТО-НИБУДЬ НРАВИТСЯ? ― МНЕ НРАВИТСЯ СЛУШАТЬ МУЗЫКУ ― ХОЧЕШЬ ПОГОВОРИТЬ? ― БУДУ РАДА ИНТЕРЕСНОЙ БЕСЕДЕ ― О ЧЁМ? ― ДАВАЙ БУДЕМ ДРУЗЬЯМИ
Итог
Для тестирования специально выбирались вопросы, которых нет в обучающей базе (кроме первого), чтобы проверить «разумность» построенных моделей. Как мне показалось, рекуррентные сети работают гораздо лучше, на них сильно не сказывается отсутствие некоторых слов в вопросе или порядок слов в предложении (ответ на «Как тебя зовут?», «Как зовут тебя?» одинаков). Конечно, и этот результат всё ещё далёк от «хорошего».
Интересно, что первая модель из трёх наиболее адекватно отвечает на приветствие, её не сбивает собственное имя в предложении. Вместе с тем, она всё же точно не знает, как её зовут. Вторая модель, напротив, на приветствие, отличное от обучаемого, отвечает как угодно ужасно. Но, в отличие от первой модели, попыталась правильно ответить на вопрос о своём имени («Тебя зовут Олег?» ― «Меня зовут»). Хоть в данной реализации не предполагается запоминание контекста диалога и предыдущих ответов, выбор темы разговора в первых двух моделях выглядит адекватнее.
Вывод: Из всей тестовой базы первые модели отвечают адекватно на одну часть вопросов, великолепно проваливая тест на остальной. Другие модели отвечают на вторую часть вопросов и блестяще не справляются с первой. Жаль, что нельзя создать совокупность нейронных сетей, которые бы смогли ответить на все вопросы тестового набора правильно…
Поэтому дальнейшая задача ― исследование влияния типов и количества слоёв ИНС на качество её ответов при неизменных обучающем и тестовом наборах, чтобы сконструировать такую модель нейронной сети, которая пройдёт мой тест.