| """ |
| uncertainty.py |
| Monte Carlo Dropout uncertainty estimation. |
| Exact implementation from [IDSC]_D4.ipynb Cell 11. |
| """ |
|
|
| import torch |
| import torch.nn as nn |
| import numpy as np |
| from typing import Tuple |
|
|
| UNCERTAINTY_THRESHOLD = 0.05 |
| MC_SAMPLES = 1000 |
|
|
| def enable_dropout(model: nn.Module): |
| """ |
| Enable dropout layers during inference for MC Dropout. |
| (Sets all Dropout modules to training mode.) |
| """ |
| for m in model.modules(): |
| if isinstance(m, nn.Dropout): |
| m.train() |
|
|
|
|
| def mc_dropout_predict(model: nn.Module, |
| x_tensor: torch.Tensor, |
| n_samples: int = MC_SAMPLES, |
| device: str = 'cpu') -> Tuple[float, float, np.ndarray]: |
| """ |
| Run model n_samples forward passes with dropout active. |
| |
| Args: |
| model: MLPClassifier with dropout layers |
| x_tensor: input feature tensor shape (1, input_dim) |
| n_samples: number of MC passes (default 1000) |
| device: 'cpu' or 'cuda' |
| |
| Returns: |
| mean_prob: float, mean prediction probability |
| variance: float, prediction variance (= uncertainty) |
| all_preds: np.ndarray shape (n_samples,) |
| """ |
| x_tensor = x_tensor.to(device) |
| model.eval() |
| enable_dropout(model) |
|
|
| with torch.no_grad(): |
| |
| x_batch = x_tensor.repeat(n_samples, 1) |
| |
| |
| preds = model(x_batch).cpu().numpy().flatten() |
|
|
| mean_prob = float(preds.mean()) |
| variance = float(preds.var()) |
|
|
| return mean_prob, variance, preds |
|
|
|
|
| def interpret_uncertainty(variance: float) -> dict: |
| """ |
| Interpret the uncertainty level for display. |
| """ |
| is_ambiguous = variance > UNCERTAINTY_THRESHOLD |
| level = 'HIGH' if variance > 0.10 else ('MEDIUM' if variance > 0.05 else 'LOW') |
|
|
| return { |
| 'variance': round(variance, 6), |
| 'threshold': UNCERTAINTY_THRESHOLD, |
| 'is_ambiguous': is_ambiguous, |
| 'uncertainty_level': level, |
| 'uncertainty_pct': round(min(variance / 0.15, 1.0) * 100, 1), |
| 'refer_to_specialist': is_ambiguous, |
| } |
|
|