NABP-LSTM-Att / scripts /evaluate_test_set.py
wuxing0105's picture
Upload folder using huggingface_hub
bf928ee verified
Raw
History Blame Contribute Delete
5.85 kB
#!/usr/bin/env python3
"""Evaluate the official test set and weights on a single DCU."""
import argparse
import pickle
import time
from pathlib import Path
from _bootstrap import DATA_DIR, WEIGHT_DIR
import numpy as np
import tensorflow as tf
import tf_keras
from sklearn.metrics import average_precision_score, roc_auc_score
DEFAULT_DATA_DIR = DATA_DIR / "features" / "cdr_kmer3_ag_kmer1"
DEFAULT_WEIGHT_PATH = WEIGHT_DIR / "cdr_kmer3_ag_kmer1" / "Model99.h5"
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--data-dir", type=Path, default=DEFAULT_DATA_DIR)
parser.add_argument("--weights", type=Path, default=DEFAULT_WEIGHT_PATH)
parser.add_argument("--batch-size", type=int, default=64)
parser.add_argument(
"--output",
type=Path,
help="optional .npz path for labels and predictions",
)
return parser.parse_args()
def load_test_set(data_dir):
# Register features.InputFeatures before loading the official pickles.
import model # noqa: F401
with (data_dir / "cdr_features_te.pickle").open("rb") as reader:
cdr_features = pickle.load(reader)
with (data_dir / "ag_features_te.pickle").open("rb") as reader:
ag_features = pickle.load(reader)
if not cdr_features:
raise ValueError("The test set is empty")
if len(cdr_features) != len(ag_features):
raise ValueError(
f"Unpaired test features: CDR={len(cdr_features)}, AG={len(ag_features)}"
)
cdr_labels = np.asarray([item.label_id for item in cdr_features], dtype=np.int32)
ag_labels = np.asarray([item.label_id for item in ag_features], dtype=np.int32)
if not np.array_equal(cdr_labels, ag_labels):
mismatch_count = int(np.count_nonzero(cdr_labels != ag_labels))
raise ValueError(f"CDR/AG labels differ for {mismatch_count} test samples")
if set(np.unique(cdr_labels).tolist()) != {0, 1}:
raise ValueError(f"Expected binary labels 0/1, got {np.unique(cdr_labels)}")
inputs = [
np.asarray([item.input_ids for item in cdr_features], dtype=np.int32),
np.asarray([item.cdr_number_ids for item in cdr_features], dtype=np.int32),
np.asarray([item.input_ids for item in ag_features], dtype=np.int32),
]
sample_count = len(cdr_features)
expected_shapes = ((sample_count, 24), (sample_count, 24), (sample_count, 2371))
actual_shapes = tuple(array.shape for array in inputs)
if actual_shapes != expected_shapes:
raise ValueError(f"Unexpected input shapes: {actual_shapes}, expected {expected_shapes}")
return inputs, cdr_labels
def main():
args = parse_args()
if args.batch_size < 1:
raise ValueError(f"--batch-size must be positive, got {args.batch_size}")
if not args.data_dir.is_dir():
raise FileNotFoundError(f"Data directory not found: {args.data_dir}")
if not args.weights.is_file():
raise FileNotFoundError(f"Weight file not found: {args.weights}")
gpus = tf.config.list_physical_devices("GPU")
if not gpus:
raise RuntimeError(
"TensorFlow cannot see a DCU. Set HIP_VISIBLE_DEVICES and "
"CUDA_VISIBLE_DEVICES before starting Python."
)
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
inputs, labels = load_test_set(args.data_dir)
# Import after configuring the accelerator to avoid initializing it early.
from model import get_model
with tf.device("/GPU:0"):
model = get_model()
model.load_weights(str(args.weights))
start_time = time.perf_counter()
predictions = model.predict(
inputs,
batch_size=args.batch_size,
verbose=1,
).reshape(-1)
elapsed_seconds = time.perf_counter() - start_time
if predictions.shape != labels.shape:
raise ValueError(
f"Prediction/label shape mismatch: {predictions.shape} vs {labels.shape}"
)
if not np.all(np.isfinite(predictions)):
raise FloatingPointError("Test predictions contain NaN or Inf")
if np.any((predictions < 0.0) | (predictions > 1.0)):
raise ValueError("Test predictions are outside [0, 1]")
auroc = float(roc_auc_score(labels, predictions))
aupr = float(average_precision_score(labels, predictions))
positive_count = int(labels.sum())
negative_count = int(labels.size - positive_count)
dcu_variable_count = sum("GPU:0" in variable.device for variable in model.variables)
print("\nFull official test-set evaluation")
print(f"TensorFlow: {tf.__version__}")
print(f"tf_keras: {tf_keras.__version__}")
print(f"DCU: {gpus[0]}")
print(f"Samples: {labels.size}")
print(f"Positive/negative: {positive_count}/{negative_count}")
print(f"Batch size: {args.batch_size}")
print(f"Variables placed on GPU:0: {dcu_variable_count}/{len(model.variables)}")
print(f"Prediction min/max/mean: {predictions.min():.10g} / "
f"{predictions.max():.10g} / {predictions.mean():.10g}")
print(f"Elapsed seconds: {elapsed_seconds:.3f}")
print(f"Throughput samples/s: {labels.size / elapsed_seconds:.3f}")
print(f"AUROC: {auroc:.10f}")
print(f"AUPR: {aupr:.10f}")
print("Paper reference AUROC/AUPR: 0.926 / 0.952")
if dcu_variable_count == 0:
raise RuntimeError("No model variables were placed on GPU:0")
if args.output is not None:
args.output.parent.mkdir(parents=True, exist_ok=True)
np.savez_compressed(
args.output,
labels=labels,
predictions=predictions,
auroc=np.asarray(auroc),
aupr=np.asarray(aupr),
)
print(f"Saved predictions: {args.output}")
print("Full test-set inference: PASS")
if __name__ == "__main__":
main()