Keras

Overview

A video-based binary classifier that labels any clip as Normal or Suspicious. Trained end-to-end on the UCF-Crime dataset β€” 1,950 annotated surveillance videos across 13 crime categories (Abuse, Arrest, Arson, Assault, Burglary, Explosion, Fighting, Road Accidents, Robbery, Shooting, Shoplifting, Stealing, Vandalism) plus matched normal footage.

Model Usage Code on Google Colab can be found here.

Model Creation Code on Kaggle can be found here.


Architecture

Raw video
   ↓
ResNet50 (frozen, ImageNet)       ← feature extractor, 25M params
   ↓  16 frames Γ— 2048-dim vectors
LayerNorm + Dense(256) + Dropout(0.4)
   ↓
Bidirectional GRU (64 units)      ← temporal modelling
   ↓
Temporal Attention                ← learned frame weighting
   ↓
Dense(64) + Dropout(0.6)
   ↓
Sigmoid β†’ P(suspicious)

Head parameters: 660,738 (2.52 MB) Backbone: Frozen ResNet50 β€” features extracted once and cached, not retrained


Code Snippet 1

import requests

url = "https://shirish9354-ucf-crime.hf.space/predict"

with open(r"FILE_PATH", "rb") as f: res = requests.post(url, files={"file": f})

print(res.json())


Code Snippet 2

!pip install suspectiq

from suspectiq import SuspectIQ

detector = SuspectIQ()

result = detector.predict(r"FILE_PATH")

print(result)


Training Details

Setting Value
Framework TensorFlow 2.19.0 / Keras 3
GPU 2Γ— Tesla T4 (Kaggle)
Loss Focal Loss (Ξ±=0.60, Ξ³=2.0)
Optimiser Adam + gradient clipping (clipnorm=1.0)
LR schedule ReduceLROnPlateau on val_AUC, min 1e-5
Early stopping Patience 6 on val_AUC, restore best weights
Epochs run 19 (best at epoch 13)
Batch size 32
Sequence length 16 frames per 2-second clip
Threshold 0.325 (macro-F1 tuned on validation set)

Dataset Splits

Split Clips Normal Suspicious
Train 1,328 680 (51.2%) 648 (48.8%)
Val 332 170 (51.2%) 162 (48.8%)
Test 290 150 (51.7%) 140 (48.3%)

Splits are at video level β€” no frame-level leakage between train and val. Val is a stratified 20% carve-out of the training pool.


Results

Metric Value
Test accuracy 90.3%
Test AUC-ROC 0.930
Macro F1 0.903
Normal precision / recall 89.6% / 92.0%
Suspicious precision / recall 91.2% / 88.6%
False alarms (FP) 12 / 150 normal clips
Misses (FN) 16 / 140 suspicious clips

Inference

Supports both recorded video and live streams (webcam, RTSP, RTMP) via a sliding window with configurable overlap:

model = tf.keras.models.load_model('best_model.keras')
# No custom_objects needed β€” @register_keras_serializable handles it

Latency: ~135 ms per 2-second window on T4 GPU (after tf.function warm-up) Overlap: 50% default β€” events spanning clip boundaries are always fully captured


Fixes Applied Across Versions

Issue Fix
Class weight collapse (v1) Focal Loss Ξ±=0.60
Backbone overfitting ResNet50 frozen throughout
Slow extraction Batched GPU extraction (~8Γ— faster)
Threshold bias Macro-F1 tuning instead of suspicious-only F1
Custom class serialisation @register_keras_serializable
Training resume after crash Epoch history + weight checkpoint
Feature extraction resume Incremental partial .npz checkpoint every 200 clips
Dataset path resolution BFS auto-discovery + 5-layout fallback
Leakage Video-level splits confirmed

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