benedictpepper/pneumonia-classifier-efficientnetb4
EfficientNetB4 Pneumonia Classification: Fixed Size vs. Progressive Resizing
   
Paper: Perbandingan Strategi Pelatihan EfficientNetB4 dengan dan tanpa Progressive Resizing untuk Klasifikasi Pneumonia Bakterial dan Viral pada Citra X-Ray Dada Presented at SEMNAS (National Seminar on Technology and Applied Science), 2025.
Overview
This repository accompanies a comparative study evaluating two training strategies for EfficientNetB4 on the task of distinguishing bacterial from viral pneumonia in chest X-ray images:
- Fixed Size — trains exclusively at the target resolution (384 × 384 px) using a two-phase head-training + global fine-tuning schedule.
- Progressive Resizing — a curriculum learning approach that trains through progressively higher resolutions (224 → 256 → 384 px) with continuous weight transfer between stages.
Both models share an identical architecture, loss function, optimizer, and augmentation pipeline. The only variable is the training resolution schedule.
Key finding: Fixed-size training at 384 × 384 px achieves 86.92% accuracy and 0.9198 AUC, outperforming Progressive Resizing (78.46%, AUC 0.8011) by 8.46 percentage points, despite using fewer total epochs (32 vs 41). The result suggests that sustained high-resolution exposure during fine-tuning is more critical than curriculum-based resolution scaling for this task.
Results
Main Experiments — Test Set (N=390, 242 bacterial : 148 viral, with 2-step TTA)
Per-Class Metrics
Note: The test set uses the original Kaggle test/PNEUMONIA distribution (unbalanced: 242 bacterial, 148 viral). Both models show higher false-negative rates for the viral class, reflecting the intrinsic difficulty of this clinically important sub-task.Legacy Architecture Comparison (v1 pipeline, archive/legacy_experiments/)
Architecture
EfficientNetB4 (ImageNet pretrained, include_top=False)
→ top_activation feature maps [None, H, W, 1792]
├── GlobalAveragePooling2D → [None, 1792]
└── GlobalMaxPooling2D → [None, 1792]
→ Concatenate → [None, 3584] ← Concat Pooling
→ Dense(512, activation='swish')
→ BatchNormalization
→ Dropout(0.5)
→ Dense(2, activation='softmax', dtype='float32')
Total parameters: 18,594,913
Head parameters: 921,090
Fine-tuned (block6a+): 9,556,294Dataset
All experiments use the Kermany et al. Chest X-Ray dataset (bacterial vs. viral pneumonia subset).
- Source: Kaggle — Chest X-Ray Images (Pneumonia)
- Classes used: Bacterial Pneumonia (label 0), Viral Pneumonia (label 1). Normal class excluded.
- Labeling: Derived from filename prefix (
bacteria_*→ 0,virus_*→ 1)
Split protocol (v2 pipeline):
Class imbalance handling: Computed via sklearn.compute_class_weight('balanced'). Bacterial weight = 0.765 · Viral weight = 1.444. No physical oversampling was performed.Visualizations
Architecture & Pipeline
<table> <tr> <td align="center"><b>Model Architecture — Concat Pooling</b></td> <td align="center"><b>Training Strategy Comparison</b></td> </tr> <tr> <td><img src="figures/01architectureconcatpooling.png" width="420"/></td> <td><img src="figures/02trainingstrategycomparison.png" width="420"/></td> </tr> <tr> <td align="center" colspan="2"><b>Data Pipeline & Augmentation Strategy</b></td> </tr> <tr> <td colspan="2" align="center"><img src="figures/03datapipeline.png" width="840"/></td> </tr> </table>
Experimental Results (from Kaggle Execution)
<table> <tr> <td align="center"><b>ROC Curve — Both Models (N=390)</b></td> <td align="center"><b>Confusion Matrix — Both Models (N=390, TTA)</b></td> </tr> <tr> <td><img src="kaggleoutput/roccomparison.png" width="420"/></td> <td><img src="kaggleoutput/confusionmatrixcomparison.png" width="420"/></td> </tr> <tr> <td align="center"><b>Training Curves — Fixed Size (32 epochs)</b></td> <td align="center"><b>Training Curves — Progressive Resizing (41 epochs)</b></td> </tr> <tr> <td><img src="kaggleoutput/learningcurvesfixed.png" width="420"/></td> <td><img src="kaggleoutput/learningcurves_progressive.png" width="420"/></td> </tr> </table>
Grad-CAM Interpretability: Fixed Size vs. Progressive Resizing
<table> <tr> <td align="center"><b>Grad-CAM Comparison (Both Models)</b></td> </tr> <tr> <td align="center"><img src="figures/09gradcamcomparison.png" width="840"/></td> </tr> </table>
Grad-CAM activations computed on the top_activation layer (12×12×1,792 feature maps). Fixed Size (left column) shows precise, focused activation on the pathological lung parenchyma. Progressive Resizing (right column) shows slightly more diffuse activation patterns. Both models misclassify the viral samples (bottom two rows), reacting to the bilateral interstitial infiltrates but failing to find sufficient discriminative features for a correct viral prediction.Repository Structure
.
├── kaggle_pipeline/ # 8-cell Kaggle notebook, broken into scripts
│ ├── 01_setup_and_imports.py
│ ├── 02_data_pipeline.py # tf.data + Albumentations + MixUp
│ ├── 03_model_architecture.py # Concat Pooling + Focal Loss
│ ├── 04_experiment_1_fixed_size.py
│ ├── 05_experiment_1_evaluation.py
│ ├── 06_experiment_2_progressive.py
│ ├── 07_experiment_2_evaluation.py
│ ├── 08_final_comparison_and_gradcam.py
│ └── README.md
│
├── kaggle_output/ # Figures and execution log from Kaggle run
│ ├── *.png # Training curves, ROC, confusion matrices
│ ├── gradcam_images/ # Grad-CAM sample visualizations
│ └── pneumonia-fix-vs-progressive-resizing-v2.md # Full execution log
│
├── figures/ # Generated diagrams (architecture, pipeline, strategy)
│ ├── 01_architecture_concat_pooling.png
│ ├── 02_training_strategy_comparison.png
│ └── 03_data_pipeline.png
├── paper/ # Conference paper (manuskrip_deep_learning.md)
├── demo/ # Flask demo — Fixed Size vs Progressive comparison
│ ├── app.py
│ ├── model.py # .keras loader + Concat Pooling Grad-CAM
│ ├── templates/index.html
│ └── static/
│ ├── style.css
│ └── script.js
│
├── models/ # Model weights — NOT tracked in git
│ ├── .gitkeep
│ ├── README.md # Download instructions
│ ├── fixed_size_model.keras ← download from GitHub Releases
│ └── progressive_model.keras ← download from GitHub Releases
│
├── test_dataset/ # Small sample subset for local Grad-CAM testing
├── scripts/ # Utility scripts
├── archive/
│ └── legacy_experiments/ # v1 pipeline results (old architecture, H5 weights)
│
├── requirements.txt
├── CITATION.cff
└── LICENSELocal Demo
A Flask-based web demo is included in demo/. It supports:
- Single model inference — select Fixed Size or Progressive Resizing
- Compare mode — run both models on the same image side-by-side with Grad-CAM
# 1. Download the pre-trained weights (see models/README.md)
# Place both .keras files in models/
# 2. Install dependencies
pip install -r requirements.txt
# 3. Run the demo server
cd demo
python app.py
# → open http://localhost:5000Upload any chest X-ray (JPEG/PNG). The interface returns:
- Predicted class with confidence scores
- Per-class probability bars
- Grad-CAM activation heatmap highlighting diagnostically relevant lung regions
Model Weights
Trained weights are tracked via GitHub Releases (not in the repository — each ~332 MB).
Place both files in the models/ directory at the repository root.
Reproducing the Experiments
The full pipeline is available as 8 modular Python scripts in kaggle_pipeline/. See `kaggle_pipeline/README.md` for execution instructions.
The original Kaggle notebook is available on Kaggle at:
(link to be added upon public Kaggle release)
Update History
Citation
@inproceedings{pepper2025efficientnetb4pneumonia,
title = {Perbandingan Strategi Pelatihan EfficientNetB4 dengan dan tanpa
Progressive Resizing untuk Klasifikasi Pneumonia Bakterial dan
Viral pada Citra X-Ray Dada},
author = {Pepper, Benedict},
booktitle = {Prosiding Seminar Nasional Teknologi dan Sains Terapan},
year = {2025}
}License
Released under the MIT License.
The Kermany chest X-ray dataset is made available under CC BY 4.0 — please cite the original paper when using it:
Kermany, D. S., et al. (2018). Identifying Medical Diagnoses and Treatable Diseases by Image-Based Deep Learning. Cell, 172(5), 1122–1131. https://doi.org/10.1016/j.cell.2018.02.010
