Что делает сеточный лемматизатор?
Вот скриншот обучающейся модели, на котором видно, что поступало на вход сетки и что получалось на выходе:
Для разнообразия показана выдача с одной ошибкой (приколочить вместо приколотить).
Таким образом, задача сеточного лемматизатора - для любого входного слова выдать его нормальную форму (лемму). Лемматизация понимается достаточно формально и узко, в частности прилагательные КРАСИВЫЙ и НЕКРАСИВЫЙ рассматриваются как разные слова. В других задачах отличие КРАСИВЫЙ от НЕКРАСИВЫЙ ничем не отличается от пар КРАСИВАЯ-КРАСИВЫЙ, то есть к набору грамматических признаков добавляется еще один - отрицательность. Аналогичный подход можно распространить на пары ОДНОЭТАЖНЫЙ-ДВУХЭТАЖНЫЙ и прочие случаи регулярного словообразования, таким образом сводя лемматизацию к поиску базовых корней. Но мы для сеточной лемматизации ограничимся самой простой постановкой задачи.
Почему я выбрал лемматизацию для проверки разных технических решений в нейросетевых моделях? Как и MNIST для распознавания изображения, лемматизация является с одной стороны достаточно простой задачей, для решения которой не нужно выстраивать сложные последовательности вычислений. С другой стороны, это часто встречающаяся на практике задача, поэтому ее решение само по себе может быть использовано в реальных проектах.
Теперь пара слов об особенностях реализации.
Прежде всего, для каждой части речи со словоизменением строится отдельная модель. Как уже было сказано в разделе про датасеты, выгрузка пар слово-лемма дополнена столбцом с названием части речи. Таким образом, лемматизация слов с омонимичными формами типа стали-(сталь,стать) выполняется более качественно. Количество слов внутри одной части речи, которые имеют совпадающие формы при разных леммах (лис-лиса, судно-суда-суд), достаточно мало. Само собой, разбивка модели по частям речи требует, чтобы какой-то внешний алгоритм определил, к какой части речи относится слово. В парсере (
http://solarix.ru/parser.shtml) для этого используется отдельно обучаемый part of speech tagger. Можно также обучить отдельный сеточный классификатор определять часть речи по контексту слова.
Таким образом, из общего массива в ~3,5 миллиона пар слово-лемма получается четыре датасета для четырех моделей: существительные, прилагательные, глаголы и наречия.
Наречия и drop-out.
И тут появляется первая неприятная особенность сеточных моделей. Для прилагательных, существительных и глаголов в словарной базе есть по несколько сотен тысяч паттернов. Для наречий объем датасета намного меньше, он не дотягивает и до полусотни тысяч пар. Такой небольшой объем материала приводит к плохой обучаемости модели. Это выражается в медленном падении ошибки на тестовом наборе наречий (показаны результаты для char-rnn модели с 64 элементами LSTM в кодирующей части):
На графике очень хорошо видно, что модель для наречий (подписана как adverb в легенде) имеет существенно меньшую точность, и в ходе обучения наблюдаются большие скачки. Остальные три модели резво и кучно обучаются в течении ста эпох, достигая очень неплохой точности. Мало данных и много обучаемых параметров намекают на то, что можно попробовать улучшить обучение с помощью
drop-out. Модель char-rnn становится такой:
model = Sequential()
model.add( Masking( mask_value=0,input_shape=(max_word_len,bits_per_char) ) )
DROPOUT = 0.1
model.add( RNN( HIDDEN_SIZE, input_shape=(max_word_len, bits_per_char), dropout_W=DROPOUT, dropout_U=DROPOUT ) )
model.add( RepeatVector(right_len) )
model.add( RNN(HIDDEN_SIZE, return_sequences=True))
model.add(TimeDistributedDense(bits_per_char))
model.add(Activation('softmax'))
Экспериментальная проверка показывает, что ситуацию можно немного улучшить правильным подбором величины дропаута:
По оси OY отложена ошибка (доля наречий, лемматизированных неверно).
Видно, что с небольшим дропаутом 0.05 модель обучается медленнее, но финальная достигаемая точность улучшается. Без дропаута модель в какой-то момент застревает в локальном минимуме, validation loss перестает падать и обучение прекращается по early stopping.
В целом, наречия представляют определенную проблему. В этом классе фактически собраны две группы слов - с регулярным словоизменением быстро-побыстрее-побыстрей-быстрее-быстрей и прочие когда, где, мало-меньше. Небольшое количество примеров не позволяют сеточной модели выявить общие правила, кроме того разнообразие неизменяемых наречий запутывает сетку.
Объединенная сеточная лемматизация
Нет никаких причин не проверить сеточную лемматизацию для всех частей речи в одной модели. С одной стороны, неоднозначности объединенного датасета будут приводить к ошибкам. С другой, больший объем датасета дает больше возможностей найти общие правила лемматизации. К примеру, компаративы наречий (проблемы с ними описаны ранее) строятся по тем же правилам, что и компаративы прилагательных.
Кривая обучения (по OY - доля ошибок лемматизации для 1000 случайно выбранных слов):
Рекуррентная модель с использованием LSTM показывает лучшие результаты, чем char-rnn модель на GRU при сравнимых скоростях обучения.
Скачки кривой объясняются тем, что после каждой эпохи выбираются новые 1000 слов для оценки точности.