P4 Food-101 VGG-Style CNN with Batch Normalization and Label Smoothing
This repository contains a TensorFlow/Keras image classification model trained on the Food-101 dataset.
The model was designed as a lightweight CNN inspired by the VGG design principle of repeatedly stacking small 3×3 convolution layers before spatial downsampling.
The final model combines:
- VGG-style repeated 3×3 convolution blocks
- Batch Normalization after each convolution layer
- ReLU activations
- GlobalAveragePooling2D
- Label Smoothing during training
The goal is to classify food images into 101 Food-101 classes.
Model Summary
| Item | Description |
|---|
| Task | Image Classification |
| Dataset | Food-101 |
| Number of classes | 101 |
| Input size | 128 × 128 × 3 |
| Framework | TensorFlow / Keras |
| Model file | model.keras |
| Main architecture | VGG-style lightweight CNN |
| Regularization | Batch Normalization, Label Smoothing |
| Output layer | Dense + Softmax |
The model includes a Rescaling(1./255) layer internally, so input images should be provided as RGB arrays in the original 0–255 pixel range.
Architecture
The model is not the original VGG-16 architecture.
Instead, it uses the VGG idea of applying multiple 3×3 convolution layers before pooling, but with a smaller custom CNN structure.
A simplified block structure is:
1Input image: 128 × 128 × 3
2→ Rescaling(1./255)
3
4→ Conv2D → BatchNorm → ReLU
5→ Conv2D → BatchNorm → ReLU
6→ MaxPooling2D
7
8→ Conv2D → BatchNorm → ReLU
9→ Conv2D → BatchNorm → ReLU
10→ MaxPooling2D
11
12→ Conv2D → BatchNorm → ReLU
13→ Conv2D → BatchNorm → ReLU
14→ MaxPooling2D
15
16→ Conv2D → BatchNorm → ReLU
17→ GlobalAveragePooling2D
18→ Dense
19→ Softmax output over 101 classes
Dataset Split
The model was trained using the Food-101 dataset with the following split:
| Split | Number of images |
|---|
| Train | 60,600 |
| Validation | 15,150 |
| Test | 25,250 |
The official Food-101 test split was used only for final evaluation.
A validation set was separated from the official training split for model selection and early stopping.
Preprocessing
The preprocessing pipeline used during training was:
- Read image file path and label
- Decode JPEG image as RGB
- Resize image to 128 × 128
- Convert image to
float32
- Convert label to one-hot encoding
- Batch and prefetch data
The model itself includes:
Therefore, no external normalization is required at inference time if the input image uses the original 0–255 pixel range.
Training Configuration
| Item | Value |
|---|
| Optimizer | Adam |
| Learning rate | 0.001 |
| Loss | CategoricalCrossentropy(label_smoothing=0.1) |
| Batch size | 64 |
| Maximum epochs | 80 |
| EarlyStopping monitor | val_accuracy |
| EarlyStopping patience | 10 |
| ModelCheckpoint monitor | val_accuracy |
EarlyStopping restored the best weights based on validation accuracy.
The best validation performance was reached before the maximum epoch limit.
Test Results
Final evaluation was performed on the Food-101 test set.
| Metric | Value |
|---|
| Test Loss | 2.2240 |
| Test Accuracy | 0.5704 |
| Test Top-5 Accuracy | 0.8228 |
The Top-5 Accuracy indicates that the correct class was included among the model's top five predicted classes for approximately 82.28% of test images.
Repository Files
| File | Description |
|---|
model.keras | Trained Keras model |
class_names.json | Food-101 class labels |
training_config.json | Training, preprocessing, and evaluation configuration |
inference.py | Simple local inference helper |
model_summary.txt | Keras model architecture summary |
test_result.csv | Final test evaluation result |
requirements.txt | Minimal Python package requirements |
Usage
Option 1. Load the model directly from Hugging Face
1import os
2os.environ["KERAS_BACKEND"] = "tensorflow"
3
4import keras
5
6model = keras.saving.load_model(
7 "hf://neck392/p4-food101-vggstyle-cnn-bn-labelsmoothing"
8)
Option 2. Use the included inference helper
Clone or download this repository, then run:
1from inference import predict
2
3result = predict("sample_food_image.jpg", top_k=5)
4print(result)
Example output format:
1[
2 {"label": "pizza", "score": 0.42},
3 {"label": "lasagna", "score": 0.18},
4 {"label": "garlic_bread", "score": 0.09},
5 {"label": "ravioli", "score": 0.07},
6 {"label": "spaghetti_bolognese", "score": 0.05}
7]
Local Inference Example
1import json
2import numpy as np
3from PIL import Image
4from tensorflow import keras
5
6IMG_SIZE = 128
7
8model = keras.models.load_model("model.keras", compile=False)
9
10with open("class_names.json", "r", encoding="utf-8") as f:
11 class_names = json.load(f)
12
13image = Image.open("sample_food_image.jpg").convert("RGB")
14image = image.resize((IMG_SIZE, IMG_SIZE))
15
16arr = np.asarray(image).astype("float32")
17arr = np.expand_dims(arr, axis=0)
18
19# The model already includes Rescaling(1./255).
20probs = model.predict(arr, verbose=0)[0]
21
22top_k = 5
23top_idx = np.argsort(-probs)[:top_k]
24
25for idx in top_idx:
26 print(class_names[int(idx)], float(probs[int(idx)]))
Intended Use
This model is intended for educational and experimental food image classification tasks using the Food-101 label space.
It may be useful for:
- Food-101 classification experiments
- CNN architecture comparison
- Lightweight computer vision model demonstrations
- Top-1 and Top-5 classification analysis
Limitations
- The model was trained from scratch and does not use a large pretrained backbone.
- Input images are resized to 128 × 128, which may lose fine-grained food texture details.
- Visually similar food classes can still be confused, such as soups, desserts, sandwiches, or meat dishes.
- The model is intended for Food-101 style images and may not generalize well to out-of-distribution images.
- This model should not be used for medical, dietary, or nutrition-critical decisions.
Notes
This model uses the name "VGG-style" because it follows the VGG idea of stacking small 3×3 convolution layers before pooling.
It is not the original VGG-16 model and does not use pretrained VGG weights.
Citation
If you use this model or reproduce the project, please cite the Food-101 dataset and the relevant architecture papers:
1L. Bossard, M. Guillaumin, and L. Van Gool,
2"Food-101 – Mining Discriminative Components with Random Forests,"
3Computer Vision – ECCV 2014 Workshops, 2014.
4
5K. Simonyan and A. Zisserman,
6"Very Deep Convolutional Networks for Large-Scale Image Recognition,"
7International Conference on Learning Representations, 2015.
8
9S. Ioffe and C. Szegedy,
10"Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift,"
11International Conference on Machine Learning, 2015.
12
13M. Lin, Q. Chen, and S. Yan,
14"Network in Network,"
15International Conference on Learning Representations, 2014.
16
17C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna,
18"Rethinking the Inception Architecture for Computer Vision,"
19IEEE Conference on Computer Vision and Pattern Recognition, 2016.