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

    image

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

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

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

    Начало


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

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

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

    image

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

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

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

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

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

    image

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

    image

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

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

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

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


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

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

    К тому же получилось так, что у Keras есть в лёгком доступе несколько примеров, с которых можно начать работу, включая задачу классификации разнообразных текстов. И вот, что интересно – данный пример использует такие же функции, какие инженер использовал ранее. Он определяет 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%. В любом случае, инженер выяснил, что можно было улучшить свой старый результат с использованием современной библиотеки машинного обучения.

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

    Продолжение следует…
    • +16
    • 18,7k
    • 5
    Pechkin.com
    69,00
    Новый инструмент для e-mail маркетинга
    Поделиться публикацией

    Комментарии 5

      +1
      Почему прямо не указать, что пост является переводом?
      По основному посту (читал только оригинал, сорри) — забавно, что затея с feature engineering как раз показала, что его делать не надо — лучше предавать сети все, она разберётся. Ну и takeaway про мало данных тоже конечно неудивителен.
      И, наконец, урок на будущее про то, что можно повысить точность, выключив категории, которые не нужны — тоже жизненный.
        0
        Не думаю что с Bag-of-words можно достичь высоких результатов (>90%) какую бы крутую нейронную сеть Вы не использовали бы… Как на счет использования word embeddings (GloVe, word2vec) или что-то в этом вроде?
          0
          Я ему задал этот вопрос в комментах, говорит, не добрался. Это такой проект, очень на коленке.
          0
          Мне кажется, что здесь или неправильно поняли Bag of words, или он сам по себе какой-то неправильный. Разве не нужно удалять из набора признаков слова, которые являются частотными по всей выборке, а не в пределах нескольких классов? Это бы отсеяло всю общеупотребительную лексику.
            –1

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое