想象一下小区门口那位干了十年的保安老王。他从不用翻什么《可疑人员手册》,却能一眼看出“今天不对劲”:早上七点半该出门上学的小张没出现、平时遛弯的李奶奶在喷泉边躺了十分钟没动弹、半夜有人翻墙进来……老王凭什么?凭的是十年来对“正常”的熟悉——他知道这个小区每天该是什么样,所以任何“反常”都藏不住。 视频异常检测要做的事,就是给摄像头装上“老王的直觉”:先让 AI 大量观看正常的监控画面,学会“常态”长什么样;之后一旦画面里出现跌倒、斗殴、闯入、徘徊这类偏离常态的事件,系统就能自动打上“异常”标记并报警。这个技术听起来很玄,但背后无非四件事——如何描述“正常”、如何量化“偏离”、如何在标签很少时训练、如何把它可靠地部署到真实场景。这篇文章就用老王的故事,把这四件事一层层讲透。

岗位关联

掌握视频异常检测,你就能为智能安防、工厂监控、公共场所预警构建“自动发现反常”的视觉大脑,这是 AI 落地需求最刚性、最缺人的方向之一。

目录
  1. 可视化演示
  2. 一、异常检测问题:给“反常”画像
  3. 二、重构误差方法:用“还原”检验熟悉
  4. 三、预测误差方法:预判下一秒
  5. 四、密度估计方法:让“眼熟”可量化
  6. 五、弱监督方法:只知道“大概出事”
  7. 六、异常事件识别:不止“有情况”
  8. 七、部署与优化:让老王三班倒
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示视频异常检测中的重构误差方法、预测误差方法、以及异常分数时间线分析,支持模式切换查看不同检测策略。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+_captions.recon+'

一、异常检测问题:给“反常”画像

有人问老王:“你天天说'不对劲',到底什么叫反常?”老王挠挠头:“不好说,但我一看就知道。”这句话道破了异常检测的本质——反常无法靠一本手册穷举,它只能用“偏离常态”来定义。让机器也学会这招,思路是一样的:先用大量正常画面喂出一个关于“常态”的判断力,再让每个新画面跟常态做对比,对不上的地方就是可疑信号。

落实到技术上,我们给每个视频片段或事件算一个异常分数 s(x),分数越高越可疑;再设定一个阈值 τ,分数跨过红线就判为异常,没过线就当正常。整个视频异常检测的大厦,就建立在“分数 + 阈值”这两块地基上。围绕“怎么算分数”这个核心问题,学界和工业界走出了四条经典路线:重构误差、预测误差、密度估计、弱监督排序。它们各有各的“直觉”,但殊途同归。

应用场景则是异常检测最好的试金石:智能安防里要揪出斗殴和翻墙,工厂里要盯着工人是否闯入危险区域、有没有违规操作,养老院和地铁站要第一时间发现跌倒和人群异常聚集。难点也摆在台面上:异常的种类无限多、形态千奇百怪,训练数据里正常样本多、异常样本极少,真实部署还要求秒级响应。

老王从不背犯罪嫌疑人的照片,他只需要熟记每一张业主的脸。异常检测也一样:不需要见过所有“坏事”,只要把“好事”学到骨子里,反常自然藏不住。

