Expand description
Training on demand: “Train now” in the mail settings, and
sioul spam train (docs/spam-filter.md, “Training on demand”).
The model learns in one of two ways (Model). The filter’s, by default,
is fastText’s classifier (supervised, which says its own steps after
the second): a message’s words and its header facts as words, two
labels; it ranked a real mailbox’s mail better than the centroid did,
and gave the same numbers from one training to the next. The centroid’s,
on request, is the one below, the filter’s before features version 3:
- The corpus is brought up to date (
corpus::update, byrun). - Each message gets one label (
labels), and its words and header features from sioul-core’s spam module, read as the Porch reads mail. - fastText learns your mail’s words: skip-gram, 100 dimensions, character n-grams of 3 to 6, 200 000 buckets, words seen 5 times.
- A message’s vector is the plain mean of its words’ vectors (fastText’s
get_word_vector), never normalized, so that the model folds; the header features follow it; each dimension is standardized with the training messages’ mean and deviation. - Oldest 80 % to learn, newest 20 % to test, by INTERNALDATE. The SVM’s
cost is chosen among 0.01, 0.1, 1 and 10 on the newest fifth of the
learning part; ham weighs 5. Outside material (
external), when imported, is split alike, source by source, by its own dates: its oldest 80 % joins the learning part at its dates, with its header features at the learning part’s mean (0 once standardized: only its words weigh); its newest 20 % is held out, the baseline. - Platt’s A and B are fitted on scores each message got from an SVM trained on older mail only (forward folds).
- The numbers, on the newest 20 % of your own mail: aggregates only
(
eval); the same numbers on each outside source’s held-out part, apart: the baseline. - The model is folded into the reduced table (one scalar per word and per
bucket, the header weights, the bias); the table must give the model’s
score within 1e-4 on every test message, or nothing is exported. It
replaces
table.binonly if it loses no more ham on the newest 20 %, at your spam threshold, than the table in place, on those of them the table in place never learned from (it learned from all mail before its training: on that mail it would be judged on what it was taught); the one before is kept astable.prev.bin.trained.tomlsays what happened, for the settings. - Kept, the model is learned again, with the same cost, from every message, the newest month included (spam changes, and the filter that runs must have seen this month’s): standardized anew, calibrated by Platt on forward folds over all of it (each fifth scored by an SVM that learned the fifths before it), folded and tested the same way. That is the table written; the numbers said are those of steps 5 to 7.
A trial (Options::replace false: sioul spam train --no-replace, the
MCP’s spam_train unless asked) stops after step 8’s comparison: it says
what the table in place would become, and changes nothing of the filter,
the table, the one before, the language model nor trained.toml.
train_with also says what the test said message by message (detail).
Structs§
- Compared
- The replacement’s comparison: the test messages the table in place never learned from, and the ham each table sets aside among them.
- Counts
- Evaluation
- The table in place, tested on the newest 20 % of the corpus as it is now.
- Message 🔒
- One message on its way to the classifier.
- Model
Summary - The model learned from the oldest 80 %, whose numbers
testgives, and how it was asked to learn (Options: the command line’s overrides too). - Options
- How training goes;
Defaultholds the values of docs/spam-filter.md. - Outside
- An outside source in a training: its oldest 80 % learned from, its newest 20 % held out, and the numbers there (the baseline).
- Parts 🔒
- The messages’ parts: every message in time order; the learning part
(time order); your own mail’s test part; each outside source’s held-out
part (
newest_fifths). - Read 🔒
- What the corpus and the outside material gave, read once, for the classifier’s own steps (
supervised). - Refit
- The table written: the model learned again, with the same cost, from every labelled message, the newest included.
- Rows 🔒
- The classifier’s rows: each message’s vector, then its header features.
- Split
- Summary
- The last training, as
trained.tomlkeeps it for the settings: numbers only. - Token
File 🔒 - The tokenized corpus, removed whatever happens.
- Unseen
- The numbers on the test messages the table in place never learned from.
- Why
- What weighed in one message’s verdict. It names words of the message: for
you, in your terminal (
sioul spam why), never through MCP.
Enums§
- Model
- Which model learns: fastText’s classifier (the filter’s), or the language model’s centroid and the SVM (the filter’s before features version 3, on request).
Constants§
- LINE_
WORDS 🔒 - fastText reads lines of at most 1024 words: longer messages are cut in lines of this many.
Functions§
- against_
current 🔒 - The table in place, on the same test messages: those of them it never
learned from (it learned from every message before its training), so
that both are judged on mail they never saw; then whether the new table
takes its place (
replacement), and why.test_wordsandnew_scoredare intest_ids’ order, read with this training’s words (Options::lexicon). Each table reads with its own words: when those of the table in place (Table::lexicon: its own, or the built-in French and English ones when it keeps none) are not this training’s, its test messages are read again from the corpus with them, and one that can no longer be read is left out for both tables; a change of words never makes the table in place look worse than it is. - counted 🔒
- What was learned from and tested on, in all and per account: your own mail’s.
- evaluate
- Tests the table in place on the newest fifth of the corpus as it is now,
without training: aggregate numbers only (
sioul spam eval). New mail since the training makes it a test of how the table holds up. - evaluate_
with evaluate, and what the test said message by message (detail), with up toerrorserrors of each kind (sioul spam eval --errors).- features_
of 🔒 - A card’s words and header features;
own, Sioul’s checks kept apart from it (a corpus record’s), else those its headers carry (Sioul’s stamp first, your provider’s second:features::auth_results); its words read withlexicon. - fit_
prefix 🔒 - The SVM learned from the first
endrows ofx(time order), costc. - fit_
with_ 🔒platt - The SVM learned from every row (time order), cost
c, and Platt’s sigmoid from forward folds over them: each fifth scored by an SVM learned from the fifths before it. When the folds give none (too few of a kind early on), the model’s own scores, which make it surer than it is.stepis told after each fit; the scores the sigmoid was fitted on are counted. - fold 🔒
- The model folded into the reduced table (spam-core-api.md): with
u = w/σover the vector’s dimensions, each vocabulary word’s scalar isu · get_word_vector(word), each bucket’su · its input row; the standardization’s means becometext_mean = u · μand the header means. - fold_
error 🔒 - The largest difference between a table’s score and its model’s on some
messages (
x, their standardized rows); over 1e-4, the fold is broken. - held_
out 🔒 - An outside source’s held-out part, scored: its counts and its numbers, the baseline.
- hinge_
loss 🔒 - The mean weighted squared hinge loss of scores (lower is better).
- is_zero 🔒
- is_
zero_ 🔒f - kept 🔒
- The words fastText can learn: it splits on whitespace, so a word never holds any.
- lacking 🔒
- What outside material, which has no headers, is scored with: every header feature missing, which weighs nothing in either kind of table (the classifier reads no word for it, the centroid stands it at its mean).
- last
- The last training’s summary; none before the first.
- message_
vectors 🔒 - Every message’s vector: the plain mean of its words’ fastText vectors,
computed on
threadsthreads, in f64, from the tokenized corpus. - metrics 🔒
- The test’s numbers the table carries, for the settings of every device.
- newest_
fifths 🔒 - The oldest 80 % and the newest 20 % of each group of
ids(in time order): an account’s ham, its spam; an outside source’s. Every group is on both sides, so that a group whose mail all came late (a provider that keeps spam a month) is learned from too, and none is told apart by when it came. - parts 🔒
- Your own mail: each account’s ham, and its spam, oldest 80 % to learn, newest 20 % to test; each outside source alike, its ham and its spam, by their own dates, the newest 20 % held out (the baseline).
- read_
message 🔒 - A message’s words and header features, from its corpus record, as the
Porch reads the message itself: Sioul’s own checks of it first (made on
the whole message when it was fetched, as the Porch reads the stamp the
sync writes on it; beside a signature, their failures unknown when made
long after it came:
corpus::Checked::reading), your provider’s second. The words are read withlexicon(a training’s, or the table’s own). - refit_
all 🔒 - The model learned again, cost
c, from every message (order, time order), the newest included: standardized anew, Platt on forward folds over all of it, folded; the fold tested on the test messages. The table to write (its metadata counts what it learned from; its metrics are the caller’s), and what to say of it. - replacement 🔒
- Whether the new table replaces the one in place, and why, from the ham
each sets aside among the
comparedtest messages the one in place never learned from. None of them (nothing came since it was trained): nothing says it is better; the new one learned from the same mail, and replaces it. - run
- “Train now”: the corpus brought up to date from every account (each
password as the sync uses it), then
trainwith your thresholds. For the window: run it on a thread of its own;progresssays each step,cancelstops it at the next. - standardization 🔒
- The mean and the deviation (population) of
widthcolumns overnrows, in two passes, rows made one at a time; 0 for a column that never changes. The columns fromdimon (the header features) only over the rows that have them (known); without any, 0. A missing value (NaN) counts in neither. - tested_
of 🔒 - A test message as
detailtakes it: where it is, its label, how likely spam. - train
- Trains on the corpus as it is (see the module’s steps). The table is
replaced only when no worse;
trained.tomlsays what happened. - train_
with train, and what its test said message by message (detail): the test messages counted by account and folder, the grid of thresholds, and up toerrorserrors of each kind, your own mail’s and each outside source’s, as the model learned from the oldest 80 % judged them.- trusted_
ids - The authserv-ids each account trusts, as the Porch reads them (Sioul’s
own first, then the provider’s:
Config::mail_sources). - why
- The table’s verdict on a whole message (a file’s bytes), and why.
trustedare its account’s authserv-ids;internal_datewhen it reached the server (a Maildir file’s modification time). - words_
of 🔒 - The words of some messages, read back from the tokenized corpus.
- words_
of_ 🔒record - A record’s words alone, read with
lexiconasread_messagereads them: what the table in place reads of a test message when its words are not the training’s (against_current).