Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
benchmarking/bench-sklearn-scoring.pl view on Meta::CPAN
push @experiments,
{
sweep => 'qsize',
label => $sz,
train_csv => $train_csv,
query_csv => write_csv($q),
query_data => $q,
pure_model => $pure_model,
c_model => $c_model,
omp_model => $omp_model,
n_features => $N_FEATURES,
};
} ## end for my $sz (@query_sizes)
}
# Feature sweep: vary feature count, fix query size at $FEATURE_QUERY_SIZE.
for my $nf (@feature_sizes) {
my $train_data = make_data( $N_TRAIN, $nf );
my $train_csv = write_csv($train_data);
my $pure_model = build_model( $train_data, use_c => 0, use_openmp => 0 );
my $c_model = $HAS_C ? build_model( $train_data, use_c => 1, use_openmp => 0 ) : undef;
my $omp_model = $HAS_OPENMP ? build_model( $train_data, use_c => 1, use_openmp => 1 ) : undef;
my $q = make_data( $FEATURE_QUERY_SIZE, $nf );
push @experiments,
{
sweep => 'features',
label => $nf,
train_csv => $train_csv,
query_csv => write_csv($q),
query_data => $q,
pure_model => $pure_model,
c_model => $c_model,
omp_model => $omp_model,
n_features => $nf,
};
} ## end for my $nf (@feature_sizes)
sub exp_key { "$_[0]{sweep}_$_[0]{label}" }
# -----------------------------------------------------------------------
# Locate Python + scikit-learn
# -----------------------------------------------------------------------
my $python_bin;
for my $cmd (qw(python3 python)) {
my $probe = `$cmd -c "import sklearn; print('ok')" 2>/dev/null`;
if ( defined $probe && $probe =~ /\bok\b/ ) {
$python_bin = $cmd;
last;
}
}
# -----------------------------------------------------------------------
# Python benchmarking script (embedded, written to a temp file).
# -----------------------------------------------------------------------
my $py_script = <<'END_PY';
import sys, json
import time as pytime
import numpy as np
from sklearn.ensemble import IsolationForest
def bench(fn, seconds):
t0 = pytime.perf_counter()
while pytime.perf_counter() - t0 < 0.3:
fn()
t0 = pytime.perf_counter()
n = 0
while pytime.perf_counter() - t0 < seconds:
fn()
n += 1
return n / (pytime.perf_counter() - t0)
def load_csv(path):
with open(path) as f:
return np.array([[float(v) for v in ln.strip().split(',')]
for ln in f if ln.strip()])
bench_secs = float(sys.argv[1])
specs = sys.argv[2:]
models = {}
results = {}
for spec in specs:
train_csv, query_csv, label = spec.split('|', 2)
clf = models.get(train_csv)
if clf is None:
X_train = load_csv(train_csv)
psi = min(256, len(X_train))
clf = IsolationForest(n_estimators=100, max_samples=psi,
contamination='auto', random_state=1)
clf.fit(X_train)
models[train_csv] = clf
X_q = load_csv(query_csv)
results[label] = {
'score_samples': bench(lambda X=X_q: clf.score_samples(X), bench_secs),
'predict': bench(lambda X=X_q: clf.predict(X), bench_secs),
'decision_function': bench(lambda X=X_q: clf.decision_function(X), bench_secs),
}
print(json.dumps(results))
END_PY
# -----------------------------------------------------------------------
# Run Python (one subprocess for all experiments)
# -----------------------------------------------------------------------
my $sk;
if ( defined $python_bin ) {
my ( $py_fh, $py_path ) = tempfile( SUFFIX => '.py', UNLINK => 1 );
print $py_fh $py_script;
close $py_fh;
my $specs = join( ' ', map { qq("$_->{train_csv}|$_->{query_csv}|@{[exp_key($_)]}") } @experiments );
my $raw = `$python_bin "$py_path" $BENCH_SECS $specs 2>/dev/null`;
$sk = eval { JSON::PP->new->decode($raw) };
}
# -----------------------------------------------------------------------
# Run Perl benchmarks for all three backends
# -----------------------------------------------------------------------
my ( %pure_pl, %c_pl, %omp_pl );
for my $exp (@experiments) {
my $key = exp_key($exp);
my $q = $exp->{query_data};
# Pure Perl
{
my $m = $exp->{pure_model};
$pure_pl{$key} = {
score_samples => wall_rate( sub { $m->score_samples($q) }, $BENCH_SECS ),
predict => wall_rate( sub { $m->predict($q) }, $BENCH_SECS ),
score_predict_samples => wall_rate( sub { $m->score_predict_samples($q) }, $BENCH_SECS ),
score_predict_split => wall_rate( sub { $m->score_predict_split($q) }, $BENCH_SECS ),
path_lengths => wall_rate( sub { $m->path_lengths($q) }, $BENCH_SECS ),
};
}
# C serial (single-threaded Inline::C)
if ($HAS_C) {
my $m = $exp->{c_model};
my $packed = $m->pack_data($q);
$c_pl{$key} = {
score_samples => wall_rate( sub { $m->score_samples($q) }, $BENCH_SECS ),
score_samples_packed => wall_rate( sub { $m->score_samples($packed) }, $BENCH_SECS ),
predict => wall_rate( sub { $m->predict($q) }, $BENCH_SECS ),
predict_packed => wall_rate( sub { $m->predict($packed) }, $BENCH_SECS ),
score_predict_samples => wall_rate( sub { $m->score_predict_samples($q) }, $BENCH_SECS ),
score_predict_split => wall_rate( sub { $m->score_predict_split($q) }, $BENCH_SECS ),
score_predict_split_packed => wall_rate( sub { $m->score_predict_split($packed) }, $BENCH_SECS ),
path_lengths => wall_rate( sub { $m->path_lengths($q) }, $BENCH_SECS ),
};
} ## end if ($HAS_C)
# C + OpenMP (parallel Inline::C)
if ($HAS_OPENMP) {
my $m = $exp->{omp_model};
my $packed = $m->pack_data($q);
( run in 0.697 second using v1.01-cache-2.11-cpan-6aa56a78535 )