Козиев Илья (kelijah) wrote,
Козиев Илья
kelijah

Categories:

Сеточная регрессия char-векторов в word2vector встраивания

При использовании word2vector представлений слов для синтаксического парсинга реальных текстов, а не искусственно подобранных предложений, всегда возникает проблема out-of-vocabulary слов. Эти несловарные токены возникают по разным причинам, включая опечатки, слияние соседних слов, ошибочное разделение одного слова на несколько, образование новых слов с помощью продуктивных приставок или составных слов:

Прибежал медицинский персопал

Пунктирные изобары соответствуют мвтастабильному равновесию.

рисунки замечательны и сделаны от чистого сеодца

мы были в двоем

нет одеял в номере для в сех

Предлагаю замечательных малышей той терьера.

Я в займы брал

отдыхала сдетьми первый раз

Смотрели этот отель врекламном туре.


Сосредоточимся на словообразовании и отчасти на опечатках.

Что может сделать морфологический анализатор, когда встречает несловарный токен? Очевидное решение - применить один из вариантов нечеткого сопоставления слов, например расстояние редактирования Левенштейна. При использовании вспомогательного префиксного дерева поиск подходящих слов выполняется почти так же быстро, как и поиск словарных токенов. Остается проблема новообразований. Для русских глаголов это выражается в легком образовании аспектных вариантов глагола с помощью различных приставок: обчитаться, напрограммироваться etc. Возникает соблазн использовать явные корреляции семантики глагола с набором морфем. К сожалению, объединение морфем в слово в русском языке часто сопровождается изменениями на границах морфем, что выражается в чередовании согласных, беглых гласных и прочих неприятностях. Можно ли поймать эти процесс с помощью нелинейной аппроксимации на сетке?

