第9章 计算神经科学:预测与控制
原课程: Robots That Learn, UC Berkeley CS294-291, Spring 2026 本章基于 Lecture 6A: Computational Neuroscience — Prediction and Control 精读论文: Land, Mennie & Rusted, “The roles of vision and eye movements in the control of activities of daily living,” Perception, 1999 延伸理论: Rao & Ballard (1999) Predictive Coding; Friston (2010) Free Energy Principle; Marr-Albus-Ito Cerebellar Model
一、本章概要
1999年,Michael Land 在 Sussex 大学的实验室里做了一个看似平淡无奇的实验:他给三位受试者戴上一个轻量级头盔式眼动追踪摄像机,然后请他们每人泡一杯茶。接下来的四分钟里,三台摄像机同时记录——一台拍摄受试者前方的场景并以白点标注中央凹注视方向(精度约1度),一台从房间对面拍摄身体与手部的动作,第三台记录被摄者的眼部特写。三卷录像带被逐帧分析,共计约36000帧。
这个实验的结果改变了我们对”自动行为”的理解。
长期以来,认知心理学中占据主导地位的观点是:过度学习的日常行为——如泡茶、刷牙、开车回家——是由记忆脚本(memory script)驱动的开环控制(open-loop control),不需要在线的感觉反馈和监督注意(Norman & Shallice, 1986; Underwood & Everatt, 1996)。一旦学会,这些行为就变得”自动化”,不再消耗认知资源。
Land 的数据彻底推翻了这一假设。在泡茶的全部45个独立动作(拿起水壶、走到水槽、拧开水龙头、观察水位、关水、盖上壶盖、放回底座……)中,几乎每一个动作都伴随着精确的注视。注视不是随机的,不是被”显著性”(salience)驱动的——它们是被任务需求精确编排的。事实上,Land 发现眼动始终领先手部动作约0.56秒,并在当前动作完成前约0.61秒提前跳转到下一个目标。眼睛不是在”看”正在发生的事,而是在”准备”即将发生的事。
这一发现背后是一套深层的计算原理:神经系统维持着对世界的内部预测模型(internal forward model),眼睛的每一次跳动(saccade,平均每0.49秒一次,每次20度)都是一次主动的信息采样——在需要信息的精确位置、精确时刻获取信息,以降低对世界状态的不确定性。这正是本章要展开的核心主题:计算神经科学中的预测与控制。
本章的结构安排如下。第二节从第一性原理出发构建三个数学框架——卡尔曼滤波作为贝叶斯感觉运动整合的统一语言、预测编码作为分层变分推断的神经实现、自由能原理与主动推断作为感知与行动的统一目标函数。第三节以 Land et al. (1999) 的茶实验为锚点,逐层解读注视模式的数据、四类注视功能的定义(定位/指引/导向/检查)、以及”对象相关动作”(Object-Related Action, ORA)作为行为基本单元的理论意义。第四节提供两个完整的 Python/PyTorch 实现——卡尔曼滤波器和预测编码网络——让读者能够亲手操作这些模型。第五节提炼核心 Takeaway。第六节给出思考题。
与前后章节的逻辑关系:第8章(机器人动力学与控制)介绍了基于精确模型的工程控制方法(LQR, MPC);本章从生物神经系统出发,揭示大脑如何在模型不精确、观测不完整的条件下实现鲁棒的预测性控制。这些计算原理——特别是前向模型和主动信息采样——直接构成了第10章(视频世界模型)的概念基础,后者将内部的预测模型外化为可学习的深度神经网络。
二、核心概念与数学基础
2.1 卡尔曼滤波:作为贝叶斯感觉运动整合的数学语言
2.1.1 问题设定
考虑一个智能体(生物或机器人)试图估计其环境的状态 \(\mathbf{x}_t \in \mathbb{R}^n\)。智能体拥有两类信息源:
- 前向模型(Forward Model) ——基于上一时刻的状态估计和当前运动指令 \(\mathbf{u}_t\),预测当前状态:
其中 \(\mathbf{F} \in \mathbb{R}^{n \times n}\) 是状态转移矩阵,\(\mathbf{B} \in \mathbb{R}^{n \times m}\) 是控制矩阵,\(\mathbf{w}_t\) 是过程噪声(运动噪声 + 模型不精确性),\(\mathbf{Q}\) 是过程噪声协方差矩阵。
- 感觉观测(Sensory Observation) ——通过传感器(眼睛、本体感觉、触觉等)获得带噪声的状态测量:
其中 \(\mathbf{H} \in \mathbb{R}^{p \times n}\) 是观测矩阵(\(p \ll n\) 对应部分可观测情形),\(\mathbf{R}\) 是观测噪声协方差矩阵。
核心问题:给定到时刻 \(t\) 为止的所有观测 \(\mathbf{y}_{1:t}\) 和控制信号 \(\mathbf{u}_{1:t}\),如何最优地推断当前状态 \(\mathbf{x}_t\)?
2.1.2 贝叶斯视角下的卡尔曼滤波
卡尔曼滤波(Kalman, 1960)的标准推导通常使用最小均方误差(MMSE)准则。但更深刻的视角是贝叶斯推断——这正是连接卡尔曼滤波与大脑计算的桥梁。
卡尔曼滤波维护一个关于状态的高斯信念:
\[p(\mathbf{x}_t \mid \mathbf{y}_{1:t}, \mathbf{u}_{1:t}) = \mathcal{N}(\mathbf{x}_t \mid \hat{\mathbf{x}}_t, \mathbf{P}_t)\]其中 \(\hat{\mathbf{x}}_t\) 是均值估计,\(\mathbf{P}_t\) 是估计的协方差矩阵(量化不确定性)。
滤波过程分为两步——预测(prior update)和更新(posterior update),这两步恰好对应贝叶斯推断的先验→后验流程。
步骤 1 — 预测(Prior):利用前向模型,从上一时刻的后验推出当前时刻的先验:
\[\begin{aligned} \hat{\mathbf{x}}_{t\vert t-1} &= \mathbf{F} \hat{\mathbf{x}}_{t-1} + \mathbf{B} \mathbf{u}_t \\ \mathbf{P}_{t\vert t-1} &= \mathbf{F} \mathbf{P}_{t-1} \mathbf{F}^\top + \mathbf{Q} \end{aligned}\]这等价于计算预测分布 \(p(\mathbf{x}_t \mid \mathbf{y}_{1:t-1}, \mathbf{u}_{1:t})\)。先验的不确定性 \(\mathbf{P}_{t\vert t-1}\) 源于两项:上一时刻的残余不确定性通过动力学传播,加上过程噪声 \(\mathbf{Q}\)。
步骤 2 — 更新(Posterior):当新的观测 \(\mathbf{y}_t\) 到达时,用贝叶斯定理将先验与似然融合:
\[p(\mathbf{x}_t \mid \mathbf{y}_{1:t}) \propto p(\mathbf{y}_t \mid \mathbf{x}_t) \cdot p(\mathbf{x}_t \mid \mathbf{y}_{1:t-1})\]对于高斯先验和高斯似然,后验也是高斯分布,其参数可解析计算。定义创新(innovation)或预测误差:
\[\tilde{\mathbf{y}}_t = \mathbf{y}_t - \mathbf{H} \hat{\mathbf{x}}_{t\vert t-1}\]这是实际观测与预测观测之间的差异——它是驱动信念更新的核心信号。创新协方差为:
\[\mathbf{S}_t = \mathbf{H} \mathbf{P}_{t\vert t-1} \mathbf{H}^\top + \mathbf{R}\]卡尔曼增益(Kalman Gain)决定观测相对于预测的可信度:
\[\boxed{\mathbf{K}_t = \mathbf{P}_{t\vert t-1} \mathbf{H}^\top \mathbf{S}_t^{-1}}\]状态更新:
\[\boxed{\hat{\mathbf{x}}_t = \hat{\mathbf{x}}_{t\vert t-1} + \mathbf{K}_t \tilde{\mathbf{y}}_t}\]协方差更新:
\[\boxed{\mathbf{P}_t = (\mathbf{I} - \mathbf{K}_t \mathbf{H}) \mathbf{P}_{t\vert t-1}}\]卡尔曼增益的直觉:
\[\mathbf{K}_t = \mathbf{P}_{t\vert t-1} \mathbf{H}^\top (\mathbf{H} \mathbf{P}_{t\vert t-1} \mathbf{H}^\top + \mathbf{R})^{-1}\]将其重写为精度加权的形式:
\[\mathbf{K}_t = \underbrace{(\mathbf{P}_{t\vert t-1}^{-1} + \mathbf{H}^\top \mathbf{R}^{-1} \mathbf{H})^{-1}}_{\text{后验精度倒数}} \mathbf{H}^\top \mathbf{R}^{-1}\]这意味着状态更新是先验预测和观测之间的精度加权平均:
- 如果观测噪声 \(\mathbf{R}\) 很大(传感器不可靠)→ 增益 \(\mathbf{K}_t\) 小 → 更信任前向模型预测
- 如果过程噪声 \(\mathbf{Q}\) 很大(模型不可靠)→ 先验不确定性 \(\mathbf{P}_{t\vert t-1}\) 大 → 增益 \(\mathbf{K}_t\) 大 → 更信任感觉观测
- 如果 \(\mathbf{P}_{t\vert t-1} \to \mathbf{0}\)(预测完全确定)→ \(\mathbf{K}_t \to \mathbf{0}\) → 忽略观测
- 如果 \(\mathbf{R} \to \mathbf{0}\)(观测完全精确)→ \(\mathbf{K}_t \to \mathbf{H}^{-1}\) → 完全信任观测
2.1.3 与小脑前向模型的联系
小脑(cerebellum)的 Marr-Albus-Ito 模型为卡尔曼滤波提供了一个令人信服的神经实现候选(Wolpert et al., 1998)。
小脑的微电路:
- 苔藓纤维(Mossy fibers) 携带感觉上下文和运动指令的副本(efference copy),类似于卡尔曼滤波中的 \(\mathbf{u}_t\) 和 \(\hat{\mathbf{x}}_{t-1}\)。
- 颗粒细胞(Granule cells) 执行高维稀疏扩展编码——将低维输入映射为极高维的稀疏表示(颗粒细胞数量是苔藓纤维输入数量的约 \(10^4\) 倍)。这种扩展编码实现了输入的非线性展开,使得线性读出层可以学习复杂的非线性动力学映射。
- 平行纤维(Parallel fibers) 向浦肯野细胞(Purkinje cells)的树突传递信号,每个浦肯野细胞接收来自约 \(10^5-2\times10^5\) 根平行纤维的输入。
- 浦肯野细胞 是小脑皮层的唯一输出——其放电率编码预测。在卡尔曼滤波的类比中,浦肯野细胞的输出对应于 \(\mathbf{H} \hat{\mathbf{x}}_{t\vert t-1}\)——即预测的感觉后果。
- 爬行纤维(Climbing fibers) 来自下橄榄核,以极低的频率(约 1-10 Hz)发放,携带预测误差信号。这对应于卡尔曼滤波中的创新 \(\tilde{\mathbf{y}}_t\)。爬行纤维-浦肯野细胞突触的长时程抑制(LTD) 就是学习规则——当预测与实际感觉不匹配时,下调产生错误预测的平行纤维-浦肯野突触强度,从而改善未来的预测。
形式化:小脑前向模型学习函数 \(f_{\text{cereb}}: (\mathbf{x}_{t-1}, \mathbf{u}_t) \mapsto \hat{\mathbf{y}}_t\),其中 \(\hat{\mathbf{y}}_t = \mathbf{H}\hat{\mathbf{x}}_{t\vert t-1}\) 是预测的感觉后果。预测误差 \(\epsilon_t = \mathbf{y}_t - \hat{\mathbf{y}}_t\) 驱动小脑学习,这与卡尔曼滤波的创新信号完全对应。
一个关键区别在于:卡尔曼滤波假设线性的状态转移和观测模型,而小脑通过颗粒细胞的扩展编码实现了非线性映射。扩展卡尔曼滤波(EKF)或无迹卡尔曼滤波(UKF)可以视为更贴近小脑非线性计算能力的工程近似。
2.1.4 感觉运动整合中的多模态融合
在机器人学和生物系统中,状态估计通常涉及多个感觉模态。卡尔曼滤波的贝叶斯框架天然支持多模态融合:
\[\begin{aligned} \hat{\mathbf{x}}_t &= \arg\max_{\mathbf{x}} p(\mathbf{x} \mid \mathbf{y}_t^{\text{vision}}, \mathbf{y}_t^{\text{proprioception}}, \mathbf{y}_t^{\text{touch}}, \ldots) \\ &\propto p(\mathbf{y}_t^{\text{vision}} \mid \mathbf{x}) \cdot p(\mathbf{y}_t^{\text{proprioception}} \mid \mathbf{x}) \cdot p(\mathbf{y}_t^{\text{touch}} \mid \mathbf{x}) \cdot p(\mathbf{x} \mid \text{history}) \end{aligned}\]每个感觉模态按照其精度(逆噪声协方差)被加权融合——精确的模态获得更高的权重。这在 Land 的茶实验中有直接体现:当手已经接触水壶时,视觉从壶身移开(转向水龙头或水流),此时触觉和本体感觉承担了感知任务,因为它们在该情境下对状态估计的贡献精度足够高。卡尔曼滤波完美地解释了这种多模态感觉权重的动态切换。
2.2 预测编码:作为分层变分推断的神经架构
2.2.1 从感觉处理到生成模型
传统的感觉处理理论将大脑视为一个自底向上的特征检测器层次:V1 检测边缘 → V2 检测角点和轮廓 → V4 检测形状 → IT 检测物体。然而,Rao & Ballard (1999) 提出了一个根本不同的观点:大脑皮层的层级结构实现的是预测编码(Predictive Coding)——一种自上而下传递预测、自下而上传递预测误差的计算架构。
其核心洞察是:与其被动地从感官数据中提取特征,大脑更应该被理解为一个分层生成模型(Hierarchical Generative Model),持续尝试预测即将到来的感觉输入。当预测与实际输入不匹配时,预测误差(而非原始感觉数据)被向上传递。
2.2.2 预测编码的形式化:两层层级
考虑一个两层生成模型。高层(例如 V2)编码潜在原因 \(\mathbf{h}^{(2)}\),低层(例如 V1)编码潜在原因 \(\mathbf{h}^{(1)}\)。生成过程为:
\[\begin{aligned} \mathbf{h}^{(2)} &\sim \mathcal{N}(\mathbf{0}, \mathbf{I}) \\ \mathbf{h}^{(1)} &= f^{(1)}(\mathbf{h}^{(2)}) + \boldsymbol{\epsilon}^{(1)}, \quad \boldsymbol{\epsilon}^{(1)} \sim \mathcal{N}(\mathbf{0}, \mathbf{\Sigma}^{(1)}) \\ \mathbf{y} &= f^{(0)}(\mathbf{h}^{(1)}) + \boldsymbol{\epsilon}^{(0)}, \quad \boldsymbol{\epsilon}^{(0)} \sim \mathcal{N}(\mathbf{0}, \mathbf{\Sigma}^{(0)}) \end{aligned}\]其中 \(f^{(0)}\) 和 \(f^{(1)}\) 是前馈生成映射(例如,\(f^{(1)}\) 从高级特征”预测”低级特征),\(\mathbf{y} \in \mathbb{R}^d\) 是感觉输入。
推断问题:给定感觉输入 \(\mathbf{y}\),如何推断潜在状态 \(\mathbf{h} = [\mathbf{h}^{(1)}; \mathbf{h}^{(2)}]\)?
精确的后验 \(p(\mathbf{h} \mid \mathbf{y})\) 通常不可计算,因为 \(f^{(0)}, f^{(1)}\) 是非线性函数。预测编码通过变分推断来解决这个问题:用可处理的近似后验 \(q(\mathbf{h})\) 来逼近真实后验。
2.2.3 变分自由能与预测误差最小化
假定近似后验分解为独立高斯:
\[q(\mathbf{h}) = \prod_i \mathcal{N}(\mathbf{h}^{(i)} \mid \boldsymbol{\mu}^{(i)}, \mathbf{\Pi}^{(i)-1})\]其中 \(\boldsymbol{\mu}^{(i)}\) 和 \(\mathbf{\Pi}^{(i)}\) 分别是第 \(i\) 层的后验均值和精度矩阵。
变分自由能(Variational Free Energy)\(\mathcal{F}\) 定义为:
\[\boxed{\mathcal{F} = \mathbb{E}_q[\ln q(\mathbf{h}) - \ln p(\mathbf{y}, \mathbf{h})] = D_{\text{KL}}[q(\mathbf{h}) \| p(\mathbf{h} \mid \mathbf{y})] - \ln p(\mathbf{y})}\]最小化 \(\mathcal{F}\) 等价于同时实现两个目标:(1) 使近似后验接近真实后验(KL 散度项最小化);(2) 解释感觉数据(证据下界最大化,因为 \(-\ln p(\mathbf{y})\) 是常数)。
在高斯假设下展开 \(\mathcal{F}\):
\[\begin{aligned} \mathcal{F} &= \frac{1}{2} \sum_i \left[ \boldsymbol{\epsilon}^{(i)\top} \mathbf{\Sigma}^{(i)-1} \boldsymbol{\epsilon}^{(i)} + \ln \vert \mathbf{\Sigma}^{(i)}\vert \right] + \text{const} \end{aligned}\]其中预测误差 \(\boldsymbol{\epsilon}^{(i)}\) 的定义为:
\[\begin{aligned} \boldsymbol{\epsilon}^{(0)} &= \mathbf{y} - f^{(0)}(\boldsymbol{\mu}^{(1)}) \quad \text{(感觉层预测误差)} \\ \boldsymbol{\epsilon}^{(1)} &= \boldsymbol{\mu}^{(1)} - f^{(1)}(\boldsymbol{\mu}^{(2)}) \quad \text{(隐藏层预测误差)} \end{aligned}\]这揭示了一个优雅的结构:变分自由能正是各层精度的加权预测误差平方和。
2.2.4 梯度下降推断:预测编码的动力学
预测编码的关键创新在于:推断(感知)和生成(学习)通过相同的局部计算实现。
推断(E-step 的神经等价):通过梯度下降更新 \(\boldsymbol{\mu}^{(i)}\) 以最小化 \(\mathcal{F}\)。由于 \(\mathcal{F}\) 的结构,梯度呈现出简洁的”自顶向下预测减自底向上预测误差”的形式。对于线性生成函数 \(f^{(i)}(\mathbf{h}^{(i+1)}) = \mathbf{W}^{(i)} g(\mathbf{h}^{(i+1)})\):
\[\boxed{\frac{d \boldsymbol{\mu}^{(i)}}{dt} \propto -\frac{\partial \mathcal{F}}{\partial \boldsymbol{\mu}^{(i)}} = \underbrace{g'(\boldsymbol{\mu}^{(i)}) \odot \mathbf{W}^{(i-1)\top} \mathbf{\Sigma}^{(i-1)-1} \boldsymbol{\epsilon}^{(i-1)}}_{\text{自底向上的预测误差}} - \underbrace{\mathbf{\Sigma}^{(i)-1} \boldsymbol{\epsilon}^{(i)}}_{\text{当前层的预测误差}}}\]其中第一项是来自低层的预测误差(加权后向上传递),第二项是当前层的预测误差。这对应于 Rao & Ballard (1999) 的核心发现:预测编码的推断动力学严格等价于变分自由能的梯度下降。
学习(M-step 的神经等价):通过梯度下降更新生成权重 \(\mathbf{W}^{(i)}\) 以最小化 \(\mathcal{F}\):
\[\boxed{\frac{\partial \mathcal{F}}{\partial \mathbf{W}^{(i)}} = -\mathbf{\Sigma}^{(i)-1} \boldsymbol{\epsilon}^{(i)} g(\boldsymbol{\mu}^{(i+1)})^\top}\]这就是一个Hebbian-like 的更新规则:突触权重的变化正比于突触后预测误差 \(\boldsymbol{\epsilon}^{(i)}\) 和突触前活动 \(g(\boldsymbol{\mu}^{(i+1)})\) 的外积。这个学习规则的局部性(只需要突触两端的信息)使其在生物学上是合理的。
2.2.5 预测编码与卡尔曼滤波的统一
值得注意的是,卡尔曼滤波预测步骤中的创新 \(\tilde{\mathbf{y}}_t = \mathbf{y}_t - \mathbf{H}\hat{\mathbf{x}}_{t\vert t-1}\) 与预测编码中的感觉层预测误差 \(\boldsymbol{\epsilon}^{(0)} = \mathbf{y} - f^{(0)}(\boldsymbol{\mu}^{(1)})\) 在概念上是同构的:两者都是实际感觉输入与内部模型预测之间的差异。区别在于计算架构——卡尔曼滤波维护的是显式的高斯信念,而预测编码将推断实现为分布式神经群体上的梯度下降动力学。从计算的层次看,卡尔曼滤波是预测编码在线性高斯系统中的精确解析形式。
2.3 自由能原理与主动推断
2.3.1 自由能原理:一个统一的理论框架
Karl Friston 的自由能原理(Free Energy Principle, FEP)(Friston, 2010)提出了一条更为激进的理论:任何自组织系统(包括大脑),为了维持其存在,必须持续地最小化其感觉输入的惊奇(surprise)。
数学上,惊奇定义为感觉数据的负对数边际似然:
\[\text{Surprise}(\mathbf{y}) = -\ln p(\mathbf{y}) = -\ln \int p(\mathbf{y}, \boldsymbol{\theta}) d\boldsymbol{\theta}\]其中 \(\boldsymbol{\theta}\) 是环境的所有隐藏变量(包括外部世界状态、自身身体状态等)。惊奇直接最小化是困难的,因为积分在高维空间中不可计算。自由能原理的巧妙之处在于通过变分推理为惊奇构造了一个上界——这正是变分自由能 \(\mathcal{F}\):
\[\boxed{\mathcal{F} = \mathbb{E}_{q(\boldsymbol{\theta})}[\ln q(\boldsymbol{\theta}) - \ln p(\mathbf{y}, \boldsymbol{\theta})] \geq -\ln p(\mathbf{y})}\]因此,最小化自由能 \(\mathcal{F}\) 等价于最小化惊奇的(变分)上界。
2.3.2 将行动纳入推断:主动推断
自由能原理不仅统一了感知和推断,还自然地将行动(action)纳入了同一个优化框架。这就是主动推断(Active Inference)。
在主动推断中,自由能可以关于两个变量进行优化:(1) 内部信念 \(\mathbf{h}\)(感知/推断);(2) 行动 \(\mathbf{a}\)(控制/行为)。两者分别最小化自由能,但作用于不同的”节点”:
感知:\(\boldsymbol{\mu}^* = \arg\min_{\boldsymbol{\mu}} \mathcal{F}(\boldsymbol{\mu}, \mathbf{y})\) ——更新内部信念以更好地解释当前感觉。
行动:\(\mathbf{a}^* = \arg\min_{\mathbf{a}} \mathcal{F}(\boldsymbol{\mu}, \mathbf{y}(\mathbf{a}))\) ——执行动作以改变未来的感觉输入,使其更符合内部模型的预测。换言之,行动通过改变世界来实现预测(而非仅仅更新信念以适应世界)。
2.3.3 期望自由能与前瞻性策略选择
在主动推断中,行动选择(策略 \(\pi\))是通过最小化期望自由能(Expected Free Energy, \(G\))来实现的:
\[\boxed{G(\pi) = \mathbb{E}_{q(\mathbf{o}, \mathbf{s} \mid \pi)} \left[ \ln q(\mathbf{s} \mid \pi) - \ln p(\mathbf{o}, \mathbf{s} \mid \pi) \right]}\]其中 \(\mathbf{o}\) 是未来预期的观测,\(\mathbf{s}\) 是隐藏状态,\(\pi\) 是策略(行动序列)。
将 \(G(\pi)\) 拆解为两个信息论量:
\[G(\pi) = \underbrace{-\mathbb{E}_{q(\mathbf{o} \mid \pi)} \left[ \ln p(\mathbf{o} \mid C) \right]}_{\text{实用价值(Pragmatic Value)}} - \underbrace{\mathbb{E}_{q(\mathbf{o} \mid \pi)} \left[ D_{\text{KL}}[q(\mathbf{s} \mid \mathbf{o}, \pi) \| q(\mathbf{s} \mid \pi)] \right]}_{\text{认知价值(Epistemic Value)}}\]- 实用价值 衡量预期观测与先验偏好 \(p(\mathbf{o} \mid C)\) 的匹配程度(”这个策略能让我达到目标吗?”)
- 认知价值(或信息增益)衡量观测能多大程度地减小对隐藏状态的不确定性(”这个策略能让我学到关于世界的信息吗?”)
这正是 Land 茶实验的计算解释。泡茶时的每一次注视(saccade)都是一次认知行动(epistemic action)——它的目的不是直接实现物理目标(如拿起水壶),而是获取信息以降低不确定性(”水壶在哪里?”“水位够了吗?”“壶盖对准了吗?”)。Land 发现的四类注视功能——定位(locating)、指引(directing)、导向(guiding)、检查(checking)——恰好映射到主动推断框架中不同类型的认知行动:
| Land 的注视功能 | 主动推断中的计算角色 |
|---|---|
| 定位(Locate) | 降低对物体身份和位置的不确定性(认知价值主导) |
| 指引(Direct) | 建立精确的感觉运动映射向量(混合认知与实用价值) |
| 导向(Guide) | 持续的闭环反馈控制(以实用目标为约束的认知采样) |
| 检查(Check) | 检验变量状态是否达到先验偏好(实用价值主导) |
2.3.4 小脑-皮层预测层级:从 Marr-Albus-Ito 到自由能原理
将这些理论统一起来的视角是:大脑维持着一个多层级、多时间尺度的预测层级。
- 脊髓水平(\(\sim\)10 ms):反射回路,预测本体感觉后果。
- 小脑水平(\(\sim\)100 ms):前向模型预测运动的即时感觉后果,生成感觉预测误差以驱动快速在线修正。Marr-Albus-Ito 模型提供了该层级的电路级实现。
- 皮层感知水平(\(\sim\)200-500 ms):预测编码,持续预测更低层皮层的活动模式(视觉、听觉、体感),预测误差在层级间传播以更新内部表征。
- 前额叶/策略水平(\(\sim\)1-10 s):主动推断,根据期望自由能选择行动策略。Land 实验中 ORA 的时间尺度(约 3 秒)恰好对应这一层级——每个对象相关动作都涉及前瞻性的注视编排、信息获取和动作执行。
三、论文精读:Land et al. (1999) — 茶实验
3.1 论文贡献陈述
This paper introduced 第一项在日常生活中自然环境下对眼动与动作协调的量化研究,demonstrating that 即使在完全”自动化”的日常任务(泡茶)中,眼睛也以前瞻性(proactive)、任务驱动的方式精确监控每一个动作步骤——注视始终领先手部动作约 0.5-0.6 秒,revealing “自动化行为”并非开环控制,而是包含一套完整的、但无意识的视觉监控系统。
3.2 实验设计与方法
受试者与场景:三名受试者(ML, 男 55 岁; SF, 女 28 岁; JB, 男 46 岁)在 University of Sussex 的一个小型矩形厨房中各自泡一杯茶。房间布局包含左侧工作台、正前方水槽、右侧工作台和冰箱。受试者在前一天仅见过该厨房一次,且物品位置已被改变——这要求在完成任务时进行搜索。
眼动追踪装置:一个基于头盔的轻量级眼动摄像机,通过分光镜将视野分为上下两部分:
- 上方三分之二记录场景前方的视图(含一个白点标注中央凹注视方向,精度约 1 度)。
- 下方三分之一记录眼部特写(通过凹面镜反射)。
- 两路视频被存入便携式录像机(背包中)。后期逐帧播放,通过计算机生成的眼部模型(带亮环的虹膜轮廓)拟合真实眼部图像以获得注视坐标,并将白点叠加到场景视频上。
数据规模:每名受试者约 4 分钟的录像被逐帧分析,共计约 36000 帧,以优于 0.1 秒的精度记录了所有身体动作、物体操作和眼动的时间点。
3.3 关键结果一:注视与动作的时间耦合
图 4(原论文)展示了整个泡茶过程中 137 个对象相关动作(ORAs)的平均时序关系,这是论文最核心的量化发现:
| 时序关系 | 平均延迟(秒) | 含义 |
|---|---|---|
| 身体运动 → 首次注视 | 0.61 | 身体先转向目标方向,然后眼睛跳过去 |
| 首次注视 → 首次操作 | 0.56 | 视觉领先动作约半秒 |
| 操作完成 ← 视觉转移 | 0.61 | 在当前动作完成前,眼睛已跳到下一个对象 |
这三个数字揭示了两个根本性的发现:
-
视觉的前瞻性(Proactive Vision):眼睛不是在反应性地跟踪动作,而是在主动地为即将发生的动作获取信息。Land 提出了一个”视觉缓冲区”假说:视觉系统在动作执行前约 1 秒开始向缓冲区填充信息,动作执行时从缓冲区消耗信息,缓冲区清空后视觉已转移到下一个目标——整个过程类似于一个前瞻性流水线(proactive pipeline)。
-
“自动行为”的错觉来源:受试者主观上感觉泡茶是”不用动脑”的自动化行为,但眼动录像显示,眼球以每秒 2-3 次的速度在执行精密的、任务相关的信息采样。这种眼动编排完全是无意识的——正如一位朋友观看眼动录像后感叹:”难怪我一天下来这么累!”我们对自己的眼动系统如何为我们工作的主观洞察几乎为零。
3.4 关键结果二:四类注视功能
Land 通过对第一个子任务(”烧水”)的 80 次注视的逐一定性分析,将约 32 次(约 40%)可明确归类为以下四种功能:
-
定位(Locating):注视到将在后续使用的物体上(如茶壶、牛奶),建立物体的身份和空间位置。例如,在准备水壶的过程中看一眼远处的茶壶——这是一种认知行动,为未来的操作获取信息。
-
指引(Directing):单个注视指向手即将接触的对象或对象的部位。这似乎为运动系统建立了一个用于控制接近运动的目标向量。在许多情况下,在手完成接触之前注视已经移开——这表明接触的最后阶段可能不依赖闭环视觉控制,而是由本体感觉和触觉完成。
-
导向(Guiding):一次或多次注视,在两个相互靠近的物体之间(例如水壶和壶盖、茶壶和杯口),为精确对准(docking)提供持续反馈。不同于指引注视,导向注视需要连续的闭环反馈以匹配方向和减少距离。
-
检查(Checking):注视某个变量的状态被评估的位置(例如水位、开关状态、茶壶嘴的角度)。这本质上是将当前观测与先验偏好(”水满了”“开关已按下”“壶嘴朝下”)进行比较。
核心发现:大约一半的注视承担着与直接操作物体无关的认知功能(定位未来要用的物品、检查状态变量),这说明眼动系统不仅服务于当前的动作,还在持续地为未来几个步骤做准备并验证已完成步骤的正确性。
3.5 关键结果三:对象相关动作(ORA)作为行为基本单元
论文最重要的理论贡献之一是提出了对象相关动作(Object-Related Action, ORA)的概念。
ORA 的定义:以物体为中心的感觉-运动关联集合,时间上由跳向该物体的首次眼跳(saccade)开始,到跳离该物体的最后一次眼跳结束。在每个 ORA 期间,眼睛始终保持在相关物体上(不到 5% 的注视是”无关”的),所有感觉运动设备都聚焦于同一个以物体为中心的任务。
ORA 的定量特征(跨三名受试者的平均值):
- ORA 平均持续时间:视觉部分 3.04 秒,运动部分 3.25 秒
- 每个 ORA 内的注视次数:约 7 次
- 单个注视的平均持续时长:0.42 秒(剔除 70ms 的平均眼跳时长后)
ORA 与行为层次结构的张力。认知心理学中普遍认为日常活动的记忆是按层次组织的(Brewer & Dupree, 1983; Norman & Shallice, 1986)。例如”泡茶”(Level 1) → “烧水”(Level 2) → “灌满水壶”(Level 3) → “拧开水龙头”“观察水位”“关闭水龙头”(Level 4, 即 ORA)。然而,Land 发现了一个重要的事实:更高层次的目标边界(Level 2 → Level 3)在眼动和动作的记录中没有留下任何可见的痕迹。从一个 ORA 到另一个 ORA 的过渡在行为上看起来完全一样——无论它们是否跨越了子目标的边界。
Land 的结论既大胆又精确:对象相关动作(ORA)似乎是”自然的”行为单元——它们有清晰的视觉-运动共现结构、一致的时序模式、明确的物体锚定。而更高层次的单位(”烧水”“泡茶”)可能只是事后在记忆中被施加的结构(imposed organization),而不是在执行中被实施的结构(executed architecture)。
这一点与主动推断的计算理论高度一致:每个 ORA 对应一个短时程的策略(\(\pi\)),该策略通过认知行动(注视)获取信息,通过实用行动(手部操作)改变世界状态,并持续将观察到的结果与先验偏好进行比较(检查注视),直到达到终止条件(例如”水满了”或”壶盖盖好了”),然后大脑选择下一个 ORA 策略。
3.6 补充发现与后续影响
注视目标的驱动机制:Land 特别比较了两种眼动控制假说——显著性驱动(salience-driven)模型 vs. 脚本驱动(script-driven)模型。他的数据强有力地支持后者:受试者注视物体是因为它们对任务相关,而不是因为它们”大、亮、显眼”。这与 Yarbus (1967) 的经典发现完全一致——当人被赋予不同任务时(例如”估计房间里人的年龄”vs.”记住物体位置”),面对同一张画会产生完全不同的注视模式。
视觉的工作前提:Land 列出了三个”不看什么”的规则:(1) 手本身很少被注视——目标物体被注视;(2) 已经接触的物体很少被再次注视——触觉接管;(3) 某些熟悉的操作可以完全不用视觉。这些规则揭示了多感觉模态之间的高效分工——大脑根据每个模态在当前情境下的精度,动态分配感觉权重。这再次指向了第 2.1.4 节中卡尔曼滤波的多模态融合框架。
时间尺度的普适性:ORA 约 3 秒的持续时间与多个独立研究的结果高度一致——Newell (1990) 的 2 秒认知单元、Schleidt (1988) 的 3 秒行为模态、Ballard et al. (1998) 的 1.7 秒块操作。Land 推测这一时间尺度可能反映了大脑运算的一个内在节奏——或许是与工作记忆的刷新周期或皮层 theta 振荡(4-8 Hz)相关。
四、算法与代码实现
4.1 卡尔曼滤波器(Python/NumPy)
本实现展示了一个一维位置跟踪的卡尔曼滤波器,可用于模拟(例如)大脑如何融合前向运动模型预测和带噪声的视觉观测来估计手的位置。
import numpy as np
import matplotlib.pyplot as plt
class KalmanFilter:
"""
卡尔曼滤波器实现: 贝叶斯感觉运动整合。
数学回引:
预测: x_{t|t-1} = F x_{t-1} + B u_t, P_{t|t-1} = F P_{t-1} F^T + Q
更新: K_t = P_{t|t-1} H^T (H P_{t|t-1} H^T + R)^{-1}
x_t = x_{t|t-1} + K_t (y_t - H x_{t|t-1})
P_t = (I - K_t H) P_{t|t-1}
直觉: 卡尔曼增益 K_t 是 "预测精度" 与 "观测精度" 之比。
当观测噪声 R 大 → K_t 小 → 更信任前向模型预测。
当过程噪声 Q 大 → P_{t|t-1} 大 → K_t 大 → 更信任感觉观测。
"""
def __init__(self, F, B, H, Q, R, x0, P0):
"""
参数:
F: 状态转移矩阵 (n x n)
B: 控制矩阵 (n x m)
H: 观测矩阵 (p x n)
Q: 过程噪声协方差 (n x n)
R: 观测噪声协方差 (p x p)
x0: 初始状态估计 (n,)
P0: 初始估计协方差 (n x n)
"""
self.F = F # 前向模型动力学
self.B = B # 运动指令 → 状态变化的映射
self.H = H # 状态 → 感觉观测的映射
self.Q = Q # 模型不精确性的量化
self.R = R # 传感器噪声的量化
self.x = x0 # 当前状态估计(后验均值)
self.P = P0 # 当前估计协方差(后验不确定性)
self.n = F.shape[0]
def predict(self, u=None):
"""
预测步骤 (prior update): 利用前向模型预测下一时刻的状态分布。
这一步骤对应于小脑前向模型的计算功能——
在运动指令发出后、感觉反馈到达之前,预测感觉后果。
"""
# 先验均值: x_{t|t-1} = F x_{t-1} + B u_t
self.x = self.F @ self.x
if u is not None:
self.x += self.B @ u
# 先验协方差: P_{t|t-1} = F P_{t-1} F^T + Q
# 不确定性因动力学传播和过程噪声而增大
self.P = self.F @ self.P @ self.F.T + self.Q
def update(self, y):
"""
更新步骤 (posterior update): 用感觉观测修正先验预测。
这一步骤对应于感觉皮层中预测误差驱动的信念更新:
创新 (innovation) y - H x 是预测编码中 \epsilon^{(0)} 的等价物。
"""
# 创新 (预测误差): \tilde{y}_t = y_t - H x_{t|t-1}
innovation = y - self.H @ self.x
# 创新协方差: S_t = H P_{t|t-1} H^T + R
S = self.H @ self.P @ self.H.T + self.R
# 卡尔曼增益: K_t = P_{t|t-1} H^T S_t^{-1}
# 精度加权: 高观测精度 → 大增益 → 强修正
K = self.P @ self.H.T @ np.linalg.inv(S)
# 状态更新: x_t = x_{t|t-1} + K_t \tilde{y}_t
self.x = self.x + K @ innovation
# 协方差更新: P_t = (I - K_t H) P_{t|t-1}
# 观测提供了信息 → 不确定性收缩
I = np.eye(self.n)
self.P = (I - K @ self.H) @ self.P
def get_state(self):
"""返回当前状态估计和协方差。"""
return self.x.copy(), self.P.copy()
# ========================
# 演示: 1D 位置跟踪 (手在视觉引导下的运动)
# ========================
def demo_kalman_filter():
"""
模拟场景: 手在桌面上从左向右运动。
- 前向模型 (运动指令): 每一步期望前进 1.0 单位,但有噪声 (Q=0.05)
- 视觉观测: 提供带噪声的位置测量 (R=0.5, 比模型噪声大 10 倍)
- 问题: 大脑如何融合不可靠的视觉和带噪声的运动预测?
"""
np.random.seed(42)
T = 50 # 时间步数
# 系统参数 (标量状态: 位置)
F = np.array([[1.0]]) # 单位转移 (位置不变,除非有控制输入)
B = np.array([[1.0]]) # 控制输入直接加到位置上
H = np.array([[1.0]]) # 直接观测位置
Q = np.array([[0.05]]) # 过程噪声: 运动指令的执行噪声
R = np.array([[0.5]]) # 观测噪声: 视觉位置的感知噪声
x0 = np.array([0.0]) # 初始状态
P0 = np.array([[1.0]]) # 初始不确定性 (完全不确定)
kf = KalmanFilter(F, B, H, Q, R, x0, P0)
# 生成真实轨迹和带噪声的观测
true_velocity = 1.0
true_states = []
observations = []
x_true = 0.0
for t in range(T):
# 真实动力学: x_{t+1} = x_t + v*dt + w_t
x_true = x_true + true_velocity + np.sqrt(Q[0,0]) * np.random.randn()
true_states.append(x_true)
# 带噪声的观测: y_t = x_t + v_t
obs = x_true + np.sqrt(R[0,0]) * np.random.randn()
observations.append(obs)
# 逐步运行卡尔曼滤波
estimates = []
uncertainties = []
for t in range(T):
# 控制输入: u_t = 期望速度 (1.0)
u = np.array([true_velocity])
kf.predict(u)
kf.update(np.array([observations[t]]))
x_est, P_est = kf.get_state()
estimates.append(x_est[0])
uncertainties.append(np.sqrt(P_est[0,0])) # 标准差
# 结果可视化
t_arr = np.arange(T)
estimates = np.array(estimates)
uncertainties = np.array(uncertainties)
true_states = np.array(true_states)
observations = np.array(observations)
fig, axes = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
# 上图: 真实轨迹 vs. 观测 vs. 估计
ax = axes[0]
ax.plot(t_arr, true_states, 'k-', linewidth=1.5, label='True position')
ax.scatter(t_arr, observations, s=15, c='red', alpha=0.5,
label='Noisy observation (visual)')
ax.plot(t_arr, estimates, 'b-', linewidth=1.5, label='Kalman estimate')
ax.fill_between(t_arr,
estimates - 2*uncertainties,
estimates + 2*uncertainties,
alpha=0.2, color='blue', label='95% confidence')
ax.set_ylabel('Position')
ax.legend(fontsize=8, loc='upper left')
ax.set_title('Kalman Filter: Bayesian Sensorimotor Integration')
# 下图: 估计误差 |x_est - x_true| vs. 观测误差 |obs - x_true|
ax = axes[1]
est_error = np.abs(estimates - true_states)
obs_error = np.abs(observations - true_states)
ax.plot(t_arr, obs_error, 'r-', alpha=0.4, label='|observation error|')
ax.plot(t_arr, est_error, 'b-', linewidth=1.5, label='|estimation error|')
ax.set_xlabel('Time step')
ax.set_ylabel('Absolute error')
ax.legend(fontsize=8)
ax.set_title('Error Comparison: Kalman estimate consistently beats raw observation')
plt.tight_layout()
plt.savefig('kalman_demo.png', dpi=150, bbox_inches='tight')
print(f"Mean |observation error|: {obs_error.mean():.3f}")
print(f"Mean |estimation error|: {est_error.mean():.3f}")
print(f"Improvement: {(1 - est_error.mean()/obs_error.mean())*100:.1f}%")
return fig
# 取消注释以运行
# demo_kalman_filter()
4.2 预测编码网络(Python/PyTorch)
以下实现基于 Rao & Ballard (1999) 的两层预测编码网络。网络接收带噪声的图像块作为感觉输入,通过变分自由能的梯度下降,同时进行推断(更新隐藏状态)和学习(更新生成权重)。
import torch
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
class PredictiveCodingLayer(nn.Module):
"""
单层预测编码模块。
每层维护:
- 生成权重 W (自上而下, 从高层生成低层预测)
- 隐藏状态的变分均值 mu (通过梯度下降推断)
- 预测误差 epsilon (自下而上传播)
数学回引 (见第 2.2.4 节):
\epsilon^{(0)} = y - f^{(0)}(\mu^{(1)}) -- 感觉层预测误差
\epsilon^{(1)} = \mu^{(1)} - f^{(1)}(\mu^{(2)}) -- 隐藏层预测误差
d\mu^{(i)}/dt \propto W^{(i-1)T} \epsilon^{(i-1)} - \epsilon^{(i)}
\Delta W^{(i)} \propto \epsilon^{(i)} \cdot g(\mu^{(i+1)})^T
"""
def __init__(self, input_dim, hidden_dim, nonlinearity=True):
super().__init__()
# 生成权重: 从高层 hidden_dim → 低层 input_dim
self.W = nn.Parameter(torch.randn(input_dim, hidden_dim) * 0.01)
self.b = nn.Parameter(torch.zeros(input_dim))
self.nonlinearity = nonlinearity
def generate(self, h_above):
"""自上而下的生成 (预测): \hat{h}_{below} = f(W h_{above} + b)"""
z = h_above @ self.W.T + self.b
if self.nonlinearity:
return torch.tanh(z)
return z
def prediction_error(self, h_below, h_above):
"""
计算该层的预测误差: epsilon = h_below - generate(h_above)
这是驱动所有更新的核心信号。
"""
pred = self.generate(h_above)
return h_below - pred
class PredictiveCodingNetwork(nn.Module):
"""
两层预测编码网络 (Rao & Ballard, 1999)。
架构:
感觉输入 y ∈ R^d
↓ (生成映射 f^{(0)}, 权重 W_0)
V1 隐藏状态 h1 ∈ R^n1 ← 预测误差 ε_0
↓ (生成映射 f^{(1)}, 权重 W_1)
V2 隐藏状态 h2 ∈ R^n2 ← 预测误差 ε_1 (默认先验 = 0)
推断: 通过梯度下降更新 h1, h2 以最小化变分自由能。
学习: 通过梯度下降更新 W_0, W_1 以最小化变分自由能。
"""
def __init__(self, input_dim, hidden1_dim, hidden2_dim):
super().__init__()
self.layer0 = PredictiveCodingLayer(input_dim, hidden1_dim) # V2 → V1
self.layer1 = PredictiveCodingLayer(hidden1_dim, hidden2_dim) # prior → V2
def forward(self, y, n_inference_steps=20, lr_inference=0.05):
"""
完整的前向传播: 推断 + 生成。
参数:
y: 感觉输入 (batch_size, input_dim)
n_inference_steps: 推断迭代次数 (E-step)
lr_inference: 推断学习率
返回:
h1, h2: 推断后的隐藏状态
errors: 各层的预测误差
"""
batch_size = y.shape[0]
# 初始化隐藏状态为 0 (相当于先验)
h1 = torch.zeros(batch_size, self.layer0.W.shape[1], device=y.device)
h2 = torch.zeros(batch_size, self.layer1.W.shape[1], device=y.device)
# 变分推断: 通过梯度下降更新 h1, h2 (E-step 的神经等价)
# 不通过计算图追踪此循环的梯度 (推断是迭代过程)
for step in range(n_inference_steps):
# --- 自上而下生成预测 ---
pred_h1 = self.layer1.generate(h2) # V2 → V1 预测
pred_y = self.layer0.generate(h1) # V1 → 感觉预测
# --- 计算预测误差 ---
eps_0 = y - pred_y # 感觉层预测误差
eps_1 = h1 - pred_h1 # 隐藏层预测误差
# --- 梯度下降更新 h1 ---
# dF/dh1 = -eps_0 * df0/dh1 + eps_1
# 对于 tanh: df0/dh1 = (1 - tanh^2) 的链式法则已由 autograd 处理
# 这里用简化版本: 假设生成函数近似线性
# Rao & Ballard 的实现: h1 ← h1 + lr * (W0^T eps_0 - eps_1)
grad_h1 = (eps_0 @ self.layer0.W) - eps_1
h1 = h1 + lr_inference * grad_h1
# --- 梯度下降更新 h2 ---
# dF/dh2 = -eps_1 * df1/dh2 + (h2 - 0) (0 = 先验)
grad_h2 = (eps_1 @ self.layer1.W) - h2
h2 = h2 + lr_inference * grad_h2
# 最终预测误差 (用于学习阶段 M-step)
pred_h1_final = self.layer1.generate(h2)
pred_y_final = self.layer0.generate(h1)
eps_0_final = y - pred_y_final
eps_1_final = h1 - pred_h1_final
return h1, h2, [eps_0_final, eps_1_final]
def learning_step(self, y, lr_weight=1e-4):
"""
学习步骤 (M-step): 用推断后的预测误差更新生成权重。
更新规则 (参见第 2.2.4 节):
Delta W^{(0)} = lr * eps_0 * g(h1)^T -- Hebbian-like
Delta W^{(1)} = lr * eps_1 * g(h2)^T
"""
h1, h2, errors = self.forward(y)
eps_0, eps_1 = errors
# 积累梯度
# dF/dW0 = -eps_0 * h1^T (因为 pred_y = W0 h1, d(pred_y)/dW0 = h1)
grad_W0 = -(eps_0.T @ h1) / y.shape[0]
# dF/dW1 = -eps_1 * h2^T
grad_W1 = -(eps_1.T @ h2) / y.shape[0]
with torch.no_grad():
self.layer0.W -= lr_weight * grad_W0
self.layer1.W -= lr_weight * grad_W1
# 计算变分自由能作为损失 (简化版: 预测误差平方和的加权平均)
loss = (eps_0.pow(2).sum() + eps_1.pow(2).sum()) / y.shape[0]
return loss.item()
# ========================
# 演示: 带噪声的 MNIST 图像上的预测编码
# ========================
def demo_predictive_coding():
"""
用两层预测编码网络处理带高斯噪声的 MNIST 数字图像。
网络的目标:
1. 推断隐藏状态 h1, h2 (E-step) —— 感知
2. 学习生成权重 W0, W1 (M-step) —— 学习
3. 最小化重建误差 —— 通过变分自由能梯度下降
"""
import torchvision
import torchvision.transforms as transforms
torch.manual_seed(42)
# 加载 MNIST
transform = transforms.Compose([transforms.ToTensor()])
dataset = torchvision.datasets.MNIST(
root='./data', train=True, download=True, transform=transform
)
loader = torch.utils.data.DataLoader(dataset, batch_size=64, shuffle=True)
# 网络参数
input_dim = 28 * 28 # 784 像素
hidden1_dim = 100 # V1-like
hidden2_dim = 30 # V2-like (瓶颈层, 强制压缩表示)
pcn = PredictiveCodingNetwork(input_dim, hidden1_dim, hidden2_dim)
optimizer = torch.optim.Adam(pcn.parameters(), lr=1e-3)
n_epochs = 5
losses = []
for epoch in range(n_epochs):
epoch_loss = 0.0
for batch_idx, (images, _) in enumerate(loader):
# 添加噪声: 模拟感觉输入的不确定性
noisy_images = images + 0.3 * torch.randn_like(images)
noisy_images = torch.clamp(noisy_images, 0., 1.)
y = noisy_images.view(-1, input_dim)
# 学习步骤: 推断 + 权重更新
loss = pcn.learning_step(y, lr_weight=1e-4)
epoch_loss += loss
avg_loss = epoch_loss / len(loader)
losses.append(avg_loss)
print(f"Epoch {epoch+1}/{n_epochs}, Avg Loss = {avg_loss:.4f}")
# 可视化重建
test_images, _ = next(iter(loader))
test_noisy = test_images + 0.3 * torch.randn_like(test_images)
test_noisy = torch.clamp(test_noisy, 0., 1.)
y_test = test_noisy.view(-1, input_dim)
with torch.no_grad():
h1, h2, errors = pcn.forward(y_test)
reconstruction = pcn.layer0.generate(h1)
# 绘制: 原始 vs 噪声 vs 重建
fig, axes = plt.subplots(3, 8, figsize=(12, 5))
for i in range(8):
axes[0,i].imshow(test_images[i,0], cmap='gray')
axes[0,i].axis('off')
axes[1,i].imshow(test_noisy[i,0], cmap='gray')
axes[1,i].axis('off')
axes[2,i].imshow(reconstruction[i].view(28,28), cmap='gray')
axes[2,i].axis('off')
axes[0,0].set_title('Original', fontsize=8)
axes[1,0].set_title('Noisy input', fontsize=8)
axes[2,0].set_title('PCN reconst.', fontsize=8)
plt.suptitle('Predictive Coding: Denoising via Hierarchical VI')
plt.tight_layout()
plt.savefig('predictive_coding_demo.png', dpi=150, bbox_inches='tight')
# 绘制学习曲线
fig2, ax = plt.subplots(figsize=(6, 3))
ax.plot(range(1, n_epochs+1), losses, 'o-', linewidth=1.5)
ax.set_xlabel('Epoch'); ax.set_ylabel('Variational Free Energy')
ax.set_title('Predictive Coding Learning Curve')
plt.tight_layout()
return fig, fig2
# 取消注释以运行
# demo_predictive_coding()
4.3 代码要点说明
卡尔曼滤波器:
predict()对应于前向模型——从上一时刻的状态和运动指令预测当前状态(小脑计算的功能等价)。update()对应于感觉修正——用预测误差(创新)修正预测(皮层预测编码机制的等价)。- 卡尔曼增益 \(\mathbf{K}_t\) 自动实现了精度加权融合:观测噪声大时,\(\mathbf{R}\) 大 \(\to\) \(\mathbf{S}\) 大 \(\to\) \(\mathbf{K}\) 小 \(\to\) 更多地信任预测。
- 演示脚本展示了卡尔曼估计的误差始终低于原始观测误差——这正是大脑融合多种信息源、降低不确定性的数学机制。
预测编码网络:
forward()实现了变分推断的 E-step:通过多步梯度下降更新隐藏状态 \(\boldsymbol{\mu}^{(1)}\) 和 \(\boldsymbol{\mu}^{(2)}\)。learning_step()实现了学习 M-step:用推断后的预测误差更新生成权重。- 两层瓶颈结构(784 → 100 → 30)迫使网络学习压缩的生成表示——高层 V2(30 维)必须捕获图像的本质结构才能重建低层 V1 和感觉输入。
- 关键机制:自顶向下的预测(
generate())与自底向上的预测误差(prediction_error())之间的双向信息流。
五、核心 Takeaway 与延伸阅读
5.1 五个核心洞察
-
“自动化”是错觉,而非现实。Land 茶实验最深刻的教训是:我们称之为”自动行为”的东西,仍然包含着一套完整的、每秒 2-3 次的精确视觉监控系统。只是这套监控系统在意识层面是完全不可见的。这对机器人学有直接启示:即使在”自动”执行任务的机器人中,持续的多模态感觉监控和信息缓冲也是必须的,不应被省略。
-
视觉是前瞻性的(proactive),而非反应性的(reactive)。眼睛领先手约半秒,并在手完成当前动作前已跳转到下一个目标。这表明视觉系统不是在被动地记录场景,而是在主动地、前瞻性地为即将到来的动作获取信息。对于机器人视觉系统,这意味着跟踪(tracking)的范式应当让位于预测性注视(predictive gaze)的范式——将视觉注意力定向到任务将需要的下一个位置,而非仅仅跟踪正在被操作的物体。
-
预测编码是大脑的通用计算语言。从 Rao & Ballard 的皮层预测编码到 Friston 的自由能原理,一个统一的图景正在浮现:大脑的多层级架构实现了分层变分推断——每一层尝试预测下一层的活动,预测误差向上传播以修正高层表征。卡尔曼滤波是该框架在线性高斯系统中的精确解析形式;预测编码是非线性、分层版本的推广;主动推断则将行动纳入该框架。
-
精度加权是多感觉运动整合的核心机制。卡尔曼增益和预测编码中的精度矩阵都实现了一个相同的计算原理:根据每个信息源的可信度,动态调整其在信念更新中的权重。Land 实验中视觉-触觉的精确分工(手接触物体后视觉移开,触觉接管)为这一机制提供了生动的行为证据。
-
认知行动(Epistemic Action)是具身智能的基本操作。Land 的四类注视功能——定位、指引、导向、检查——约一半都是为获取信息而非直接实现物理目标。在主动推断框架中,这些认知行动的期望信息增益被形式化为期望自由能中的认知价值项。对机器人来说,这意味着规划不仅应考虑”什么动作能到达目标”,还应考虑”什么动作能最优地减少我的不确定性”。
5.2 开放问题与研究方向
- 如何将预测编码从视觉推广到多模态感觉运动学习? Rao & Ballard (1999) 的框架仅处理静态视觉输入。将触觉、本体感觉、前庭感觉等纳入同一预测编码层级是一个开放问题。
- 小脑前向模型的深度神经网络实现:能够学习非线性前向动力学的循环神经网络(LSTM, GRU, Mamba)是否可以视为小脑前向模型的计算等价物?如何将爬行纤维的”预测误差作为教学信号”机制融入现代深度学习?
- 主动推断的计算可扩展性:期望自由能在高维连续状态-动作空间中的精确计算尚不可行。变分推断和蒙特卡洛采样方法的结合是当前活跃的研究方向。
5.3 延伸阅读
-
Rao, R. P. N., & Ballard, D. H. (1999). Predictive coding in the visual cortex: a functional interpretation of some extra-classical receptive-field effects. Nature Neuroscience, 2(1), 79-87. — 预测编码的开山之作,首次将视觉皮层的”非经典感受野效应”解释为分层预测编码的推断动力学。
-
Friston, K. (2010). The free-energy principle: a unified brain theory? Nature Reviews Neuroscience, 11(2), 127-138. — 自由能原理的综述,从物理学的必要性和生物学的合理性出发,构建统一的大脑理论。
-
Wolpert, D. M., Miall, R. C., & Kawato, M. (1998). Internal models in the cerebellum. Trends in Cognitive Sciences, 2(9), 338-347. — 系统阐述了小脑作为内部模型(前向模型和逆向模型)的计算理论,Marr-Albus-Ito 模型的现代版本。
-
Friston, K., FitzGerald, T., Rigoli, F., Schwartenbeck, P., & Pezzulo, G. (2017). Active inference: a process theory. Neural Computation, 29(1), 1-49. — 主动推断的完整形式化,包括期望自由能、策略选择和认知行动的数学框架。
-
Wolpert, D. M., & Flanagan, J. R. (2001). Motor prediction. Current Biology, 11(18), R729-R732. — 简洁地阐述了运动预测在感觉运动控制中的多种角色:状态估计、感觉衰减(sensory attenuation)、运动规划。
六、练习与思考
基础题
-
卡尔曼增益的直觉:推导卡尔曼增益 \(\mathbf{K}_t = \mathbf{P}_{t\vert t-1}\mathbf{H}^\top(\mathbf{H}\mathbf{P}_{t\vert t-1}\mathbf{H}^\top + \mathbf{R})^{-1}\)。分别讨论当 (a) \(\mathbf{R} \to 0\), (b) \(\mathbf{R} \to \infty\), (c) \(\mathbf{P}_{t\vert t-1} \to 0\), (d) \(\mathbf{P}_{t\vert t-1} \to \infty\) 时,增益的行为及其物理含义。在 Land 茶实验中,什么情境对应 \(\mathbf{R}\) 小(视觉可信)?什么情境对应 \(\mathbf{R}\) 大(视觉不可信)?
-
预测编码的推断动力学:考虑一个两层线性预测编码网络,其中 \(f^{(0)}(\mathbf{h}^{(1)}) = \mathbf{W}^{(0)}\mathbf{h}^{(1)}\) 且 \(f^{(1)}(\mathbf{h}^{(2)}) = \mathbf{W}^{(1)}\mathbf{h}^{(2)}\)。写出变分自由能 \(\mathcal{F}\) 关于 \(\mathbf{h}^{(1)}\) 的梯度,并验证在推断的固定点(\(\partial\mathcal{F}/\partial\mathbf{h}^{(1)} = 0\)),后验均值 \(\boldsymbol{\mu}^{(1)}\) 满足精度加权形式。
-
主动推断与信息获取:期望自由能 \(G(\pi) = -\mathbb{E}_{q(\mathbf{o}\vert \pi)}[\ln p(\mathbf{o}\vert C)] - \mathbb{E}_{q(\mathbf{o}\vert \pi)}[D_{KL}[q(\mathbf{s}\vert \mathbf{o},\pi) \| q(\mathbf{s}\vert \pi)]]\) 的第二项是认知价值。解释这一项为什么衡量”信息获取”。在 Land 实验中,”定位(locate)注视”和”指引(direct)注视”的认知价值在量级上有什么差异?为什么?
进阶题
-
扩展卡尔曼滤波仿真:修改 4.1 节的卡尔曼滤波器以适应非线性观测模型,例如 \(\mathbf{y}_t = \text{arctan}(\mathbf{x}_t) + \mathbf{v}_t\)(模拟眼睛在周边视野中的位置编码压缩)。比较线性 KF 和 EKF 在状态估计误差上的差异。这个差异对模拟大脑周边视野与中央凹视野的感觉精度差异有什么启示?
-
预测编码与反向传播的关系:Whittington & Bogacz (2017) 证明了在某些条件下,预测编码的推断-学习动力学可以在数学上等价于反向传播(backpropagation)。在你的预测编码网络实现中,验证:当推断步骤足够多时,权重更新方向是否逼近标准反向传播给出的梯度。这一等价性对理解大脑如何进行信用分配(credit assignment)有何启示?
-
设计一个机器人主动注视系统:基于 Land 的四类注视功能(定位/指引/导向/检查),设计一个机器人视觉注意系统的算法框架。该系统需要自主决定”什么时候看什么”。将你的框架形式化为一个部分可观测马尔可夫决策过程(POMDP),并讨论其与主动推断中期望自由能最小化的关系。
研究级思考题
-
Land 发现更高层次的行为单位(Level 2/3 的子目标)在眼动和动作记录中没有留下可见的边界痕迹,但 Schwartz et al. (1991, 1995) 发现额叶损伤患者恰恰在这些层次上表现出”动作组织紊乱”(action disorganization)。如何协调这两个发现?额叶在自动化行为的执行层级中到底扮演什么角色——它是在实时”编排”子目标的切换,还是在”编译”子目标序列为不可分割的单位?
-
自由能原理与强化学习的统一:最近的文献(如 Tschantz et al., 2020; Millidge, 2020)尝试将主动推断与强化学习统一——将累积奖励重新解释为未来观测与先验偏好之间的 KL 散度。讨论这种统一的优势与局限。在什么条件下,最大化期望奖励等价于最小化期望自由能?在什么条件下它们会分道扬镳?
引用说明: 本章的神经科学内容基于 Land et al. (1999), Rao & Ballard (1999), Friston (2010), Wolpert et al. (1998), Marr (1969), Albus (1971), Ito (1984) 等经典文献;术语”自由能原理”和”主动推断”源自 Karl Friston 及合作者的工作;卡尔曼滤波源自 Kalman (1960)。所有数学推导均为作者独立完成,所有代码为原创实现。分析是否与论文原文一致,建议读者直接阅读原始文献。