KeepersEye —— Gravekeeper应用使用模型
这是一个面向中文短视频画面、提取文本和相关元数据的模型,用于识别与健康相关的商业推广内容。它是一个为本地和移动端推理设计的自定义多阶段流程,不是 Transformers 兼容模型,也不提供 from_pretrained 接口。
当前状态
本仓库对应当前 App 内置使用的模型,模型标识为 day43-fusion-only-frozen-visual-v1,版本号为 day43-frozen-v1。App 当前加载的就是本发布包对应的视觉模型、int8 文本分类器和 18 特征融合模型。
该模型用于当前个人、非商业版本。README 中的评估结果来自项目内部开发和验证数据,只能说明它在对应数据拆分上的表现,不能当作对所有平台、画面和内容的准确率保证。
仓库内容
deployment/:模型发布包,包括视觉检查点、int8 文本分类器、融合模型、规则 schema、测试向量、评估证据、标签和运行时源码。deployment/runtime-day43-v1/fusion/:可移植的融合运行时参数、schema 和一致性测试向量。data-cards/frozen-labels-source/:已脱敏的人工标签记录和标签冻结记录。原始媒体和私有源路径不在仓库中。training/config/:训练工具使用的标注和规则 schema。training/tools/:数据准备、模型导出、版本固定和交付校验工具。
Android 软件使用单独导出的移动端视觉模型。仓库中的 PyTorch 视觉检查点是导出时使用的源检查点,本身不是可以直接放进 Android 应用的资源文件。
模型流程
模型组合了四类信号:
- 视觉模型读取 RGB、NCHW 布局的张量,形状为
1 x 3 x 416 x 192。画面使用保持比例的 letterbox 缩放,并用黑色填充;输入类型为 float32,只做 uint8 到[0,1]的归一化。 - int8 文本分类器根据提取出的文本特征输出文本分数。
- 规则特征记录价格、购物车、下单提示、账号名单、OCR 是否可用、画面是否不可用等信号。
- 标准化逻辑回归融合模型将这些特征组合为最终概率。
融合特征顺序定义在发布包的版本清单和 deployment/runtime-day43-v1/fusion/fusion_schema.json 中。当前版本使用阈值 0.48764924527277753;当校准概率大于或等于该阈值时,输出正向判断。
视觉分数定义为:
sum(softmax(marketing_logits)[1:]) * max(sigmoid(domain_logits))
模型总体结构
这个版本不是一个端到端的大语言模型,也不是单一的图像分类器,而是三个可独立复核的部分组合而成:
画面 RGB
-> MobileNetV3-Small 视觉模型
OCR 拼接文本
-> 字符级 HashingVectorizer + 三个逻辑回归分类器
规则和元数据
-> 18 个融合特征
视觉分数 + 文本分数 + 规则特征
-> StandardScaler + LogisticRegression
-> 最终概率和阈值判断
视觉、文本和融合部分的参数格式不同,不能把其中一个文件当作另一个部分的模型直接加载。移动端运行时应按照版本清单中的输入布局、特征顺序和阈值执行。
视觉模型
基础模型和结构
视觉骨干来自 torchvision.models.mobilenet_v3_small,使用 MobileNet_V3_Small_Weights.IMAGENET1K_V1 的 ImageNet-1K V1 预训练权重。其后接全局平均池化和一个共享投影层:
MobileNetV3-Small backbone
-> global average pooling
-> Linear(in_features, 512)
-> Hardswish
-> Dropout(p=0.2)
-> 四个任务输出头
四个输出头分别为:
| 输出头 | 形式 | 输出维度 |
|---|---|---|
mode_head |
屏幕/画面模式多类分类 | 5 |
marketing_head |
推广相关多类分类 | 3 |
domain_head |
领域标签多标签输出 | 5 |
elderly_head |
老年人相关多类分类 | 3 |
最终视觉分数只使用 marketing_head 和 domain_head 的概率,其他头用于多任务训练和诊断。视觉检查点是 PyTorch 源检查点;Android 使用的是另行导出的移动端模型,不是直接把 .pt 文件放入应用。
输入和预处理
视觉输入契约为 RGB、NCHW、float32、1 x 3 x 416 x 192。原图先按比例缩放,再用黑色填充到目标尺寸。训练代码在此基础上进行 ImageNet 标准化:
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
训练样本还会随机进行亮度和对比度调整(各自概率 0.8、范围 0.85 到 1.15)、高斯模糊(概率 0.2)以及随机黑色遮挡(概率 0.25)。导出的 Android/LiteRT 运行时契约记录为仅把 uint8 转换到 [0,1];因此复现训练或移动端推理时,必须以对应导出版本的契约为准,不能把两个阶段的预处理无条件混用。
视觉训练方法
视觉模型使用多任务损失。mode 和 elderly 使用交叉熵,marketing 使用带掩码的交叉熵,domain 使用带正负不对称权重的 BCE with logits,其中 gamma_neg=4.0、gamma_pos=1.0。总损失为:
total = 1.0 * mode_loss
+ 0.8 * marketing_loss
+ 0.8 * domain_loss
+ 0.5 * elderly_loss
训练分两个阶段:第一阶段训练新加入的共享层和四个输出头,冻结视觉骨干;第二阶段允许全模型微调。配置中的默认参数是 batch size 32、最多每个视频采样 2 帧、AdamW、权重衰减 0.0001、混合精度、1 个 warmup epoch 加余弦学习率、验证集早停耐心 5 个 epoch。第一阶段最多 3 个 epoch,学习率 0.003;第二阶段最多 25 个 epoch,学习率 0.0003。
需要特别区分训练过程和最终版本动作:上述“第二阶段允许微调”是视觉训练脚本的通用配置;day43-fusion-only-frozen-visual-v1 版本构建时没有再次微调视觉骨干,只重新训练了融合层,并沿用了固定的视觉检查点。
文本分类器
文本部分不是基于 BERT、GPT 或其他预训练语言模型,也没有使用词向量。它接收 OCR 拼接文本,使用 scikit-learn HashingVectorizer 生成字符级稀疏特征,再分别训练三个独立的 LogisticRegression:
OCR joined text
-> analyzer=char, ngram_range=1..4
-> 262144 维 HashingVectorizer 特征
-> sales / health / elderly 三个 LogisticRegression
-> 概率和各自阈值
特征配置为 alternate_sign=true、L2 归一化、lowercase=false,哈希算法为 sklearn_murmurhash3_32。三个分类器均使用 solver=liblinear、class_weight=balanced、max_iter=1000、random_state=2026。每个目标的分类阈值在验证集上按 F1 选择,而不是固定假设为 0.5。
交付的移动端文件是 text_classifier_int8.bin,大小为 786,510 bytes。独立的 float 与 int8 概率一致性检查覆盖 248 条开发验证记录,最大概率误差分别为:
| 目标 | 最大误差 | 平均误差 | 阈值翻转 |
|---|---|---|---|
sales |
0.0039304 | 0.0016300 | 2 |
health |
0.0029484 | 0.0007635 | 0 |
elderly |
0.0021764 | 0.0006609 | 0 |
报告状态为 PASS,但 sales 的两个阈值翻转没有被隐藏,仍保留在随附报告中。
融合模型
融合层不是神经网络,而是 StandardScaler -> LogisticRegression。它接收 18 个按固定顺序排列的特征:
visual_score
text_sales_score
text_health_score
text_elderly_score
health_keyword_count
sales_keyword_count
elderly_keyword_count
negative_context_count
price_present
shopping_cart_present
order_prompt_present
account_blacklist_hit
account_whitelist_hit
ocr_available
collector_overlay
black_occlusion
loading_or_blank
strong_positive_rule
融合训练使用旧开发集的 3-fold OOF 特征,加上 dataset2 的防泄漏预测;选择的正则化参数为 C=10.0,分类器使用 solver=liblinear 和 class_weight=balanced,校准方式为 identity。最终阈值为 0.48764924527277753,即校准概率大于或等于该值时输出正向判断。248 条一致性测试记录的原始和校准概率最大误差均约为 2.22e-16,决策翻转为 0。
数据集与数据拆分
数据收集工具
训练数据收集阶段使用了 ShortsScreenShot-Collector。该工具的 Android 端通过 MediaProjection 截取用户当前观看的短视频或直播画面,通过用户授权的无障碍服务执行翻页;Windows 接收端按 video_XXXXXX/frame_XXXXXX.png 分组保存 PNG。采集器只负责截图、视频分组和传输,不参与 OCR、人工标签、模型训练或模型推理。
采集完成后,图片还需要经过筛选、清洗、OCR、人工标注、去重、数据拆分和训练前校验等流程,才能进入模型训练输入。采集器属于早期测试工具,可能误判前台状态或意外暂停,采集结果不能未经检查直接视为完整数据。当前公开模型目录不包含原始截图、视频、OCR 原始日志、真实配对码或采集端配置。
初始视觉和文本训练输入
初始冻结输入包含 2,535 条标签记录,其中 2,523 条满足训练条件。按视频拆分为:
| 拆分 | 视频数 | 说明 |
|---|---|---|
| 训练集 | 2,021 | 用于视觉和文本分类器训练 |
| 验证集 | 248 | 用于选择模型、阈值和一致性检查 |
| 锁定测试集 | 254 | 不读取、不用于训练配置 |
训练和验证清单共有 12,431 行,锁定测试清单共有 1,387 行。视觉版本选择基于三次训练的验证 AUPRC 中位数:seed 8911 为 0.8595467,seed 2026 为 0.8663405,seed 3407 为 0.8687793,因此选择 seed 2026,而不是简单选择单次最高分。
dataset2 内部验证集
后续 dataset2 有 676 条标签记录,654 条满足训练条件,22 条被排除或标为不确定,另有 25 条进入第二轮队列。分类统计为:正向健康推广 345 条;普通商业负类 213 条;健康教育负类 1 条;其他负类 93 条;宠物健康负类 2 条;不可用 13 条;不确定 9 条。屏幕类型包括 live room 602 条、short video 63 条和 live preview 11 条。
dataset2 只作为内部验证和防泄漏融合特征来源。原始视频、截图、OCR 原始日志和私有数据集没有放入本仓库;公开前仍需确认所有衍生标签和资源具有再分发权利。
模型版本和训练边界
当前模型 ID 是 day43-fusion-only-frozen-visual-v1。它的含义是:视觉检查点已经固定,本版本只训练融合模型;没有在同一批数据上继续做视觉微调,也没有读取旧的锁定测试集。这样可以把本版本的变化限定在融合层,便于复核每个信号来源和比较后续版本。
评估结果
以下结果来自项目已有开发集和内部验证集,只能说明对应数据拆分上的表现,不能当作覆盖所有平台、画面和内容的准确率保证。
| 评估拆分 | 视频数 | Precision | Recall | F1 | AUPRC | 负类 FPR |
|---|---|---|---|---|---|---|
| 既有开发集 | 248 | 0.7647 | 0.9559 | 0.8497 | 0.9491 | 0.1111 |
| 内部验证集 | 90 | 0.8431 | 0.9149 | 0.8776 | 0.9268 | 0.1860 |
| 合并后的开发数据 | 338 | 0.7941 | 0.9391 | 0.8606 | 0.9334 | 0.1256 |
融合一致性测试向量在 248 条检查记录上没有出现决策翻转,最大绝对概率误差约为 2.22e-16。
数据与来源
当前版本基于固定的人工标签和避免数据泄漏的开发产物构建。仓库包含已脱敏的标签、schema、数据拆分信息和校验和,但不包含原始截图、视频、OCR 日志或原始数据集。所有由数据集派生的文件在公开前都应再次确认是否具有再分发权利。
版本清单记录了以下事实:没有进行语义重标注;版本构建过程中没有读取或使用旧的锁定测试集。
校验方式
发布包中包含 SHA256SUMS.txt。在本 model 目录下,将下面命令中的 <版本目录> 替换为 deployment 下实际的版本目录后运行:
python training/tools/verify_delivery_sha256_manifest.py deployment/<版本目录> deployment/<版本目录>/SHA256SUMS.txt ../gravekeeper-model-verification.json
预期结果是 "status": "PASS"。该工具会检查发布包文件是否全部存在、是否每个文件只列出一次,以及文件内容是否与发布的 SHA-256 摘要一致。生成的 JSON 只是临时校验结果,上传仓库前应删除它。
适用用途
本包适用于:
- 本地研究和可复现开发;
- 查看模型和运行时契约;
- 在受控的移动端运行时中导出或集成模型;
- 使用附带的测试向量和评估证据比较后续模型版本。
限制与安全说明
- 内部验证数据规模有限,可能不能代表新的平台、语言、画面布局、地区或内容形式。
- 对健康科普、普通商业内容、宠物健康内容、遮挡画面和低质量画面,模型可能产生误报或漏报。
- 不得把模型作为医疗、法律、金融、就业、账号权限或其他高影响决策的唯一依据。
- 不要上传私人媒体、凭据、原始采集结果,或任何尚未确认具有再分发权利的数据。
许可证
本仓库中由项目作者拥有并明确发布的模型权重、人工标签、训练产物、文档和示例配置,采用 Creative Commons Attribution-NonCommercial 4.0 International(CC BY-NC 4.0) 许可。
在遵守许可证的前提下,允许:
- 个人使用、学习、研究和非商业部署;
- 复制、修改、继续训练和制作衍生版本;
- 发布修改后的模型、标签或训练产物。
发布时必须保留原作者署名、许可证链接,并说明做过的修改。禁止直接或间接的商业使用,包括销售模型或数据、付费部署、商业服务、商业产品集成,以及把模型作为商业业务的一部分提供给客户。
这是一份明确限制商业用途的开放发布许可,严格来说不属于 OSI 对“开源软件”的定义。仓库中的 PyTorch、torchvision、scikit-learn、ImageNet 预训练权重和其他第三方内容,仍然按照各自上游许可证和使用条件执行;本条款不扩大对第三方内容的授权范围。