Обучение
Встроенная модель работает сразу. Модель, обученная на вашей собственной почте, работает лучше, потому что узнаёт, как выглядит ваш hamНужная почта: противоположность спама.: ваши рассылки, манеру письма ваших коллег, языки, на которых вам пишут.
Обучение модели#
Укажите train папки со спамом и ham:
spamscanner train --spam ~/Maildir/.Junk --ham ~/Maildir/cur --ham ~/Maildir/.Archive --out my-model.jsonИсточниками могут быть:
- файлы mbox, в том числе сжатые gzip (
.mbox.gz), - каталог Maildir (читаются его папки
curиnew,tmpпропускается), - папка с файлами
.eml, читаемая рекурсивно, - набор данных: файл CSV или JSON Lines со столбцом текста и столбцом метки (
--dataset). Столбцы с именамиtext,message,body,emailилиcontentиlabel,category,class,spamилиis_spamнаходятся автоматически; иначе используйте--text-columnи--label-column. Распознаются такие метки, какspam,1,phishingиham,0,not_spam,legitimate.
Повторяющиеся письма учитываются один раз. Чтобы дообучить встроенную модель, а не начинать с пустой, добавьте --merge.
Использование модели:
spamscanner scan message.eml --model my-model.json
SPAMSCANNER_MODEL=/var/lib/spamscanner/model.json spamscanner milterconst scanner = new SpamScanner({classifier: '/var/lib/spamscanner/model.json'});Сколько почты достаточно: несколько сотен писем каждого вида дают полезную модель, несколько тысяч — хорошую. Держите оба класса примерно в равновесии и включайте в ham почту, которую не нужно фильтровать (сброс пароля, счета от ваших поставщиков).
Измерение качества#
Отложите часть почты при обучении и измеряйте на ней:
spamscanner eval --model my-model.json --spam held-out/spam --ham held-out/hamВстроенная модель на SMS-сообщениях на 21 языке, которых она никогда не видела, причём большинство — на языках, которые она почти не знает:
Messages: 13028 spam, 92406 ham
Precision: 89.72% Recall: 11.18% F1: 19.89%
False positives: 167 (0.18% of ham) False negatives: 132
Unsure: 91247 (86.54%)Точность (precision) показывает, какая доля того, что модель называет спамом, действительно спам; полнота (recall) — какую долю спама она ловит. Неуверенные письма здесь считаются пропущенным спамом, хотя при проверке их всё ещё могут поймать остальные проверки и языковая модель. Следить нужно за ложными срабатываниями: ham, помеченным как спам. В прогоне выше модель не уверена в большинстве этих писем, а не ошибается в них, и это задуманное поведение для языков, на которых у неё мало почты.
--json выдаёт те же числа для скриптов.
Обучение по жалобам#
Когда пользователи перемещают почту в папку Junk или из неё, обучайте модель по одному письму:
spamscanner learn spam message.eml --model /var/lib/spamscanner/model.json
spamscanner learn ham message.eml --model /var/lib/spamscanner/model.jsonПервый learn создаёт файл из встроенной модели. По HTTP то же делают POST /learn/spam и /learn/ham в HTTP API, а spamc -L spam работает с сервером spamd при --allow-tell. IMAPSieve в Dovecot может вызывать любой из них при перемещении письма.
Из Node.js:
await scanner.learn(raw, 'spam');
await scanner.unlearn(raw, 'spam'); // undo, before learning it as ham
scanner.saveModel('/var/lib/spamscanner/model.json');Если письмо, о котором сообщили как о неверно классифицированном, уже было выучено, его нужно сначала разучить из неверного класса, а затем выучить в правильном.
Встроенная модель#
model/classifier.json собирается командой npm run model:train из этих публичных наборов данных на Hugging Face, все под открытыми лицензиями:
| Набор данных | Лицензия | Содержимое |
|---|---|---|
| FredZhang7/all-scam-spam | Apache-2.0 | Сообщения и письма на 43 языках |
| SetFit/enron_spam | Публичный исследовательский корпус | Корпус Enron-Spam |
| alt-gnome/telegram-spam | CC0-1.0 | Русские сообщения из Telegram |
| tanaos/synthetic-spam-detection-dataset-german, -italian, -spanish | MIT | Синтетические сообщения |
Она обучена на 62 480 письмах со спамом и 76 489 письмах ham. Скрипт откладывает каждое десятое письмо, обучается на остальных и измеряет только классификатор, без остальных проверок:
| Отложенный тест | Письма | Точность | Полнота | Ложные срабатывания | Unsure |
|---|---|---|---|---|---|
| Английский | 6 564 | 100,0 % | 97,0 % | 0,0 % | 2,4 % |
| Русский | 1 682 | 100,0 % | 97,4 % | 0,0 % | 2,2 % |
| Итальянский | 1 389 | 98,1 % | 85,3 % | 1,8 % | 10,9 % |
| Немецкий | 1 309 | 97,7 % | 76,1 % | 2,2 % | 20,7 % |
| Испанский | 1 281 | 97,5 % | 82,5 % | 2,6 % | 16,8 % |
| Enron-Spam | 2 888 | 100,0 % | 93,1 % | 0,0 % | 4,5 % |
| all-scam-spam | 4 236 | 100,0 % | 88,8 % | 0,0 % | 11,2 % |
| Всего | 13 840 | 99,2 % | 85,1 % | 0,5 % | 12,4 % |
Спамом здесь считается вероятность по оценке классификатора 99 % и выше — точка, в которой один классификатор достигает порога спама. При проверке спам, в котором он менее уверен, всё равно получает баллы, а остальные проверки добавляют свои.
Результаты для немецкого, испанского и итальянского получены на синтетических наборах данных, где есть почти одинаковые письма, размеченные и как спам, и как ham: часть ошибки заключена в разметке, а не в модели. Лучшее решение — почта на ваших собственных языках. Числа для каждого языка и набора данных находятся в metadata.metrics модели.
Больше языков#
npm run model:train -- --with multilingual-sms добавляет SMS Spam Multilingual Collection: коллекцию SMS Spam Collection, машинно переведённую на 21 язык. Она не входит во встроенную модель, потому что в её карточке указана лицензия GPL; проверьте, подходит ли это для того, как вы распространяете модель. С ней результаты на отложенных письмах для языков, которые встроенная модель почти не знает, были такими:
| Язык | Письма | Точность | Полнота | Ложные срабатывания |
|---|---|---|---|---|
| Китайский | 430 | 100,0 % | 82,3 % | 0,0 % |
| Арабский | 430 | 100,0 % | 84,6 % | 0,0 % |
| Корейский | 412 | 100,0 % | 80,4 % | 0,0 % |
| Японский | 486 | 96,0 % | 85,7 % | 0,5 % |
| Хинди | 412 | 100,0 % | 63,9 % | 0,0 % |
| Французский | 480 | 98,6 % | 94,2 % | 0,6 % |
| Турецкий | 220 | 100,0 % | 73,1 % | 0,0 % |
Переобучение#
npm run model:train # downloads the datasets into data/ the first time
npm run model:train -- --no-download # reuse data/
npm run model:train -- --out /tmp/model.json --max-features 200000Файл модели#
Модель — это JSON-файл: количество выученных писем со спамом и ham, а для каждого хешированного признака — сколько писем со спамом и ham его содержали, в отсортированном виде и в кодировке base64. В нём нет ни слов, ни текста писем. --max-features оставляет только самые частые признаки, а --min-count отбрасывает редкие, жертвуя точностью ради размера; встроенная модель хранит 400 000 признаков примерно в 6 МБ.
Модели из Spam Scanner 6 и более ранних версий загрузить нельзя: они хешировали другие признаки. Обучите новую на той же почте.