Vinay-Umrethe/SigMamba-V1
GitHub: Vinay-Umrethe/SigMamba-V1
该项目将 SigLIP 2 视觉编码器与 Mamba SSM 结合,以线性计算复杂度实现高精度、高效率的长视频异常事件检测。
Stars: 1 | Forks: 0
# SigMamba-V1:使用 SigLIP 2 和 Mamba SSM 的统一视频异常检测
一种将 **SigLIP 2**(Google 的 SOTA 视觉编码器)与 **Mamba**(线性复杂度状态空间模型)相结合的统一架构,用于检测监控视频中的异常情况。该系统实现了线性 $O(N)$ 扩展性,使得处理长篇视频内容成为可能,而这在使用具有二次方复杂度开销的 Transformers 时 previously 是不切实际的。
# 模型对比
### 基准测试
| 指标 | V1 (Large) | V1 (Small) |
| :--- | :--- | :--- |
| **AUC-ROC** | **89.82%** | 87.57% |
| **Average Precision** | **41.05%** | 32.04% |
| **Best F1-Score** | 41.18% | **41.90%** |
| **Inference FPS** | 1,022 | **3,242** |
| **Peak VRAM** | 5,148 MB | **3,207 MB** |
## 核心功能
- **线性复杂度**:通过 Mamba SSM 实现 $O(N)$ 扩展性(相比之下,Transformers 的复杂度为 $O(N^2)$)
- **双输入模式**:接受原始像素或预提取的特征
## 架构
该模型在两种模式下运行:
| 模式 | 输入 | 使用场景 |
|------|-------|----------|
| **统一模式** | `pixel_values` (B, T, 3, 384, 384) | 端到端推理 |
| **模块化模式** | `features` (B, T, 1024) | 训练 / 批处理 |
**该架构在序列长度上实现了线性计算复杂度 $O(N)$,能够实时处理长监控视频,同时保持高检测精度。**
```
graph LR
subgraph "Preprocessing Stage"
A[Raw Video] --> B[SigLIP2 Vision Encoder]
B --> C[Extracted Features]
end
subgraph "Training Stage"
C --> D[Dataset Loader]
D --> E[Mamba Encoder]
E --> F[MIL Head]
F --> G[RTFM Loss]
end
subgraph "Inference Stage"
C --> H[Trained Model]
H --> I[Anomaly Scores 0-100%]
end
```
## 超参数
### Large
| 参数 | 值 | 描述 |
|-----------|-------|-------------|
| Feature Dim | 1024 | SigLIP 输出维度 |
| Mamba d_model | 768 | 内部隐藏维度 |
| Mamba Depth | 8 | 堆叠层数 |
## Small
| 参数 | 值 | 描述 |
|-----------|-------|-------------|
| Feature Dim | 768 | SigLIP 输出维度 |
| Mamba d_model | 768 | 内部隐藏维度 |
| Mamba Depth | 8 | 堆叠层数 |
**SigMamba:** Mamba 模型约有 ~32M 个参数。
## 用法
#### 前置条件
```
pip install opencv-python
pip install transformers==4.57.3
```
### 加载模型
```
from transformers import AutoModel, AutoProcessor
import torch
model = AutoModel.from_pretrained(
"VINAY-UMRETHE/SigMamba-V1-Large",
trust_remote_code=True
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
model.eval()
processor = AutoProcessor.from_pretrained(model.config.vision_model_id)
```
## 推理模式 1:统一模式(原始像素 → 分数)
当您拥有原始视频文件时请使用此模式。模型会在内部处理特征提取。
### 示例:单个视频
```
import cv2
import numpy as np
def load_video_frames(video_path, num_frames=32):
"""Sample frames uniformly from a video."""
cap = cv2.VideoCapture(video_path)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
indices = np.linspace(0, total_frames - 1, num_frames, dtype=int)
frames = []
for idx in indices:
cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
ret, frame = cap.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frames.append(frame)
cap.release()
return frames
frames = load_video_frames("test_video.mp4", num_frames=32)
inputs = processor(images=frames, return_tensors="pt")
pixel_values = inputs.pixel_values.to(device)
pixel_values = pixel_values.unsqueeze(0)
# 推理。
with torch.no_grad():
scores = model(pixel_values=pixel_values)
# 获取结果。
anomaly_scores = scores.squeeze().cpu().numpy()
max_score = anomaly_scores.max()
print(f"Max Anomaly Score: {max_score:.4f}")
```
## 推理模式 2:模块化模式(预提取特征 → 分数)
当您已经提取了特征用于训练模型时,请使用此模式。
### 示例:从特征文件加载
```
def load_features_from_txt(feature_path):
"""Load features from text file (one line per segment)."""
with open(feature_path, 'r') as f:
lines = f.readlines()
features = []
for line in lines:
values = [float(v) for v in line.strip().split()]
features.append(values)
return torch.tensor(features, dtype=torch.float32)
# 加载 features。
features = load_features_from_txt("video_features.txt")
features = features.unsqueeze(0).to(device)
# 推理。
with torch.no_grad():
scores = model(features=features)
print(f"Anomaly Scores: {scores.squeeze().cpu().numpy()}")
```
## 批量处理多个视频
在一次前向传递中处理多个视频以提高效率。
```
# 加载多个视频。
video_paths = ["video1.mp4", "video2.mp4", "video3.mp4"]
batch_frames = []
for path in video_paths:
frames = load_video_frames(path, num_frames=32)
inputs = processor(images=frames, return_tensors="pt")
batch_frames.append(inputs.pixel_values)
pixel_values = torch.stack(batch_frames).to(device)
with torch.no_grad():
scores = model(pixel_values=pixel_values)
for i, path in enumerate(video_paths):
max_score = scores[i].max().item()
print(f"{path}: {max_score:.4f}")
```
## 单帧
用于处理单个帧。
```
from PIL import Image
# 加载单张图像。
image = Image.open("suspicious_frame.jpg")
inputs = processor(images=image, return_tensors="pt")
pixel_values = inputs.pixel_values.to(device)
pixel_values = pixel_values.unsqueeze(0)
with torch.no_grad():
score = model(pixel_values=pixel_values)
print(f"Frame Anomaly Score: {score.item():.4f}")
```
## 仅提取特征(无分类)
直接访问 Mamba 编码器输出,用于自定义的下游任务。
```
# 加载 frames。
frames = load_video_frames("video.mp4", num_frames=32)
inputs = processor(images=frames, return_tensors="pt")
pixel_values = inputs.pixel_values.unsqueeze(0).to(device)
# 访问 internal components。
with torch.no_grad():
# Step 1: Extract vision features.
b, t, c, h, w = pixel_values.shape
flat_pixels = pixel_values.view(b * t, c, h, w)
vision_features = model.vision_model.get_image_features(pixel_values=flat_pixels)
vision_features = vision_features / vision_features.norm(dim=-1, keepdim=True)
vision_features = vision_features.view(b, t, -1)
# Step 2: Get Mamba-encoded features.
mamba_features = model.mamba_encoder(vision_features)
print(f"Vision Features: {vision_features.shape}")
print(f"Mamba Features: {mamba_features.shape}")
```
## 基于阈值的检测
应用阈值将分数转换为二元预测。
```
def detect_anomalies(video_path, threshold=0.5):
"""Returns list of anomalous segment indices."""
frames = load_video_frames(video_path, num_frames=32)
inputs = processor(images=frames, return_tensors="pt")
pixel_values = inputs.pixel_values.unsqueeze(0).to(device)
with torch.no_grad():
scores = model(pixel_values=pixel_values)
scores = scores.squeeze().cpu().numpy()
anomalous_segments = np.where(scores > threshold)[0]
return {
"scores": scores,
"max_score": scores.max(),
"is_anomalous": scores.max() > threshold,
"anomalous_segments": anomalous_segments.tolist()
}
# 推理。
result = detect_anomalies("test.mp4", threshold=0.5)
print(f"Anomalous: {result['is_anomalous']}")
print(f"Segments: {result['anomalous_segments']}")
```
## 输出参考
| 方法 | 输入形状 | 输出形状 | 描述 |
|:---|:---|:---|:---|
| `model(pixel_values=...)` | `(B, T, C, H, W)` | `(B, T, O)` | 端到端原始帧推理 |
| `model(features=...)` | `(B, T, D)` | `(B, T, O)` | 使用预提取特征进行训练 |
| `model.mamba_encoder(...)` | `(B, T, D)` | `(B, T, M)` | 通过 Mamba 处理特征 |
| `model.vision_encoder(...)` | `(N, C, H, W)` | `(N, D)` | 从帧中提取 SigLIP 特征 |
其中:
* **B**:Batch size
* **T**:视频序列长度(总帧数)
* **N**:展平后的总帧数 (B x T)
* **C**:图像通道数 (3)
* **H, W**:帧的高度和宽度 (384)
* **O**:输出异常维度 (1)
* **M**:Mamba 内部隐藏维度 (768)
* **D**:视觉特征嵌入维度(Large 为 1024,Small 为 768)
## 许可条款
SigMamba-V1:使用 SigLIP 2 和 Mamba SSM 的统一视频异常检测
Copyright © 2026 Vinay Umrethe。
本程序为自由软件:您可以根据自由软件基金会发布的 GNU Affero General Public License 条款重新分发和/或修改它,选择适用该许可证的第 3 版或(由您选择的)任何更高版本。
发布本程序是希望它能够派上用场,但对此不作任何保证;甚至不包含对适销性或特定用途适用性的暗示保证。有关更多详细信息,请参阅 GNU Affero General Public License。
您应该已经随本程序收到了一份 GNU Affero General Public License 的副本。如果没有,请访问 。
所有模型权重、生成的输出以及建模代码(位于 `sigmamba_release/` 目录中)均基于 **MIT License** 获得许可。
## 参考文献
[1] Tschannen, Michael, et al. "Siglip 2: Multilingual vision-language encoders with improved semantic understanding, localization, and dense features." arXiv preprint arXiv:2502.14786 (2025).
[2] Gu, Albert, and Tri Dao. "Mamba: Linear-time sequence modeling with selective state spaces." First conference on language modeling. 2024.
[3] Zhang, Yiling, Erkut Akdag, and Egor Bondarev. "MTFL: multi-timescale feature learning for weakly-supervised anomaly detection in surveillance videos." Seventeenth International Conference on Machine Vision (ICMV 2024). Vol. 13517. SPIE, 2025.
## 引用
```
@misc{vinayumrethesigmamba2026,
title = {SigMamba: Unified Video Anomaly Detection using SigLIP 2 and Mamba SSM},
author = {Vinay Umrethe},
year = {2026},
publisher = {Hugging Face},
howpublished = {\url{https://huggingface.co/collections/VINAY-UMRETHE/sigmamba-inventory}}
}
```
标签:Mamba, PyTorch, SigLIP, 凭据扫描, 状态空间模型, 视频异常检测, 计算机视觉, 逆向工具