our_knp/cats-dogs/run.py
int 8f43927575 Initial import: KNP experiments (examples, viz, cats-dogs, reports)
examples/ is based on KasperskyLab/knp at 55470ed6 with local changes
to the mnist-learn altai/blifat models, cuda-backend CMake and model_loader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:17:15 +03:00

74 lines
3.8 KiB
Python

"""Run real KNP training/inference and preserve logs, settings and count-based metrics."""
import argparse
import csv
import io
import json
import os
from pathlib import Path
import subprocess
import time
ap = argparse.ArgumentParser()
ap.add_argument('name')
ap.add_argument('--dataset', default='validation')
ap.add_argument('--train', type=int, default=8000)
ap.add_argument('--count', type=int, default=2000)
ap.add_argument('--threshold', type=int, default=60)
ap.add_argument('--data-dir', type=Path, default=Path('/home/int/run/cats-dogs/data'))
ap.add_argument('--columns', type=int, default=20)
ap.add_argument('--seed', type=int, default=42)
ap.add_argument('--jitter', type=float, default=20)
ap.add_argument('--quant', choices=['default', 'weights'], default='default')
ap.add_argument('--backend', choices=['single', 'multi', 'tuned', 'fast'], default='single')
ap.add_argument('--threads', type=int, default=2)
a = ap.parse_args()
if a.backend == 'multi':
ap.error('Stock multi-threaded KNP has no AltAI types; use --backend tuned for the experimental AltAI port')
if not 1 <= a.threads <= 256:
ap.error('--threads must be between 1 and 256')
root = Path('/home/int/run/cats-dogs')
out = root / a.name
out.mkdir(exist_ok=False)
env = dict(os.environ, LD_LIBRARY_PATH='/home/int/knp-build/bin:/home/int/deps/lib',
KNP_COL_JITTER=str(a.jitter), KNP_COL_SEED=str(a.seed), KNP_COL_SIZE=str(a.columns),
KNP_MNIST_THR=str(a.threshold), KNP_MNIST_ADD_THR_SCALE='0',
KNP_MNIST_INFER_INHIB='255', KNP_MNIST_DUMP=str(out))
if a.quant == 'weights':
env['KNP_MNIST_QUANT'] = 'weights'
else:
env.pop('KNP_MNIST_QUANT', None)
env['KNP_CPU_THREADS'] = str(a.threads)
backends = {'single': '/home/int/knp-build/bin/libknp-cpu-single-threaded-backend.so',
'multi': '/home/int/knp-build/bin/libknp-cpu-multi-threaded-backend.so',
'tuned': str(root / 'acceleration/libknp-cpu-tuned-backend.so'),
'fast': str(root / 'fast-cpu/libknp-cpu-fast-backend.so')}
command = [str(root / 'build/cats_dogs'), '-m', 'altai',
'--images', str(a.data_dir / (a.dataset + '.bin')),
'--labels', str(a.data_dir / (a.dataset + '.target')),
'-t', str(a.train), '-i', str(a.count), '-l', 'error',
'--training_backend', backends[a.backend]]
settings = {'arguments': {k: str(v) if isinstance(v, Path) else v for k, v in vars(a).items()}, 'command': command,
'environment': {k: v for k, v in env.items() if k.startswith('KNP_')},
'started_utc': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
(out / 'settings.json').write_text(json.dumps(settings, indent=2) + '\n')
start = time.monotonic()
with (out / 'run.log').open('w') as log:
result = subprocess.run(command, input='\n', text=True, env=env, stdout=log, stderr=subprocess.STDOUT)
text = (out / 'run.log').read_text()
if result.returncode:
raise RuntimeError(f'KNP exited {result.returncode}: {text[-2000:]}')
lines = text[text.index('CLASS,TOTAL_VOTES'):].splitlines()[:3]
(out / 'result.csv').write_text('\n'.join(lines) + '\n')
rows = list(csv.DictReader(io.StringIO('\n'.join(lines))))
metrics = {'elapsed_seconds': round(time.monotonic() - start, 2), 'classes': {}}
for row in rows:
label = 'cat' if row['CLASS'] == '0' else 'dog'
metrics['classes'][label] = {'correct': int(row['TRUE_POSITIVES']),
'unanswered': int(row['FALSE_NEGATIVES']),
'wrong': int(row['FALSE_POSITIVES'])}
for key in ('correct', 'unanswered', 'wrong'):
metrics[key] = sum(row[key] for row in metrics['classes'].values())
assert metrics['correct'] + metrics['unanswered'] + metrics['wrong'] == a.count
metrics['accuracy'] = metrics['correct'] / a.count
(out / 'metrics.json').write_text(json.dumps(metrics, indent=2) + '\n')
print(json.dumps(metrics), flush=True)