| import os
|
| import time
|
| import argparse
|
| import torch
|
| import numpy as np
|
| from glob import glob
|
| from PIL import Image, ImageFilter
|
| import matplotlib.pyplot as plt
|
| from sklearn.metrics import precision_score, recall_score, accuracy_score, roc_curve, auc
|
| import torchvision.transforms as transforms
|
| from TrainModel import SimpleAE
|
|
|
|
|
| def load_test_set(data_dir, img_size, noise_std):
|
| files = glob(os.path.join(data_dir, '*.png')) + glob(os.path.join(data_dir, '*.jpg'))
|
| X, y = [], []
|
| transform = transforms.Compose([
|
| transforms.Resize((img_size, img_size)),
|
| transforms.Grayscale(num_output_channels=1),
|
| transforms.ToTensor()
|
| ])
|
| for p in files:
|
| img = Image.open(p).convert('L')
|
| x = transform(img)
|
|
|
| X.append(x); y.append(1)
|
|
|
| arr = np.array(img).astype(np.float32)
|
| arr_n = np.clip(arr + np.random.normal(0, noise_std, arr.shape), 0, 255).astype(np.uint8)
|
| img_n = Image.fromarray(arr_n)
|
| X.append(transform(img_n)); y.append(0)
|
|
|
| img_b = img.filter(ImageFilter.GaussianBlur(radius=2))
|
| X.append(transform(img_b)); y.append(0)
|
| return torch.stack(X), np.array(y)
|
|
|
|
|
| def main(args):
|
| os.makedirs(args.output_dir, exist_ok=True)
|
|
|
|
|
| checkpoint = torch.load(args.model_path, map_location='cpu', weights_only=False)
|
| model = SimpleAE()
|
| model.load_state_dict(checkpoint['model_state'])
|
| threshold = checkpoint['threshold']
|
| model.eval()
|
|
|
|
|
| X, y_true = load_test_set(args.data_dir, args.img_size, args.noise_std)
|
|
|
|
|
| errors, times = [], []
|
| with torch.no_grad():
|
| for x in X:
|
| start = time.time()
|
| out = model(x.unsqueeze(0))
|
| times.append(time.time() - start)
|
| err = ((out - x.unsqueeze(0))**2).mean().item()
|
| errors.append(err)
|
| y_pred = np.array([1 if e <= threshold else 0 for e in errors])
|
|
|
|
|
| acc = accuracy_score(y_true, y_pred)
|
| prec = precision_score(y_true, y_pred)
|
| rec = recall_score(y_true, y_pred)
|
| fpr, tpr, _ = roc_curve(y_true, [-e for e in errors])
|
| roc_auc = auc(fpr, tpr)
|
| avg_time = np.mean(times)
|
| model_size = os.path.getsize(args.model_path) / (1024*1024)
|
|
|
|
|
| with open(os.path.join(args.output_dir, 'metrics.txt'), 'w') as f:
|
| f.write(f"Accuracy: {acc:.4f}\nPrecision: {prec:.4f}\nRecall: {rec:.4f}\nROC AUC: {roc_auc:.4f}\n")
|
| f.write(f"Avg inference time (s): {avg_time:.6f}\nModel size (MB): {model_size:.2f}\n")
|
|
|
|
|
| plt.figure()
|
| plt.hist(errors, bins=50)
|
| plt.title('Reconstruction Error Distribution')
|
| plt.xlabel('MSE Error')
|
| plt.ylabel('Count')
|
| plt.savefig(os.path.join(args.output_dir, 'error_distribution.png'))
|
| plt.close()
|
|
|
| plt.figure()
|
| plt.plot(fpr, tpr, label=f'AUC = {roc_auc:.2f}')
|
| plt.plot([0,1],[0,1],'--')
|
| plt.title('ROC Curve')
|
| plt.xlabel('False Positive Rate')
|
| plt.ylabel('True Positive Rate')
|
| plt.legend(loc='lower right')
|
| plt.savefig(os.path.join(args.output_dir, 'roc_curve.png'))
|
| plt.close()
|
|
|
| plt.figure()
|
| plt.plot(sorted(times), marker='.')
|
| plt.title('Inference Time per Sample')
|
| plt.xlabel('Sample index')
|
| plt.ylabel('Time (s)')
|
| plt.savefig(os.path.join(args.output_dir, 'inference_time.png'))
|
| plt.close()
|
|
|
| print(f"Test results saved in {args.output_dir}")
|
|
|
| if __name__ == '__main__':
|
| parser = argparse.ArgumentParser(description='Evaluate QA model')
|
| parser.add_argument('--data_dir', type=str, default='./data', help='Test images directory')
|
| parser.add_argument('--model_path', type=str, default='./models/autoencoder_qc.pth', help='Path to QC model')
|
| parser.add_argument('--output_dir', type=str, default='./TestModel', help='Directory to save results')
|
| parser.add_argument('--img_size', type=int, default=128, help='Image resize')
|
| parser.add_argument('--noise_std', type=float, default=25.0, help='Synthetic noise std')
|
| args = parser.parse_args()
|
| main(args) |