想象你是一位舞蹈新手,想学会老师的招牌动作。老师在你面前跳了八遍,每一遍节奏略有不同、手的幅度有大有小、结尾还总差半拍。如果直接照着某一遍模仿,你会学到太多偶然的“歪扭”;如果把八遍逐帧平均,动作又会糊成一团。真正聪明的做法是:先看清构成这段舞蹈的“关键姿势”——起势、展臂、转体、收势——再在每一拍上推断出最接近这些姿势、又平滑连贯的动作。 这正是 GMM/GMR 技能编码在做的事。GMM(高斯混合模型)相当于从多次演示中“提炼关键姿势”,把一条条轨迹归纳为若干簇高斯分布;GMR(高斯混合回归)相当于“每拍即时编舞”,在任意时刻从学过的高斯簇中推算最合理的位姿。两者结合,让机器人能从人类示范中学会一项“技能”,而不是死记一条轨迹。 本文以舞蹈示教为线索,带你走完“采集示教 → 时间对齐 → GMM 建模 → EM 参数估计 → 分量数量选择 → GMR 轨迹生成 → 技能应用”的完整链路。读完你会发现,机器人学动作,和人类学跳舞,其实是同一件事。
对 AI 从业者而言,理解 GMM/GMR 意味着掌握一套“从演示中提炼概率化技能”的建模范式:它不只是机器人模仿学习的核心工具,其“混合模型 + 条件回归”的思想在运动生成、人机交互领域同样适用,是构建可泛化机器人系统的必备技能。
可视化演示
演示高斯混合模型对多次示教轨迹建模、高斯混合回归生成平滑动作及混合分量概率分布分析的交互式可视化。
本节配有交互动效(进入视口后自动加载,约 3KB)。
GMM示教轨迹建模 多次示教轨迹经时间对齐后用GMM拟合分布 高斯分量沿时间轴捕获轨迹的空间变异 p(x|t) = Σ πk N(x|μk,Σk) GMM从示教数据中学习运动的概率分布特征
示教轨迹采集
舞蹈老师为同一支舞示范八遍,每遍节奏快慢不一、手的幅度有大有小。如果想真正学会,学徒第一件事不是急着模仿,而是“对齐”:把八遍动作拉到同一个节拍上,才能逐拍比较老师这一拍通常摆出什么姿势。若不对齐,把第 3 秒的动作硬跟另一遍 2.8 秒的动作放在一起比,原本清晰的手位会被时序错位糊成一团,后面的统计建模就全乱了。
机器人学技能也是同理。工程师先让人操作机械臂把同一任务——比如“把杯子从 A 点端到 B 点”——示范五到十次,并记录轨迹。记录既可以在关节空间(各关节角随时间变化),也可以在任务空间(末端位姿随时间变化)。由于每次示范的节奏、路径都有扰动,轨迹长短不一、速度各异,直接叠加平均只会得到模糊的“重影”。所以采集之后的第一件事,就是用动态时间规整(DTW)把各条轨迹对齐到统一时间轴。DTW 不要求两条轨迹逐帧对齐,而是允许时间轴被局部拉伸或压缩,找到“语义上对应”的点对——就像把老师慢动作里的每一拍,都映到正常速度演示的对应拍上。其核心是一个动态规划递推式:
对齐之后还要做滤波和重采样:用低通滤波抹掉传感器的高频毛刺,再把轨迹重新采样到统一密度。到此,八遍舞蹈终于落在同一个节拍上,每一拍都有八个版本的姿势,接下来就能统计“这一拍最像哪些关键姿势”了。
- D(i,j)(累积代价)从起点一路对齐到参考第 i 帧、示教第 j 帧的最小累计偏差,就像“前几拍对齐总共歪了多少”。
- c(i,j)(局部代价)参考第 i 帧与示教第 j 帧的欧氏距离,衡量这两帧“姿势差多远”。
- min{……}(三种走法)分别对应参考前进、示教前进、二者同时前进,即允许时间轴被拉伸或压缩。
高斯混合模型
一段舞蹈可以分解成几个“关键姿势”:起势、展臂、转体、收势。老师整段舞蹈的任何一帧,其实都是这几个姿势的某种“混合”——转体的前一刻略带展臂,收势时又残留转体的惯性。GMM(高斯混合模型)正是把这种直觉数学化:它把对齐后的轨迹数据(时间 + 位姿)看成 K 个高斯分量的加权混合,每个分量就是一个“关键姿势”。
每个高斯分量带三样东西。均值 μ_k 描述该姿势的“典型模样”(典型时刻加典型位姿);协方差 Σ_k 描述该姿势的“容许变化”——手可以抬高一点或压低一点,变化的方向和幅度全在矩阵里;混合权重 π_k 描述该姿势在整段舞蹈中的“出镜率”。K 个分量组合起来,就能回答:在任意时刻、任意位姿上,一个轨迹点出现的概率有多大。
当 GMM 拟合完成,成百上千个轨迹点就被浓缩成了 K 个关键姿势。舞蹈的“骨架”被提取出来了,接下来要做的,是精确地估计这具骨架的每个关节——这正是 EM 算法的用武之地。
- x(数据点)对齐后的一条轨迹点,通常由时间与位姿拼接而成。
- K(分量个数)关键姿势的数量,是建模前需要人为选定的超参数。
- π_k(混合权重)第 k 个姿势在整段动作中的占比,所有权重之和为 1。
- N(x|μ_k, Σ_k)(多元高斯密度)以 μ_k 为中心、Σ_k 为散布的高斯分布,给出“在这个姿势下出现 x 的概率”。
EM参数估计
知道老师有四个关键姿势,但“每个姿势的标准样子和允许晃动的范围”是多少?学徒需要反复比对:先凭感觉划个大概,然后逐帧判断“这一帧更像起势还是展臂”,再根据判断结果微调姿势模板,如此循环往复。这就是 EM(期望最大化)算法的思路:E 步与 M 步交替,像学徒对照练习一样,一圈圈把姿势模板磨准。
E 步是“判断归属”。固定当前的姿势模板,计算每个轨迹点 x_i 属于第 k 个姿势的责任度 γ_ik,也就是后验概率——“这一帧属于每一个关键姿势的程度”:
M 步是“更新模板”。拿所有帧的责任度当权重,重新计算每个姿势的均值和协方差:
E 步和 M 步交替执行,每一轮迭代后模型对数据的解释能力只会更好、不会更差。几十轮后,姿势模板收敛——学徒终于“读懂”了每个关键姿势的精确定义。需要提醒的是,EM 的目标函数不是凸的,对初始值敏感,工程上通常随机初始化多组、取似然最高的一组,避免困在糟糕的“局部最优”里。
- 分子 Σγx(加权求和)所有点按责任度加权求和,离该姿势越近的点权重越大。
- 分母 Σγ(归一化)责任度总和,把上式变成“加权平均”而不是简单的累加。
- 协方差更新每个点相对新均值的偏差平方,再按责任度加权求平均,刻画这个姿势的“活动范围”。
分量数量选择
K 到底选几个?选少了,两个不同的关键姿势被揉成一团,动作细节丢失;选多了,老师甩头发的小习惯也被当成必学动作,换个舞台就露馅。这是模型复杂度与拟合能力之间的权衡,统计上常用信息准则来定。BIC(贝叶斯信息准则)在“拟合优度”之外加了一项“复杂度惩罚”:
实际操作是:把不同 K 的模型分别用 EM 拟合,算出各自的 BIC,取最小的那个 K。同理还有 AIC,只是把惩罚项换成 2m。选好 K,就完成了“用最少的姿势讲清楚整段舞蹈”,为下一步的轨迹生成奠定基础。
- L(最大似然)模型在数据上能达到的最大似然值,衡量拟合好坏。
- -2lnL(拟合项)似然越大该项越小,代表模型解释数据越充分。
- m(自由参数个数)K 个高斯分量的均值、协方差、权重总计的参数数量,K 越大 m 越大。
- m ln N(惩罚项)随 K 增大而增长的惩罚,专门抑制分量过多导致的过拟合。
GMR轨迹生成
关键姿势已经就位,该正式跳一遍了。问题是:某一时刻 t 到底该摆什么姿势?GMR(高斯混合回归)的做法是:把每个高斯分量切成“时间部分”和“位姿部分”,然后求“给定时间 t 时位姿的条件分布”。
对第 k 个分量,把均值写成 μ_k = [μ_t; μ_o],协方差按时间与位姿分块为 Σ_tt、Σ_to、Σ_ot、Σ_oo。给定当前时刻 t,该分量下的条件期望为:
与此同时,条件协方差刻画了这一时刻位姿的不确定性:
沿着整段时间轴逐点计算条件期望,就得到一条平滑、连续、贴合示教风格的轨迹。机械臂照着这条轨迹运动,动作既不会生硬,也不会把演示中的小抖动照单全收。
- Σ_oo(位姿协方差)该姿势位姿部分的原始变化范围。
- Σ_ot Σ_tt^{-1} Σ_to(可解释项)时间能解释掉的位姿变化,把它从总变化里减去。
技能编码应用
学会一段舞,只是开始。换一个舞台、加一个障碍、配合一位搭档,都需要临场调整。GMM/GMR 编码出的技能,恰好是“概率化的骨架”,天然适合泛化。实际推理时,机器人要综合所有关键姿势:在时刻 t,每个姿势被“激活”的程度不同,用一个归一化的激活权重 h_k(t) 表示:
最终输出,是所有分量的条件期望按激活权重融合:
这套编码技能可以落地到许多场景:机械臂示教复现(把老师几遍示范浓缩成稳定技能)、动态环境适应(检测到障碍时把轨迹在时间轴上平移并重新回归)、人机协作(从交互力中估计新目标点并实时调整)。至此,一段舞真正变成了机器人自己的“肌肉记忆”。
- h_k(t)(激活权重)时刻 t 上第 k 个关键姿势被启用多少。
- 括号内(条件位姿)第 k 个姿势在时刻 t 下的条件期望位姿。
AI 应用场景
场景1:工业装配线的“手把手”示教编程
阶段:模仿学习 / 技能编码与轨迹生成
解决的问题:传统示教编程靠工程师在示教盒上逐点押坐标,耗时数小时,且来料位置一波动就得返工。GMM/GMR 把人牵引示教的几次轨迹编码成“带概率的轨迹”,自动适应位置变化,就像学徒学会的是“骨骼框架”而非某次具体的动作。
具体案例:一家 3C 电子厂,机械臂任务是把柔性排线插入连接器。工程师牵着机械臂完成 6 次插入动作(每次来料略有偏移)。系统先做 DTW 对齐,再用 GMM(K=5)编码,产线上实时用 GMR 根据当前插孔位置生成插入轨迹,一次成功率从 82% 提升到 97%。
场景2:人机协作搬运中的力顺应调整
阶段:技能泛化 / 人机交互
解决的问题:人机共同搬运大件物体时,人的节奏和用力方向随时在变,刚性轨迹会让协作显得生硬甚至危险。GMM/GMR 编码的轨迹携带协方差信息,当力传感器信号偏大时,系统可以在时间轴上局部压缩或偏置轨迹,动作依旧平滑。
具体案例:汽车总装线上,协作机器人学习“扶住车门并随工人移动”的示教轨迹。当工人脚步加快,GMR 对时间轴做局部压缩,轨迹随之加速且保持平滑,全程末端力峰值下降约 40%。
场景3:康复外骨骼的个性化运动辅助
阶段:技能迁移 / 运动生成
解决的问题:康复训练中每位患者的关节活动范围和节奏都不同,固定轨迹无法适配。治疗师引导外骨骼完成标准动作数次,GMM/GMR 提取“动作模式”,再按当前患者的关节限制实时生成个性化轨迹,相当于把老师的舞蹈改编成适合自己身形的版本。
具体案例:下肢康复外骨骼记录治疗师 5 次“抬腿-屈膝-落地”示范并编码为技能库。患者使用时,系统根据其腿长与活动度调整目标点,GMR 生成平滑屈伸轨迹,训练舒适度和依从性明显提升。
Python 演示
import numpy as np def dtw_align(ref, traj): """将一条示教轨迹对齐到参考轨迹的时间轴上""" n, m = len(ref), len(traj) cost = np.linalg.norm(ref[:, None, :] - traj[None, :, :], axis=2) D = np.full((n + 1, m + 1), np.inf) D[0, 0] = 0.0 for i in range(1, n + 1): for j in range(1, m + 1): D[i, j] = cost[i - 1, j - 1] + min(D[i - 1, j], D[i, j - 1], D[i - 1, j - 1]) i, j = n, m align_idx = [0] * n while i > 0 and j > 0: align_idx[i - 1] = j - 1 if i == 1 and j == 1: break if i == 1: j -= 1 elif j == 1: i -= 1 else: idx = np.argmin([D[i - 1, j], D[i, j - 1], D[i - 1, j - 1]]) if idx == 0: i -= 1 elif idx == 1: j -= 1 else: i -= 1 j -= 1 return traj[align_idx] def em_gmm(X, K=6, iters=80, seed=0): """EM 算法拟合高斯混合模型""" rng = np.random.default_rng(seed) N, D = X.shape pi = np.full(K, 1.0 / K) mu = X[rng.choice(N, K, replace=False)] cov = np.tile(np.eye(D) * 0.5, (K, 1, 1)) for _ in range(iters): resp = np.zeros((N, K)) for k in range(K): diff = X - mu[k] inv_cov = np.linalg.inv(cov[k]) z = np.einsum('ni,ij,nj->n', diff, inv_cov, diff) resp[:, k] = pi[k] * np.exp(-0.5 * z) / np.sqrt( np.linalg.det(cov[k])) resp /= resp.sum(axis=1, keepdims=True) + 1e-12 Nk = resp.sum(axis=0) + 1e-12 pi = Nk / N mu = (resp.T @ X) / Nk[:, None] for k in range(K): diff = X - mu[k] cov[k] = (resp[:, k][:, None] * diff).T @ diff / Nk[k] cov[k] += np.eye(D) * 1e-6 return pi, mu, cov def gmr_trajectory(t_query, pi, mu, cov): """高斯混合回归: 由时间序列生成平滑位姿轨迹""" K = mu.shape[0] out = np.zeros((len(t_query), mu.shape[1] - 1)) for idx_t, t in enumerate(t_query): num = np.zeros_like(out[0]) den = 0.0 for k in range(K): mu_t = mu[k, 0] var_t = cov[k, 0, 0] w = pi[k] * np.exp(-0.5 * (t - mu_t) ** 2 / var_t) num += w * (mu[k, 1:] + cov[k, 1:, 0] * (t - mu_t) / var_t) den += w out[idx_t] = num / (den + 1e-12) return out def main(): rng = np.random.default_rng(42) t = np.linspace(0, 1, 100) base = np.column_stack([t, np.sin(2 * np.pi * t)]) demos = [] for _ in range(8): speed = rng.uniform(0.85, 1.15) idx = np.clip(np.arange(100) * speed, 0, 99).astype(int) demos.append(base[idx] + rng.normal(0, 0.02, base.shape)) aligned = [dtw_align(demos[0], d) for d in demos] X = np.concatenate([np.column_stack([t, a]) for a in aligned], axis=0) pi, mu, cov = em_gmm(X, K=6) t_test = np.linspace(0, 1, 200) traj = gmr_trajectory(t_test, pi, mu, cov) print("生成轨迹点数:", len(traj)) print("起点:", np.round(traj[0], 3)) print("终点:", np.round(traj[-1], 3)) if __name__ == "__main__": main()
cost = np.linalg.norm(ref[:, None, :] - traj[None, :, :], axis=2)用广播计算参考与示教轨迹的逐点距离矩阵,作为 DTW 的局部代价。D[i, j] = cost[i - 1, j - 1] + min(D[i - 1, j], D[i, j - 1], D[i - 1, j - 1])DTW 累积代价递推,允许时间轴拉伸或压缩。z = np.einsum('ni,ij,nj->n', diff, inv_cov, diff)用爱因斯坦求和高效计算每个点的马氏距离平方。resp[:, k] = pi[k] * np.exp(-0.5 * z) / np.sqrt(np.linalg.det(cov[k]))E 步计算未归一化的责任度。resp /= resp.sum(axis=1, keepdims=True) + 1e-12责任度按行归一化,让每个样本对全部分量权重和为 1。mu = (resp.T @ X) / Nk[:, None]M 步用责任度做加权平均,更新每个关键姿势的均值。w = pi[k] * np.exp(-0.5 * (t - mu_t) ** 2 / var_t)GMR 中按时刻 t 计算每个关键姿势的激活权重。num += w * (mu[k, 1:] + cov[k, 1:, 0] * (t - mu_t) / var_t)用条件期望公式合成当前时刻的位姿。
常见误区
误区我以为 GMM 学到的 K 个“关键姿势”是从示教数据里抽出来的 K 个轨迹点,就像老师八遍示范里恰好摆过的某个姿势,直接挑一个代表就行。
正解高斯分量的均值是 EM 对所有示教数据做加权平均得到的“统计代表姿势”,它通常不存在于任何一条原始轨迹中。就像舞蹈老师从不曾在一个瞬间恰好摆出“平均姿势”,但这个抽象的平均姿势恰恰是对所有示范的准确总结。如果拿真实样本点当关键姿势,会带入该次示范特有的偶然偏差。
为何常见:K-means 等硬聚类先入为主,让人误以为“中心 = 某个样本点”,忽略了 GMM 是概率生成模型,其参数是从整体分布估计出来的。
误区既然 GMM 是 K 个高斯加起来,那我把 K 设大一点,总能更好地贴合示教轨迹,动作学得更像。
正解K 太大会把示范中的偶然抖动也当成关键姿势(过拟合),生成轨迹在新场景下泛化很差;K 太小又会把不同姿势揉成一团(欠拟合)。BIC/AIC 正是用来平衡“拟合度”与“参数复杂度”的,原则是“用最少的姿势讲清楚整段舞蹈”。把老师甩头发的小习惯当成必修动作,换个舞台就露馅。
为何常见:人直觉上认为“更精细的模型 = 更好”,但忽略了机器学习里模型复杂度与泛化能力之间的此消彼长。
误区老师示范了八遍,我把每条轨迹在同一时刻取平均,噪声应该就抵消了,得到的轨迹自然平滑,何必还要 DTW 对齐?
正解八遍演示的快慢节奏不同,同一时刻对应的动作语义并不相同——第 3 秒可能是“展臂到一半”也可能是“已经开始转体”。直接平均产生的是时序错位的“重影”,而非干净的动作。DTW 先把语义对应的帧配好,再建模才有意义。时间错位是系统性偏差,不是随机噪声,平均无法消除。
为何常见:人们习惯性地认为“平均能消除随机误差”,却没意识到节奏变化带来的错位是结构性的,必须先做时间配准。
误区EM 每轮迭代似然都在上升,最后收敛了,那得到的参数应该就是全局最优的吧,直接拿它上线就行。
正解EM 只能保证收敛到似然函数的局部极大值,因为它本质上是坐标上升法作用在非凸目标上。初始值不同,收敛结果可能天差地别。工程上要对多组随机初始化分别跑 EM,取似然最高的一组。就像学徒如果一开始把“展臂”和“转体”搞混了,练得再久也可能停在错误的动作理解上。
为何常见:看到“迭代中目标函数单调不减”就误以为找到了全局最优,忽略了非凸优化中“单调上升”与“全局最优”是两回事。
面试题
Q1. GMM 中每个高斯分量的参数组是?
- A.均值、协方差与混合权重← 正确答案
- B.方差、梯度与学习速率
- C.均值、偏置与激活函数
- D.权重、动量与正则系数
答案:A。GMM 的三个参数——均值 μ、协方差 Σ、混合权重 π——就像舞蹈课上的“标准动作模板、允许晃动的幅度、这个动作出现多少回”。选项 B/C/D 混入了梯度、激活函数、动量等深度学习术语,与高斯混合模型无关。
Q2. GMM 联合分布中 K 个分量如何组合?
- A.加权求和← 正确答案
- B.逐点相乘
- C.取最大值
- D.逐个平均
答案:A。GMM 把 K 个高斯分量的概率密度按权重做加权求和,就像把舞蹈的各个关键姿势按出镜率混合成整段动作。逐点相乘(B)是贝叶斯融合的思路,取最大(C)和平均(D)都会丢失分布的形状信息。
Q3. EM 算法中 E 步计算的是哪个量?
- A.样本属于各分量的责任度← 正确答案
- B.分量两两之间的欧氏距
- C.数据集的均值和总方差
- D.相邻两次迭代的参数差
答案:A。E 步计算的是责任度 γ_ik,也就是每个轨迹点对各关键姿势的后验归属程度,就像学徒逐帧判断“这一帧更像哪个姿势”。距离矩阵、均值方差、参数差都不是 E 步的输出。
Q4. 多条示教轨迹长短不一时,应先用什么方法?
- A.动态时间规整← 正确答案
- B.线性判别分析
- C.傅里叶变换
- D.卡尔曼滤波
答案:A。示教轨迹长短不一时需要先用动态时间规整(DTW)对齐到统一时间轴,如同把节奏不同的舞蹈节拍拉到同一拍点。线性判别分析是降维分类、傅里叶变换是频域分析、卡尔曼滤波是状态估计,解决的不是同一个问题。
Q5. 选择 GMM 分量数 K 的常用准则包括?
- A.BIC 信息准则← 正确答案
- B.AIC 信息准则← 正确答案
- C.ReLU 激活函数
- D.Adam 优化器
答案:AB。BIC 和 AIC 是选择分量数 K 的标准信息准则,都在拟合度之外加入复杂度惩罚,就像“用最少姿势讲清楚整段舞蹈”。ReLU 是神经网络的激活函数,Adam 是优化器,与模型选择无关。
Q6. GMR 生成平滑轨迹的核心计算是哪个?
- A.条件期望← 正确答案
- B.最大似然
- C.贝叶斯因子
- D.梯度更新
答案:A。GMR 的核心是条件期望:给定时刻 t,按关键姿势的激活权重推算最可能的位姿。最大似然用于参数估计而非轨迹生成,贝叶斯因子用于模型比较,梯度更新是优化手段,它们都不是 GMR 生成轨迹的直接依据。
Q7. 关于 EM 算法的描述正确的有?
- A.可能陷入局部最优解← 正确答案
- B.对初始值选择很敏感← 正确答案
- C.必然找到全局最优解
- D.每次迭代似然单调不减← 正确答案
答案:ABD。EM 的目标函数非凸,只能保证收敛到局部最优(A),对初始值敏感(B),但每次迭代似然单调不减(D)。C 说“必然全局最优”是错的——这正是工程上多用几组随机初始化取最优值的原因。
Q8. GMR 中条件协方差 Σ_{oo|t} 表示什么?
- A.给定 t 时位姿的不确定度← 正确答案
- B.观测变量之间的总协方差
- C.时间方差的估计值
- D.混合权重的估计值
答案:A。条件协方差 Σ_{oo|t} 是“扣掉时间能解释的位姿变化后剩下的不确定度”,对应舞蹈里“即使看准了节拍,手仍可能抖多少”。它衡量的是给定时刻 t 时的位姿不确定性,而不是观测总协方差、时间方差或权重。
Q9. BIC 公式中的惩罚项起什么作用?
- A.抑制分量数过多导致过拟合← 正确答案
- B.提升 EM 迭代收敛速度
- C.消除轨迹中的测量噪声
- D.提高数据采集的采样率
答案:A。BIC 的惩罚项 m·lnN 随参数个数 m 增大而变大,专门抑制 K 过大导致的过拟合,就像防止把老师甩头发的小习惯也当成必学动作。它不负责加速收敛、消除噪声或提高采样率。
Q10. 相比直接平均示教轨迹,GMM/GMR 的优势有?
- A.保留姿势的不确定性信息← 正确答案
- B.生成平滑可泛化的轨迹← 正确答案
- C.完全省去时间对齐步骤
- D.可随新目标点实时调整← 正确答案
答案:ABD。GMM/GMR 保留协方差信息(A),生成平滑且可泛化的轨迹(B),并支持按新目标点实时调整(D)。但它同样需要时间对齐作为前置步骤,C 的说法不成立——对齐是建模的前提,不能被省略。