svn commit: r1933098 - spamassassin/trunk/lib/Mail/SpamAssassin/Plugin
[email protected] Thu, 16 Apr 2026 07:31:12 -0000
| Newsgroups | gmane.mail.spam.spamassassin.cvs |
|---|---|
| Message-ID | <177632467220.3274626.7039529012154493175@svn03-he-fi> |
Author: gbechis
Date: Thu Apr 16 07:31:11 2026
New Revision: 1933098
Log:
speedup learning phase
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/NeuralNetwork.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/NeuralNetwork.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/NeuralNetwork.pm Thu Apr 16 07:30:49 2026 (r1933097)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/NeuralNetwork.pm Thu Apr 16 07:31:11 2026 (r1933098)
@@ -794,9 +794,14 @@ sub learn_message {
$class_weight = 2.0 if $class_weight > 2.0;
my $weighted_epochs = int($train_epochs * $class_weight) || 1;
+ # Scale epochs down for large vocabularies to keep per-message training time
+ # roughly constant.
+ if ($num_input > 1000) {
+ $weighted_epochs = int($weighted_epochs * 1000 / $num_input) || 1;
+ }
dbg("Incremental training: weighted_epochs=$weighted_epochs " .
"(base=$train_epochs, class_weight=$class_weight, " .
- "spam_docs=$spam_docs, ham_docs=$ham_docs, isspam=$isspam)");
+ "spam_docs=$spam_docs, ham_docs=$ham_docs, isspam=$isspam, num_input=$num_input)");
for my $e (1 .. $weighted_epochs) {
for my $i (0 .. $#$feature_vectors) {
@@ -1025,7 +1030,10 @@ sub _prune_vocabulary {
my $terms_count = scalar keys %{$terms};
return () unless $terms_count > $vocab_cap;
- my $half = int($vocab_cap / 2);
+ # Prune to 90% of cap so the vocabulary has room to grow before the next
+ # prune is triggered.
+ my $prune_target = int($vocab_cap * 0.9) || 1;
+ my $half = int($prune_target / 2);
my %kept;
for my $w (sort { ($terms->{$b}{spam}||0) <=> ($terms->{$a}{spam}||0) } keys %{$terms}) {
@@ -1033,12 +1041,12 @@ sub _prune_vocabulary {
$kept{$w} = $terms->{$w};
}
for my $w (sort { ($terms->{$b}{ham}||0) <=> ($terms->{$a}{ham}||0) } keys %{$terms}) {
- last if scalar keys %kept >= $vocab_cap;
+ last if scalar keys %kept >= $prune_target;
$kept{$w} = $terms->{$w};
}
# Fill any remaining slots
for my $w (sort { ($terms->{$b}{total}||0) <=> ($terms->{$a}{total}||0) } keys %{$terms}) {
- last if scalar keys %kept >= $vocab_cap;
+ last if scalar keys %kept >= $prune_target;
$kept{$w} = $terms->{$w};
}
my @pruned = grep { !exists $kept{$_} } keys %{$terms};
@@ -1057,7 +1065,7 @@ sub _prune_vocabulary {
dbg("Failed to delete terms: " . ($@ || 'unknown'));
};
}
- dbg("Pruned vocabulary from $terms_count to $vocab_cap terms");
+ dbg("Pruned vocabulary from $terms_count to $prune_target terms (cap: $vocab_cap)");
return @pruned;
}