y={1,s(x)≥τ0,s(x)<τy = \begin{cases} 1, & s(x) \ge \tau \\ 0, & s(x) < \tau \end{cases}
这个分段函数的意思是:异常分数超过阈值就报警(输出 1),否则视为正常(输出 0)。它是所有异常检测系统做出最终决策的那道闸门。
  1. 异常分数 s(x)模型给每个候选片段打的“可疑程度”,分数越高越不像正常画面。
    s(x)∈[0,1]s(x) \in [0, 1]
  2. 判定阈值 τ一条经验分界线,通常由验证集上的误报率和漏检率权衡选出。
    0<τ<10 < \tau < 1
  3. 判定规则分数不小于阈值时判为异常事件,否则放行,对应“报警/不报警”。
    y=1  ⟺  s(x)≥τy = 1 \iff s(x) \ge \tau

二、重构误差方法:用“还原”检验熟悉

老王脑海里有一张小区的“底图”:午后三点,中心广场应该只有晒太阳的大爷;如果有人倒在长椅边一动不动,他会瞬间起疑。为什么?因为他脑中“还原”出的画面和眼前对不上。重构误差方法学的正是这套本事:让模型练出一双“脑补正常画面”的眼睛,还原得越吃力,画面越可疑。

技术上这双眼睛叫自编码器,一个“压缩再还原”的网络。训练阶段只喂正常视频,编码器把画面压成一段紧凑的摘要,解码器再把摘要还原回画面。经过大量正常样本的打磨,模型成了“正常画面还原专家”。推理时来一段新画面:如果还原得滴水不漏,说明它熟悉;如果还原得面目全非,说明它没见过这种东西——异常。

这套方法简单可靠,但也有个“太聪明反而坏事”的隐患:如果自编码器容量过大,它可能连异常画面也强行背下来还原好,误差区分度就消失了。工程上通常用降噪自编码器、记忆增强模块或限制隐层维度来“拴住”它的记性。重构误差的数学表达如下。

老王脑中底图越精细,越能发现“不该出现在这里的物事”;自编码器把正常景象还原得越熟练,任何跳出常规的画面都会在误差信号里原形毕露。

Lrec=1N∑i=1N∥x^i−xi∥22\mathcal{L}_{\text{rec}} = \frac{1}{N} \sum_{i=1}^{N} \| \hat{x}_i - x_i \|_2^2
这行公式计算的是“模型还原出来的画面”和“真实画面”之间的平均差异,差异越大,说明模型越没见过这个画面,异常分数越高。
  1. 编码器压缩先把画面 x_i 压成紧凑的隐向量 z_i,丢掉冗余细节,只留“常态骨架”。
    zi=fθ(xi)z_i = f_\theta(x_i)
  2. 解码器还原再从隐向量把画面还原成 \hat{x}_i,还原过程步步受限,所以只能还原熟面孔。
    x^i=gθ(zi)\hat{x}_i = g_\theta(z_i)
  3. 逐像素差异求还原画面与真实画面的欧氏距离,差异大说明还原失败。
    ∥x^i−xi∥2\lVert \hat{x}_i - x_i \rVert_2
  4. 平方与平均平方放大明显差异,再对全部样本取平均,得到整体重建损失。
    1N∑i=1N∥x^i−xi∥22\frac{1}{N} \sum_{i=1}^{N} \lVert \hat{x}_i - x_i \rVert_2^2

三、预测误差方法:预判下一秒

老王有个绝活:他几乎能预判每个人接下来三秒的动作。买菜的大姐会往菜市场方向走,放学的小孩会在路口打闹着拐弯。所以当有人毫无征兆地一头栽倒、或者突然拔腿狂奔时,老王的第一反应是“这一下我没想到”——预判失败,就是异常。预测误差方法把这个直觉搬进了神经网络。

具体做法是让模型当“预言家”:给定最近连续 K 帧画面,预测下一秒会发生什么。正常视频的运动规律是连贯的——人走着走着继续走,车开着开着继续开——模型在大量正常视频上学透了这些规律,预测得八九不离十。可一旦画面里出现跌倒、急刹、斗殴这类无法从历史推断的突变,预测结果和真实画面会差得十万八千里,偏差大到离谱的正是异常时刻。

这种方法的优势在于对“运动突变”极其敏锐,比单纯看单帧画面更能捕捉“动作上的不对劲”。实现时常用卷积长短时记忆网络(ConvLSTM)或三维卷积网络(3D CNN)来建模时间维度的规律,它们就像老王的“肌肉记忆”,把常见的运动惯性刻进了参数里。

老王“没想到”的那一下,正是危险发生的那一下。预测误差方法告诉系统:能被惯性推断的,是日常;推断不了的,才是警报。

x^t+1=f(xt,xt−1,…,xt−K+1)\hat{x}_{t+1} = f(x_t, x_{t-1}, \ldots, x_{t-K+1})
Lpred=∥x^t+1−xt+1∥22\mathcal{L}_{\text{pred}} = \| \hat{x}_{t+1} - x_{t+1} \|_2^2
前一个公式用过去 K 帧预测未来帧,后一个公式计算预测帧与真实帧的差距。预测越不准,说明画面越不按常理出牌。
  1. 历史窗口取当前时刻 t 及之前共 K 帧画面,作为预测的上下文依据。
    xt,xt−1,…,xt−K+1x_t, x_{t-1}, \ldots, x_{t-K+1}
  2. 预测函数 f由时序网络建模运动规律,输出下一帧的预测结果。
    x^t+1\hat{x}_{t+1}
  3. 预测误差预测帧与真实帧的逐像素平方差,作为该时刻的异常分数。
    ∥x^t+1−xt+1∥22\lVert \hat{x}_{t+1} - x_{t+1} \rVert_2^2

四、密度估计方法:让“眼熟”可量化

老王在岗十年,对小区里的行为有个模糊的“眼熟度”:晨练的、遛狗的、下班的,这些行为像广场舞队伍一样聚成一片一片;而某些罕见行为孤零零地待在角落,一眼就能扫见。密度估计方法就是把这种“眼熟”变成数学:先搞清楚正常样本在特征空间里是怎样分布的,再问新样本“你落在人多的地方还是人少的地方”。

具体做法是先为大量正常视频片段提取特征,然后估计这些特征的概率分布 p(x),常用工具包括高斯混合模型、核密度估计,以及深度生成模型。正常样本集中在概率密度高的区域,异常样本落在密度极低的区域——好比广场上人头攒动的热闹处没人会觉得异常,一个人半夜蹲在空荡荡的停车场里就显得扎眼。

这条路线还有个优雅的变体叫稀疏表示:把正常模式浓缩成一本“字典”,任何正常画面都能用字典里少数几个基元稀疏地拼出来;异常画面拼不出来,只能留下很大的残差。无论哪种手法,最后都归结为给每个样本一个“离群程度”分数,而惯用的做法是取负对数概率。

老王的“眼熟”从来说不清道不明,密度估计却把它变成了一条光滑的钟形曲线:所有人都挤在热闹的日常里,离群的孤影自然无所遁形。

p(x)=1(2π)d/2∣Σ∣1/2exp⁡(−12(x−μ)⊤Σ−1(x−μ))p(x) = \frac{1}{(2\pi)^{d/2} |\Sigma|^{1/2}} \exp\left( -\frac{1}{2}(x-\mu)^{\top} \Sigma^{-1} (x-\mu) \right)
s(x)=−log⁡p(x)s(x) = -\log p(x)
第一行是多维高斯分布,描述正常样本在特征空间里的分布形状;第二行把概率转成异常分数,概率越小分数越大。
  1. 均值向量 μ正常样本的平均位置,相当于老王心目中“最常见行为”的中心。
    μ=1N∑i=1Nxi\mu = \frac{1}{N} \sum_{i=1}^{N} x_i
  2. 协方差矩阵 Σ刻画正常样本围绕中心散布的密集程度,决定概率分布的形状。
    Σ=1N∑i=1N(xi−μ)(xi−μ)⊤\Sigma = \frac{1}{N} \sum_{i=1}^{N} (x_i - \mu)(x_i - \mu)^{\top}
  3. 概率密度离中心越近、越顺应正常散布的样本,概率越高。
    p(x)p(x)
  4. 负对数分数概率值太小容易下溢,取负对数后转为一个大分数,越离群分越高。
    s(x)=−log⁡p(x)s(x) = -\log p(x)

五、弱监督方法:只知道“大概出事”

这天老王接到投诉:“昨天下午 3 号楼那边好像出事了。”但老王没盯着看,不知道具体是几点、哪一层、发生了什么。他只知道那段时间大概率有异常,却给不出精确到秒的定位。真实世界的监控数据往往就是这样:海量录像堆积如山,人工逐帧标注贵到没人做得起,最多只有“这段视频有问题/那段视频正常”级别的粗标签。弱监督方法就是为这种场景而生的。

它的核心武器叫多实例学习。把一段视频切成一个个短片段,每个片段看作一个“实例”;一整段标了“异常”的视频就是一个“袋子”,袋子里至少有一个实例是异常的(但不知道是谁);标了“正常”的视频袋里则全部正常。训练时模型无法直接看到片段级标签,只能通过“袋级”信号间接学习——用袋内最大实例分数代表整袋的预测,让正常袋的最高分尽量低、异常袋的最高分尽量高。

有了袋级预测,还需要一个训练目标把两类袋子分开。经典的排序损失是:正袋(异常视频)的最高分要比负袋(正常视频)的最高分高出至少一个间隔。这套方法在学界和工业界被称为“深度多实例排序”,是弱监督视频异常检测的标志性框架,也是目前落地最广的范式之一。

老王记不清具体几秒出事,但他能确定“那段时间不对”。弱监督方法告诉他:不用记住每一秒,只要大概知道哪段时间出事,模型自己会把可疑片段揪出来。

Lrank=max⁡(0,  1−max⁡i∈Ps(xi)+max⁡j∈Ns(xj))\mathcal{L}_{\text{rank}} = \max\left( 0, \; 1 - \max_{i \in \mathcal{P}} s(x_i) + \max_{j \in \mathcal{N}} s(x_j) \right)
这个损失函数要求“异常视频里最可疑的片段”分数明显高于“正常视频里最可疑的片段”。只凭视频级标签,就能训练出片段级的判别力。
  1. 正袋与负袋把异常视频的片段集合记为 \mathcal{P},正常视频的片段集合记为 \mathcal{N}。
    P:含至少一个异常片段N:全部正常\mathcal{P}: \text{含至少一个异常片段} \quad \mathcal{N}: \text{全部正常}
  2. 袋级预测每个袋子的预测取袋内所有片段分数的最大值,模拟“袋子里最可疑的一帧”。
    max⁡i∈Ps(xi)与max⁡j∈Ns(xj)\max_{i \in \mathcal{P}} s(x_i) \quad \text{与} \quad \max_{j \in \mathcal{N}} s(x_j)
  3. 排序约束正袋最高分至少比负袋最高分大 1,差值不足或反了都要受罚。
    max⁡(0,  1−sP+sN)\max\left( 0, \; 1 - s_{\mathcal{P}} + s_{\mathcal{N}} \right)

六、异常事件识别:不止“有情况”

如果老王只会喊“出事了!”,值班室的人还是不知道该往哪跑。真正经验丰富的保安会喊得具体些:“3 号楼有人摔倒了!”“广场东侧有人打起来了!”异常事件识别要做的正是这一步:在检测出异常的基础上,进一步判明异常的类型,让报警从“含糊的提醒”变成“可执行的指令”。

常见的异常类型有跌倒、斗殴、入侵、徘徊、人群异常聚集等。识别这些类型不能只看单帧画面——因为“跌倒”和“蹲下系鞋带”在某一帧可能长得差不多,必须结合时间维度的运动信息才能分清。于是模型要同时吃下两路特征:一路是空间特征,描述“画面里有什么人、什么物体”;另一路是时间特征,描述“他们在怎么动”。双流网络、三维卷积网络就是为此设计的,相当于让老王既看清了人脸,又记住了动作轨迹。

有了帧级异常分数和类型判断,最后一步是把“哪一秒可疑”定位出来。一个常用的工程技巧是时间平滑:把每个片段的分数跟前后邻居取平均,消除单帧闪烁造成的误报,让异常时段变成连续、稳定的区间,方便联动摄像头追踪和事后调阅。

老王喊出“有人摔倒了”而不是干吼一句“不对劲”,安保才能真正跑起来。异常识别的意义正在于此:把分数变成事件,把事件变成行动。

s~t=12K+1∑k=−KKst+k\tilde{s}_t = \frac{1}{2K+1} \sum_{k=-K}^{K} s_{t+k}
c^t=arg⁡max⁡c  p(c∣xt)\hat{c}_t = \underset{c}{\arg\max} \; p(c \mid x_t)
第一个公式对异常分数做滑动平均,让报警区间更稳定;第二个公式选择概率最大的异常类别作为判定结果。
  1. 邻域平均用前后各 K 帧共 2K+1 帧的分数取平均,抹平单帧的偶发跳变。
    12K+1∑k=−KKst+k\frac{1}{2K+1} \sum_{k=-K}^{K} s_{t+k}
  2. 平滑后分数以 \tilde{s}_t 作为 t 时刻的最终异常分数,异常时段更连贯。
    s~t\tilde{s}_t
  3. 类型判别在异常片段上计算各类别的条件概率,取最大者作为识别结果。
    c^t=arg⁡max⁡c  p(c∣xt)\hat{c}_t = \underset{c}{\arg\max} \; p(c \mid x_t)

七、部署与优化:让老王三班倒

老王再厉害,也不可能 24 小时瞪大眼睛不眨眼。现实中的安保靠的是轮班、巡逻路线、对讲机调度——异常检测系统要真正落地,同样离不开一套“值班体系”。模型训练得再准,部署时跑不动、报警太多没人信,都是白搭。这一节聊聊把“老王”送进监控机房要过的三道关。

第一道关是实时推理。监控视频是连续流,模型必须做到“边看边报”而不是事后跑批。常用手段是把模型轻量化——剪枝砍掉冗余参数、量化把浮点计算压成低精度整数、用 TensorRT 等推理引擎加速;同时控制抽帧率和处理分辨率,把单帧延迟压到几十毫秒以内,边缘设备和 GPU 服务器各有各的优化套路。

第二道关是科学评估。异常检测的数据天然极度不平衡,不能只看正确率,业界标准是 AUC 指标——衡量模型把异常排到正常前面的能力。AUC 对阈值不敏感,能公正地比较不同模型;落地时再结合具体业务的误报率、漏检率,选一个真正好用的工作点。

第三道关是误报控制。老王看到可疑情况,不会立刻冲上去按倒对方,而是先瞥一眼监控、拿起对讲机确认。系统也该如此:异常分数先过时间平滑和置信度阈值两道滤网,再推给人工复核平台,由值班人员确认后才会触发真正告警。这个“机器初筛 + 人工终审”的闭环,是把误报率压到可接受范围的关键。

老王三班倒、有对讲机、有巡逻路线,才撑得起一整个小区的安宁。异常检测系统也一样:轻量高效的推理、客观严谨的指标、人机协同的闭环,三样凑齐,才是一套真正能上岗的“数字老王”。

AUC=1N+N−∑i∈S+∑j∈S−I(si>sj)\text{AUC} = \frac{1}{N^+ N^-} \sum_{i \in \mathcal{S}^+} \sum_{j \in \mathcal{S}^-} \mathbb{I}(s_i > s_j)
AUC 表示“任意抽一个异常片段,它的分数高于任意正常片段”的概率。它不关心阈值设在哪,只关心模型把异常排在正常前面的能力。
  1. 正负样本集合\mathcal{S}^+ 是异常片段集合,\mathcal{S}^- 是正常片段集合,数量分别为 N^+ 和 N^-。
    S+,  S−\mathcal{S}^+, \; \mathcal{S}^-
  2. 两两比较把所有异常片段与所有正常片段逐一配对,比较分数高低。
    I(si>sj)\mathbb{I}(s_i > s_j)
  3. 概率估计统计异常分数高于正常分数的占比,即随机正样本排在负样本前面的概率。
    1N+N−∑i∈S+∑j∈S−I(si>sj)\frac{1}{N^+ N^-} \sum_{i \in \mathcal{S}^+} \sum_{j \in \mathcal{S}^-} \mathbb{I}(s_i > s_j)

AI 应用场景

智慧养老:独居老人的跌倒守护

阶段:异常检测与识别(重构误差/预测误差 + 异常类型分类)

解决的问题:独居老人跌倒后无人知晓,经常错过黄金救援时间。传统靠人工盯守不值夜班、成本高昂,事后查看录像更是亡羊补牢。AI 用老人日常活动的正常视频训练模型,再实时计算每一帧的重构误差或预测误差,一旦误差飙升并识别出“跌倒”类型,立即通知家属和社区医护人员。

具体案例:某养老机构在卧室和卫生间安装摄像头,系统先学习每位老人“行走—坐下—躺下—缓慢移动”的日常轨迹;某夜老人起夜时在床边滑倒,系统在 1.2 秒内推送报警,护士 3 分钟到场处理。

工厂生产安全:危险区域的违规闯入告警

阶段:弱监督训练 + 密度估计 + 实时推理

解决的问题:工厂车间存在机械臂作业区、高压电柜等高危区域,工人违规闯入极易出事故。传统靠安全员巡逻,无法覆盖所有班次。AI 利用厂区已有海量监控录像——只要标注“哪个时段出过事”这种粗粒度视频级标签,就能用弱监督方法训练闯入检测模型;再结合正常作业轨迹的密度分布,对偏离常态的行为实时告警。

具体案例:某汽车零部件工厂在冲压车间部署边缘计算盒,对闯入机器人围栏区域的行为在 0.5 秒内声光报警并联动急停,半年内违规闯入事件下降 90%。

地铁与大型活动:斗殴与人群异常聚集的预警

阶段:异常事件识别 + 时间平滑定位 + 人工复核闭环

解决的问题:地铁站、演唱会等人流密集场所,斗殴和人群异常聚集一旦发生,蔓延极快。传统靠民警盯屏和网格巡逻,人力有限且反应滞后。AI 系统先以弱监督方式在海量历史监控上训练“帧级异常分数”,再叠加异常类型的时空分类,输出“时段 + 位置 + 事件类型”的结构化告警,联动站内广播和安保调度。

具体案例:某大型体育赛事场馆部署异常检测平台,在观众区出现推搡聚集后 3 秒内自动放大对应摄像头画面并通知安保组,事件在 40 秒内得到处置,未升级为群体事件。

Python 演示

python42 行
import numpy as np rng = np.random.RandomState(42)  def gen_sequence(n, dim=8, jump=False):    # 生成一段视频的特征序列, 每行代表一帧画面的特征向量    x = np.zeros((n, dim))    for i in range(1, n):        x[i] = x[i - 1] + 0.1 * rng.randn(dim)    if jump:        # 从中间开始叠加大幅跳变, 模拟异常事件的突然发生        x[n // 2:] += rng.randn(n - n // 2, dim) * 4.0    return x  def pca_basis(X, k):    # 用PCA训练一个线性自编码器, 只学习正常数据的主方向    Xc = X - X.mean(axis=0)    _, _, Vt = np.linalg.svd(Xc, full_matrices=False)    return X.mean(axis=0), Vt[:k].T  def recon_error(X, mean, basis):    # 重构误差: 原始特征与投影还原特征的均方误差    Z = (X - mean) @ basis @ basis.T + mean    return np.mean((X - Z) ** 2, axis=1)  train = gen_sequence(600)                     # 只用正常序列训练mean, basis = pca_basis(train, k=3)err_train = recon_error(train, mean, basis)threshold = np.percentile(err_train, 95)      # 用正常误差的95分位做阈值 normal = gen_sequence(200)anomaly = gen_sequence(200, jump=True)err_n = recon_error(normal, mean, basis)err_a = recon_error(anomaly, mean, basis) print('正常样本误报率: %.2f%%' % (100 * (err_n > threshold).mean()))print('异常样本召回率: %.2f%%' % (100 * (err_a > threshold).mean()))print('异常分数阈值: %.4f' % threshold)
目的:用 PCA 实现一个最简“线性自编码器”,只从正常序列学习主方向,再用重构误差区分正常帧与异常帧,完整跑通“正常训练 → 阈值设定 → 异常判定”的全流程。
  1. x[i] = x[i - 1] + 0.1 * rng.randn(dim)让下一帧只在上帧基础上微变,模拟日常画面的连贯性
  2. x[n // 2:] += rng.randn(n - n // 2, dim) * 4.0从中段起叠加大幅扰动,人为制造“异常事件”
  3. Xc = X - X.mean(axis=0)数据中心化,让主成分分析只关注变化模式而不是绝对位置
  4. _, _, Vt = np.linalg.svd(Xc, full_matrices=False)奇异值分解求出正常数据的主方向,等效于给自编码器“练功”
  5. Z = (X - mean) @ basis @ basis.T + mean把特征投影到主方向再还原,还原能力来自正常数据的主干模式
  6. return np.mean((X - Z) ** 2, axis=1)逐帧计算重构误差,误差越大代表越不像训练时的正常画面
  7. threshold = np.percentile(err_train, 95)从正常序列的误差分布取 95 分位做阈值,保证正常帧大部分能通过
  8. (err_a > threshold).mean()统计异常帧中被判为异常的占比,即召回率

常见误区

误区“异常检测不用标签,所以训练视频随便找一堆就能用,里面混点异常画面也无所谓,反正不用标注。”

正解训练数据必须干净,只能包含正常画面。异常检测的整个逻辑是“只见过正常,所以看得出反常”;如果训练集里混入了异常片段,模型会把这些异常也当作“常态”的一部分学进去,真正出事时反而熟视无睹。好比老王上岗前被人带着看了一周打架斗殴的现场,他可能就把打架当成小区日常了。

为何常见:人们常把“无监督”误解为“无需管理数据”,却忘了无监督学习的前提是数据源本身代表你要学习的分布——垃圾进,垃圾出。

误区“自编码器是万能照妖镜,只要重建误差大就是异常,误差小就一定是正常。”

正解自编码器越强大,越可能连异常画面也强行还原得七七八八,误差失去区分度;背景占主导的画面也可能把异常淹没在大量正常像素里。工程上要通过限制隐层维度、降噪训练、记忆增强等手段约束模型的“记性”,并且往往要结合预测误差或密度分数共同投票。

为何常见:人们直观以为“还原不了=没见过”,却忽略了还原能力取决于模型容量——一个过目不忘的模型连怪东西都能背下来。

误区“弱监督嘛,就是完全不需要标签,扔一堆视频进去它自己就会学。”

正解弱监督仍然有标签,只是标签粒度很粗——整段视频是正常还是异常,而不是精确到帧。它依靠多实例学习,用“袋内至少一个可疑”的假设把视频级标签转化为片段级判别力。完全没有标签、连视频级信息都没有,那是无监督,两者训练设定和难度完全不同。

为何常见:大家习惯把“弱监督”和“无监督”都归为“省标注”,忽略了弱监督省的是帧级标注、保留的仍是视频级监督信号这种中间状态。

误区“部署之后模型输出 0.8 分,就应该马上拉响警笛通知所有人。”

正解直接拿原始分数报警会导致大量误报,因为单帧特征抖动、光照变化、镜头晃动都可能造成虚惊。成熟系统会先做时间平滑、置信度阈值过滤,再交给人工复核平台确认,最后才触发正式告警。老王看到可疑情况也是先瞥一眼监控、按下对讲机,而不是直接冲上去抓人。

为何常见:实验室里关注 AUC 这类排序指标,让人误以为分数高就能直接当结论;忽略了真实场景对误报率极其苛刻,需要“人机协同复核”的缓冲带。

面试题

Q1. 视频异常检测最核心的设计思路是什么?

单选题 · easy

  • A.学习正常模式并检测偏离← 正确答案
  • B.枚举所有异常事件类型
  • C.对每帧人工标注后分类
  • D.直接用目标检测网络

答案:A。异常的种类无限多,无法枚举,核心是用大量正常数据学到“常态”,再以偏离程度判断反常。人工标注逐帧分类成本太高,目标检测只能识别已知物体,抓不住“没见过的怪事”。就像老王靠熟悉业主面孔来发现陌生人,而不是背一本罪犯图鉴。

Q2. 重构误差方法判断异常的依据是什么?

单选题 · easy

  • A.图片压缩体积变大
  • B.重建画面与输入差异大← 正确答案
  • C.编码特征维度变高
  • D.解码速度明显变慢

答案:B。自编码器只学过正常画面的“压缩—还原”,遇到没见过的异常画面时还原质量差,重建画面与输入的差异(即重构误差)大,差异大判为异常。压缩体积、特征维度和解码速度都不是异常判据。

Q3. 预测误差方法为什么能检测异常?

单选题 · mid

  • A.正常运动模式可预测← 正确答案
  • B.异常帧画质更高
  • C.预测网络无需训练
  • D.异常事件出现频率高

答案:A。正常视频的运动是连贯可预测的,模型从历史帧学到的惯性规律能猜中下一帧;异常动作无法从过去推断,预测与真实差距大,偏差大即异常。预测网络必须训练,异常帧画质和出现频率与原理无关。

Q4. 密度估计方法中,为什么常用负对数概率作为异常分数?

单选题 · mid

  • A.让概率值归一化到零一
  • B.概率过小时转为大分数← 正确答案
  • C.方便计算均值方差
  • D.能让判定阈值小于零

答案:B。正常样本概率高、异常样本概率极低,极小的概率值在计算机里容易下溢,取负对数后转成一个大分数,越离群分数越高,数值也更稳定。归一化、均值方差和阈值正负都不是取负对数的原因。

Q5. 弱监督视频异常检测的训练数据具有哪些特点?

多选题 · mid

  • A.整段视频级正常异常标签← 正确答案
  • B.每个片段帧级像素标注
  • C.正视频含至少一个异常片段← 正确答案
  • D.依赖完整人工逐帧标注

答案:AC。弱监督只有视频级标签,标注“这段正常/那段异常”,正视频袋中至少有一个片段是异常的,但不知道具体是哪段,这正是多实例学习的假设。帧级像素标注和逐帧人工标注属于强监督,不是弱监督的特点。

Q6. 多实例排序损失追求的训练目标是?

单选题 · mid

  • A.正袋最高分高于负袋← 正确答案
  • B.正袋平均分低于负袋
  • C.所有片段分数都大于零
  • D.负袋最高分高于正袋

答案:A。因为不知道异常具体出现在正视频的哪一段,排序损失用袋内最高分代表整袋,要求正袋最高分显著高于负袋最高分,从而让模型把最可疑的片段标出来。平均分和全体大于零都不符合“袋内至少一个异常”的设定。

Q7. AUC 指标衡量的是什么能力?

单选题 · easy

  • A.正样本分数高于负样本← 正确答案
  • B.模型推理的平均耗时
  • C.异常样本占总样本比例
  • D.自编码器隐藏层维度

答案:A。AUC 表示随机抽一个异常片段,其分数高于随机一个正常片段的概率,衡量模型把异常排在正常前面的排序能力。它不依赖具体阈值,因此适合评价异常检测这类极度不平衡的任务。

Q8. 哪些情况会让重构误差方法失效?

多选题 · hard

  • A.自编码器容量过大致重建异常← 正确答案
  • B.背景区域占主导干扰判断← 正确答案
  • C.训练正常数据非常干净
  • D.输入帧分辨率设置过低

答案:AB。容量过大的自编码器会“过目不忘”,把异常画面也还原得很好,误差失去区分度;背景占主导时,异常像素占比太小,平均误差被大量正常背景稀释。训练数据干净是方法有效的必要条件而非失效原因,分辨率过低削弱细节但不是方法失效的本质问题。

Q9. 对异常分数做时间平滑的主要作用是?

单选题 · mid

  • A.减少单帧误报与闪烁← 正确答案
  • B.提高视频画面分辨率
  • C.加快模型推理速度
  • D.增大异常分数数值

答案:A。单帧的特征抖动、光照变化会造成偶发高分误报,用前后帧分数取平均能抹平这种“闪烁”,让异常时段变成连续稳定的区间。平滑与分辨率、推理速度和分数大小无关。

Q10. 部署真实异常检测系统时需要考虑哪些要素?

多选题 · hard

  • A.模型轻量化与实时推理← 正确答案
  • B.误报人工复核闭环← 正确答案
  • C.帧级像素级人工标注
  • D.评估指标结合业务阈值← 正确答案

答案:ABD。监控是连续视频流,必须轻量化保证实时;真实场景误报率高会让人失去信任,需要时间平滑和人工复核闭环;AUC 之外还要结合具体业务的误报率、漏检率选择工作点。弱监督方法正是为了避免帧级像素级人工标注,因此它不是部署必需项。