Downloads · 30 days
4
2% of all-time downloads
shirish9354/Criminal_Activity_Detector_UCFCrimeDataset
Criminal_Activity_Detector_UCFCrimeDataset is a machine learning model from shirish9354. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for keras. The card lists the license as mit.
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…
Downloads · 30 days
4
2% of all-time downloads
All-time downloads
162
Public
Repo size
8 MB
Likes
1
Public
Click a slice to open those files.
.keras8 MB · 100%
From the Hugging Face model README
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.
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
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())
!pip install suspectiq
from suspectiq import SuspectIQ
detector = SuspectIQ()
result = detector.predict(r"FILE_PATH")
print(result)
| 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) |
| 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.
| 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 |
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
| 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 |