Gokulnathan G
Deploy DR Grading v10 — FastAPI + Material Design 3 UI with runtime model download
648beff | """DR Grading Model Architecture — extracted from notebook v10.""" | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import timm | |
| import numpy as np | |
| from typing import Dict, Tuple, Optional, List | |
| NUM_CLASSES = 5 | |
| IMAGENET_MEAN = [0.485, 0.456, 0.406] | |
| IMAGENET_STD = [0.229, 0.224, 0.225] | |
| GRADE_MAP = {0: "No DR", 1: "Mild DR", 2: "Moderate DR", 3: "Severe DR", 4: "Proliferative DR (PDR)"} | |
| GRADE_COLORS = ["#2ecc71", "#f1c40f", "#e67e22", "#e74c3c", "#8e44ad"] | |
| class GeM(nn.Module): | |
| def __init__(self, p=3.0, eps=1e-6): | |
| super().__init__() | |
| self.p = nn.Parameter(torch.tensor(p)) | |
| self.eps = eps | |
| def forward(self, x): | |
| return F.adaptive_avg_pool2d(x.clamp(min=self.eps).pow(self.p), 1).pow(1.0 / self.p) | |
| class CoralHead(nn.Module): | |
| def __init__(self, in_features, num_classes): | |
| super().__init__() | |
| self.linear = nn.Linear(in_features, 1, bias=False) | |
| self.bias = nn.Parameter(torch.zeros(num_classes - 1)) | |
| def forward(self, x): | |
| return self.linear(x) + self.bias | |
| class DRHead(nn.Module): | |
| def __init__(self, in_features, num_classes=5, dropout=0.3): | |
| super().__init__() | |
| self.net = nn.Sequential( | |
| nn.Linear(in_features, 512), nn.BatchNorm1d(512), nn.SiLU(inplace=True), nn.Dropout(dropout), | |
| nn.Linear(512, 256), nn.BatchNorm1d(256), nn.SiLU(inplace=True), nn.Dropout(dropout / 2), | |
| nn.Linear(256, num_classes), | |
| ) | |
| def forward(self, x): | |
| return self.net(x) | |
| class DRModel(nn.Module): | |
| def __init__(self, backbone="tf_efficientnetv2_m", num_classes=5, pretrained=False): | |
| super().__init__() | |
| self.backbone = timm.create_model(backbone, pretrained=pretrained, num_classes=0, global_pool="") | |
| in_feat = self.backbone.num_features | |
| self.pool = GeM(p=3.0) | |
| self.head_cls = DRHead(in_feat, num_classes) | |
| self.head_coral = CoralHead(in_feat, num_classes) | |
| self.num_classes = num_classes | |
| def forward(self, x): | |
| feat = self.backbone(x) | |
| feat = self.pool(feat).flatten(1) | |
| return {"logits": self.head_cls(feat), "coral": self.head_coral(feat), "feat": feat} | |
| PRETRAINED_BACKBONE = "convnext_tiny.fb_in22k" | |
| class FundusValidator(nn.Module): | |
| def __init__(self, pretrained=True, backbone_name=PRETRAINED_BACKBONE): | |
| super().__init__() | |
| self.backbone = timm.create_model(backbone_name, pretrained=pretrained, num_classes=0, global_pool="avg") | |
| for p in self.backbone.parameters(): | |
| p.requires_grad = False | |
| self.backbone.eval() | |
| with torch.no_grad(): | |
| feat_dim = self.backbone(torch.zeros(1, 3, 224, 224)).shape[1] | |
| self.feat_dim = feat_dim | |
| self.head = nn.Sequential(nn.Linear(feat_dim, 256), nn.GELU(), nn.Dropout(0.3), nn.Linear(256, 2)) | |
| def extract_features(self, x): | |
| with torch.no_grad(): | |
| return self.backbone(x) | |
| def forward(self, x): | |
| return self.head(self.extract_features(x)) | |
| def train(self, mode=True): | |
| super().train(mode) | |
| self.backbone.eval() | |
| return self | |
| class SingleLogitModel(nn.Module): | |
| def __init__(self, inner): | |
| super().__init__() | |
| self.inner = inner | |
| self.backbone = getattr(inner, "backbone", None) | |
| def forward(self, x): | |
| return self.inner(x)["logits"] | |
| def safe_load(path, map_location="cpu"): | |
| try: | |
| return torch.load(path, map_location=map_location, weights_only=False) | |
| except Exception: | |
| return torch.load(path, map_location=map_location) | |