从规则到偏好——用强化学习做游戏直播AI切片
三角洲行动直播切片 AI 系统 — 项目文档
一、项目简介
本项目是一个游戏直播自动切片系统,针对「三角洲行动」等 FPS 游戏直播,通过语音转写 + 画面 OCR + 弹幕联合分析自动识别高光时刻,并使用强化学习(偏好学习)逐步学习用户切片偏好,最终输出可直接发布的短视频片段。
核心功能
- 语音转写 — 从 FLV 视频提取音频,通过 faster-whisper 将主播语音转为带时间戳的文本,并做情绪/语速/音量分析
- 弹幕分析 — 解析抖音弹幕 JSON 数据,计算密度曲线、检测峰值、提取关键词和高频词
- 画面 OCR — GPU 硬件解码视频帧,PaddleOCR 识别击杀信息和比分面板,精确到秒级定位击杀时刻
- 多模态联合分析 — 语音情绪 + 弹幕密度 + OCR 事件三流融合,自动生成候选切片并评分
- RL 偏好学习 — 用成对偏好学习替代硬编码规则评分,每次用户标注最佳切片后模型自动训练改进
- 双模式切割 — 同时生成长切片(15-150s,全类型高光)和短切片(<30s,仅 PvP 击杀真人)
工作流程
1 | FLV 视频 ──→ ffmpeg 提取音频 ──→ faster-whisper 转写 ──→ 带时间戳文本 + 情绪标注 |
二、开发过程
2.1 项目起点
项目起步于原版 delta-force-clip skill,使用硬编码规则评分——手工设置每个特征的加减分值(”弹幕密度 > 3x 基线 +2 分,出现击杀事件 +3 分”)。规则系统可以产出及格的切片(约 70% 可用率),但存在两个问题:
- 不同剪辑师的偏好差异大,规则无法适应
- 调整评分逻辑需要直接修改 Python 源码,门槛高
RL 版的目标是将评分替换为可学习的偏好模型,让用户通过标注行为而非修改代码来定制切片策略。
2.2 迭代过程
Phase 1 — 规则系统基线
- 实现完整的多模态分析 pipeline:语音转写 → 弹幕分析 → 画面 OCR → 事件推断 → 候选生成 → 评分 → 切割
- 事件推断:从语音中检测击杀/死亡/灭队/救援,从 OCR 中检测击杀/对局结束
- 锚点聚类:基于时间窗口合并邻近事件,生成候选片段
- 硬编码评分:
score_candidate()按特征加减分,输出 0-10 分 - GPU 加速:ffmpeg NVENC/NVDEC 硬件编解码,PaddleOCR GPU 推理
Phase 2 — RL 模型设计
- 设计 35 维特征向量(弹幕密度 4 + 弹幕内容 4 + 高频词 4 + 语音情绪 5 + 游戏事件 8 + OCR 事件 4 + 叙事结构 3 + 位置 1 + 其他 2)
- 实现
FeatureExtractor:从候选片段提取固定长度特征 - 实现
PairwisePreferenceLearner:基于 LogisticRegression 的成对偏好学习器 - 数据增强:每个正对 (A-B, 1) 生成负对 (B-A, 0),保证二分类信号
Phase 3 — Warm Start 合成数据初始化
- 生成 3000 个随机特征向量,用经验分布模拟真实数据
- 用原规则系统为每个样本计算伪评分,Linear Regression 拟合 → 得到近似规则的初始权重
- OCR 特征 ×2.5、高频词特征 ×2.0 显式增强(画面客观证据 + 弹幕话题信号)
Phase 4 — 反馈收集与训练
- 实现
FeedbackStore:JSONL 持久化 +.npz特征向量缓存 - 每次标注自动生成 N×(M-N) 个训练对
- 增量训练:用
partial_fit+ 高样本权重加速适应新反馈 --feedback交互式标注、--retrain批量重训练、--reset-model回退
Phase 5 — 实际使用迭代
- 第一版:自动分析 25 个候选 → 用户手工筛选 12 个 + 后补对局结算
- 反馈训练:11 个选中 vs 14 个未选中 → 9 个成对比较 → 权重更新
- 关键发现:用户舍弃了所有弹幕高潮/纯搞笑类片段,偏好纯击杀内容
- 弹幕关键词词典评估:好评词/笑声词权重下降,灭队/对局结束权重上升
三、技术栈
| 层级 | 技术 | 用途 |
|---|---|---|
| 语言 | Python 3.10+ | 全部代码 |
| 语音转写 | faster-whisper large-v3 | CUDA float16 推理,中文语音→文本 |
| 音频处理 | ffmpeg, soundfile, numpy | 音频提取、RMS 能量、语速计算 |
| 画面 OCR | PaddleOCR GPU | 击杀信息区域文字识别 |
| 视频处理 | ffmpeg NVENC/NVDEC | GPU 硬件解码取帧 + 硬件编码切割 |
| 机器学习 | scikit-learn LogisticRegression | 成对偏好学习分类器 |
| 序列化 | joblib, numpy .npz | 模型权重持久化 + 特征向量缓存 |
| 弹幕协议 | JSON (抖音格式) | events[].content 聊天消息解析 |
| 数据格式 | JSON (转录/分析/切割信息), JSONL (反馈历史) | |
| 分词 | jieba (可选) | 弹幕中文分词,不可用时回退字符 n-gram |
四、技术实现细节
4.1 音频提取与语音转录
音频提取:
1 | ffmpeg -i input.flv -ac 1 -ar 16000 -y output.wav |
-ac 1单声道,-ar 1600016kHz(Whisper 标准输入)- 输出 PCM WAV,约 256 kbps
语音转录:使用 faster-whisper large-v3 模型,CUDA + float16 推理。参数配置:
1 | model = WhisperModel("large-v3", device="cuda", compute_type="float16") |
每段输出 [start, end, text],转写过程中每 50 段增量保存,防止中断丢失。51 分钟音频转写耗时约 2 分钟。
情绪分析:
- RMS 能量:音频采样值的均方根,反映音量
- 语速:字符数/时长,>8 chars/s 标记快速
- 关键词匹配:激动词(卧槽/离谱/啊?)、笑声词(哈哈/笑死)
- 音量突增:当前段 RMS > 前 20 段均值 × 2
4.2 画面 OCR 击杀检测
每 1 秒从视频截取一帧,裁剪到击杀信息区域 (665, 596, 1256, 931),送入 PaddleOCR:
1 | ffmpeg_cmd = [ |
检测三类事件:
- PvP 击杀:匹配”淘汰”+ 玩家名模式,玩家名包含
#数字标识 - PvE 击杀:匹配 AI 敌人名称(如”护卫兵”),自动忽略,不参与评分
- 对局结束:匹配”对局时间”或”战绩总结”文字
单帧 OCR 去重:同一击杀事件连续出现时,取置信度最高的帧。
首次运行保存 OCR 缓存(.ocr_cache.json),后续运行直接读取。
4.3 弹幕分析
抖音弹幕 JSON 格式:
1 | { |
时间归一化:rel_time = event.timestamp - first_event.timestamp,所有时间戳转为相对秒数。
密度计算:2 秒分桶,统计每桶弹幕数。基线 = 均值 × 1.5。超级峰值 ≥ 5x 基线,普通峰值 ≥ 3x 基线。
关键词分类:
1 | POS_DM = ['666', '牛逼', '牛', '强', '厉害', '帅', '猛', '太强', '好强', '无敌', '太猛', '操作'] |
特征计算:dm_pos_ratio = 含好评词的弹幕数 / 总弹幕数,以此类推。
高频词提取:
1 | def extract_top_words(texts, top_n=10): |
has_hot_topic 当单一关键词占比 > 40% 时触发(权重 +0.39,是弹幕类最有效特征)。
4.4 RL 模型评分
特征提取
从候选片段提取 35 维向量(FEATURE_NAMES 定义在 feature_extractor.py):
| 类别 | 特征 | 维数 |
|---|---|---|
| 弹幕密度 | duration, anchor_count, max_dm_ratio, dm_count, has_super_dm, has_dm_peak | 6 |
| 弹幕内容 | dm_pos_ratio, dm_neg_ratio, dm_laugh_ratio, dm_excited_count | 4 |
| 高频词 | top_word_max_freq, top_word_count, top_word_ratio, has_hot_topic | 4 |
| 语音情绪 | voice_excited_count, voice_surge_count, voice_fast_count, has_voice_excited, has_volume_surge | 5 |
| 游戏事件 | kill_count, has_squad_wipe, has_clutch, has_loot_found, has_match_start, has_match_end, has_death, has_revive | 8 |
| OCR 事件 | ocr_kill_count, has_ocr_kill, has_ocr_match_end, ocr_confidence_max | 4 |
| 叙事结构 | narrative_full, narrative_start_end, has_climax | 3 |
| 对局位置 | round_position | 1 |
Warm Start
用 3000 个采样自经验分布的随机特征向量模拟真实数据,原规则系统为每个样本计算伪评分,Linear Regression 拟合得到初始权重。OCR 特征 ×2.5、高频词特征 ×2.0 显式增强。
1 | # 伪规则评分(近似原 score_candidate) |
偏好学习
1 | class PairwisePreferenceLearner: |
关键设计:fit_intercept=False,确保 score = w · features,权重直接可解释为特征贡献。
特征版本管理
特征列表变更时递增 FEATURE_VERSION,旧模型自动失效,重新 Warm Start:
1 | FEATURE_VERSION = 2 # 修改 FEATURE_NAMES 时必须递增 |
4.5 反馈存储与训练
1 | class FeedbackStore: |
训练时机:每次 --feedback 标注后立即增量训练,--retrain 用全部历史反馈批量重训练。
4.6 视频切割
1 | ffmpeg -hwaccel cuda -hwaccel_output_format cuda \ |
- 使用 NVENC 硬件编码,
-preset p1最快,-cq 20质量控制 - 短切片(<30s)额外使用 scale 滤镜裁剪为 1440×1080
- 实际切割在源素材起止点基础上前后各加 30s padding
4.7 缓存机制
| 缓存 | 路径 | 说明 |
|---|---|---|
| 转录缓存 | {video_dir}/transcript_output/transcript.json |
Whisper 转录结果,幂等跳过 |
| 音频缓存 | {video_dir}/transcript_output/audio.wav |
已提取音频,幂等跳过 |
| OCR 缓存 | {video_path}.ocr_cache.json |
画面 OCR 事件列表,避免重复 GPU 推理 |
| 模型权重 | model_data/model_weights.pkl |
joblib 序列化的 PairwisePreferenceLearner |
| 特征缓存 | model_data/features/{run_id}.npz |
每次运行的候选特征向量 |
| 反馈记录 | model_data/feedback_history.jsonl |
用户标注历史 |
五、核心技术难点
5.1 OCR 画面识别的精确性
问题:击杀信息在屏幕上仅持续 2-3 秒,文字半透明叠加在游戏画面上,检测窗口窄且干扰多。
解决方案:
- 裁剪到固定信息区域
(665, 596, 1256, 931),排除画面主体干扰 - 每 1 秒 1 帧高密度采样(51 分钟 = 3045 帧),不漏检
- 连续帧去重 + 置信度取最大值,避免同一击杀重复计数
- PvP/PvE 区分:通过玩家名格式(
#数字vs 固定名)过滤人机 - OCR 结果缓存到 JSON 文件,后续运行直接读取
5.2 偏好学习的冷启动
问题:RL 模型从零开始(随机权重)时,前几次分析评分毫无意义,用户体验极差。
解决方案:
- Warm Start:用 3000 个采样的随机特征向量 + 原规则系统伪评分 → Linear Regression 拟合得到初始权重
- OCR 和高频词特征显式增强(×2.5 / ×2.0),反映这些信号的客观性
- 初始模型行为 ≈ 规则系统,但权重是连续可微调的值
- Warm Start 后的模型已有合理的排序能力,用户第一次分析就能看到有意义的评分
5.3 特征工程与词典覆盖
问题:关键词词典(好评/笑声/惊叹)比较通用,覆盖不全。例如”拉闸””天才”在实战弹幕中出现 16/15 次,但未被任何词典收录,无法参与特征计算。
解决方案:
- 当前:高频词特征(
has_hot_topic、top_word_ratio)部分弥补,不依赖具体词典的通用高频信号 - 未来:自动发现高频新词 → 提示用户加入词典;从特征级权重下沉到词级权重
5.4 短切片与长切片的协调
问题:长切片提供上下文(15-150s),短切片提供精剪(<30s 仅 PvP 击杀),两者评分标准不同但共享同一个 RL 模型。
解决方案:
- 短切片使用”OCR 必录”机制:PvP 击杀检测到即强制收录,不依赖评分
- 短切片评分只影响优先级排序,不影响是否收录
- 长切片仍由 RL 模型全权评分
- 两者在
analysis_result.json中通过clip_type字段区分
5.5 用户偏好的快速适应
问题:单次标注样本量小(10-25 个候选),传统批量训练容易过拟合。
解决方案:
- 成对比较天然做数据增强:11 个选中 × 14 个未选中 = 154 个理论对
- 加入
min_score_gap=1.0过滤噪音对(分数接近的跳过) partial_fit+ 高样本权重(learning_rate × 10)加速适应新反馈- 每次训练后输出 Top-N 权重变化,用户可直观理解模型学到了什么
六、项目使用
1 | # 标准用法:分析 + 切割 |
底层命令:
1 | # 步骤1: 语音转写 |
输出结构:
1 | recordings/{主播名}/{日期}/ |
七、项目结构
1 | delta-force-clip-rl/ |