Desant Phishing Detector β€” MobileNetV2 INT8 for Google Coral Edge TPU

A fully quantized (INT8) MobileNetV2 model for real-time phishing screenshot detection on Google Coral Edge TPU devices.

Distilled from the Desant CLIP-based phishing classifier by Desant.ai for ultra-low-latency edge deployment.

Feed any web page screenshot and the model classifies it as SAFE (class 0) or MALICIOUS / Phishing (class 1) β€” entirely on-device, with no cloud round-trip.


Model Details

Property Value
Architecture MobileNetV2 (ImageNet backbone) + custom dense classifier head
Base model MobileNetV2 1.0 224 via tf.keras.applications
Teacher model Desant CLIP ViT-B/32 Phishing Classifier
Task Binary image classification (safe vs. phishing)
Input Web page screenshot β†’ [1, 224, 224, 3] uint8
Output [1, 2] uint8 softmax probabilities [safe, malicious]
Quantization Full INT8 post-training quantization (300 representative samples)
Edge TPU ops mapped 100% (68/68 operators) β€” fully compiled for Coral
Edge TPU Compiler v16.0.384591198
Model size 2.93 MB (Edge TPU) Β· 2.75 MB (CPU int8 fallback)
Framework TensorFlow / TFLite
Target hardware Google Coral USB Accelerator Β· Coral Dev Board Β· Raspberry Pi + Coral
License CC-BY-4.0

Architecture

Input Image (web page screenshot)
    β”‚
    β–Ό  Aspect-ratio-preserving resize + CLIP-mean padding β†’ 224Γ—224
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   MobileNetV2 1.0            β”‚  ← ImageNet-pretrained, fine-tuned
β”‚   Depthwise Separable Convs  β”‚
β”‚   Input: 224Γ—224Γ—3 (uint8)   β”‚
β”‚   Inverted Residual Blocks   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ 1280-dim feature map
           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   GlobalAveragePooling2D     β”‚
β”‚   Dropout(0.3)               β”‚
β”‚   Dense(128, ReLU)           β”‚
β”‚   Dropout(0.2)               β”‚
β”‚   Dense(2, Softmax)          β”‚  ← [safe, malicious] probabilities
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚
           β–Ό
     uint8 output β†’ dequantize β†’ prediction

Edge TPU Operator Mapping (100% on-chip)

All operators execute on the Edge TPU β€” zero fallback to CPU:

Operator Count
CONV_2D 35
DEPTHWISE_CONV_2D 17
ADD 10
FULLY_CONNECTED 2
QUANTIZE 2
MEAN 1
SOFTMAX 1
Total 68

Quantization Details

Property Input Tensor Output Tensor
Name serving_default_image:0 StatefulPartitionedCall_1:0
Shape [1, 224, 224, 3] [1, 2]
Dtype uint8 uint8
Scale 0.00784314 0.00390625
Zero point 127 0

Performance

Evaluated on a held-out stratified validation set (20% of dataset, 570 images):

Metric Score
Validation Accuracy 88.95%
Validation Loss 0.287

Note: This is a distilled edge model optimized for speed and size. For maximum accuracy, use the CLIP-based teacher model (92–96% accuracy, ~335 MB).

Training

Knowledge Distillation Pipeline

This model was trained as a student in a knowledge distillation pipeline:

  1. Teacher: CLIP ViT-B/32 fine-tuned phishing classifier (~335 MB, 92–96% accuracy)
  2. Student: MobileNetV2 trained on the same labeled dataset with class-weighted loss
  3. Export: Full INT8 post-training quantization with representative calibration dataset
  4. Compile: Edge TPU compiler maps all operations to the Coral accelerator

Data

Property Value
Total images 2,846
Train set 2,276 (1,138 safe + 1,138 malicious)
Validation set 570 (285 safe + 285 malicious)
Class balance Perfectly balanced (50/50)
  • Malicious class (1): Real phishing login page screenshots from PhishTank, OpenPhish, URLhaus, AlienVault OTX
  • Safe class (0): Legitimate web pages β€” real login pages (Google, Microsoft, banks), search engines, normal web pages

Training Configuration

Parameter Phase 1 (Frozen Backbone) Phase 2 (Fine-tuning)
Optimizer Adam (lr=1e-3) Adam (lr=1e-5)
Epochs Up to 20 Up to 5
Backbone Frozen Last 30 layers unfrozen
Loss SparseCategoricalCrossentropy SparseCategoricalCrossentropy
Class balancing Inverse-frequency class weights Inverse-frequency class weights
Scheduler ReduceLROnPlateau (patience=2, factor=0.5) ReduceLROnPlateau
Early stopping patience=6 on val_loss patience=6 on val_loss
Batch size 32 32

Preprocessing Pipeline

# 1. Load screenshot (any resolution)
# 2. Aspect-ratio-preserving resize to 224Γ—224
# 3. Pad with CLIP-mean color: (123, 117, 104)
# 4. MobileNetV2 normalization: [0, 255] β†’ [-1.0, 1.0]
# 5. INT8 quantization: scale=0.00784314, zero_point=127

Augmentation (training only)

  • Random horizontal flip (50%)
  • Brightness jitter Γ—0.85–1.15 (80%)
  • Contrast jitter Γ—0.85–1.15 (80%)
  • Color/saturation jitter Γ—0.85–1.15 (50%)

