Using One-Class SVM for Counterfeit Detection
Drawing a mathematical boundary around authenrics when counterfeits are unknown.
Most introductory machine learning tutorials focus on a neat, balanced world. You have a thousand images of cats, a thousand images of dogs, and you train a Convolutional Neural Network (CNN) to draw a line between them. But in production environments, the real world rarely offers perfectly balanced datasets.
In my recent work developing an ML pipeline for wine authenticity verification, this imbalance was the core engineering challenge. When building a system to detect counterfeit products, you easily have access to thousands of authentic examples. But counterfeits? They are rare, highly varied, and constantly evolving to bypass existing security measures.
You cannot train a standard binary classifier to recognize “fakes” because you can never collect a dataset that represents every possible way a product might be counterfeited in the future. To solve this, we have to flip the problem upside down: instead of learning what a fake looks like, the system must learn to aggressively defend the mathematical definition of “authentic.”
This is where an uncommon but highly effective technique comes in: the One-Class Support Vector Machine (OC-SVM).
The Flaw in Standard Classification
If you feed an imbalanced dataset into a standard multi-class or binary model, the model optimizes for the dominant class. It becomes incredibly good at recognizing the real product but will likely misclassify a high-quality counterfeit as real simply because it hasn’t seen that specific type of forgery before.
Counterfeit detection is fundamentally an anomaly detection problem. In systems engineering, the most robust approach is to establish a rigorous baseline of normal operations and flag any statistical deviation from that baseline.
Enter the One-Class SVM
A standard Support Vector Machine draws a hyperplane between two different classes to separate them. A One-Class SVM, however, maps the data into a high-dimensional feature space and draws a boundary around your single class of known, good data.
It effectively creates a tightly bound, mathematical hypersphere. During inference:
- If a new data point falls inside the boundary, the model accepts it as authentic.
- If a new data point falls outside the boundary, the model flags it as an anomaly (a counterfeit).
This means the system doesn’t need to know what a fake looks like; it only needs to know that the input is statistically distinct from the authentic baseline.
The Pipeline: ResNet50 meets OC-SVM
An SVM cannot process raw image pixels efficiently or accurately. To make this work, the architecture must separate feature extraction from classification. Here is how the pipeline is constructed in code.
1. Robust Data Augmentation
To ensure the OC-SVM doesn’t learn a brittle boundary, the baseline data must be robust. Using Albumentations, the authentic dataset is heavily augmented to teach the model the natural tolerances, lighting variations, and physical orientations of the real product.
import albumentations as A
from albumentations.pytorch import ToTensorV2
import cv2
# Define a robust augmentation pipeline for authentic wine bottles
# This ensures our feature extractor learns structural geometry, not lighting artifacts.
transform = A.Compose([
A.RandomBrightnessContrast(p=0.5),
A.HorizontalFlip(p=0.5),
A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.05, rotate_limit=15, p=0.5),
# ImageNet standards for normalization since we are using a pre-trained ResNet
A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
ToTensorV2()
])
2. Deep Feature Extraction
Instead of training a model from scratch, a fine-tuned ResNet50 acts as the feature extractor. We deliberately sever the final classification layer of the network. When an image passes through, the network strips away spatial noise and condenses the image into a dense, 2048-dimensional feature vector.
import torch
import torchvision.models as models
import torch.nn as nn
class FeatureExtractor(nn.Module):
def __init__(self):
super(FeatureExtractor, self).__init__()
# Load pre-trained ResNet50 weights
resnet = models.resnet50(pretrained=True)
# Strip the final fully connected classification layer (fc)
# We only want the high-dimensional feature vector, not a class prediction
self.features = nn.Sequential(*list(resnet.children())[:-1])
def forward(self, x):
x = self.features(x)
# Flatten the tensor from (batch_size, 2048, 1, 1) to (batch_size, 2048)
# This 1D array is the mathematical "fingerprint" of the bottle
return x.view(x.size(0), -1)
# Initialize the model and freeze weights for inference
extractor = FeatureExtractor()
extractor.eval()
3. Anomaly Prediction
These extracted feature embeddings are then passed to the One-Class SVM. Because ResNet50 has already translated the complex image into a structured array of numbers, the scikit-learn OC-SVM can efficiently calculate whether those numbers fit within the established hypersphere of authenticity.
from sklearn.svm import OneClassSVM
import numpy as np
# 'authentic_features' is a numpy array of shape (N_samples, 2048)
# generated by running our entire training set of real bottles through the FeatureExtractor.
# Initialize the One-Class SVM
# nu: represents an upper bound on training errors and a lower bound on support vectors
# gamma='scale': automatically calculates the kernel coefficient for the RBF kernel
oc_svm = OneClassSVM(kernel='rbf', gamma='scale', nu=0.05)
# Train the boundary strictly on the authentic feature vectors
oc_svm.fit(authentic_features)
# --- Inference Pipeline ---
# 'new_bottle_feature' is a (1, 2048) vector extracted from a new image being tested
prediction = oc_svm.predict(new_bottle_feature)
# The OC-SVM returns 1 for an inlier (authentic) and -1 for an outlier (anomaly/counterfeit)
if prediction[0] == 1:
print("Status: Authentic - Feature vector falls within the established hypersphere.")
else:
print("Status: Anomaly Detected - Potential Counterfeit flagged for manual review.")
graph TD
A[Input Image: Unknown Bottle] --> B{Feature Extraction};
B -- ResNet50 (Stripped fc layer) --> C[/High-Dimensional Feature Vector (2048d)/];
C --> D{Anomaly Detection};
D -- One-Class SVM (Trained Boundary) --> E{Position vs. Hypersphere};
E -- Inside Boundary (Inlier) --> F[Result: Authentic];
E -- Outside Boundary (Outlier) --> G[Result: Anomaly / Potential Counterfeit];
%% Styling for visual distinctness
classDef processing fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
classDef data fill:#fff3e0,stroke:#e65100,stroke-width:2px,stroke-dasharray: 5 5;
classDef resultGood fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
classDef resultBad fill:#ffebee,stroke:#c62828,stroke-width:2px;
class B,D,E processing;
class C data;
class F resultGood;
class G resultBad;
Why This Architecture Scales
This hybrid approach—pairing the deep-learning perception of a CNN with the rigid, boundary-drawing mathematics of an SVM—is incredibly powerful. It is computationally efficient during inference, highly resistant to novel counterfeit strategies, and modular. If a new product line is introduced, you simply extract its features and map a new SVM boundary, without needing to retrain a massive neural network from the ground up.
As engineers, we often default to throwing larger neural networks at complex problems. But sometimes, the most elegant solution is recognizing when a problem isn’t about classifying two knowns, but protecting a system against the unknown.