A Convolutional Neural Network that classifies satellite images into 4 categories: Cloudy, Desert, Green Area, and Water.
Being able to automatically identify different types of land cover from satellite images is useful for a wide range of environmental monitoring tasks. For example, tracking desertification over time, monitoring crop health and farm outputs, detecting habitat loss for wildlife conservation, and observing changes in sea ice or glacier coverage all depend on reliably telling different terrain types apart across large areas. Doing this by hand from satellite data is slow and expensive. A trained CNN can classify thousands of images in seconds, making large-scale monitoring far more practical.
This project trains and compares three CNN architectures on a 4-class satellite image dataset to explore how well simple convolutional networks handle this task, and what effect data augmentation and architectural changes have on performance.
The dataset contains 5,631 satellite images split across 4 classes, sourced from Kaggle.
| Class | Images |
|---|---|
| Cloudy | 1,500 |
| Desert | 1,131 |
| Green Area | 1,500 |
| Water | 1,500 |
| Total | 5,631 |
- Image size: 250 x 250 pixels
- Train / Validation split: 80% / 20%
- Source: Kaggle - Satellite Image Classification
- Python 3.8+
- TensorFlow 2.x
- Jupyter Notebook
1. Clone the repository
git clone https://github.com/RealGoldenGeneral/mini-project-5.git
cd mini-project-52. Install required libraries
pip install -r requirements.txt3. Download the dataset
Download from Kaggle and place it in a data/ folder at the root of the project:
data/
cloudy/
desert/
green_area/
water/
4. Run the notebook
cd notebooks
jupyter notebook cnn_model.ipynbRun all cells from top to bottom. The notebook trains the Baseline CNN, the Augmented CNN, and the Bonus GAP CNN in sequence and displays results after each.
Three models were trained and compared:
| Model | Train Accuracy | Val Accuracy | F1 Score | Train-Val Gap |
|---|---|---|---|---|
| Baseline CNN | 0.9487 (94.9%) | 0.9174 (91.7%) | 0.9171 | 0.0313 (3.1%) |
| Augmented CNN | 0.7738 (77.4%) | 0.7131 (71.3%) | 0.6203 | 0.0607 (6.1%) |
| GAP CNN (Bonus) | 0.9400 (94.0%) | 0.9400 (94.0%) | 0.9400 | 0.0020 (0.2%) |
- The Baseline CNN achieved 91.7% validation accuracy with a tight 3.1% train-val gap, showing solid generalisation with no regularisation at all.
- The Augmented CNN underperformed despite added BatchNorm and Dropout. The combination of aggressive contrast augmentation with BatchNormalization caused training instability, with validation loss spiking above 1,600 at epoch 16. It also completely failed on
green_area, misclassifying every single one aswater. - The GAP CNN was the best overall with 94% validation accuracy and a near-zero 0.2% gap. Swapping
FlattenforGlobalAveragePooling2Dreduced the parameter count from ~13M to ~0.5M, greatly cutting overfitting.
Green = correct, Red = wrong
The baseline model predicts confidently and correctly across all four classes in this batch, with most confidence scores at 0.99-1.00.
Green = correct, Red = wrong
The augmented model misclassifies green_area as water (shown in red). This matches the confusion matrix result where all 318 validation green_area images were predicted as water.
All 12 shown are green_area images wrongly predicted as water. Many look visually very similar to water from satellite altitude, especially after contrast augmentation is applied during training, which removes the subtle colour differences the model needs to tell them apart.
- Learning rate scheduling — adding
ReduceLROnPlateauwould likely have prevented the augmented model's loss spike at epoch 16 by automatically reducing the learning rate when validation loss stops improving - Milder augmentation — reducing or removing
RandomContrastshould fix the green_area vs water confusion, since that augmentation destroys the colour difference the model needs to separate those two classes - Transfer learning — using a pretrained backbone like EfficientNetB0 or MobileNetV2 would give a much stronger starting point than training from scratch and would likely outperform all three current architectures
- Proper test set — splitting the data into train / validation / test (e.g. 70/15/15) would give a more honest measure of how well the models actually generalise to unseen data
| Member | Contributions |
|---|---|
| Nicky Cheng | Exploratory data analysis (EDA), written report, README |
| Sepehr Mansouri | CNN model implementation, training, and results analysis |