File size: 4,829 Bytes
52e8264 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | # Quick Mitigation Options for Class B Bias
This document outlines immediate workarounds for the Class B bias while you retrain the model.
## Option 1: Logit-Bias Correction (Inference-Time Hack)
Add this function to `main.py` in the `/analyze` endpoint before softmax:
```python
def apply_logit_bias_correction(logits, bias_correction=None):
"""
Apply bias correction to logits before softmax.
This temporarily mitigates the Class B overprediction.
Args:
logits: Raw model output (before softmax)
bias_correction: Dict with per-class bias adjustments
Returns:
Adjusted logits
"""
if bias_correction is None:
# DEFAULT: Reduce Class B, boost others
bias_correction = {
0: +0.3, # Adenocarcinoma: slight boost
1: -1.2, # Small Cell: heavy penalty
2: +0.3, # Large Cell: slight boost
3: +0.3, # Squamous Cell: slight boost
}
for class_idx, bias in bias_correction.items():
logits[class_idx] += bias
return logits
```
**Usage in classification code:**
```python
# in the /analyze endpoint, after model inference:
with torch.no_grad():
logits = model(input_tensor) # Raw output
logits_corrected = apply_logit_bias_correction(logits[0]) # Apply correction
probs = torch.softmax(logits_corrected, dim=0) # Then softmax
```
## Option 2: Confidence-Based Filtering
Add confidence thresholds per-class:
```python
CONFIDENCE_THRESHOLDS = {
0: 0.30, # Adenocarcinoma: accept if >= 30%
1: 0.60, # Small Cell: require higher confidence (70%+)
2: 0.25, # Large Cell: accept lower confidence
3: 0.25, # Squamous Cell: accept lower confidence
}
if confidence < CONFIDENCE_THRESHOLDS[class_idx]:
logger.warning(f"LOW CONFIDENCE: {class_idx} at {confidence*100:.1f}% (threshold: {CONFIDENCE_THRESHOLDS[class_idx]*100}%)")
# Optionally flag as uncertain
```
## Option 3: Report Confidence Scores
Return all confidence scores to the frontend and let the UI handle the ambiguity:
**API Response Structure:**
```json
{
"success": true,
"detections": [
{
"tumor_id": 1,
"prediction": "Small Cell (Class B)",
"confidence": 75.97,
"all_confidences": {
"Adenocarcinoma": 3.5,
"Small Cell": 75.97,
"Large Cell": 6.89,
"Squamous Cell": 13.64
},
"confidence_status": "UNCERTAIN", // NEW: Add this
"note": "Low confidence in this prediction. Multiple classes viable."
}
]
}
```
Then in Flutter UI:
```dart
// Show warning if confidence is borderline
if (allConfidences.values.any((c) => c > 20 && c != maxConfidence)) {
showConfidenceWarning("Multiple classes possible. Review with specialist.");
}
```
## Option 4: Ensemble Multiple Models
If you have other trained models:
```python
def ensemble_predict(input_tensor, models_list):
"""Average predictions from multiple models"""
all_probs = []
for model in models_list:
with torch.no_grad():
probs = torch.softmax(model(input_tensor), dim=1)[0]
all_probs.append(probs)
ensemble_probs = torch.stack(all_probs).mean(dim=0)
return ensemble_probs
```
## Comparison of Options
| Option | Ease | Effectiveness | Drawbacks |
|--------|------|---------------|-----------|
| **Logit Bias Correction** | ⭐⭐⭐ Easy | ⭐⭐ Moderate | Doesn't fix root issue; magic numbers |
| **Confidence Filtering** | ⭐⭐⭐ Easy | ⭐⭐ Moderate | Still wrong predictions, just flagged |
| **Report All Scores** | ⭐⭐⭐ Easy | ⭐⭐ Moderate | Defers to human; adds complexity |
| **Ensemble Models** | ⭐⭐ Medium | ⭐⭐⭐ Good | Need multiple models |
| **Retrain with Weights** | ⭐ Hard | ⭐⭐⭐⭐⭐ Excellent | Takes time; need training data |
## ⚠️ Recommendation
**Use Option 3 (Report All Scores) + Option 1 (Logit Correction) as SHORT-TERM fix**
- Apply light logit correction to reduce Class B dominance
- Return all confidence scores to frontend
- Show warnings when confidence is low (< 60%)
- **Plan to retrain model properly** (highest priority)
**Then retrain the model** (Option 5 - see `retrain_with_balanced_weights.py`)
## Testing Your Fix
After implementing mitigation:
```bash
# Test with images from each class
LABELS=("Class_A" "Class_B" "Class_E" "Class_E")
for label in "${LABELS[@]}"; do
img=$(ls test-images/${label}_*.png | head -1)
echo "Testing: $img"
curl -X POST -F "file=@$img" http://localhost:5001/analyze | grep -A 10 '"prediction"'
done
```
Expected results after fix:
```
Class A image → Mostly Class A (not Class B)
Class B image → Mostly Class B (correct)
Class E image → Mix of E and others (not all B)
Class G image → Mix of G and others (not all B)
```
|