Lightweight CNN framework for classifying documents based on visual layout and limited text, designed for on-device deployment with only 3.7M parameters. Published at IEEE ISEC-2025.
This research project developed a lightweight deep learning framework for document classification that operates on-device without requiring cloud connectivity. The key challenge was building a model compact enough for edge deployment while maintaining classification accuracy across diverse document types.
The framework uses a custom CNN architecture with only 3.7 million parameters (significantly smaller than standard document classification models) by combining visual layout features from document images with limited extracted text features. This dual-modality approach allows the model to classify documents even when OCR quality is poor or text content is minimal, such as with forms, invoices, receipts, and ID documents.
The model was designed for real-world deployment scenarios where documents need to be classified at the point of capture: on mobile devices, embedded systems, or in air-gapped environments where data cannot be sent to cloud APIs. The architecture prioritizes inference speed and memory efficiency without sacrificing accuracy.
The research was published at the IEEE International Symposium on Electronics and Communications (ISEC-2025) and presented at the ICOICI conference.
class DocumentClassifier(tf.keras.Model):
"""Lightweight dual-modality document classifier (3.7M params)."""
def __init__(self, num_classes: int):
super().__init__()
# Visual branch: lightweight CNN for document layout
self.visual = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, 3, activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, activation="relu"),
tf.keras.layers.GlobalAveragePooling2D(),
])
# Text branch: embedding + dense for limited OCR text
self.text_embed = tf.keras.layers.Embedding(10000, 64)
self.text_dense = tf.keras.layers.Dense(128, activation="relu")
# Fusion and classification
self.classifier = tf.keras.layers.Dense(num_classes, activation="softmax")
def call(self, image, text):
visual_features = self.visual(image)
text_features = self.text_dense(self.text_embed(text))
fused = tf.concat([visual_features, text_features], axis=-1)
return self.classifier(fused)