- PVSM.RU - https://www.pvsm.ru -

Как навести порядок в почтовом ящике с помощью нейронной сети. Часть 1

image [1]

В нашем блоге мы много пишем о создании email-рассылок [2] и работе с электронной почтой. Мы уже обсудили сложности борьбы со спамом [3], будущее email, вопросы защиты почтовой переписки [4], а также техники работы с email [5], применяемые руководителями крупных ИТ-компаний. 

В современном мире люди получают множество писем, и в полный рост встает проблема с их классификацией и упорядочиванием почтового ящика. Инженер из США Андрей Куренков в своем блоге рассказал [6] о том, как решил эту задачу с помощью нейронной сети. Мы решили осветить ход этого проекта и представляем вам первую часть рассказа.

Код проекта доступен здесь [7].

Начало

Куренков пишет, что один из его любимых мини-проектов, EmailFiler [8], появился благодаря заданию на курсе «Введение в машинное обучение» в Технологическом Институте Джорджии. Задание состояло в том, чтобы взять какой-либо набор данных, применить к нему ряд контролируемых обучающихся алгоритмов и проанализировать результаты. Суть в том, что по желанию можно было использовать собственные данные. Разработчик так и поступил – экспортировал данные своего gmail для исследования возможностей машинного обучения в решении задачи сортировки электронной почты.

Куренков пишет, что давно понял, что электронные письма лучше всегда иметь под рукой на случай, если вдруг когда-нибудь понадобится к ним обратиться. С другой стороны, ему всегда хотелось свести количество непрочитанных входящих сообщений к нулю, какой бы безнадежной ни была эта идея. Поэтому много лет назад инженер начал сортировать электронные письма примерно по дюжине папок, и к моменту поступления на курсы машинного обучения, в этих папках накопились тысячи писем.

Так возникла идея проекта по созданию классификатора, который мог бы предложить единственную категорию для каждого входящего письма – так, чтобы отправлять письмо в соответствующую папку одним нажатием кнопки.

image

Категории (папки) и количество писем в каждой из них на момент старта проекта

В качестве входных данных выступали письма, в число выходных данных попадали категории писем. Сложность заключалась в том, что разработчику хотелось использовать тексты писем и метаданные, но понять, как превратить все это в пригодный для машинного обучения набор данных, было нелегко.

Любой, кто изучал обработку естественных языков, сразу предложит один простой подход – использование модели Bag of Words (Множество слов). Это один из простейших алгоритмов классификации текстов – найти N общих слов для всех текстов и составить таблицу бинарных признаков для каждого слова (признак равен 1, если заданный текст содержит слово, и 0 – если не содержит).

Куренков проделал это для группы слов, найденных во всех его письмах, а также для топ-20 отправителей писем (так как в некоторых случаях отправитель строго коррелирует с категорией письма; например, если отправитель –научный руководитель в университете, то категорией будет «Исследования») и для топ-5 доменов, с которых ему присылали письма (поскольку домены типа gatech [9].edu строго указывают на такие категории как, например, «Обучение»). Так, где-то после часа, потраченного на написание парсера [10] электронной почты, он смог получать данные о своём ящике в формате csv (значения, разделённые запятыми).

Насколько хорошо все работало? Неплохо, но хотелось большего. Куренков говорит, что тогда увлекался фреймворком для машинного обучения Orange ML на Python, и, как и было положено по заданию, протестировал [11] несколько алгоритмов на своем наборе данных. Выделялись два алгоритма – лучше всего показали себя деревья принятия решений, а хуже всего – нейронные сети:

image

Так с небольшим набором данных справились деревья принятия решений

image

А так – нейронные сети

Если внимательно взглянуть на эти графики из OpenOffice Calc, то можно увидеть, что лучший результат деревьев принятия решений на тесте – где-то 72%, а нейронных сетей – жалкие 65%. Ужас! Это, конечно, лучше, чем разложить всё наугад, учитывая, что там 11 категорий, но до отличного результата далеко.

Почему же результаты оказались такими удручающими? Дело в том, что признаки, полученные для набора данных, оказались весьма примитивны – простой поиск 500 наиболее часто встречающихся в письмах слов даст нам не так уж много полезных индикаторов, но много общеупотребительных конструкций, которые встречаются в английском, например «that» или «is». Инженер понял это и предпринял следующее: полностью убрал из списка слова из трёх и менее букв и написал немного кода, чтобы выбрать наиболее часто встречающиеся слова для каждой категории отдельно; но он все еще не представлял, как улучшить результат.

Попытка номер два

Спустя пару лет Куренков решил еще раз попытаться решить задачу — хоть сам проект в университете уже был давно сдан, хотелось улучшить результаты.

В этот раз инженер решил в качестве одного из основных инструментов применить Keras [12], потому как он написан на Python и также неплохо ладит с пакетами NumPy [13], pandas [14] и scikit-learn [15] и поддерживается библиотекой Theano.

К тому же получилось так, что у Keras есть в лёгком доступе несколько примеров, с которых можно начать работу, включая задачу [16] классификации разнообразных текстов. И вот, что интересно – данный пример использует такие же функции, какие инженер использовал ранее. Он определяет 1000 наиболее часто встречающихся в документах слов, бинарные признаки и обучает нейронную сеть с одним скрытым слоем и dropout-регуляризацией предсказывать категорию заданного текста, основываясь исключительно на этих признаках.

Итак, первое, что приходит в голову: испробовать этот пример на собственных данных – посмотреть, улучшит ли работу Keras. К счастью, сохранился старый код для парсинга почтового ящика, а у Keras есть удобный класс Tokenizer для получения признаков текста. Поэтому можно легко создать набор данных в таком же формате, как и в примере, и получить новую информацию о текущем количестве электронных писем:

