(Часть 1, Часть 2) В прошлый раз я преждевременно упомянул токенизацию; теперь можно поговорить и о ней, а заодно и о маркировке частей речи (POS tagging).
Предположим, мы уже выловили все ошибки (какие догадались выловить) на уровне анализа текста регулярными выражениями. Стало быть, пора переходить на следующий уровень, на котором мы будем работать с отдельными словами предложения. Разбиением на слова занимается модуль токенизации. Даже в столь простой задаче есть свои подводные камни. Я даже не говорю о языках вроде китайского и японского, где даже вычленение отдельных слов текста нетривиально (иероглифы пишут без пробелов); в английском или в русском тоже есть над чем подумать. Например, входит ли точка в слово-сокращение или представляет собой отдельный токен? («др.» — это один токен или два?) А имя человека? «J. S. Smith» — сколько здесь токенов? Конечно, по каждому пункту можно принять волевое решение, но в дальнейшем оно может привести к различным последствиям, и это надо иметь в виду.
Примерно так я рассуждал на начальных этапах нашего проекта, теперь же склоняюсь к тому, что в задачах обработки текстов частенько приходится подчиняться решениям других людей. Это будет уже ясно на примере маркировки частей речи.
«I love big dogs.» -> «I_PRP love_VBP big_JJ dogs_NNS ._.»
В этом примере используются следующие маркеры: PRP — местоимение; VBP — глагол настоящего времени, единственного лица, не третьего числа; JJ — прилагательное; NNS — существительное во множественном числе. Ну а точка — это просто точка.
Зная части речи отдельных слов, можно формулировать более сложные паттерны ошибок. Например, «DT from» -> «DT form». Маркер DT обозначает «определяющее слово» — артикль или указатели вроде this/that. Если в тексте встретилось сочетание «the from» или «this from», скорее всего, это опечатка, и имелся в виду не предлог from, а «форма» — form. Можно ещё хитрее: «MD know VB» -> «MD now VB». Здесь идёт отлов опечатки «know вместо now» — паттерн «модальный глагол + know + глагол». Под него попадает, скажем, фраза «I can know say something more».
Само собой, несложно реализовать простейшие операции, такие как «или» («если встретилось то или это») и отрицание («встретилось не это»). Именно на таких выражениях работает уже упомянутая система LanguageTool. Поскольку распространяется она по лицензии LGPL, я решил перенести все её правила в нашу систему. Почему бы и нет? Люди проделали большую работу, было бы глупо не воспользоваться результатами, коли разрешают. Об ограничениях этого подхода мы ещё поговорим, а пока вернёмся к маркировке частей речи.
Наиболее популярный на сегодня способ POS-разметки сводится к той же самой задаче классификации, на сей раз уже в полном варианте. Мы даём на вход обучающемуся алгоритму слово и его контекст — обычно начальные и конечные символы слова, а также данные о предыдущих словах предложения — сами эти слова и соответствующие им части речи. Также мы сообщаем часть речи слова в текущем контексте, и алгоритм эту информацию запоминает. Если теперь подать на вход контекст, алгоритм сможет сделать разумную догадку о части речи.
Здесь тоже частенько используют модель максимальной энтропии. Хотя можно бы и поиграться с другими алгоритмами. Например, существует разработка на основе support vector machines (SVMTool).
Такие коллекции («аннотированные корпусы») существуют, хотя их не так много. Чаще всего встречается POS-маркировка, реже — глубокое аннотирование, то есть маркировка синтактико-семантических связей между словами в предложении. Крупнейший глубоко аннотированный корпус английского языка называется Penn Treebank и содержит почти три миллиона слов. Хорошие корпусы существуют также для немецкого и русского — это из тех, что я лично изучал.
Теперь подумаем вот о чём. Существуют языковые тонкости, относительно которых различные лингвисты придерживаются различных мнений. Например, сколько падежей в русском языке? Ответ школьника — шесть, однако я могу назвать, по крайней мере, восемь-девять. В английском языке какой частью речи является слово book в сочетании book market? Я бы сказал, что это прилагательное, но можно отстаивать и трактовку как «существительного в роли прилагательного».
Таким образом, можно по-разному размечать текст, исходя из каких-либо лингвистических или практических соображений. К сожалению, наши соображения вряд ли воплотятся в итоговой системе, ибо пользуясь готовым корпусом, мы вынужденно принимаем правила игры его разработчиков. Если я тренирую POS tagger на корпусе Penn Treebank, придётся смириться, что «book» в роли прилагательного всё равно трактуется как существительное. Кому не нравится — может создавать свой собственый корпус и размечать его по своему усмотрению.
Аналогично, в Penn Treebank знак препинания всегда является отдельным токеном, поэтому запись «etc.» — это два токена, а «J. S. Smith» — пять токенов, даже если это соглашение для меня неудобно. Выбора нет. Это, кстати, к вопросу о наличии лингвистов в проекте. Если бы у меня были неограниченные бюджеты и куча времени, можно было бы попытаться сделать полностью свою систему, воплощающую наши взгляды на проверку правописания. Однако в реальных условиях существующие NLP инструменты и текстовые корпусы направляют действия по достаточно чёткому маршруту, оставля не так уж и много простора для фантазии.
Да, ещё замечание. Естественно, готовые коллекции содержат корректные тексты, лишённые явных грамматических ошибок. Что это значит для нас? Ну, возьмём тот же POS tagger. Сначала мы его тренируем на корректных текстах (где он никогда не видит сочетаний вроде «I has»), а потом используем его для маркировки слов в текстах с ошибками. Будет ли он столь же хорош в новых условиях? Да кто ж его знает; но создавть корпус с типичными ошибками ради тренировки разметчика для нас слишком большая роскошь.
Продолжим в следующей части.
Предположим, мы уже выловили все ошибки (какие догадались выловить) на уровне анализа текста регулярными выражениями. Стало быть, пора переходить на следующий уровень, на котором мы будем работать с отдельными словами предложения. Разбиением на слова занимается модуль токенизации. Даже в столь простой задаче есть свои подводные камни. Я даже не говорю о языках вроде китайского и японского, где даже вычленение отдельных слов текста нетривиально (иероглифы пишут без пробелов); в английском или в русском тоже есть над чем подумать. Например, входит ли точка в слово-сокращение или представляет собой отдельный токен? («др.» — это один токен или два?) А имя человека? «J. S. Smith» — сколько здесь токенов? Конечно, по каждому пункту можно принять волевое решение, но в дальнейшем оно может привести к различным последствиям, и это надо иметь в виду.
Примерно так я рассуждал на начальных этапах нашего проекта, теперь же склоняюсь к тому, что в задачах обработки текстов частенько приходится подчиняться решениям других людей. Это будет уже ясно на примере маркировки частей речи.
Маркировка частей речи
Зная разбиение предложения на слова, можно уже искать по тексту часто встречающиеся опечатки. Например, переправлять «egg yoke» на «egg yolk» (эта опечатка, видимо, так популярна, что о ней даже упоминает Википедия). Но настоящий прогресс по сравнению с регулярными выражениями обеспечивает маркировка частей речи, то есть сопоставление каждому слову текста его части речи:«I love big dogs.» -> «I_PRP love_VBP big_JJ dogs_NNS ._.»
В этом примере используются следующие маркеры: PRP — местоимение; VBP — глагол настоящего времени, единственного лица, не третьего числа; JJ — прилагательное; NNS — существительное во множественном числе. Ну а точка — это просто точка.
Зная части речи отдельных слов, можно формулировать более сложные паттерны ошибок. Например, «DT from» -> «DT form». Маркер DT обозначает «определяющее слово» — артикль или указатели вроде this/that. Если в тексте встретилось сочетание «the from» или «this from», скорее всего, это опечатка, и имелся в виду не предлог from, а «форма» — form. Можно ещё хитрее: «MD know VB» -> «MD now VB». Здесь идёт отлов опечатки «know вместо now» — паттерн «модальный глагол + know + глагол». Под него попадает, скажем, фраза «I can know say something more».
Само собой, несложно реализовать простейшие операции, такие как «или» («если встретилось то или это») и отрицание («встретилось не это»). Именно на таких выражениях работает уже упомянутая система LanguageTool. Поскольку распространяется она по лицензии LGPL, я решил перенести все её правила в нашу систему. Почему бы и нет? Люди проделали большую работу, было бы глупо не воспользоваться результатами, коли разрешают. Об ограничениях этого подхода мы ещё поговорим, а пока вернёмся к маркировке частей речи.
Наиболее популярный на сегодня способ POS-разметки сводится к той же самой задаче классификации, на сей раз уже в полном варианте. Мы даём на вход обучающемуся алгоритму слово и его контекст — обычно начальные и конечные символы слова, а также данные о предыдущих словах предложения — сами эти слова и соответствующие им части речи. Также мы сообщаем часть речи слова в текущем контексте, и алгоритм эту информацию запоминает. Если теперь подать на вход контекст, алгоритм сможет сделать разумную догадку о части речи.
Здесь тоже частенько используют модель максимальной энтропии. Хотя можно бы и поиграться с другими алгоритмами. Например, существует разработка на основе support vector machines (SVMTool).
Аннотированные корпусы, великие и ужасные
В прошлый раз я не заострял на этом внимание, но теперь уж точно пора. Чтобы POS tagger заработал, его нужно натренировать на большой коллекции текстов, где каждому слову приписан тег части речи. Тогда возникает резонный вопрос: а где ж эту коллекцию взять?Такие коллекции («аннотированные корпусы») существуют, хотя их не так много. Чаще всего встречается POS-маркировка, реже — глубокое аннотирование, то есть маркировка синтактико-семантических связей между словами в предложении. Крупнейший глубоко аннотированный корпус английского языка называется Penn Treebank и содержит почти три миллиона слов. Хорошие корпусы существуют также для немецкого и русского — это из тех, что я лично изучал.
Теперь подумаем вот о чём. Существуют языковые тонкости, относительно которых различные лингвисты придерживаются различных мнений. Например, сколько падежей в русском языке? Ответ школьника — шесть, однако я могу назвать, по крайней мере, восемь-девять. В английском языке какой частью речи является слово book в сочетании book market? Я бы сказал, что это прилагательное, но можно отстаивать и трактовку как «существительного в роли прилагательного».
Таким образом, можно по-разному размечать текст, исходя из каких-либо лингвистических или практических соображений. К сожалению, наши соображения вряд ли воплотятся в итоговой системе, ибо пользуясь готовым корпусом, мы вынужденно принимаем правила игры его разработчиков. Если я тренирую POS tagger на корпусе Penn Treebank, придётся смириться, что «book» в роли прилагательного всё равно трактуется как существительное. Кому не нравится — может создавать свой собственый корпус и размечать его по своему усмотрению.
Аналогично, в Penn Treebank знак препинания всегда является отдельным токеном, поэтому запись «etc.» — это два токена, а «J. S. Smith» — пять токенов, даже если это соглашение для меня неудобно. Выбора нет. Это, кстати, к вопросу о наличии лингвистов в проекте. Если бы у меня были неограниченные бюджеты и куча времени, можно было бы попытаться сделать полностью свою систему, воплощающую наши взгляды на проверку правописания. Однако в реальных условиях существующие NLP инструменты и текстовые корпусы направляют действия по достаточно чёткому маршруту, оставля не так уж и много простора для фантазии.
Да, ещё замечание. Естественно, готовые коллекции содержат корректные тексты, лишённые явных грамматических ошибок. Что это значит для нас? Ну, возьмём тот же POS tagger. Сначала мы его тренируем на корректных текстах (где он никогда не видит сочетаний вроде «I has»), а потом используем его для маркировки слов в текстах с ошибками. Будет ли он столь же хорош в новых условиях? Да кто ж его знает; но создавть корпус с типичными ошибками ради тренировки разметчика для нас слишком большая роскошь.
Продолжим в следующей части.