Обучение

Встроенная модель работает сразу. Модель, обученная на вашей собственной почте, работает лучше, потому что узнаёт, как выглядит ваш hamНужная почта: противоположность спама.: ваши рассылки, манеру письма ваших коллег, языки, на которых вам пишут.

Обучение модели#

Укажите train папки со спамом и ham:

Shell
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.

Использование модели:

Shell
spamscanner scan message.eml --model my-model.json
SPAMSCANNER_MODEL=/var/lib/spamscanner/model.json spamscanner milter
JavaScript
const scanner = new SpamScanner({classifier: '/var/lib/spamscanner/model.json'});

Сколько почты достаточно: несколько сотен писем каждого вида дают полезную модель, несколько тысяч — хорошую. Держите оба класса примерно в равновесии и включайте в ham почту, которую не нужно фильтровать (сброс пароля, счета от ваших поставщиков).

Измерение качества#

Отложите часть почты при обучении и измеряйте на ней:

Shell
spamscanner eval --model my-model.json --spam held-out/spam --ham held-out/ham

Встроенная модель на SMS-сообщениях на 21 языке, которых она никогда не видела, причём большинство — на языках, которые она почти не знает:

Text
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 или из неё, обучайте модель по одному письму:

Shell
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:

JavaScript
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-spamApache-2.0Сообщения и письма на 43 языках
SetFit/enron_spamПубличный исследовательский корпусКорпус Enron-Spam
alt-gnome/telegram-spamCC0-1.0Русские сообщения из Telegram
tanaos/synthetic-spam-detection-dataset-german, -italian, -spanishMITСинтетические сообщения

Она обучена на 62 480 письмах со спамом и 76 489 письмах ham. Скрипт откладывает каждое десятое письмо, обучается на остальных и измеряет только классификатор, без остальных проверок:

Отложенный тестПисьмаТочностьПолнотаЛожные срабатыванияUnsure
Английский6 564100,0 %97,0 %0,0 %2,4 %
Русский1 682100,0 %97,4 %0,0 %2,2 %
Итальянский1 38998,1 %85,3 %1,8 %10,9 %
Немецкий1 30997,7 %76,1 %2,2 %20,7 %
Испанский1 28197,5 %82,5 %2,6 %16,8 %
Enron-Spam2 888100,0 %93,1 %0,0 %4,5 %
all-scam-spam4 236100,0 %88,8 %0,0 %11,2 %
Всего13 84099,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; проверьте, подходит ли это для того, как вы распространяете модель. С ней результаты на отложенных письмах для языков, которые встроенная модель почти не знает, были такими:

ЯзыкПисьмаТочностьПолнотаЛожные срабатывания
Китайский430100,0 %82,3 %0,0 %
Арабский430100,0 %84,6 %0,0 %
Корейский412100,0 %80,4 %0,0 %
Японский48696,0 %85,7 %0,5 %
Хинди412100,0 %63,9 %0,0 %
Французский48098,6 %94,2 %0,6 %
Турецкий220100,0 %73,1 %0,0 %

Переобучение#

Shell
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 и более ранних версий загрузить нельзя: они хешировали другие признаки. Обучите новую на той же почте.

Редактировать эту страницу на GitHub · Markdown ·