Синтаксический анализ на сверточных и рекуррентных сетках. Часть 1: syntax_chars

Nov 06, 2016 15:25

Посмотрим, как с помощью нейросетевых моделей можно строить синтаксическое дерево зависимостей для предложения.

Синтаксическое дерево во всех описываемых далее моделях представляется матрицей связности узла с родителем. Таким образом, для предложения длиной N слов получается сильно разряженная квадратная булевская матрица N*N, в каждой строке которой только одна ячейка имеет значение 1. Такую матрицу можно развернуть в список и подавать на сетку в качестве эталонного выхода. В обучающем датасете матрица представлена компактно, через относительное расстояние до родителя:

победа всегда достается сильнейшему    2 1 0 -1
иванов проявил грубость в разговоре    1 0 -1 -1 -1
розничные цены гораздо выше оптовых    1 2 1 0 -1
этот человек всегда хорошо выглядит    1 3 2 1 0
Тип связи не определяем. Это с одной стороны упрощает парсинг на сетке, с другой стороны, определение типа ребер можно считать отдельной задачей, более близкой к SRL. А в некоторых задачах тип связи вообще не нуженю Достаточно получить матрицу связности, и рассматривать ее как новый уровень representation для предложения.

Начнем с самой простой модели - syntax_chars. На самом деле я сделал ее в последнюю очередь, и был сильно удивлен, что она вообще работает, да еще и дает достаточно хорошие результаты, учитывая располагаемую сеткой информацию. Впрочем, на фоне штучек типа Pixel Recurrent Neural Networks или Neural Machine Translation это не выглядит технологическим прорывом.

На входе сетки имеем цепочку символов предложения. Каждый символ представлен 1-hot вектором, так что для усеченного русского алфавита без цифр получаем 33 бита на символ.

С помощью LSTM-слоя эта цепочка векторов упаковывается в вектор длиной 256 элементов (самый главный настроечный метапараметр).

Далее один или два feedforward-слоя преобразуют полученный вектор в выходную матрицу связности.

Необычно здесь вот что. Синтаксическое дерево - высокоуровневая абстракция, присущая предложению в целом. Чтобы подняться на этот уровень с уровня символов, сначала пройти уровень слов (именно между ними определяются синтаксические связи). Таким образом, перед сеткой стоят сразу несколько NLP-задач: токенизация, морфологический разбор и наконец парсинг.

Поэтому достигаемая на предложениях длиной 6 слов точность в ~97...98% правильных ребер не может не удивлять:


В конце обучения ошибаемость падает до 2.1%. В  табличке ниже показана ошибка в простановке ребер сеткой по эпохам обучения:

1    0.107217805328
2    0.0794828457177
3    0.0651907578855
4    0.0594675492061
5    0.0538753523155
6    0.0489606398096
7    0.0455366290077
8    0.0431211729214
9    0.0410651140393
10    0.038713983561
11    0.0368821790919
12    0.0352097132848
13    0.0339072672593
14    0.032639049539
15    0.0320595289241
16    0.0313861755416
17    0.0300778280842
18    0.0291684174248
19    0.0283876579813
20    0.0278045965073
21    0.0270592456554
22    0.0261232785523
23    0.0251902621652
24    0.0252581286323
25    0.0247393927663
26    0.024499204487
27    0.0233903254286
28    0.0232357079122
29    0.0226314012832
30    0.0225900912597
31    0.0222389560603
32    0.0219503760392
33    0.021477081199
34    0.021225680199

Важное замечание по поводу обучаемости данной модели. Эксперименты показывают, что очень важное значение имеет объем обучающего датасета. Уменьшение датасета приводит к неприятной динамике кривой обучения, если смотреть на val_loss (оценивающая функция на тестовом наборе паттернов). Сначала сетка улучшает точность. Затем несколько эпох точность болтается около достигнутого значения, иногда сильно ухудшаясь. Потом снова улучшается до нового оптимума, снова болтается и т.д. Увеличение датасета сглаживает кривую обучения и уменьшает вероятность преждевременного прекращения обучения по критерию early stopping (10 эпох без улучшения val_loss). В результате график обучения при уменьшенном до 100,000 паттернов датасете выглядит примерно так:


Модель реализована на Keras, обучение на 300,000 паттернах длится около 5 часов на GTX 980.

нейросети, language model, синтаксический разбор, lstm, rnn, keras, синтаксический анализатор, tree bank, python

Previous post Next post
Up