Using Theano backend.
Label email count breakdown:
	Personal:440
	Group work:150
	Financial:118
	Academic:1088
	Professional:388
	Group work/SolarJackets:1535
	Personal/Programming:229
	Professional/Research:1066
	Professional/TA:1801
	Sent:513
	Unread:146
	Professional/EPFL:234
	Important:142
	Professional/RISS:173
Total emails: 8023

Восемь тысяч писем никак не назовёшь большим набором данных, но всё же этого достаточно для того, чтобы немного позаниматься серьёзным машинным обучением. После перевода данных в нужный формат остаётся лишь посмотреть, работает ли обучение нейронной сети на этих данных. Пример с использованием Keras даёт легко сделать следующее:

7221 train sequences
802 test sequences
Building model...
Train on 6498 samples, validate on 723 samples
Epoch 1/5
6498/6498 [==============================] - 2s - loss: 1.3182 - acc: 0.6320 - val_loss: 0.8166 - val_acc: 0.7718
Epoch 2/5
6498/6498 [==============================] - 2s - loss: 0.6201 - acc: 0.8316 - val_loss: 0.6598 - val_acc: 0.8285
Epoch 3/5
6498/6498 [==============================] - 2s - loss: 0.4102 - acc: 0.8883 - val_loss: 0.6214 - val_acc: 0.8216
Epoch 4/5
6498/6498 [==============================] - 2s - loss: 0.2960 - acc: 0.9214 - val_loss: 0.6178 - val_acc: 0.8202
Epoch 5/5
6498/6498 [==============================] - 2s - loss: 0.2294 - acc: 0.9372 - val_loss: 0.6031 - val_acc: 0.8326
802/802 [==============================] - 0s     
Test score: 0.585222780162

Точность: 0.847880299252

85% точности! Это намного выше жалких 65% старой нейронной сети. Отлично.

Но…почему?

Старый код делал, в общем-то, следующее – определял наиболее часто встречающиеся слова, создавал бинарную матрицу признаков и обучал нейронную сеть с одним скрытым слоем. Может быть, всё из-за нового нейрона «relu», dropout-регуляризации и использования методов оптимизации, отличных от стохастического градиентного спуска? Поскольку признаки, найденные по старым данным, бинарные и представлены в виде матрицы, их очень легко превратить в набор данных для обучения этой нейронной сети. Итак, вот результаты:

Epoch 1/5
6546/6546 [==============================] - 1s - loss: 1.8417 - acc: 0.4551 - val_loss: 1.4071 - val_acc: 0.5659
Epoch 2/5
6546/6546 [==============================] - 1s - loss: 1.2317 - acc: 0.6150 - val_loss: 1.1837 - val_acc: 0.6291
Epoch 3/5
6546/6546 [==============================] - 1s - loss: 1.0417 - acc: 0.6661 - val_loss: 1.1216 - val_acc: 0.6360
Epoch 4/5
6546/6546 [==============================] - 1s - loss: 0.9372 - acc: 0.6968 - val_loss: 1.0689 - val_acc: 0.6635
Epoch 5/5
6546/6546 [==============================] - 2s - loss: 0.8547 - acc: 0.7215 - val_loss: 1.0564 - val_acc: 0.6690
808/808 [==============================] - 0s     
Test score: 1.03195088158

Точность: 0.64603960396

Итак, старое решение по определению категорий электронных писем было неудачным. Возможно причиной стало сочетание сильных ограничений признаков (вручную определённые топовые отправители, домены и слова из каждой категории) и слишком маленького количества слов.

Пример, использующий Keras, просто отбирает 1000 наиболее часто встречающихся слов в большую матрицу без дополнительного фильтрования и передает её нейронной сети. Если сильно не ограничивать отбор признаков, из них могут быть выбраны более подходящие, что увеличивает общую точность работы алгоритма.

Причина или в этом или в наличии ошибок в коде: его изменение с целью сделать процесс отбора признаков менее ограничивающим приводит к повышению точности лишь до 70%. В любом случае, инженер выяснил, что можно было улучшить свой старый результат с использованием современной библиотеки машинного обучения.

Теперь возникал новый вопрос – можно ли добиться еще более высокой точности?

Продолжение следует…

Автор: Pechkin-mail.ru

Источник [17]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/email/116168

Ссылки в тексте:

[1] Image: https://habrahabr.ru/company/pechkin/blog/280198/

[2] email-рассылок: https://pechkin-mail.ru/?utm_source=habr&utm_medium=referral&utm_campaign=neuaral

[3] борьбы со спамом: https://habrahabr.ru/company/pechkin/blog/277259/

[4] защиты почтовой переписки: https://habrahabr.ru/company/pechkin/blog/276761/

[5] работы с email: https://habrahabr.ru/company/pechkin/blog/275809/

[6] рассказал: http://www.andreykurenkov.com/writing/organizing-my-emails-with-a-neural-net/

[7] здесь: https://github.com/andreykurenkov/emailinsight/tree/master/pyScripts

[8] EmailFiler: http://www.andreykurenkov.com/projects/hacks/email-filer/

[9] gatech: https://habrahabr.ru/users/gatech/

[10] парсера: https://github.com/andreykurenkov/emailinsight/blob/master/pyScripts/mboxConvert.py

[11] протестировал: https://github.com/andreykurenkov/emailinsight/blob/master/pyScripts/orangeClassify.py

[12] Keras: http://keras.io/

[13] NumPy: http://www.numpy.org/

[14] pandas: http://pandas.pydata.org/

[15] scikit-learn: http://scikit-learn.org/stable/

[16] задачу: https://github.com/fchollet/keras/blob/master/examples/reuters_mlp.py

[17] Источник: https://habrahabr.ru/post/280198/