Usage

Files in this Repository

File Description
student_best_int8_edgetpu_edgetpu.tflite Edge TPU compiled model (use with Coral devices)
student_best_int8_edgetpu.tflite CPU-compatible INT8 TFLite (fallback, no Coral needed)
labels.txt Class labels (SAFE, MALICIOUS)
metadata.json Training metadata and hyperparameters
training_history.csv Epoch-by-epoch training curves

Quick Start β€” Edge TPU Inference (Python)

import numpy as np
from PIL import Image
from pycoral.adapters import classify, common
from pycoral.utils.edgetpu import make_interpreter

CLIP_MEAN_PAD = (123, 117, 104)

def preprocess(image_path, size=224):
    """Aspect-ratio-preserving resize with CLIP-mean padding."""
    img = Image.open(image_path).convert("RGB")
    w, h = img.size
    scale = min(size / w, size / h)
    new_w, new_h = int(w * scale), int(h * scale)
    img = img.resize((new_w, new_h), Image.LANCZOS)
    canvas = Image.new("RGB", (size, size), CLIP_MEAN_PAD)
    canvas.paste(img, ((size - new_w) // 2, (size - new_h) // 2))
    return np.array(canvas, dtype=np.uint8)

# Load Edge TPU model
interpreter = make_interpreter("student_best_int8_edgetpu_edgetpu.tflite")
interpreter.allocate_tensors()

# Preprocess and run inference
image = preprocess("screenshot.png")
common.set_input(interpreter, image)
interpreter.invoke()

# Get results
output = common.output_tensor(interpreter, 0)
safe_score = output[0]
malicious_score = output[1]

label = "MALICIOUS" if malicious_score > safe_score else "SAFE"
print(f"{label} β€” safe: {safe_score}, malicious: {malicious_score}")

CPU-only Inference (no Coral hardware)

import numpy as np
from PIL import Image
import tflite_runtime.interpreter as tflite

CLIP_MEAN_PAD = (123, 117, 104)

def preprocess(image_path, size=224):
    img = Image.open(image_path).convert("RGB")
    w, h = img.size
    scale = min(size / w, size / h)
    new_w, new_h = int(w * scale), int(h * scale)
    img = img.resize((new_w, new_h), Image.LANCZOS)
    canvas = Image.new("RGB", (size, size), CLIP_MEAN_PAD)
    canvas.paste(img, ((size - new_w) // 2, (size - new_h) // 2))
    return np.expand_dims(np.array(canvas, dtype=np.uint8), axis=0)

interpreter = tflite.Interpreter(model_path="student_best_int8_edgetpu.tflite")
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

image = preprocess("screenshot.png")
interpreter.set_tensor(input_details[0]["index"], image)
interpreter.invoke()

output = interpreter.get_tensor(output_details[0]["index"])[0]
scale = output_details[0]["quantization_parameters"]["scales"][0]
zero_point = output_details[0]["quantization_parameters"]["zero_points"][0]
probs = (output.astype(np.float32) - zero_point) * scale

label = "MALICIOUS" if probs[1] > probs[0] else "SAFE"
print(f"{label} β€” safe: {probs[0]:.4f}, malicious: {probs[1]:.4f}")

Raspberry Pi 5 + Coral USB Setup

# Install Coral runtime
echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" \
  | sudo tee /etc/apt/sources.list.d/coral-edgetpu.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt update && sudo apt install libedgetpu1-std python3-pycoral

# Run inference
python3 inference.py --model student_best_int8_edgetpu_edgetpu.tflite --image screenshot.png

Model Family

Model Size Accuracy Hardware Use Case
desant-phishing-inference ~335 MB 92–96% GPU / CPU Cloud inference, maximum accuracy
desant-phishing-detector-google-coral-int8 (this) 2.93 MB 88.95% Edge TPU / CPU On-device, real-time edge deployment

Intended Use

  • Primary use: Real-time on-device phishing detection on edge hardware (Coral USB, Raspberry Pi)
  • Input: Screenshots of web pages, especially login pages
  • Users: IoT security appliances, edge gateways, browser-integrated hardware, SOC edge nodes, security researchers

Limitations

  • Trained primarily on English-language phishing pages; reduced accuracy on non-Latin scripts
  • Optimized for login form detection β€” non-login phishing (e.g. fake download pages) may have lower recall
  • Accuracy is lower than the CLIP teacher model due to the distillation/quantization tradeoff (~89% vs ~95%)
  • Very low-resolution or heavily compressed screenshots may reduce accuracy
  • Detects visual similarity to known phishing patterns; novel zero-day designs may evade detection

Ethical Considerations

This model is designed for defensive cybersecurity β€” protecting users from phishing attacks. It should not be used to:

  • Create or improve phishing pages
  • Bypass security systems
  • Conduct adversarial attacks against phishing detection

Citation

@misc{desant2026phishing_edgetpu,
  title={Desant Phishing Detector: MobileNetV2 INT8 for Google Coral Edge TPU},
  author={Desant.ai},
  year={2026},
  url={https://huggingface.co/desant-ai/desant-phishing-detector-google-coral-int8}
}

Contact

Downloads last month
1
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for desant-ai/desant-phishing-detector-google-coral-int8

Finetuned
(77)
this model

Evaluation results