Easy4K SFDP · Siamese NET AI
面向视频帧去重的轻量孪生网络。输入相邻两帧的同一位置灰度块,输出 0~1 的连续相似度, 用于识别 1 拍 2 / 1 拍 3 等重复帧场景。模型通过知识蒸馏复现 Easy4K SFDP 四阶判决器 (像素差、dHash、QR 分解、Farnebäck 光流)的判定行为,可在 NVIDIA / AMD / Intel 显卡上 通过 DirectML 统一推理。
训练数据声明
本模型在训练过程中未分发、未再发布任何原始视频、音频或视频帧。训练仅使用从公开网络获取的视频中抽取的灰度切片,且全部监督信号由 Easy4K 自研的 SFDP 四阶判重判决器(像素差 / dHash / QR 码 / Farnebäck 光流)自动生成,不含人工标注。
视频著作权归原作者所有。所用素材清单见 training-materials.txt(含标题、BV 号、UP 主、原始链接),仅用于说明数据来源,不构成对原作品的授权或再分发。
若权利人认为其作品不应被用于本研究,请提交 issue,我们将在 72 小时内从清单中移除,并在后续版本训练中排除该来源。
模型权重以 CC BY-NC 4.0 发布,仅限研究与非商业用途。模型输出为 0~1 的相似度分数,不具备生成、重建或复现原视频内容的能力。
模型详情
| 项目 | 说明 |
|---|---|
| 开发者 | Sudabaka(Easy4K) |
| 模型类型 | 孪生卷积网络(Siamese CNN),共享权重双分支 |
| 架构 | 深度可分离卷积编码器(6 级下采样、512 维嵌入)+ 差分/乘积融合头(1024 隐层) |
| 参数量 | 2602017 |
| 输入 | frame_a、frame_b:灰度 128×128,float32,范围 [0, 1],NCHW |
| 输出 | score:形状 [batch, 1],Sigmoid 后位于 [0, 1],越接近 1 越可能重复 |
| 导出格式 | ONNX,opset 17,动态 batch |
| FP32 版本 | model.onnx,约 9.95 MB,对应 Easy4K「完美模式」 |
| FP16 版本 | model_fp16.onnx,约 5 MB(内部半精度、输入输出保持 float32),对应 Easy4K「性能模式」 |
| 运行后端 | onnxruntime:DmlExecutionProvider(DirectML)/ CPUExecutionProvider |
| 建议阈值 | 0.5;需要更低误判时可用 0.6~0.7 |
| 许可证 | CC BY-NC 4.0(仅限非商业用途) |
快速开始
1. 安装依赖
# Windows(NVIDIA / AMD / Intel 统一走 DirectML)
pip install onnxruntime-directml numpy opencv-python
# Linux / macOS(纯 CPU)
pip install onnxruntime numpy opencv-python
2. 选择模型文件
| 场景 | 文件 | 阈值建议 |
|---|---|---|
| 精度优先(对应 Easy4K 完美模式) | model.onnx(FP32,9.95 MB) |
0.5 |
| 速度优先(对应 Easy4K 性能模式) | model_fp16.onnx(FP16,5.01 MB) |
0.55~0.6 |
两份模型的输入输出签名完全一致,切换只需换文件名。FP16 版本内部半精度、输入输出仍是 float32,调用代码不用改。
3. 最小可运行示例
import numpy as np
import onnxruntime as ort
providers = [p for p in ("DmlExecutionProvider", "CPUExecutionProvider")
if p in ort.get_available_providers()]
sess = ort.InferenceSession("model.onnx", providers=providers)
# 同位置的两块灰度图,[0,1],NCHW
a = np.random.rand(1, 1, 128, 128).astype(np.float32)
b = a.copy()
score = float(sess.run(["score"], {"frame_a": a, "frame_b": b})[0][0, 0])
print(score) # 越接近 1 越可能是重复帧
print(score >= 0.5) # 判重结果
4. 从视频帧取块(预处理规范)
预处理必须与训练时一致,否则分数不可信:
- 解码后先转灰度
- 在原分辨率下裁剪出 128×128 的块(不要先缩放整帧再裁)
- 归一化到
[0, 1],float32 - 排列为
NCHW,单样本即(1, 1, 128, 128) - 两个输入块必须是同一坐标位置
import cv2
import numpy as np
def patch(gray, x, y, size=128):
p = gray[y:y + size, x:x + size]
if p.shape[:2] != (size, size):
return None
return (p.astype(np.float32) / 255.0)[None, None, :, :]
cap = cv2.VideoCapture("input.mp4")
ok, f1 = cap.read()
ok2, f2 = cap.read()
g1 = cv2.cvtColor(f1, cv2.COLOR_BGR2GRAY)
g2 = cv2.cvtColor(f2, cv2.COLOR_BGR2GRAY)
a, b = patch(g1, 320, 180), patch(g2, 320, 180)
if a is not None and b is not None:
s = float(sess.run(["score"], {"frame_a": a, "frame_b": b})[0][0, 0])
print("duplicate" if s >= 0.5 else "different", s)
5. 批量推理
batch 维度是动态的,一次送入多个帧对可显著提高吞吐(DirectML 下比逐对调用快 2~4 倍):
pairs_a = np.concatenate([a] * 32, axis=0) # (32, 1, 128, 128)
pairs_b = np.concatenate([b] * 32, axis=0)
scores = sess.run(["score"], {"frame_a": pairs_a, "frame_b": pairs_b})[0].ravel() # (32,)
6. 阈值调法
| 阈值 | 效果 |
|---|---|
| 0.5 | 默认,偏召回,适合“宁可多判不放过” |
| 0.6~0.7 | 偏精确,适合画面干净、误判代价高的场景 |
判断依据:若实际使用中误删真正不同的帧(漏检画面),就调高;若放过重复帧,就调低。
7. 常见问题
| 现象 | 原因与处理 |
|---|---|
DmlExecutionProvider 不可用 |
未装 onnxruntime-directml,或系统缺少 DirectX 12;会自动回退 CPU,不影响结果 |
| 报输入维度错误 | 必须是 (N, 1, 128, 128)、float32;FP16 模型也接收 float32 输入 |
| 分数恒为 0 或恒为 1 | 检查是否忘了 /255、是否用了彩色三通道、是否两块取自不同位置 |
| 结果和 Easy4K 不一致 | 预处理路径不同(先缩放 vs 先裁剪)、阈值不同,或用了 FP16 版本 |
完整可运行示例见 example_infer.py。
使用场景
适用
- 视频补帧 / 超分前的重复帧检测,尤其是动画 1 拍 2、1 拍 3 的帧复用;
- 作为 Easy4K SFDP 的快速前置筛选,降低后续 QR 与光流计算的调用次数;
- 需要跨厂商 GPU 统一推理路径的桌面端场景(DirectML 单套算子覆盖三家)。
不适用
- 整帧级、跨场景的重复镜头检索(模型只判断 128×128 局部块);
- 经过强压缩、去噪、缩放等处理后的一致性判定(训练分布未覆盖);
- 需要逐像素级精确对齐的场合,本模型输出的是相似度分数而非位移场。
训练方法
教师与标签
教师为 Easy4K 生产环境的 SFDP 完美模式(四阶全开)。对每个样本同时记录判决阶段与中间指标:
- 教师判重且光流位移为 0:软标签 1.0;
- 教师判重但存在可测位移:软标签
clip(1 - flow / 2.0, 0, 1); - 教师在光流阶段判否:同样按上式映射,光流 0.1~0.4 的模糊区丢弃;
- 教师在前三阶判否:明确负样本,软标签 0;
- 第一阶段判为相同、被光流救回的样本标记为 hard,损失权重 2.0。
数据
| 项目 | 数值 |
|---|---|
| 素材来源 | Wikimedia Commons(CC BY / CC BY-SA / CC0);用户提供的术力口 / 真人 MV;Bilibili 公开 MV(仅训练使用,不随模型分发) |
| 片段构造 | 固定窗口连续帧,按 1拍1 / 1拍2 / 1拍3 / 混合节奏展开,本版本使用其中 5212 个片段 |
| 样本总数 | 550158(训练 472011 / 验证 78147) |
| 正负比 | 1 : 1.00 |
| 难例 | 9972 个(光流救回,权重 2.0) |
| 划分方式 | 按来源视频隔离,验证集素材不参与训练 |
完整素材清单(462 支视频 / 7852 个切片,含标题、作者、许可证与来源链接)单独发布于 Sudabaka/SFDP-Siamese-NET-AI-Dataset; 本版本模型基于该数据集的 5212 片段快照训练。
训练配置
| 项目 | 值 |
|---|---|
| 目标函数 | 软标签 MSE 回归(非二分类交叉熵) |
| 优化器 | AdamW,weight decay 1e-4 |
| 学习率 | 2e-3,2 epoch 线性 warmup + 余弦退火 |
| Batch size | 256 |
| Epoch | 8 |
| 硬件 | NVIDIA P106-100(6 GB),CUDA 12.4,PyTorch 2.6.0 |
完整实现代码
模型训练、导出与数据来源记录的全部实现代码随仓库提供,位于 code/:
| 文件 | 作用 |
|---|---|
code/siai_all.py |
一体化流水线:视频切片(tiles)、教师打标(teacher)、软标签生成(label)、训练(train)、评测(eval)、ONNX 导出(pack) |
code/teacher_run.py |
教师打标的轻量入口:只做目录扫描与 SfdpTeacher 调用,不加载 torch / cv2,避免与训练同时运行时内存不足 |
code/append_sources.py |
训练素材清单的生成与去重追加,产出可溯源的 training-materials.txt |
code/algorithm/FrameDedupService.cs |
四阶判决器教师本体:像素差粗筛 → dHash 细筛 → QR 分解精判 → Farnebäck 光流终判,含全部阈值与标定注释 |
code/algorithm/FarnebackFlow.cs |
第四阶使用的稠密光流实现(GPU/CPU 混合路径) |
code/algorithm/Easy4K.SFDP.csproj |
上述两个源文件的编译工程(.NET 10,Windows.Graphics.Imaging) |
教师算法(四阶判决器)
| 阶段 | 方法 | 作用 |
|---|---|---|
| 1 | 像素绝对差均值(MAD) | 粗筛,明显不同的帧对直接放过 |
| 2 | dHash 汉明距离 | 细筛,感知哈希不一致的帧对放过 |
| 3 | 8×8 分块 QR 分解,取 diag(R) 特征算 Minkowski 距离 | 精判,抑制亮度/压缩噪声造成的误判 |
| 4 | Farnebäck 稠密光流,统计均值与方差 | 终判,区分“真重复帧”与“相似但不相同”的运动画面 |
阈值取论文建议值并对 1080p 动画 MV 重新标定(τ_flow=0.5、τ_var=0.1、QR 阈值 1.0 灰阶),标定过程与分布数据写在源码注释里。
ONNX 模型
| 文件 | 精度 | 体积 | 建议用途 |
|---|---|---|---|
model.onnx |
FP32 | 9.95 MB | 完美模式(精度优先) |
model_fp16.onnx |
FP16(IO 保持 float32) | 5.01 MB | 性能模式(速度优先,DirectML 下约快 1.5~2 倍) |
两份模型输入输出签名完全一致:frame_a、frame_b → score,调用方按模式切换文件名即可。
主要命令:
# 1) 从视频抽取灰度切片
python code/siai_all.py tiles --raw <视频目录> --segments 4 --out <切片目录>
# 2) 用四阶判决器教师生成逐片段标签 CSV
python code/siai_all.py teacher --tiles <切片目录> --labels <标签目录>
# 3) 生成软标签训练集与验证集
python code/siai_all.py label
# 4) 训练(结束后自动导出 FP32 与 FP16 两份 ONNX)
python code/siai_all.py train --out <输出目录> --epochs 1 --workers 8 --lr 1e-4
# 5) 评测 / 打包
python code/siai_all.py eval --out <输出目录>
python code/siai_all.py pack --onnx <输出目录>/easy4k_sfdp_siamese_fp32.onnx --out <发布目录>
依赖见 requirements.txt(PyTorch、OpenCV、onnx、onnxruntime、onnxconverter-common)。教师端二进制 SfdpTeacher 属于 Easy4K 应用程序的一部分,不随本仓库分发。
评测结果
与教师的一致性(验证集 78147 样本,按视频隔离)
| 指标 | 数值 |
|---|---|
| 软标签 MAE | 0.02788 |
| 判决准确率(阈值 0.5) | 97.56% |
| 精确率 / 召回率 | 97.42% / 98.11% |
| 正样本 MAE | 0.01063 |
| 负样本 MAE | 0.04085 |
推理性能
| 硬件 | 后端 | 批量 | 每对耗时 |
|---|---|---|---|
| AMD Radeon RX 580 | DirectML 1.24.4(Windows 11) | 64 | 0.56 ms |
| NVIDIA P106-100 | CPU 执行器 | 32 | 0.317 ms |
数值一致性
ONNX 与 PyTorch 输出最大绝对误差不超过 1.2e-7,可直接替换训练端推理。
局限与风险
- 题材覆盖:训练素材以实拍街景、开源动画与音乐视频为主,番剧 1 拍 2 / 1 拍 3 的真实样本 仍有限,建议在目标内容上先做小规模验证再上线。
- 局部判定:模型只看 128×128 灰度块,不理解整帧语义;涉及大面积平移、缩放、转场的 判定仍需上层聚合逻辑。
- 压缩与后处理:强压缩块效应、降噪、锐化会改变像素分布,可能影响分数校准。
- 系统要求:DirectML 需要 Windows 10 1903+ 或 Windows 11;更旧的系统需回退 CPU。
- 蒸馏上限:模型逼近教师而非超越教师,教师判错的样本同样会被学习。
- 许可证:CC BY-NC 4.0 禁止商业性使用;商业发行需另行授权。
引用
@misc{easy4k_sfdp_siamese_net_ai,
author = {Sudabaka},
title = {Easy4K SFDP - Siamese NET AI},
year = {2026},
howpublished = {\url{https://huggingface.co/Sudabaka/SFDP-Siamese-NET-AI}},
note = {Frame-duplicate similarity model distilled from the Easy4K SFDP judge}
}
致谢
- CC 训练素材来自 Wikimedia Commons,遵循各自 CC BY /
CC BY-SA / CC0 许可,完整作者与许可证信息见
sources.json; - 教师模型与推理实现来自 Easy4K SFDP(帧去重四阶判决器);
- 跨厂商推理基于 ONNX Runtime DirectML。
许可证
模型权重与示例代码采用 Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)许可:允许复制、修改与非商业性再分发,须保留署名并注明修改。
- Downloads last month
- 83