Dataset & Methodology

Intel Image Classification — ~14,000 training images and ~3,000 test images across 6 scene categories: buildings, forest, glacier, mountain, sea, street. Images were resized to 150×150 for the from-scratch models and 299×299 for the pretrained-backbone models (matching Xception-41's native training resolution). An 80/20 train/validation split was carved out of the training set with a fixed seed, kept identical across every model for a fair comparison; the test set was held out entirely until final evaluation.

Every model trained for 15 epochs with the Adam optimizer, sparse_categorical_crossentropy loss, and a ModelCheckpoint callback that saved only the best-val-loss weights — so every reported result reflects the best point in training, not whatever the final epoch happened to look like. That mattered more than once (see Discussion).

The five from-scratch stages were built cumulatively — each one adds a single technique on top of the previous stage, so results reflect the combined effect up to that point, not each technique in isolation. Two additional models push further: a deeper, more faithful Xception-style network with dropout and data augmentation, and transfer learning with a pretrained Xception-41 backbone (first frozen, then fine-tuned).

Results

ModelTest AccuracyTest Loss
Fine-tuned Xception-4191.0%0.367
Pretrained Xception-41 (frozen backbone)89.2%0.359
Xception-Lite V2 (deep + dropout + augmentation)87.0%0.388
Baseline CNN85.6%0.425
+ Batch Normalization85.4%0.430
+ Depthwise-Separable Convolutions84.0%0.466
Xception-Lite V1 (entry/middle/exit, no regularization)82.8%0.451
+ Residual Connections82.7%0.509

Trained model weights (.keras checkpoints) aren't in the repo — several exceed GitHub's 100MB file limit — and are hosted on the Hugging Face Hub instead. Diagrams generated via keras.utils.plot_model; curves plot per-epoch train/validation accuracy and loss from each run's history.

Discussion

Architectural sophistication alone didn't help At this dataset scale, it mostly hampered performance. Every from-scratch model that added a "best practice" technique without also increasing depth or adding regularization ended up at or below the plain baseline. Residual connections, in particular, consistently underperformed (82.7%, the weakest result in the whole comparison) — which lines up with why they were introduced in the first place: they solve a degradation/vanishing-gradient problem specific to very deep networks (dozens to hundreds of layers). At 4 blocks deep, that problem doesn't really exist yet, so the extra shortcut-path parameters mostly gave the model more capacity to overfit with, evidenced by a wider train/validation accuracy gap than the baseline showed. Depthwise-separable convolutions partially recovered some of that lost ground (84.0%), consistent with their actual selling point: parameter efficiency, not representational power.
Early batchnorm testing shaped momentum usage Initial runs of the batchnorm-augmented models showed wildly unstable validation metrics — validation loss spiking as high as 3× training loss between adjacent epochs, with no clear improving trend. The cause was BatchNormalization's default momentum=0.99: at that setting, the running mean/variance estimate used at evaluation time updates far too slowly to converge within a normal-length training run, so validation metrics were computed against an inaccurate normalization statistic. Lowering momentum to 0.9 (a 10% adaptation rate per step instead of 1%) fixed it — validation curves became smooth and well-behaved across every subsequent model.
Going deep enough let complexity pay off — once regularization came with it The first full Xception-style network (entry/middle/exit flow, no dropout, no augmentation) reached 97% training accuracy while validation accuracy stalled around 82–86% — overfitting. ModelCheckpoint caught this and saved an early, still-reasonable checkpoint (82.8% test accuracy) rather than the badly overfit final weights, but the underlying problem was clear: this network finally had enough capacity to fit the task well, but it was too complex for the problem at hand to generalize. Adding dropout and data augmentation in a deeper second version (8 middle-flow blocks instead of 4, proper pre-activation ordering) resolved that — training and validation accuracy tracked much more closely, and this was the first from-scratch model to clearly and consistently beat the baseline (87.0%).
Transfer learning boosted performance more than anything else in the project Even with the backbone completely frozen and only a small classification head trained from scratch, the pretrained Xception-41 model (89.2%) outperformed every from-scratch architecture, including the deep, well-regularized one. That suggests the ~85–87% ceiling the from-scratch models kept converging to wasn't primarily a capacity or architecture problem — it was a data problem. ~14,000 training images across 6 classes isn't enough for a randomly-initialized network to learn features as good as what ImageNet's ~1.4 million images already baked into this backbone. Fine-tuning the backbone's later layers (BatchNorm layers deliberately kept frozen, with a 100× lower learning rate to avoid destroying the pretrained weights) pushed this further to 91.0% — the best result of the project.
Fine-tuning converged almost immediately — then overfit for 12 more epochs The fine-tuning run's validation loss reaches its lowest point around epoch 2–3, while training loss keeps collapsing toward zero all the way through epoch 15. ModelCheckpoint correctly saved that early best point rather than the final weights, but it also means roughly 12 of the 15 fine-tuning epochs were pure wasted compute, actively pushing the model toward overfitting rather than improving it. In hindsight, 3–5 epochs would likely have reached the same result in a fraction of the training time — worth knowing, since fine-tuning was the slowest stage in the project per epoch.

Overall takeaway: on a dataset this size, individual architectural techniques from the CNN literature (batchnorm, residuals, separable convolutions) don't automatically improve results just because they're "best practices" — several of them measurably hurt when applied without enough depth or regularization. What actually helped was either combining sufficient depth with regularization, or sidestepping the data-scarcity problem entirely via transfer learning.

Training & Validation Curves

Per-epoch training/validation accuracy and loss for all eight models, in the same order as the results table.

Fine-tuned Xception-41 training curves
Fine-tuned Xception-41 (91.0%)
Pretrained Xception-41 frozen backbone training curves
Pretrained Xception-41, frozen (89.2%)
Xception-Lite V2 training curves
Xception-Lite V2 (87.0%)
Baseline CNN training curves
Baseline CNN (85.6%)
Batch normalization model training curves
+ Batch Normalization (85.4%)
Depthwise-separable convolutions training curves
+ Depthwise-Separable Convs (84.0%)
Xception-Lite V1 training curves
Xception-Lite V1 (82.8%)
Residual connections model training curves
+ Residual Connections (82.7%)

Architecture Diagrams

Generated directly via keras.utils.plot_model() — genuine layer-by-layer graphs, not illustrations. The deeper stages run extremely tall, so each is shown in a scroll frame; open the full diagram in a new tab for the complete layer stack.

Baseline CNN architecture diagram
Fine-tuned Xception-41 architecture diagram
Fine-tuned Xception-41Open full diagram ↗
Batch normalization architecture diagram
+ Batch NormalizationOpen full diagram ↗
Residual connections architecture diagram
+ Residual ConnectionsOpen full diagram ↗
Depthwise-separable convolutions architecture diagram
+ Depthwise-Separable ConvsOpen full diagram ↗
Xception-Lite V1 architecture diagram
Xception-Lite V1Open full diagram ↗
Xception-Lite V2 architecture diagram
Xception-Lite V2 (deep + dropout + augmentation)Open full diagram ↗

Limitations & Future Work

Stack

TensorFlow Keras Transfer Learning Xception Computer Vision