--- license: cc-by-nc-4.0 library_name: onnxruntime tags: - video - frame-deduplication - siamese-network - knowledge-distillation - onnx - directml datasets: - wikimedia-commons - Sudabaka/SFDP-Siamese-NET-AI-Dataset --- # 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. 安装依赖 ```bash # 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. 最小可运行示例 ```python 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. 从视频帧取块(预处理规范) 预处理必须与训练时一致,否则分数不可信: 1. 解码后先转**灰度** 2. 在**原分辨率**下裁剪出 128×128 的块(不要先缩放整帧再裁) 3. 归一化到 `[0, 1]`,`float32` 4. 排列为 `NCHW`,单样本即 `(1, 1, 128, 128)` 5. 两个输入块必须是**同一坐标位置** ```python 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 倍): ```python 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](https://huggingface.co/datasets/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): | 文件 | 作用 | |---|---| | `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`,调用方按模式切换文件名即可。 主要命令: ```bash # 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 禁止商业性使用;商业发行需另行授权。 ## 引用 ```bibtex @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](https://commons.wikimedia.org/),遵循各自 CC BY / CC BY-SA / CC0 许可,完整作者与许可证信息见 `sources.json`; - 教师模型与推理实现来自 Easy4K SFDP(帧去重四阶判决器); - 跨厂商推理基于 ONNX Runtime DirectML。 ## 许可证 模型权重与示例代码采用 [Creative Commons Attribution-NonCommercial 4.0 International](https://creativecommons.org/licenses/by-nc/4.0/) (CC BY-NC 4.0)许可:允许复制、修改与非商业性再分发,须保留署名并注明修改。