Neuro-symbolic fraud detection with differentiable rules

Your fraud detection model is probably lying to you. The standard advice in the WordPress and e-commerce world is to throw more data at a weighted Binary Cross-Entropy (BCE) network, and on imbalanced sets where fraud is under 0.2% of transactions that rarely buys you anything real. Neuro-Symbolic Fraud Detection is a way to hand the model some human intuition in the places where the gradient signal is too weak to lead it anywhere.

I have watched this happen in production. You train a model, get a ROC-AUC of 0.96, ship it, then look at the score distributions and find that the model worked out something simpler: predicting “not fraud” on anything ambiguous is the path of least resistance. It has no notion of what suspicious looks like. It is a black box that found a local minimum. If you build custom security work, my notes on AI agent security risks cover the same territory.

Why BCE alone runs out of signal

In a typical fraud dataset, like the one from Kaggle, you might have 492 fraud cases out of 284,000 transactions. Even with pos_weight in BCEWithLogitsLoss, the optimizer is starving. Most 2048-sample batches contain three or four labeled fraud examples. The rest of the batch tells the model nothing about fraud.

Neuro-Symbolic Fraud Detection goes at that starvation directly. Instead of hoping the model discovers on its own that unusually high amounts plus odd PCA signatures mean danger, we encode that rule in the training loop as a differentiable constraint. The model then gets a gradient signal on every transaction, whether or not it carries a fraud label.

The naive approach (pure neural)

A standard implementation leans entirely on the labels. When the labels are sparse, so is the model’s grasp of the feature space.

<?php
// Pseudo-logic of what most devs ship
function bbioon_naive_fraud_check($transaction) {
    $model_score = $neural_net->predict($transaction);
    return $model_score > 0.5; // This threshold is usually garbage for imbalanced data
}

The fix: a differentiable rule loss

The hybrid version adds a rule loss. The hard part is making the rule differentiable, because a plain if/else has zero gradient. A steep sigmoid centered on the batch mean gives you a soft suspicion score instead, which keeps the optimizer paying attention exactly where the boundary is messy. For API-level security, there is our API security patch checklist.

import torch
import torch.nn as nn

def bbioon_rule_loss(features, predicted_probs):
    # Rule: High transaction amount and atypical PCA distance are suspicious
    amount = features[:, -1]
    pca_variance = torch.norm(features[:, 1:29], dim=1)

    # Use Sigmoid to make the "if/else" differentiable
    is_suspicious = (
        torch.sigmoid(5 * (amount - amount.mean())) +
        torch.sigmoid(5 * (pca_variance - pca_variance.mean()))
    ) / 2.0

    # Only penalize if the model is UNCERTAIN (prob < 0.6) for suspicious items
    penalty = is_suspicious * torch.relu(0.6 - predicted_probs.squeeze())
    return penalty.mean()

# Official docs: https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html
criterion = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([577.0]))

What this changes in your architecture

The lesson is architectural, not really about Python. High-stakes systems cannot run on black-box heuristics alone. The hybrid model improves ROC-AUC consistently across multiple seeds because it still has something to steer by when the labels are missing.

In practice the Neuro-Symbolic Fraud Detection pattern behaves like soft regularization. Point the model at specific dimensions, transaction amount for example, and it is less likely to latch onto irrelevant correlations in the noise. That gap tends to show up late: a model that behaves in a sandbox can still fall over on a race condition in a live checkout loop.

If this Neuro-Symbolic Fraud Detection work is eating your dev hours, I can take it on. I have been wrestling with WordPress since the 4.x days.

What to check before you ship

Don’t trust single-seed results. On imbalanced data, how you pick the threshold moves F1 as much as the model architecture does. Evaluate the hybrid and the baseline symmetrically, both with validation-tuned thresholds. If ROC-AUC improves consistently across five or more seeds, you have a real signal. If it doesn’t, you are over-fitting to your own domain rules. The original experiment materials are on GitHub.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.