cda-emr-classifier / scripts /infer_unknown.py
Laibaff7's picture
Upload folder using huggingface_hub
d561d1e verified
Raw History Blame Contribute Delete
3.35 kB
"""
Inference: rank all unknown spectra by EMR probability using the 5-model ensemble.
Input : Data Parquet/unknown_data_after_noise_filter_cropped.parquet (sclk + spectrum_cropped)
Models: EMR Classifier/models/emr_model_seed_*.pth
Output: EMR Classifier/predictions/emr_candidates_unknown.csv (all rows, sorted desc)
EMR Classifier/predictions/emr_top100.csv (top 100 for manual review)
"""
import os
import numpy as np
import pandas as pd
import torch
from torch.utils.data import DataLoader, TensorDataset
from train_emr_classifier import Spectra1DCNN, TARGET_LEN, minmax
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # EMR Classifier/
DATA_PATH = os.path.join(ROOT, 'Data Parquet', 'unknown_data_after_noise_filter_cropped.parquet')
MODELS_DIR = os.path.join(HERE, 'models')
OUT_DIR = os.path.join(HERE, 'predictions')
os.makedirs(OUT_DIR, exist_ok=True)
BATCH_SIZE = 256
def main():
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'Using device: {device}')
print('Loading unknown data (sclk + spectrum_cropped)...')
df = pd.read_parquet(DATA_PATH, columns=['sclk', 'spectrum_cropped'])
X = np.stack(df['spectrum_cropped'].to_numpy()).astype(np.float32)
X = minmax(X)
print(f' {X.shape}')
model_files = sorted(f for f in os.listdir(MODELS_DIR) if f.startswith('emr_model_seed_'))
models = []
for mf in model_files:
m = Spectra1DCNN(TARGET_LEN)
m.load_state_dict(torch.load(os.path.join(MODELS_DIR, mf), map_location=device))
m.to(device).eval()
models.append(m)
print(f'Loaded {len(models)} ensemble models: {model_files}')
loader = DataLoader(TensorDataset(torch.from_numpy(X).unsqueeze(1)),
batch_size=BATCH_SIZE, shuffle=False, num_workers=0)
preds = np.zeros(len(X), dtype=np.float32)
with torch.no_grad():
for i, (bx,) in enumerate(loader):
bx = bx.to(device)
acc = torch.zeros(bx.size(0), device=device)
for m in models:
acc += torch.sigmoid(m(bx)).squeeze(-1)
acc /= len(models)
s = i * BATCH_SIZE
preds[s:s + bx.size(0)] = acc.cpu().numpy()
if (i + 1) % 40 == 0:
print(f' {(i + 1) * BATCH_SIZE:,} / {len(X):,}')
df['emr_probability'] = preds
df_sorted = (df.drop(columns=['spectrum_cropped'])
.sort_values('emr_probability', ascending=False)
.reset_index(names='original_parquet_index'))
out_all = os.path.join(OUT_DIR, 'emr_candidates_unknown.csv')
df_sorted.to_csv(out_all, index=False)
print(f'Wrote {out_all} ({len(df_sorted):,} rows)')
out_top = os.path.join(OUT_DIR, 'emr_top100.csv')
df_sorted.head(100).to_csv(out_top, index=False)
print(f'Wrote {out_top}')
print(f'\nProbability distribution: '
f'mean={preds.mean():.4f} p50={np.percentile(preds, 50):.4f} '
f'p99={np.percentile(preds, 99):.4f} p99.9={np.percentile(preds, 99.9):.4f} '
f'max={preds.max():.4f}')
for thr in (0.5, 0.75, 0.9):
print(f' rows with emr_probability >= {thr}: {(preds >= thr).sum():,}')
if __name__ == '__main__':
main()