Итак, на входе у нас есть цепочка символов длины от 1 символа (малоинтересные случаи) до некоторого максимального значения в ~30 символов (см. замечания по поводу длины слов http://kelijah.livejournal.com/194691.html). На выходе нашего регрессора надо получить вектор, примерно соответствующий встраиванию этого слова в word2vec. Отбросим пока вопросы с переходом от символьного представления к семантике (карась и крась при крайней char-близости имеют совершенно разную семантическую и синтаксическую роль - см. http://kelijah.livejournal.com/195108.html).

Далее я опишу отдельные моменты, к которым пришел после множества экспериментов.

Оценка качества регрессии

Для оценки близости двух слов в word2vector пространстве обычно используется cosine similarity, то есть фактически косинус угла между двумя векторами. Чтобы оценить качество регрессии множества слов, я просто вычисляю среднее значение косинуса между векторами char-модели и word2vector для каждого из слов в лексиконе (точнее, L2 меру косинусов). В идеальном случае точной аппроксимации получится 1, так как косинус между коллинеарными векторами равен именно 1. Чем меньше значение оценки, тем хуже char-модель аппроксимирует w2v.

Нюанс с оценочной функцией для обучения сетки

Как я отметил выше, для оценки качества сеточной регрессии я вычисляю L2 меру для косинусов. Отсюда возникает резонный вопрос - а не стоит ли сетку обучать так, чтобы она максимизировала этот самый косинус, вместо минимизации евклидового расстояния между точками?

В Keras есть соответствующая целевая функция с названием ‘cosine_proximity’. Именно ее я указываю при компиляции сетки:

model.compile( loss=’cosine_proximity’, … )

Эксперименты показывают, что замена ‘mean_squared_error’ на ‘cosine_proximity’ ощутимо улучшает итоговую оценку модели по среднему косинусу.

Вторая часть нюанса с objective для регрессора заключается в том, что выбор cosine_proximity улучшает только char_feedforward модель. Для char_rnn модели качество результата падает. Возможно это связано с каким-то багом в Keras для рекуррентных слоев.

Размерность word2vector пространства и достигаемое качество аппроксимации

Эксперименты показывают, что нет прямой однозначной корреляции между параметрами word2vector модели и качеством аппроксимации в char-модели. Иногда word2vector модель с dim=256 аппроксимируется качественнее, чем dim=32 при прочих равных параметрах char-модели. Иногда наоборот. Роль параметра win также неоднозначна. Иногда аппроксимация dim=32 win=1 работает намного хуже, чем dim=32 win=5, хотя можно было бы ожидать, что узкое окно дает более “синтаксические векторы” w2v, которые легче аппроксимировать по окончаниям слов, что лучше для char-модели. Но факты упрямо опровергают такие прямые рассуждения, приходится выяснять качество моделей сравнением или даже grid-поиском в пространстве метапараметров, не полагаясь на интуицию.

Регрессия char-векторов в w2v пространство на char-rnn моделях

После тренировки на word2vector модели с dim=32 и win=1 визуальный контроль дает такие результаты.
Вводится слово, скрипт выдает top10 максимально близких в w2v пространстве к нему. Похожесть оценивается между char-аппроксимацией вектора и w2v векторами:

Word?кошка
cos( w2v, char )=0.836656173373
кувалда ==> 0.964491554926
ботва ==> 0.958075958319
телочка ==> 0.956049445094
брюква ==> 0.954352217627
каракатица ==> 0.95428208179
удочка ==> 0.954278071922
нерпа ==> 0.953122902754
хатка ==> 0.952175273329
жадина ==> 0.952133532156
куропатка ==> 0.948194736413

Строка с cos( w2v, char ) показывает близость char-аппроксимации и w2v вектора, чем ближе к 1, тем лучше.

Еще примеры:

Word?кошкой
cos( w2v, char )=0.870036168872
лейкой ==> 0.970138984353
земляникой ==> 0.966933331011
пантерой ==> 0.965131847883
мухобойкой ==> 0.962122888206
косою ==> 0.960825656817
кофтой ==> 0.959387032411
блевотиной ==> 0.95893613741
грелкой ==> 0.958146013771
наживкой ==> 0.957694720936
курочкой ==> 0.956337641045

Word?кошками
cos( w2v, char )=0.886738657982
колышками ==> 0.984266066081
фермами ==> 0.979410138248
антеннами ==> 0.979237173761
накидками ==> 0.978399352893
бантиками ==> 0.977357444154
жуками ==> 0.977118213336
гнездами ==> 0.976737263447
раковинами ==> 0.975906303119
галстуками ==> 0.975739400838
мячиками ==> 0.975544619122

С глаголами немного хуже, как это было и в случае сеточной лемматизации (http://kelijah.livejournal.com/194249.html):

Word?замечаю
cos( w2v, char )=0.763967066937
выкидываю ==> 0.968004754197
подожгу ==> 0.959878067651
помещаю ==> 0.959834165369
советуйте ==> 0.956994660908
раздаривал ==> 0.956781357824
приготовишь ==> 0.956773068962
переделала ==> 0.95651597009
узришь ==> 0.956205546891
пустишь ==> 0.955830874168
подержит ==> 0.955706008643

Как обстоят дела с несловарными цепочками?

Word?котзилле
лотосе ==> 0.957037878439
тулуме ==> 0.95482512962
воеводстве ==> 0.95419935261
перголе ==> 0.953592137937
кактусе ==> 0.952539116651
молоте ==> 0.95202082586
хмельницком ==> 0.951074912818
фарфоре ==> 0.95090244549
мызе ==> 0.950669510362
мезонине ==> 0.950589843495

Word?громозекаются
обрабатывались ==> 0.968083417129
проектировались ==> 0.965847238575
заряжаются ==> 0.964928715424
разогреваются ==> 0.962956341311
мокли ==> 0.962259400067
мешаются ==> 0.961157743323
шились ==> 0.961076717092
осваивались ==> 0.960435013218
циркулировали ==> 0.959926447067
разлагаются ==> 0.959815832479

Регрессия char-векторов в w2v пространство на char-feedforward моделях

Данный тип сеток показал себя плохо на лемматизации, но в задаче аппроксимации w2v отыгрался по полной. Достигаемое качество оказалось лучше, чем у char-rnn моделей, при намного более высокой скорости обучения.

В этой модели получилось немного улучшить качество, используя так называемое overcomplete представление. Основные пояснения можно найти на странице примера Keras (https://blog.keras.io/building-autoencoders-in-keras.html). Попросту говоря, скрытый слой делаем намного шире, чем выходной. Например, для выходных векторов длиной 32 берем скрытый слой размером 1024. Если просто поставить полносвязный слой такого размера, то сетка откажется обучаться. Чтобы обучение началось, необходимо применить регуляризацию. Я использовал регуляризацию по средней активности слоя, как описано в вышеуказанной статье. Выглядит это так:

model.add( Dense( input_dim=input_size, output_dim=HIDDEN_SIZE, activation='sigmoid', activity_regularizer=regularizers.activity_l1(1e-8) ) )

Масштаб регуляризации (тут он равен 1e-8) играет большое значение. Слишком малое значение не вытолкнет сетку из глобального минимума и обучение не пойдет. Слишком большая зарегулированность сделает слой очень разряженным и выходной слой не сможет аппроксимировать w2v векторы. В общем, подбор этого значения выполняется вручную в серии экспериментов.

Примеры поиска ближайших слов для вектора, выдаваемого char-feedforward моделью по некоторым цепочкам на входе:

Word?кракозябровые
наблюдательные ==> 0.95930362782
двухлетние ==> 0.953208193768
ультрасовременные ==> 0.953117032337
энхаэловские ==> 0.953006237056
заградительные ==> 0.952269973855
выставочные ==> 0.951349212842
библиотечные ==> 0.949787980197
бинарные ==> 0.947666980257
слуховые ==> 0.946946198208
машинные ==> 0.946776875926

С глаголами всё всегда сложно:

Word?накракозябрили
термитники ==> 0.949898504756
барражируют ==> 0.949845306859
высвобождаются ==> 0.944703787224
вырождаются ==> 0.943822506202
сблизятся ==> 0.942801455581
кристаллизуются ==> 0.940127326434
борты ==> 0.940004386003
роторы ==> 0.93964951052
тихоходные ==> 0.939037137899
выключились ==> 0.938690707777

Деепричастия редки и легко маскируются под существительные, но в данном конкретном случае сетка признала в слове что-то глагольное:

Word?прокракозябрив
уравниваются ==> 0.917964552213
расписывайтесь ==> 0.915296816239
исключив ==> 0.912653721339
выцарапали ==> 0.912310115124
подготавливается ==> 0.911978794804
насчитаешь ==> 0.909138407829
страховались ==> 0.909129992248
подключают ==> 0.907900243783
привлекается ==> 0.906913173876
отозвало ==> 0.905102751958
Tags: char-rnn, character language model, deep learning, keras, machine learning, neuronet, python, vector model, vector space model, word embedding, word2vec
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

  • 0 comments