| | """ |
| | Autism Detector Model |
| | |
| | A feedforward neural network for ASD risk classification |
| | from structured clinical data. |
| | """ |
| |
|
| | import torch |
| | import torch.nn as nn |
| |
|
| |
|
| | class AutismDetector(nn.Module): |
| | """ |
| | Binary classifier for autism spectrum disorder screening. |
| | |
| | Input: 8 preprocessed clinical features |
| | Output: 2 logits (Healthy, ASD) |
| | |
| | Features (in order): |
| | 1. developmental_milestones - N/G/M/C (encoded 0-3) |
| | 2. iq_dq - numeric, normalized 0-1 |
| | 3. intellectual_disability - N/F70.0/F71/F72 (encoded 0-3) |
| | 4. language_disorder - N/Y (encoded 0-1) |
| | 5. language_development - N/delay/A (encoded 0-2) |
| | 6. dysmorphism - NO/Y (encoded 0-1) |
| | 7. behaviour_disorder - N/Y (encoded 0-1) |
| | 8. neurological_exam - N/abnormal (encoded 0-1) |
| | """ |
| |
|
| | def __init__(self, input_size=8, hidden_sizes=None, num_classes=2, dropout=0.3): |
| | super().__init__() |
| |
|
| | if hidden_sizes is None: |
| | hidden_sizes = [64, 32] |
| |
|
| | layers = [] |
| | prev_size = input_size |
| |
|
| | for hidden_size in hidden_sizes: |
| | layers.extend([ |
| | nn.Linear(prev_size, hidden_size), |
| | nn.ReLU(), |
| | nn.Dropout(dropout), |
| | ]) |
| | prev_size = hidden_size |
| |
|
| | layers.append(nn.Linear(prev_size, num_classes)) |
| | self.classifier = nn.Sequential(*layers) |
| |
|
| | |
| | self.input_size = input_size |
| | self.hidden_sizes = hidden_sizes |
| | self.num_classes = num_classes |
| | self.dropout = dropout |
| |
|
| | def forward(self, x): |
| | """ |
| | Forward pass. |
| | |
| | Parameters |
| | ---------- |
| | x : torch.Tensor |
| | Input tensor of shape (batch_size, 8) |
| | |
| | Returns |
| | ------- |
| | torch.Tensor |
| | Output logits of shape (batch_size, num_classes) |
| | """ |
| | return self.classifier(x) |
| |
|
| | def predict(self, x): |
| | """ |
| | Make predictions with probabilities. |
| | |
| | Parameters |
| | ---------- |
| | x : torch.Tensor |
| | Input tensor of shape (batch_size, 8) |
| | |
| | Returns |
| | ------- |
| | dict with 'prediction', 'probability', 'logits' |
| | """ |
| | self.eval() |
| | with torch.no_grad(): |
| | logits = self.forward(x) |
| | probs = torch.softmax(logits, dim=-1) |
| | pred_class = torch.argmax(probs, dim=-1) |
| |
|
| | return { |
| | 'prediction': pred_class, |
| | 'probabilities': probs, |
| | 'logits': logits |
| | } |
| |
|
| |
|
| | def load_model(model_path, device='cpu'): |
| | """Load TorchScript model.""" |
| | model = torch.jit.load(model_path, map_location=device) |
| | model.eval() |
| | return model |
| |
|
| |
|
| | def preprocess(data, config): |
| | """ |
| | Preprocess input data using JSON config. |
| | |
| | Parameters |
| | ---------- |
| | data : dict |
| | Input features as dictionary |
| | config : dict |
| | Preprocessor configuration from preprocessor_config.json |
| | |
| | Returns |
| | ------- |
| | torch.Tensor |
| | Preprocessed features tensor of shape (1, 8) |
| | """ |
| | features = [] |
| |
|
| | for feature_name in config["feature_order"]: |
| | if feature_name in config["categorical_features"]: |
| | feat_config = config["categorical_features"][feature_name] |
| |
|
| | if feat_config["type"] == "text_binary": |
| | |
| | raw_value = str(data[feature_name]).strip().upper() |
| | value = 0 if raw_value == feat_config["normal_value"] else 1 |
| | else: |
| | |
| | raw_value = data[feature_name] |
| | value = feat_config["mapping"].get(raw_value, 0) |
| |
|
| | elif feature_name in config["numeric_features"]: |
| | feat_config = config["numeric_features"][feature_name] |
| | raw = float(data[feature_name]) |
| | |
| | value = (raw - feat_config["min"]) / (feat_config["max"] - feat_config["min"]) |
| | value = max(0, min(1, value)) |
| |
|
| | features.append(value) |
| |
|
| | return torch.tensor([features], dtype=torch.float32) |
| |
|
| |
|
| | def get_risk_level(probability): |
| | """ |
| | Get risk level from ASD probability. |
| | |
| | Returns |
| | ------- |
| | str: 'low', 'medium', or 'high' |
| | """ |
| | if probability < 0.4: |
| | return "low" |
| | elif probability < 0.7: |
| | return "medium" |
| | else: |
| | return "high" |
| |
|
| |
|
| | if __name__ == '__main__': |
| | |
| | model = AutismDetector() |
| | print(f"Model architecture:\n{model}") |
| |
|
| | |
| | x = torch.randn(2, 8) |
| | output = model(x) |
| | print(f"\nInput shape: {x.shape}") |
| | print(f"Output shape: {output.shape}") |
| | print(f"Output (logits): {output}") |
| |
|
| | probs = torch.softmax(output, dim=-1) |
| | print(f"Probabilities: {probs}") |
| |
|