ResNet-34 Signature Verification System
This repository hosts a fine-tuned ResNet-34 model designed for high-precision signature authentication. It distinguishes between Genuine (Original) and Forged signatures by analyzing stroke patterns, pressure points, and curvature nuances.
π Project Highlights
- Accuracy: Achieved near-zero test loss (<0.0001) after 10 epochs.
- Architecture: ResNet-34 backbone with a custom dropout-enhanced classification head.
- Framework: Built entirely with PyTorch and Torchvision.
- Dataset: Trained on the benchmark CEDAR Signature Dataset.
βοΈ Model Architecture
The model utilizes Transfer Learning from the ImageNet-pretrained ResNet-34 weights. The final fully connected layer was replaced to accommodate binary classification:
# Custom Head Implementation
model.fc = nn.Sequential(
nn.Dropout(0.1),
nn.Linear(512, 2) # Mapping features to ['Forged', 'Original']
)
π οΈ How It Works (The Pipeline)
This project is built as a modular MLOps pipeline. Here is the step-by-step logic:
Data Ingestion: Images are pulled from Google Cloud Storage (GCS) buckets into the local environment.
Data Transformation:
- Resizing: All signatures are standardized to 224 x 224 pixels.
- Augmentation: Random rotations (Β±20Β°) are applied to make the model robust to different signing angles.
- Normalization: Applied using ImageNet stats ($mean=[0.485, 0.456, 0.406]$) to ensure stable training.
Model Training:
- Uses a 60/30/10 split (Train/Val/Test).
- Optimized using SGD Momentum (0.9) and a learning rate of $1e^{-3}$.
- The model learns to identify micro-features like stroke pressure and curvature.
Evaluation: Performance is tracked via TensorBoard, monitoring the convergence of Training and Validation loss.
Model Pushing: Once peak accuracy is reached, the final
model.ptartifact is pushed to the cloud for production readiness.
π How to Use (Inference Script)
Since the model was saved as a complete serialized object, you can load it and run inference in just a few lines:
import torch
from torchvision import transforms
from PIL import Image
# 1. Setup Device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 2. Load the entire model object
# Ensure the 'model.pt' file is in your working directory
model = torch.load("model.pt", map_location=device)
model.eval()
# 3. Define Prediction Function
def predict(image_path):
img = Image.open(image_path).convert('RGB')
# Matches the transformation pipeline used during training
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
img_tensor = transform(img).unsqueeze(0).to(device)
with torch.no_grad():
output = model(img_tensor)
probs = torch.softmax(output, dim=1)
prediction = torch.argmax(probs, dim=1).item()
labels = ['Forged', 'Original']
return labels[prediction]
# Example run:
# print(f"Verdict: {predict('test_signature.png')}")