Параллельный алгоритм составления словаря глагольного управления для новостных текстов на английском языке
Гурбанов Т.П., Клышинский Э.С.
МГТУ им. Н.Э. Баумана, каф. ИУ-7
В статье описывается решения задачи выделения групп слов из синтаксически связанных конструкций, которые в свою очередь выделяются из содержимого текстового файла с исходными данными. Решение задачи производится при помощи языка программирования Python с использованием библиотек NLTK и Pymorphy.
Введение
Информация о сочетаемости слов является важной для целого списка задач, относящихся к автоматизированной обработке текстов. При ручной обработке текстов она необходима при переводе на данный язык, когда переводчик может проверить себя, правильно ли он связал слова или подобрал переводные эквиваленты. В процессе обучения иностранному языку студент может проверить правильность составленных конструкций. Также информация о сочетаемости слов может использоваться и при автоматической обработке текстов. Так, например, она используется при проверке корректности получаемых в ходе синтаксического анализа деревьев синтаксических зависимостей. Кроме того, на основании информации о сочетаемости слов можно проводить собственно поверхностный синтаксический анализ. Возможны также и другие применения.
В предыдущих работах мы извлекали информацию из текстов на русском языке [1]. В данной статье будет рассмотрен вопрос применения тех же методов к текстам на английском языке. Метод
Из текстов на английском языке извлекались конструкции следующего вида:
1. <конструкция №1> ::= (начало предложения) <артикль>? <прилагательное >* < существительное > <глагол> +
2. <конструкция№2> ::= <глагол>+ <предлог>? <артикль>? <прилагательное> * <существительное>
3. <конструкция№3> ::= <предлог\артикль> <прилагательное> + <существительное>
Данные конструкции рассматривались с целью извлечения следующих синтаксических конструкций:
1. <глагол> ^ <предлог> ^ < существительное >
2. <существительное> ^ <прилагательное>
Однако за счет неоднозначности текста или наличия в нем ошибок возможно выделение некорректных конструкций. В связи с этим необходимо посчитать частоту встречаемости каждой конструкции. Далее конструкции, встретившиеся менее определенного количества раз, отбрасываются как шум. Тем самым снижается полнота результатов, но повышается их точность.
Исходную задачу можно разбить на следующие этапы.
1. Чтение исходных данных из файла;
2. Разбиение полученных данных на предложения;
3. Разбиение каждого предложения на токены;
4. Поиск в каждом предложении конструкций;
5. Выделение групп из полученных конструкций;
6. Приведение слов в выделенных группах к нормальной форме;
7. Сохранение полученных «нормализованных» групп в хранилище, и подсчет количества раз, которое каждая группа встречается.
После выполнения разметки текста можно приступать к шагу выделения групп из конструкций и приведения каждого слова в группе к нормальной форме. Разбить конструкцию на группы можно при помощи грамматики, для чего придется приводить полученные конструкции к списку токенов, либо решить эту же задачу при помощи реализации процедуры, которая, проходя в обратном порядке по списку токенов конструкции, ищет в прямом порядке совпадение частей речи рассмотренных токенов с частями речи каждой групп. Блок-схема алгоритма приведена на рис. 1.
Описанный алгоритм имеет линейную временную сложность, поэтому разбивать на группы предпочтительнее именно им. Выбор инструментов
Решение задачи начинается с прочтения текста из файла с исходными данными. Файл может быть очень большой, для того, чтобы прочитать его полностью в память, поэтому желательно читать файл по частям.
Для анализа текста нам потребуются инструменты, проводящие графематический и морфологический анализ текста. Кроме того, для выделения синтаксических конструкций необходимы инструменты для работы с КС-грамматиками.
В ходе проведенного обзора возможных инструментов выбор пал на следующие два продукта:
• NLTK;
• Pymorphy.
NLTK - библиотека для языка программирования Python, которая разрабатывается для работы с естественными языками [5]. Для решения описанной выше задачи данная библиотека может предоставить следующие инструменты:
• Инструмент разбиения текста на предложения. Библиотека NLTK умеет отличать пунктуацию в сокращениях от пунктуации, используемой для обозначения границ предложений
• Токенайзер предложений. Аналогично инструменту разбиения на предложения, использует информацию о пунктуации и разбивает предложения на слова. Графематика NLTK работает со стандартным размеченным корпусом. В случае если нужно реализовать другое поведение для токенайзера предложений, достаточно предоставить библиотеке NLTK свой размеченный корпус и провести переобучение токенайзера на основе предоставленного корпуса. Это касается и языка текста, так как по умолчанию инструмент умеет работать только с текстом на английском языке.
Среди недостатков NLTK можно выделить отсутствие инструментов для морфологического анализа.
Для составления конструкций необходимо получить информацию о части речи каждого слова в каждом предложении. Библиотека классов Pymorphy [2], базирующаяся на словарях группы АОТ [3], позволяет проводить морфологический анализ конкретного слова. Однако в связи с тем, что Pymorphy может обрабатывать только по одному слову за раз, решение использовать только эту библиотеку является неэффективным и непроизводительным.
С другой стороны, несмотря на отсутствие в NLTK собственных инструментов для морфологического анализа, он все же позволяет разбивать текст на части речи.
Делается это с использованием POS-тэггера1, который, как и графематика, привязан к конкретному корпусу. Т.е. как и с графематическим анализом, если надо изменить поведение POS-тэггера, достаточно переобучить его на новом корпусе.
Также в библиотеке NLTK имеются инструменты для работы с КС-грамматикой. Использование КС-грамматики на размеченном POS-тэггером тексте позволяет разбить предложения на конкретные конструкции. Такой подход позволяет не реализовывать свой метод для получения конструкций из предложения, а также задавать информацию об искомых конструкциях в виде КС-грамматики.
POS-тэггер работает с размеченным корпусом, что позволяет удалить омонимию, а воспользовавшись парсером RecursiveDescentParser (библиотекой классов NLTK), конструктор которого принимает КС-грамматику искомых конструкций, можно для каждого предложения получить соответствующее ему дерево разбора.
Как уже говорилось, библиотека NLTK не имеет инструментов для проведения морфологического анализа. Однако на данном этапе можно воспользоваться библиотекой Pymorphy. После того как текст был разбит на группы, количество слов, которое необходимо обработать, уменьшается в несколько раз, что позволяет воспользоваться библиотекой Pymorphy.
Минусом использования библиотеки Pymorphy может стать отсутствие возможности работы с контекстом слова. Это означает, что порой результаты могут быть не совсем корректными. К примеру, слово в сравнительной форме прилагательного и в форме наречия может выглядеть одинаково, но нормальные формы этого же слова для прилагательного и наречия могут различаться. Библиотека Pymorphy не будет знать, какой частью речи является слово, и, следовательно, может неправильно привести к нормальной форме.
Последним шагом является сохранение групп и подсчет количества раз, которое встречается каждая группа. Можно считать, что каждая группа - это уникальное значение. Поэтому можно хранить и считать статистику, как пару ключ-значение, где ключом является группа, а значением - количество раз, которое группа встречается. В качестве такой пары, можно воспользоваться стандартной реализацией словарей в языках программирования, либо воспользоваться базой данных (БД). Рассмотрим второй вариант.
Использование реляционной базы данных нерационально для столь простой задачи. Поэтому вместо обычной реляционной базы данных стоит воспользоваться базой данных типа key-value. В данной реализации была использована БД Redis. Распараллеливание алгоритма
На рис. 2 изображена первичная конфигурация программного продукта.
Рисунок изображает процесс получения групп из исходного файла данных. В процессе используются следующие узлы:
1. Чтение из файла 20МБ данных. В случае если файл прочитан до конца происходит завершение работы программы (READ);
2. Разбиение прочитанных 20МБ данных на предложения и передача в следующий узел по одному необработанному предложению (SPLIT);
3. Разбиение предложения на токены (TOKENIZE);
1 Part-Of-Speech-tagger — инструмент для разметки слов текста, соответствующими им частями речи. Для разметки инструмент анализирует контекст каждого слова и ищет совпадения результатов анализа в уже размеченном наборе вспомогательных данных.
4. Использование POS-тэггера и КС грамматики для получения списка конструкций (PARSE);
5. Получение списка групп из списка полученных конструкций (GROUP);
6. Сохранение полученных конструкций в БД, подсчет статистики (STORE).
READ SPLIT TOKENIZE PARSE GROUP STORE
Файл с Прочитанные Необработанное Список Список Список
исходными 20 МБ данных предложение токенов конструкций групп
Файл прочитан / Все предложения Получить новое предложение
до конца, выход / обработаны, прочитать
/ новые 20 МБ
J данных
Рисунок 2. Процесс получения групп из исходного файла данных При хронометраже выполнения задачи на тексте объемом в 3 МБ время работы программы составило 11 мин. Следовательно, время обработки 900МБ тестового текста составит приблизительно 55 часов. Для повышения производительности распараллелим работу некоторых узлов программного продукта.
Так как для реализации используется язык программирования Python, то по причине наличия GIL1 невозможно использовать параллельные потоки. При мощности вычислительного ресурса в n процессоров для оптимальной работы можно запустить до n отдельных процессов. В соответствии с этим модифицируем часть кода с учетом того, что каждый процесс использует свой экземпляр библиотеки Pymorphy, но все процессы используют вызов одного и того же метода POS-тэггинга. Теперь текст объемом в 3 МБ программа обрабатывает за 20 минут.
READ SPLIT TOKENIZE PARSE GROUP STORE
V - объем данных, Прочитанные
равный результату V МБ данных деления общего
объема данных -^
библиотеки Pymorphy, единый POS-тэггер)
:Global Interpreter Lock - используемая в языке программирования Python глобальная блокировка интерпретатора, не позволяющая выполнять больше одного потока в единицу времени.
На рис. 3 изображен процесс получения групп из исходного файла данных с использованием n параллельных процессов (раздельные экземпляры библиотеки Pymorphy, единый POS-тэггер).
Воспользовавшись профилировщиком и документацией по NLTK [5] можно прийти к выводу, что POS-тэггинг однопоточен и работает с диском, а работу с единственным экземпляром нельзя разбить на параллельные процессы. Основываясь на [5] и результатах работы профилировщика, перепишем код так, что каждый процесс использует свой Pymorphy и метод POS-тэггинга, который работает с дампом корпуса, хранящимся в памяти. У каждого процесса свой дамп. Программа обработала текста объемом в 3МБ за 19 минут.
READ SPLIT TOKENIZE PARSE GROUP STORE
V - объем данных, Прочитанные Равный Результату V МБ данных деления общего
объема данных _
на кол-во процессов n. В случае если V
экземпляры библиотеки Pymorphy, разделенный вызов POS-тэггера)
На рис. 4 изображен процесс получения групп из исходного файла данных с использованием n параллельных процессов (раздельные экземпляры библиотеки Pymorphy, раздельные POS-тэггеры).
Как видно из проведенных тестов произвести прямое распараллеливание невозможно. Однако увеличения производительности можно добиться, применив библиотеку Execnet, использование которой для работы с инструментами библиотеки NLTK описано в статье Якоба Перкинса [4].
Execnet - библиотека, предоставляющая возможность использования модели share-nothing с передачей данных при помощи каналов приема и отсылки. Данная библиотека позволяет распределить вычисления по нескольким интерпретаторам, платформам или участникам сети. Архитектура share-nothing представляет собой распределенную вычислительную архитектуру, в которой каждый узел является независимым и самодостаточным, а в системе не существует единой конкурирующей точки. В частности, ни один из узлов не имеет общего пространства памяти или дискового хранилища.
Теперь время обработки 3МБ текста уменьшилось до 6 минут. Время обработки 900МБ - 24 часа.
На рис. 5 изображен процесс получения групп из исходного файла данных с использованием п параллельных каналов Execnet.
Плюсы использования данного подхода:
• Возможность запустить количество параллельных процессов, ограниченное лишь ресурсами системы.
Минусы:
• Для каждого процесса выделяется некоторый объем памяти, в который загружаются все необходимые для работы процесса данные. В нашем случае для работы одного процесса было необходимо выделить под него память, объем которой равен размеру размеченного корпуса необходимого для работы POS-тэггера.
В текущей реализации программы в отдельные процессы была вынесена только операция POS-тэггинга. Однако возможно вынести в этот же процесс и другие операции, что позволит распараллелить, к примеру, разбиение предложения на токены.
READ SPLIT TOKENIZE PARSE GROUP STORE
Результаты экспериментов
Для проверки разработанного программного обеспечения использовался текст книги «Властелин колец» Дж.Р.Р. Толкиена (объем 3МБ). Получение синтаксически связанных конструкций должно проводиться на тексте гораздо большего объема, в связи с этим использовался дамп новостей компании Рейтерс за 2007 год (объем 900МБ).
Для демонстрации принципа работы разработанного программного продукта, предлагается рассмотреть следующий отрывок из книги The Lord of the Rings (J.R.R. Tolkien):
"This tale grew in the telling, until it became a history of the Great War of the Ring and included many glimpses of the yet more ancient history that preceded it. It was begun soon after The Hobbit was written and before its publication in 1937; but I did not go on with this sequel, for I wished first to complete and set in order the mythology and legends of the Elder Days, which had then been taking shape for some years. I desired to do this for my own satisfaction, and I had little hope that other people would be interested in this work,
especially since it was primarily linguistic in inspiration and was begun in order to provide the necessary background of 'history' for Elvish tongues. When those whose advice and opinion I sought corrected little hope to no hope, I went back to the sequel, encouraged by requests from readers for more information concerning hobbits and their adventures. But the story was drawn irresistibly towards the older world, and became an account, as it were, of its end and passing away before its beginning and middle had been told. The process had begun in the writing of The Hobbit, in which there were already some references to the older matter: Elrond, Gondolin, the High-elves, and the orcs, as well as glimpses that had arisen unbidden of things higher or deeper or darker than its surface: Durin, Moria, Gandalf, the Necromancer, the Ring. The discovery of the significance of these glimpses and of their relation to the ancient histories revealed the Third Age and its culmination in the War of the Ring.
Those who had asked for more information about hobbits eventually got it, but they had to wait a long time; for the composition of The Lord of the Rings went on at intervals during the years 1936 to 1949, a period in which I had many duties that I did not neglect, and many other interests as a learner and teacher that often absorbed me. The delay was, of course, also increased by the outbreak of war in 1939, by the end of which year the tale had not yet reached the end of Book One. In spite of the darkness of the next five years I found that the story could not now be wholly abandoned, and I plodded on, mostly by night, till I stood by Balin's tomb in Moria. There I halted for a long while. It was almost a year later when I went on and so came to Lothlorien and the Great River late in 1941. In the next year I wrote the first drafts of the matter that now stands as Book Three, and the beginnings of chapters I and III of Book Five; and there as the beacons flared in Anorien and Theoden came to Harrowdale I stopped. "
Ниже приведен список полученных из приведенного выше отрывка текста конструкций.
(clause_2 grew/VBD in/IN the/DT telling/NN)
(clause_2 became/VBD a/DT history/NN)
(clause_2 included/VBD many/JJ glimpses/NNS)
(clause_3 ancient/JJ history/NN)
(clause_2 set/VB in/IN order/NN)
(clause_2 been/VBN taking/VBG shape/NN)
(clause_3 own/JJ satisfaction/NN)
(clause_2 had/VBD little/JJ hope/NN)
(clause_3 that/IN other/JJpeople/NNS)
(clause_2 was/VBD begun/VBN in/IN order/NN)
(clause_2 provide/VB the/DT necessary/JJ background/NN)
(clause_2 sought/VBD corrected/VBN little/JJ hope/NN)
(clause_2 encouraged/VBD by/IN requests/NNS)
(clause_3 for/IN more/JJR information/NN)
(clause_2 concerning/VBG hobbits/NNS)
(clause_2 became/VBD an/DT account/NN)
(clause_1 The/DTprocess/NN had/VBD begun/VBN)
(clause_2 had/VBD arisen/VBN unbidden/VBN of/IN things/NNS)
(clause_3 the/DT ancient/JJ histories/NNS)
(clause_2 revealed/VBD the/DT Third/NNP Age/NNP)
(clause_2 had/VBD asked/VBN for/IN more/JJR information/NN)
(clause_2 wait/VB a/DT long/JJ time/NN) (clause_2 had/VBD many/JJ duties/NNS) (clause_3 other/JJ interests/NNS) (clause 1 The/DT delay/NN was/VBD) (clause_2 increased/VBD by/IN the/DT outbreak/NN) (clause_2 reached/VBN the/DT end/NN) (clause_2 found/VBD that/IN the/DT story/NN) (clause_2 stood/VBD by/INBalin/NNP) (clause_2 halted/VBD for/IN a/DT long/JJ while/NN) (clause_3 In/IN the/DT next/JJyear/NN) (clause_2 wrote/VBD the/DTfirst/JJ drafts/NNS) (clause_2 stands/VBZ as/INBook/NNP Three/NNP)
Здесь clause i - это обозначение, соответствующее номеру конструкции, а VBD, IN, DT, NN и т.д - описывают название части речи. Полный перечень обозначений частей речи можно найти на сайте документации к NLTK [5].
Результатом работы программного продукта является статистика, которая для данного отрывка и полученных конструкций будет выглядеть следующим образом (из-за использования БД порядок групп не соответствует порядку конструкций).
STAND BY BALIN -1 MANY INFORMATION - 2 MANY DUTY -1 OWN SATISFACTION -1 ENCOURAGE BY REQUEST -1 LONG TIME -1 SET IN ORDER -1 INCREASE BY OUTBREAK -1 MANY GLIMPSE -1 HALT FOR WHILE -1 LONG WHILE -1 ASK FOR INFORMA TION -1 NECESSARY BACKGROUND - 1 FOUND THAT STORY -1 NEXT YEAR -1 OTHER INTEREST - 1 ANCIENT HISTORY - 2 UNBIDDEN OF THING -1 BEGIN IN ORDER - 1 OTHER PERSON -1 FIRST DRAFT -1 STAND AS BOOK -1 LITTLE HOPE - 2
Результат работы представлен в виде словаря, где ключ - это группа, а значение - количество раз, которые данная группа встречается в конструкциях.
В ходе решения задачи был обработан текст дампа новостей компании «Рейтерс» за 2007 год, состоящий из 154 млн токенов. Текст новостей разбивался на
предложения, которые в свою очередь разбивались на токены. Из набора токенов одного предложения выделялись конструкции, из которых в свою очередь выделялись группы. В процессе выделения конструкций было задействовано 40 млн токенов. Из полученных конструкций было выделено около 1,2 млн уникальных групп и посчитана статистика встречаемости каждой группы в дампе новостей.
Заключение
В результате выполненной работы был получен программный продукт, позволяющий извлекать из английских текстов такие синтаксические конструкции, как «глагол + предлог + существительное» и «существительное + прилагательное». В качестве входных данных программный продукт получает текстовый файл, который необходимо проанализировать, список правил КС-грамматики для разбиения текста на конструкции, список групп и соответствующие им списки частей речи, характеризующие группы.
Результатом работы программного продукта является текстовый файл со списком выделенных конструкций и текстовый файл со списком выделенных из конструкций групп.
В ходе проведения экспериментов над дампом новостей компании «Рейтерс» за 2007 год было получено 1,2 млн различных групп. Заметим, что данный результат сопоставим с результатами, получаемыми для русского языка на коллекции того же объема [1]. Заметим, что для русских текстов брались лишь морфологически однозначные слова.
Таким образом, можно сделать вывод, что предлагаемый метод пригоден для извлечения синтаксически связанных конструкций из текстов на английском языке и может быть в дальнейшем использован для обработки корпусов большего объема.
Список литературы
1. Клышинский Э.С., Кочеткова Н.А., Литвинов М.И., Максимов В.Ю. Метод разрешения частеречной омонимии на основе применения корпуса синтаксической сочетаемости слов в русском языке // Научно-техническая информация. Серия 2: Информационные системы и процессы. №1 2011 г., сс. 31-35
2. Pymorphy v0.5.5 documentation: http://packages.python.org/pymorphy/usage/base.html
3. Автоматическая обработка текста: http://aot.ru/
4. Jacob Perkins, Using Execnet for Parallel and Distributed Processing with NLTK: http://www.packtpub.com/article/using-execnet-parallel-and-distributed-processing-nltk
5. Документация к NLTK: http://www.nltk.org/documentation