File size: 4,758 Bytes
e625897
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc92b7e
 
 
 
e625897
dc92b7e
 
 
 
 
 
 
 
 
 
 
 
 
 
e625897
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
title: Intel Scene CNN
emoji: πŸ”οΈ
colorFrom: blue
colorTo: green
sdk: gradio
sdk_version: 5.9.1
app_file: app.py
pinned: false
license: mit
---

# Intel Scene Classification: a CNN built from scratch

A plain convolutional neural network (no ResNet, no pretrained weights) trained on the
[Intel Image Classification](https://www.kaggle.com/datasets/puneet6060/intel-image-classification)
dataset: ~25k natural scene photos in 6 classes: **buildings, forest, glacier, mountain, sea, street**.

This is the follow-up to my EuroSAT satellite CNN. It tests whether the same architecture
generalizes to street-level photos, where orientation matters and the classes overlap visually.

**Live demo:** upload an image, get the predicted class and a Grad-CAM heatmap, plus the test metrics.

## Results

| Metric | Value |
|---|---|
| Test accuracy (seg_test, 3,000 images) | **89.87%** |
| Macro F1 | **0.900** |
| Best validation accuracy | **90.98%** |
| Parameters | **1,206,886** |

| Class | Precision | Recall | F1 | Test images |
|---|---|---|---|---|
| buildings | 0.913 | 0.860 | 0.886 | 437 |
| forest | 0.979 | 0.985 | 0.982 | 474 |
| glacier | 0.846 | 0.866 | 0.856 | 553 |
| mountain | 0.876 | 0.830 | 0.852 | 525 |
| sea | 0.895 | 0.937 | 0.916 | 510 |
| street | 0.897 | 0.918 | 0.907 | 501 |

**Where it fails:** mountain β†’ glacier (65), buildings β†’ street (46), glacier β†’ mountain (46),
street β†’ buildings (29). Almost all errors come from two pairs: snow-covered peaks vs. glaciers,
and urban scenes where a photo of a street is also a photo of buildings. Forest is near-perfect
(98% F1) because its texture and color are unique. Several high-confidence "mistakes" are
labeling errors in the dataset itself.

![Confusion matrix](images/11_confusion_matrix.png)
![Per-class accuracy](images/12_per_class_accuracy.png)
![Training curves](images/10_curves.png)

## Dataset

| Split | Images |
|---|---|
| seg_train β†’ train (85%) | ~11,900 |
| seg_train β†’ validation (15%, stratified) | ~2,100 |
| seg_test (held-out test) | 3,000 |
| seg_pred (unlabeled) | ~7,300 |

![Samples](images/01_samples.png)
![Class distribution](images/02_class_distribution.png)
![Average color per class](images/03_class_colors.png)

## Architecture

```mermaid
flowchart LR
    A[Input 3Γ—128Γ—128] --> B1[Block 1<br/>32ch β†’ 64Γ—64]
    B1 --> B2[Block 2<br/>64ch β†’ 32Γ—32]
    B2 --> B3[Block 3<br/>128ch β†’ 16Γ—16]
    B3 --> B4[Block 4<br/>256ch β†’ 8Γ—8]
    B4 --> G[Global Avg Pool<br/>256]
    G --> F1[Dropout 0.4 β†’ FC 128 β†’ ReLU]
    F1 --> F2[FC 6 β†’ softmax]
```

Each block is `Conv3Γ—3 β†’ BN β†’ ReLU β†’ Conv3Γ—3 β†’ BN β†’ ReLU β†’ MaxPool 2Γ—2 β†’ Dropout2d(0.1)`.

| Stage | Output shape |
|---|---|
| Input | 3 Γ— 128 Γ— 128 |
| Block 1 | 32 Γ— 64 Γ— 64 |
| Block 2 | 64 Γ— 32 Γ— 32 |
| Block 3 | 128 Γ— 16 Γ— 16 |
| Block 4 | 256 Γ— 8 Γ— 8 |
| Global average pool | 256 |
| FC + ReLU | 128 |
| FC (logits) | 6 |

## Training setup

- **Optimizer:** AdamW (lr 1e-3, weight decay 1e-2), cosine LR schedule, 30 epochs
- **Loss:** cross-entropy with label smoothing 0.1
- **Image size:** 128Γ—128, normalized with per-channel stats computed from the training data
- **Augmentation:** random resized crop (0.75–1.0), horizontal flip, Β±10Β° rotation, mild color jitter
- **No vertical flips or large rotations.** Scenes have gravity (sky on top), unlike satellite images.
- **Model selection:** best validation accuracy checkpoint

![Augmentation](images/04_augmentation.png)
![Bad augmentation](images/05_bad_augmentation.png)

## What the CNN learns

**Feature maps before vs. after training**

![Before](images/06_feature_maps_before.png)
![After](images/08_feature_maps_after.png)

**First-layer filters before vs. after training**

![Filters before](images/07_filters_before.png)
![Filters after](images/09_filters_after.png)

**Grad-CAM: where the network looks**

![Grad-CAM](images/15_gradcam.png)
![Grad-CAM on mistakes](images/16_gradcam_mistakes.png)

**Confidence and mistakes**

![Confidence](images/13_confidence.png)
![Mistakes](images/14_mistakes.png)
![Unlabeled predictions](images/17_unlabeled_predictions.png)

## Run locally

```bash
pip install -r requirements.txt gradio
python app.py
```

## Files

| File | Purpose |
|---|---|
| `app.py` | Gradio app: upload, prediction, Grad-CAM, metrics, plots |
| `model.py` | `SceneCNN` architecture + Grad-CAM |
| `cnn_intel.pth` | Trained weights (state_dict) |
| `cnn_intel_meta.json` | Class names, normalization stats, width, image size |
| `metrics.json` | Test metrics shown in the app |
| `images/` | All plots from training and evaluation |

## Author

Chandra Prakash Bathula, Adjunct Faculty, Saint Louis University (School for Professional Studies)