🇮🇳 Indian Currency Detector (CNN + YOLO) — Mobile Optimized
A lightweight, combined YOLOv8-nano + MobileNetV3-Small model for real-time Indian currency detection and denomination classification, optimized for mobile deployment.
🏗️ Architecture
Camera Frame → [YOLOv8-nano] → Detect & Localize Currency → [MobileNetV3-Small] → Classify Denomination
| Component |
Model |
Params |
ONNX Size |
Purpose |
| 🔍 Detector |
YOLOv8-nano |
3.01M |
11.6 MB |
Locate currency in frame |
| 🏷️ Classifier |
MobileNetV3-Small |
1.08M |
4.4 MB |
Identify denomination |
| 📱 Total |
Combined Pipeline |
~4.1M |
~16 MB |
End-to-end on mobile |
📊 Performance
| Metric |
Value |
| CNN Classification Accuracy |
100.00% (all 7 classes) |
| YOLO mAP@50 |
98.28% |
| YOLO mAP@50-95 |
68.95% |
| Inference speed (mobile est.) |
~25-35ms per frame |
| Total model size (FP32) |
~16MB |
| Total model size (INT8 est.) |
~5-6MB |
💰 Supported Indian Denominations
| Currency Notes |
| ₹10 |
| ₹20 |
| ₹50 |
| ₹100 |
| ₹200 |
| ₹500 |
| ₹2000 |
🚀 Usage
Quick Start — Classification Only
import torch
from torchvision import models, transforms
from PIL import Image
model = models.mobilenet_v3_small()
model.classifier = torch.nn.Sequential(
torch.nn.Linear(576, 256),
torch.nn.Hardswish(),
torch.nn.Dropout(0.3),
torch.nn.Linear(256, 7)
)
checkpoint = torch.load("mobilenetv3_currency.pth", map_location="cpu")
model.load_state_dict(checkpoint['model_state_dict'])
model.eval()
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])
img = Image.open("your_currency_photo.jpg").convert("RGB")
input_tensor = transform(img).unsqueeze(0)
with torch.no_grad():
output = model(input_tensor)
class_names = ["₹10", "₹100", "₹20", "₹200", "₹2000", "₹50", "₹500"]
prediction = class_names[output.argmax(1).item()]
confidence = torch.softmax(output, 1).max().item()
print(f"Detected: {prediction} ({confidence:.1%})")
YOLO Detection
from ultralytics import YOLO
model = YOLO("yolov8n_currency_best.pt")
results = model("currency_photo.jpg")
results[0].show()
ONNX Inference (Mobile/Edge)
import onnxruntime as ort
import numpy as np
from PIL import Image
session = ort.InferenceSession("mobilenetv3_currency.onnx")
img = Image.open("currency.jpg").resize((224, 224))
img_array = np.array(img).astype(np.float32) / 255.0
img_array = (img_array - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225]
input_data = img_array.transpose(2, 0, 1)[np.newaxis, ...]
outputs = session.run(None, {"input": input_data})
class_names = ["₹10", "₹100", "₹20", "₹200", "₹2000", "₹50", "₹500"]
print(f"Predicted: {class_names[np.argmax(outputs[0])]}")
📱 Mobile Deployment
| Platform |
Format |
Command |
| Android |
TFLite INT8 |
model.export(format="tflite", int8=True) |
| iOS |
CoreML |
model.export(format="coreml") |
| Cross-platform |
ONNX |
Already included! |
| Edge devices |
OpenVINO |
model.export(format="openvino") |
📁 Files
| File |
Description |
Size |
mobilenetv3_currency.pth |
CNN classifier (PyTorch) |
4.2 MB |
mobilenetv3_currency.onnx |
CNN classifier (ONNX) |
4.4 MB |
yolov8n_currency_best.pt |
YOLO detector (PyTorch) |
5.9 MB |
yolov8n_currency_best.onnx |
YOLO detector (ONNX) |
11.6 MB |
config.json |
Model configuration |
— |
🔬 Training Details
- Base Models: YOLOv8-nano (COCO pretrained) + MobileNetV3-Small (ImageNet pretrained)
- Dataset: ViratGarg/currency + ViratGarg/currency2 — 420 images, 7 balanced classes
- CNN Training: 30 epochs, AdamW (lr=1e-3), CosineAnnealing LR, label smoothing=0.1
- YOLO Training: 30 epochs, SGD (lr=0.01), mosaic augmentation, close_mosaic=10
- Augmentation: RandomResizedCrop, ColorJitter, RandomPerspective, RandomErasing, HSV jitter
- Hardware: CPU training (works on GPU too for faster training)
Training Recipe (Based on Published Research)
- YOLOBench (arxiv:2307.13901): COCO pretrain → fine-tune strategy
- HierLight-YOLO (arxiv:2509.22365): Lightweight detection architecture
- Currency CNN paper (arxiv:2509.06331): Augmentation recipe for currency images
⚠️ Limitations
- Trained on Indian currency notes only (no coins in current dataset)
- Small training set (420 images) — accuracy may vary on edge cases
- YOLO bounding boxes are pseudo-annotations (classification → detection conversion)
- For production use, recommend collecting more diverse training data with real bounding box annotations
📜 License
Apache 2.0