跑 Python 脚本的时候,很多人在 Windows 上都撞见过UnicodeEncodeError: 'gbk' codec can't encode character这个鬼错误。这里的 codec 全称是 Coder-Decoder,干的是字符和字节之间的翻译活。而我今天想聊的是另一个世界的 Codec——视频编解码器,以及它正在发生的一件事:当 Codec 开始用机器学习去“学习”,而不是靠人工规则去“翻译”,视频压缩这根链条的底层逻辑正在被重写。这个方向通常被叫作神经视频编码(Neural Video Coding),这几年论文热度一直很高,但离真正大规模落地还有一条肉眼可见的鸿沟。这篇东西不是复述论文,是我自己调过 DVC、DCVC 这类开源实现之后,对技术逻辑和工程边界的一些真实体会。
1. 先从那个报错说起:Codec 是规则,还是能力?
1.1 字符 Codec 与视频 Codec,两种“规则”
字符编码器,比如 GBK、UTF-8,本质上就是一张映射表。遇到UnicodeEncodeError,是因为你要编码的字符不在当前编码表里。它的厉害之处在于规则简单、查表快,弱项也在这:一旦遇到规则表外的东西,直接罢工。
视频 Codec 在很长一段时间里也是“规则”的艺术。从 H.264 到 H.265 再到 H.266,每个标准都是往工具箱里塞新工具:
- H.264:多参考帧、可变块大小运动补偿、CABAC 熵编码、环路滤波
- H.265:四叉树编码树单元、更细致的帧内预测方向、SAO 自适应像素补偿
- H.266:仿射运动预测、更复杂的帧内预测模式、DMVR、更灵活的变换组合等
每一代标准诞生的过程,都是大量专家坐在一起,设计更精妙的规则,然后通过率失真优化去决定何时使用这些工具。这套混合编码框架(预测、变换、量化、熵编码)从 H.261 时代一直延续到今天,已经撑了三十多年。
1.2 视频标准越做越复杂,收益却越来越小
但问题也来了。标准越做越复杂,码率节省却越来越“抠门”。业界比较公认的数字大概是这样的:
| 标准 | 相对上一代同等质量码率节省 | 关键新工具 | 编码复杂度增幅 |
|---|---|---|---|
| H.264/AVC | 基准 | 多参考帧、CABAC | 基准 |
| H.265/HEVC | 约 50% | 四叉树编码、SAO | 数倍 |
| H.266/VVC | 约 30%-40% | 仿射预测、增强帧内 | 数倍到近一个数量级 |
表格里的数字是通用测试条件下的观察,实际因配置、分辨率、内容不同有明显浮动,但趋势很清楚。
拿 H.265 到 H.266 来说,为了那 30%-40% 的码率节省,编码器的复杂度涨了不止一个数量级。也就是说,我们是在用越来越贵的算力,换越来越少的压缩率提升。视频分辨率还在往 4K、8K 走,带宽和存储压力并没有变小,传统人工规则的矿,挖起来越来越费劲。
这时候机器学习就显得很有吸引力。传统 Codec 的规则是人写的,神经网络却可以让规则“长出来”:给一堆视频,告诉它“重建质量尽量好,码率尽量低”,它自己去学一套编码策略。这里面的关键切换,是把“规则”变成“能力”——这正是神经视频编码最核心的思想转变。
2. 神经视频编码到底在“学”什么:拆传统编码器的手术台
要理解神经视频编码,先得把传统编码器拆开看。
传统混合编码器处理一帧图像时,基本是四个环节:先做帧间预测(用参考帧和运动信息生成预测帧),再对残差做变换(DCT 或类似变换),接着量化,最后用熵编码把量化后的系数压缩成码流。每一步都是数十年的经验结晶。
神经视频编码做的事情,是用神经网络模块去替换或融合其中几个环节,最彻底的做法就是把整个“编码器-解码器”当成一个巨大的自编码器来训练。
2.1 运动估计与运动补偿:光流网络替代块匹配
传统编码器做帧间预测,是以块为单位搜索运动矢量。这个搜索过程虽然效率很高,但块与块之间的独立性是人为假设的,运动边界和复杂纹理很难处理干净。
神经编码器通常用光流网络直接预估一个像素级运动场(dense motion field),比如用 PWC-Net 这样的结构输入前一帧和当前帧,输出每个像素的水平和垂直位移。得到运动场后,通过可微分的 warp 操作把参考帧变换到当前帧,生成预测帧。整个过程完全可微分,可以放进训练图里。代价是,光流场本身也要占码率——那是一个和原图尺寸相同的稠密张量,所以需要另一个网络把它压缩起来。
2.2 残差压缩:自编码器与量化
预测帧不可能完全准确,预测残差仍然要编码。神经编码里的残差压缩网络通常是卷积自编码器:编码器把残差张量映射到低维潜在张量,潜在张量经过量化后变成离散符号,再交给熵编码器。解码器从这些符号重建残差,加到预测帧上得到重建帧。
这里的量化是一个关键操作。传统编码里的量化是硬开关,梯度传不过去。神经编码训练时一般用加性噪声(additive noise)或 STE(straight-through estimator)来近似量化,让梯度能回传。这个细节直接决定了模型训不训得起来,也决定了训练和推理的差异有多大。
2.3 熵模型:神经视频编码的“灵魂”
很多人以为视频压缩的重头戏是预测和变换,但实际上,能不能压得小,很大程度上取决于熵编码。香农告诉我们,符号的理想编码长度等于它的信息量,也就是概率倒数的对数。所以,如果能准确估计每个待编码符号的概率分布,码率就能逼近理论极限。
传统 CABAC 已经用了一系列人工设计的上下文模型来估计概率。神经熵编码则更进一步,用一个小网络直接从潜在张量里提取“超先验”(hyperprior)信息,预测每个潜在值的高斯分布参数(均值和方差),再把符号按照这个分布送入算术编码器。这个方法出自 Ballé 等人的图像压缩工作,后来被几乎所有的神经视频编码器继承。
你可以把熵模型理解成一个“码率预测器”:它不仅参与压缩,还在训练时告诉整个网络“你现在生成的这些特征大概要花多少比特”。这样网络才能知道该往哪个方向调整,才能在码率和质量之间找到平衡点。
2.4 损失函数:率失真优化直接成为训练目标
传统编码器在编码时干的事,是枚举各种模式、算 RD cost(率失真代价)。神经编码器则把这个优化目标直接搬到了训练阶段:
Loss = R + λ·D
R 是码率的估计值,来自熵模型的概率输出,D 是失真,通常是 MSE 或 MS-SSIM。λ 越大,训练出的模型越倾向保质量、花更多码率;λ 越小,模型越抠码率。所以同一套代码,用不同的 λ 训练,出来的就是一个低码率档、一个高码率档——这就相当于传统编码里的“质量档位”。
“训练即优化”这个转变,是传统 Codec 和神经 Codec 最本质的区别。传统 Codec 的规则固定,编码器在规则内搜索最优;神经 Codec 把搜索变成了学习,规则本身也被数据驱动地调整。一句话总结:神经视频编码学的不是某个具体视频,而是一套“如何编码视频”的策略。
3. 拆过 DVC 和 DCVC 之后:神经 Codec 的演进与实操体会
理论说再多,不如跑一次代码。我自己的路线是从 DVC 开始,然后折腾 DCVC,中间踩了不少坑。
3.1 DVC:端到端视频压缩的开山之作
DVC(2018)是“Learning for Video Compression”那篇文章里的方案。它的结构非常直观:两帧输入,光流网络估计运动,运动残差压缩网络压缩运动信息,帧残差压缩网络压缩预测残差,重构帧作为下一帧的参考。整套流程和传统编码器很像,只是把每个模块换成了可学习的网络。
这个方案有一个非常典型的毛病:误差累积。因为解码端拿的是上一帧的“重建帧”作为参考,而不是原始帧,每一帧的失真都会传递下去。帧序号越长,画面越可能模糊,甚至出现结构性漂移。一开始训练时没注意这一点,你可能看到测试视频的前几帧 PSNR 还不错,到后面几帧指数级下滑。
3.2 DCVC:从“显式传运动”到“条件编码”
DVC 之后的很多工作在修误差累积问题,有的引入多帧参考,有的引入循环结构。DCVC(Deep Contextual Video Compression,2022)思路更激进:它不再把一个可解释的运动矢量场单独编码,而是把运动信息提取成“上下文特征”(context features),直接作为残差编码网络的输入条件。
这个做法的好处主要有两点:一是省掉了单独压缩运动场的码率开销;二是残差网络可以“看到”运动信息,不再盲目地编码残差。DCVC 在公开测试集上的 BD-Rate 比起上一代模型有显著提升,而且代码结构相对清晰,很适合做实验。
3.3 实操过的几个坑
跑这类项目最大的问题不是复现不了,而是复现结果和论文差得远。我总结了自己踩过的几次大坑,给后来者提个醒:
- 像素范围不一致:论文实现的模型输入有的归一化到 [0, 1],有的是 [0, 255]。如果你用了预处理代码的归一化方式,但测试脚本直接读原始像素,PSNR 会莫名其妙掉 0.5 dB 以上。这种低级错误最难排查,我花了一整天才发现是这里。
- 量化策略不匹配:训练时用加性噪声近似量化,推理时却换成硬量化,这种不一致会导致码率偏差巨大。DCVC 官方代码里其实已经处理了,但你如果自己改模型结构,很容易忽略。
- λ 的选择:不要幻想一个模型解决所有码率。想对比不同码率下的性能,就得训练多个 λ 档的模型。很多新手拿着一个模型去测所有 bitrate,BD-Rate 怎么算都难看。
- 数据分布泄漏:某些公开视频数据集已经被用到烂,各种预训练模型都在上面训过。如果你要对比论文结果,建议直接用官方指定的训练集和测试集,不要自己随便混数据,否则测评说服力大打折扣。
训练成本也要有心理准备。一张 V100 上跑 DCVC,256 分辨率左右的实验,通常要数天时间;想跑 1080p 甚至 4K,对显存和训练技巧的要求直线上升。资源和耐心缺一不可。
4. 从论文指标到真实视频:工程边界远比想象残酷
论文里 BD-Rate 动辄省 20% 甚至更多,看起来很美。但真实产品经理上来会问几个问题:能实时编解码吗?支持随机访问吗?码率控制怎么做?解码端跑在什么芯片上?答案往往很尴尬。
4.1 算力账:编码端和解码端都不乐观
传统编码器里,x265 做实时编码已经很成熟,中高端 CPU 甚至都能跑超实时。神经视频编码的编码端要做多个网络的前向推理,还包括运动搜索、多个 λ 模型的切换,开销和功率要求都很高。在云端 GPU 上跑还算学有余力,但要部署到直播、视频会议这种低延迟场景,差距非常大。
解码端则卡在熵编码上。神经熵模型的自回归结构天然是串行的——解码一个符号,可能依赖上一个符号的输出。这和传统 CABAC 的串行特性类似,但 CABAC 已经被无数工程师优化进了硬件;神经熵模型的上下文是深层网络的特征,硬件加速难度完全不同。实测解码速度往往是每秒几帧的量级,连播放器软件解码都不一定跑得过。
4.2 泛化和鲁棒性:训练分布之外的“坠落”
神经网络有一点点“偏科”:它对训练集里常见的自然场景表现很好,遇到屏幕录制、动画、游戏画面、监控视频这类分布外的内容,性能会明显下滑。我把一个在自然视频上训好的模型拿到监控视频上测过,同样码率下 PSNR 掉得不少,而且噪点越多,模型越吃力。
传统编码器就不存在这个问题,因为规则是固定的,对任何内容都在做相同的事;神经编码器的“能力”是数据里长出来的,长什么样完全取决于你喂了什么。这带来一个很现实的问题:产品团队无法保证输入内容都在训练分布内,也就不敢对外承诺稳定的压缩率。
4.3 随机访问、码率控制与错误恢复
视频不是单张图片,用户要看中间某一帧,就得有随机访问的能力。传统视频的 GOP 结构里面周期插入 I 帧,用户 seek 到 I 帧就能解码。神经视频编码目前对帧间依赖的管理比较原始,长依赖和随机访问之间存在很强的张力——依赖越长,压缩率越好,但 seek 和错误恢复就越难。
码率控制同样棘手。传统 x264 可以在一秒内根据场景复杂度调整量化参数,保证目标码率上下浮动很小;神经编码的码率档位是训练时选出来的 λ,想在视频播放过程中实时调整,目前只能靠切换模型或者在线微调,都不是产品级的方案。
用一张表总结工程侧的差距:
| 维度 | 传统 HEVC/VVC | 神经视频编码 |
|---|---|---|
| 压缩率(分布内) | 稳定,挖掘空间有限 | 通常可继续省码率,但不确定 |
| 编码复杂度 | 高但成熟,可并行 | 更高,需要 GPU 集群 |
| 解码实时性 | 硬件解码方案成熟 | 串行熵模型是瓶颈 |
| 随机访问 | GOP 完整支持 | 帧间依赖管理不成熟 |
| 码率控制 | CRF/ABR 非常成熟 | 依赖训练时 λ,难实时调整 |
| 标准/生态 | 容器、播放器、芯片全面支持 | 标准化刚刚开始 |
5. 部署神经 Codec 的现实路径:标准、芯片与生态
纯端到端的神经视频编码,短期内我不会建议任何团队押宝到产品主链路里。但“神经 Codec 思想”已经往工程里渗透,只不过方向不是替换整个编码器,而是改造其中一环。
5.1 混合路线:AI 工具嵌进传统编码框架
很多企业实际做的是这么一件事:主体还是 HEVC/VVC,把 AI 用在环路滤波、超分、去噪、参数预测上。因为码流还是标准码流,播放端和硬件解码器都能兼容;AI 只负责让画面更干净或更锐利。这类方案落地最快,收益也实实在在。比如解码端做 AI 超分,1080p 的内容推到 4K 屏上,用户观感提升明显,码率成本却不变。
5.2 标准化:JPEG AI 与 MPEG NVC
标准化是神经 Codec 走向产品的前提之一。图像领域已经有 JPEG AI 计划专门探索学习型编码;MPEG 也在做神经视频编码(Neural Video Coding)的探索,统一测试条件和评估方法。这项工作非常难,因为相比图像压缩,视频压缩要考虑时域预测、随机访问、一致性和端侧算力,标准的可实施性要经过大量交叉验证。目前还在早期阶段,离形成像 H.266 那样完整的规范还远。
5.3 芯片适配:NPU 的接纳与遗忘
解码端如果想跑在手机上,依赖的是 NPU/DSP 这些专用 IP。神经熵编码的串行依赖和特征张量的不规则访问,跟传统视频硬解码的流水线风格差得很远。即便强行量化部署,INT8 带来的质量损失又会让 BD-Rate 红利吃光。所以我的判断是:近三年内,神经视频编码最有希望落地的是两类场景——一类是监控和内容归档,流程可控、不要求实时随机访问;另一类是云端转码结合 AI 增强,输出标准码流。至于实时通信这种场景,神经 Codec 还得继续磨。
5.4 对学习者的一个额外建议
很多想入行机器学习的人总是在问“机器学习项目实战做什么”。其实视频压缩就是一个非常硬核且有真实价值的落点:它把计算机视觉(光流、特征提取)、信息论(熵建模)、优化(率失真损失)都串在了一条链路里。比单纯调参训练个分类模型,能学到的东西密度高得多。当然前提是先把机器学习基础打牢,否则直接被网络结构和损失函数劝退。
6. 现在入坑,我的建议路线
如果你看完前面的内容还想动手,说明你对这个方向的兴趣是真实的。我可以给一条比较务实的路线。
6.1 第一步:把基础补扎实
先修完市面上任何一套好的机器学习公开课(比如经典的“吴恩达机器学习”和进阶一点的深度学习课程),重点不是背公式,而是要理解损失函数、反向传播、训练测试数据划分的意义。如果连过拟合是什么都说不清,上来就碰 DCVC,基本是浪费时间。
6.2 第二步:吃透传统编码器
在用神经网络替代传统流程之前,你得先懂传统流程。装好 FFmpeg,把 x264/x265 的 preset 跑几遍,动手看 I/P/B 帧结构、GOP、码率控制。不会用 FFmpeg 看码率、看视频信息,后面论文里的锚点对比很难看得懂。
6.3 第三步:先用 CompressAI 把图像压缩跑明白
不要一上来就做视频。先复现图像压缩里的经典模型,比如 Ballé 的 scale hyperprior。CompressAI 这个 PyTorch 库把超先验、自回归熵模型、量化、评估工具都封装好了,非常适合用来建立对“熵模型”的直觉。用完它再回头看视频模型,你会觉得很多设计似曾相识。
6.4 第四步:再上视频,跑通 DCVC
读 DVC 和 DCVC 的论文,把官方代码拉下来在公开数据集上做一次完整复现。复现之后,尝试替换其中一个模块,比如把光流网络换掉,或者给它加一个小模块,观察 BD-Rate 的变化。这个过程才是真正学到核心的环节。
6.5 最后的几点提醒
- 训练和测试的像素值范围统一,量化策略统一,否则一堆莫名其妙的 bug。
- 别拿同一个 λ 模型测所有码率,多个码率点才能画出率失真曲线。
- 先在小分辨率上验证想法,再迁移大分辨率,直接上 4K 实验很容易变成资源黑洞。
- 保存好 checkpoint、训练曲线和测试脚本,神经编码实验周期长,丢失配置信息会让你后悔整个实验周期。
我个人做这个方向最大的体会是:神经视频编码不是“锦上添花的模型”,而是一个必须跟信息熵、失真、算力硬碰硬的方向。它逼着你去理解压缩的本质,去理解神经网络在严格约束下能做到的事。正因为工程边界还很明显,这个领域里能解决的问题才足够多,也足够新。