简介:《基于高斯过程的机器人模仿学习研究与实现》是一篇完整PDF格式的学术论文,面向机器人控制、机器学习及智能系统方向的研究人员与高年级学生,聚焦模仿学习中控制策略获取难的问题。资源共1个PDF文件、308KB,内容源自《北京工业大学学报》,包含摘要、引言、高斯过程回归模型构建、Braitenberg车辆仿真实验与结论等完整结构。论文利用高斯过程回归模型,以示教行为样本数据训练感知与行为间的映射关系,并将该映射作为模仿机器人的控制策略;以Braitenberg车辆为对象开展趋光模仿实验,验证了算法在多种任务环境下具备良好的适应性与有效性。目前已有116人学习,适合需要借鉴高斯过程在机器人领域应用方法、理解模仿学习从数据收集到行为再现全流程的读者参考。
1. 为什么模仿学习里要引入高斯过程回归
直接写死一段轨迹插值,是模仿学习最容易踩的坑:示教数据稍微抖动,复现出来的动作就不像人做的,更谈不上泛化到新目标点。常见做法是把示教轨迹看作带噪声的函数观测,然后用高斯过程回归去估计这条轨迹背后的分布,而不是一条确定的折线。高斯过程回归在机器人模仿学习里的价值,不是因为它“拟合能力强”,而是它能同时给出均值轨迹和置信区间,这两个输出分别对应控制信号和安全边界,正好契合机器人学习里“既要跟得紧、又不敢乱动”的约束。
本文面向的是准备用高斯过程做轨迹模仿、策略学习或动态系统建模的工程师和研究者。读者至少要对 Python 和 numpy 有基础,懂一点概率论更好。文章会从高斯过程回归在轨迹学习中的数学骨架讲起,给出可跑的 Python 实现,再补上与 DMP 结合、不确定性感知控制、仿真验证这一整套落地路径。相比行为克隆直接拟合状态到动作的映射,高斯过程作为非参数贝叶斯方法,在小样本示教、光滑性先验和在线更新三个维度上都有明显优势,这也是它在机器人学习研究中持续被用作基线的根本原因。
2. 高斯过程回归在轨迹学习中的核心原理与核函数选型
2.1 高斯过程回归的最小数学骨架
高斯过程回归要解决的问题可以这样描述:给定 N 组观测 $(x_i, y_i)$,其中 $x$ 是输入(时间或相位),$y$ 是输出(关节角度或末端位置),我们希望预测任意新输入 $x_*$ 处的输出分布。高斯过程假设函数 $f(x)$ 服从一个先验分布,任意有限个点上的函数值都满足联合高斯分布,即 $f \sim \mathcal{GP}(m(x), k(x, x'))$,其中 $m(x)$ 是均值函数(通常在轨迹学习中取零或线性函数),$k(x, x')$ 是核函数,用来刻画两个输入点之间的相关性。
在模仿学习的轨迹建模里,观测模型通常写成 $y = f(x) + \epsilon$,其中 $\epsilon$ 是独立同分布的高斯噪声,方差为 $\sigma_n^2$。给定训练数据后,新输入 $x_$ 处的预测均值 $\mu_$ 和方差 $\sigma_*^2$ 有闭式解:
$$ \mu_* = k_*^T (K + \sigma_n^2 I)^{-1} y $$
$$ \sigma_^2 = k_{**}(x_) - k_^T (K + \sigma_n^2 I)^{-1} k_$$
其中 $K$ 是训练点间的核矩阵,$k_$ 是训练点与新输入点间的核向量,$k_{**}$ 是新输入点自身的核值。第一次接触这套公式的工程师通常只关注均值 $\mu_$,但模仿学习场景里方差 $\sigma_*^2$ 才是体现“这个位置的知识掌握得怎么样”的关键。
提示:实际实现时不要直接对 $K + \sigma_n^2 I$ 求逆,应当用 Cholesky 分解求解线性方程组,数值稳定性会好一个量级,尤其在核矩阵条件数偏大的时候。
2.2 RBF 核与周期核在示教轨迹上的行为差异
核函数决定了模型对轨迹形状的归纳偏置,这是高斯过程模仿学习里最需要人工介入的地方。最常见的 RBF 核(径向基核)写作:
$$ k_{RBF}(x, x') = \sigma_f^2 \exp \left( -\frac{(x - x')^2}{2 l^2} \right) $$
其中 $l$ 是长度尺度,控制轨迹在输入轴上被看成“有多平滑”;$\sigma_f^2$ 是信号方差,控制函数值的整体幅度。RBF 核假设轨迹在相邻输入点上高度相关,远处的点几乎不影响当前预测。对关节空间轨迹、末端笛卡尔轨迹这一类连续光滑运动,RBF 核是默认首选。
但人演示动作往往带有周期性成分,比如往复磨削、摇手柄这类作业。RBF 核需要把长度尺度调到很小才能拟合周期特征,代价是方差在样本稀疏处急剧膨胀,预测变得极不稳定。这时应当改用周期核:
$$ k_{Per}(x, x') = \sigma_f^2 \exp \left( -\frac{2 \sin^2(\pi (x - x') / T)}{l^2} \right) $$
其中 $T$ 是周期。实际工程中常见做法是 RBF 核与周期核相加,构成多核模型,让模型自己通过超参优化决定两种成分的权重。
2.3 边缘似然优化与超参注入的三个陷阱
高斯过程的超参数(长度尺度 $l$、信号方差 $\sigma_f^2$、噪声方差 $\sigma_n^2$)一般不靠人工试,而是在训练集上最大化对数边缘似然:
$$ \log p(y | X, \theta) = -\frac{1}{2} y^T (K + \sigma_n^2 I)^{-1} y - \frac{1}{2} \log \det(K + \sigma_n^2 I) - \frac{N}{2} \log 2\pi $$
用 scipy 的 L-BFGS-B 或 Adam 都能做,关键是别把优化器跑崩。常见的三个陷阱分别是:噪声方差下界设为零导致过拟合,表现为预测均值穿过每一个示教点,但方差趋近于零,完全没有泛化能力;长度尺度初始化对优化结果影响极大,尤其在样本量少于 50 时,不同的初始化会收敛到不同的局部最优;核函数选型不当却想靠调参补救,比如用纯 RBF 拟合强周期轨迹,边际似然会不停给出“缩短长度尺度”的梯度,最终得到一个剧烈振荡的不合理函数。
3. 基于高斯过程的模仿学习落地实现:从示教数据到轨迹复现
3.1 数据对齐:时间规范化与重采样
示教数据的第一个麻烦是时间轴不一致。同一个动作演示三次,每次的完成时间可能相差 20%,关节角度序列长度也不相同,直接放进高斯过程回归会把时间维度弄得一团糟。常用的解法是动态时间规整(DTW)或者归一化时间轴。更规范的做法是把时间映射到 $[0, 1]$ 区间,然后统一重采样到固定长度,比如每条轨迹采 200 个点。
重采样时要注意低通滤波必须先于重采样做。示教轨迹里常有高频抖动,如果先重采样、后滤波,相当于在欠采样信号上做插值,会在轨迹里留下难以察觉的混叠误差。我的顺序是先 Butterworth 低通滤波(截止频率按采样率 1/10 左右),再做线性插值重采样到统一长度。
对于多示教轨迹,还有一个常见的预处理步骤是空间对齐。如果每次演示的起点和终点位置有微小的偏移,直接平均会造成轨迹模糊。简单做法是先做平移对齐,把每条轨迹的起点移到原点;如果末端姿态也参与学习,需要对旋转部分做归一化。这一步对后续高斯过程回归的预测精度影响显著。
import numpy as np from scipy.signal import butter, filtfilt from scipy.interpolate import interp1d def preprocess_trajectory(pos_seq, target_len=200, cutoff_ratio=0.1): # pos_seq: 形状为 (T, D) 的示教轨迹,D 为关节或笛卡尔维度 # 先设计低通滤波器,截止频率为采样率的 10% fs = len(pos_seq) b, a = butter(4, cutoff_ratio, btype="lowpass") pos_filt = filtfilt(b, a, pos_seq, axis=0) # 时间轴归一化到 [0, 1] 并重采样 old_t = np.linspace(0, 1, len(pos_filt)) new_t = np.linspace(0, 1, target_len) interp_funcs = [interp1d(old_t, pos_filt[:, d], kind="linear") for d in range(pos_seq.shape[1])] out = np.stack([interp_funcs[d](new_t) for d in range(pos_seq.shape[1])], axis=1) return out, new_t这段代码做了两件事:滤波降噪和时间轴规范化。滤波用filtfilt而不是lfilter是因为前者零相位,不引入滞后,这对轨迹复现的起点位置影响很大;重采样用线性插值是保守选择,高阶样条容易在滤波后产生过冲。
3.2 用 GPy 构建关节空间轨迹回归模型
在 Python 生态里,GPy 和 scikit-learn 都能做高斯过程回归,但做机器人轨迹学习我优先选 GPy,原因有三个:对核函数组合的表达更自然、超参优化接口更透明、对预测方差的控制更细。下面给出关节空间轨迹建模的完整代码。
import numpy as np import GPy def fit_gp_trajectory(time_vals, joint_traj, kern_choice="rbf"): # joint_traj: (N, D),D 个关节分别建 GP 模型 models = [] for d in range(joint_traj.shape[1]): X = time_vals.reshape(-1, 1) Y = joint_traj[:, d].reshape(-1, 1) if kern_choice == "rbf": kernel = GPy.kern.RBF(input_dim=1, variance=1.0, lengthscale=0.2) elif kern_choice == "rbf_periodic": kernel = GPy.kern.RBF(input_dim=1, variance=1.0, lengthscale=0.1) + \\ GPy.kern.StdPeriodic(input_dim=1, variance=0.5, lengthscale=0.1, period=0.5) noise = GPy.kern.White(input_dim=1, variance=0.01) model = GPy.models.GPRegression(X, Y, kernel + noise) model.optimize(messages=False, max_iters=500) models.append(model) return models def predict_trajectory(models, new_times): mu_cols, var_cols = [], [] for model in models: mu, var = model.predict(new_times.reshape(-1, 1)) mu_cols.append(mu.flatten()) var_cols.append(np.sqrt(var.flatten())) return np.stack(mu_cols, axis=1), np.stack(var_cols, axis=1)fit_gp_trajectory对每个关节独立建立高斯过程回归模型,核函数由variance控制信号幅度初值、lengthscale控制轨迹平滑度的初值,White核负责建模传感器噪声。optimize过程是在边缘似然上做超参搜索,不是拟合普通回归的残差。predict_trajectory返回的var是标准差,反映模型在该时刻对该关节位置的置信程度,后面做不确定性感知控制时直接消费这个量。
提示:如果某个关节角度变化很小(例如近伸直状态的肘关节),它的长度尺度会被优化到很大,导致预测方差在轨迹中段飙升。这时应当对这个关节单独设置长度尺度上界,避免过度平滑。
3.3 多示教轨迹的均值与方差融合
示教通常做多次,每次的轨迹略有不同。处理多示教数据有一个认知误区:先对轨迹逐点求平均再拟合成单条轨迹。正确的是把多条轨迹的点全部堆叠成训练集再去拟合高斯过程,让模型自己决定哪些区域可信、哪些区域分散。实现上只需把多条轨迹的时间坐标和关节数值拼接:
def concat_demonstrations(traj_list, time_list): # traj_list 中每个元素形状为 (N_i, D),time_list 对应 (N_i,) X_all = np.concatenate(time_list).reshape(-1, 1) Y_all = np.concatenate(traj_list, axis=0) return X_all, Y_all同一时刻多个示教点之间的距离越大,GP 预测方差就越大,这意味着方差本身就是在衡量“不同演示之间的不一致程度”。当演示之间存在策略性差异而不是随机噪声时,这个方差会被放大到一个不可用的量级,此时需要考虑分模式建模,而不是合并训练。判断方法很简单:看残差分布是否呈多峰形态,如果是,先把示教轨迹按 K-Means 或手工标签分成两组再分别训练。
4. 高斯过程与 DMP 结合:解决相位对齐与多示教轨迹融合
4.1 DMP 的基本结构与相位变量
高斯过程回归直接建模 $y \sim \mathcal{GP}(t)$ 有一个固有问题:时间轴作为输入时,轨迹无法自然地应对时间缩放和中间目标点修改。比如机器人需要一个更快或更慢地执行同一动作,GPR 模型需要重新训练或对时间轴做变换,而动态运动原语(DMP)把时间替换成相位变量,天然地解耦了几何轨迹与执行速度。
DMP 的典型形式分两部分:变换系统和正则系统。一维 DMP 变换系统写作:
$$ \ddot{y} = \alpha_y (\beta_y (g - y) - \dot{y}) + f(s) $$
其中 $g$ 是目标位置,$\alpha_y, \beta_y$ 是弹簧阻尼参数,保证系统收敛到目标点,$f(s)$ 是强迫项,由高斯核加权叠加而成,用来拟合示教轨迹的复杂形状。相位 $s$ 从 1 衰减到 0,控制整个运动的进度,与物理时间解耦。
通常做法是让强迫项 $f(s)$ 由高斯过程回归来拟合,而不是 DMP 原有的径向基函数加权和。
4.2 用高斯过程拟合强迫项而非原始轨迹
直接对原始轨迹做 GP 回归,得到的是“时间到位置”的映射;对 DMP 的强迫项做 GP 回归,得到的是“相位到非线性力”的映射。后者有更好的泛化性质:当目标点 $g$ 改变时,DMP 的线性吸引子部分负责引导系统到达新目标,GP 预测的强迫项负责保留示教轨迹的形状特征。
具体做法是:对每条示教轨迹先用 DMP 反推出强迫项序列 $f_{demo}(s)$,再把 $(s, f_{demo}(s))$ 作为训练集送给 GP。这样 GP 拟合的对象是去掉“弹簧阻尼动态”之后的残差形状。理论上这一步等价于让 GP 只学习轨迹的细节部分,而把稳定性和收敛性交给 DMP 的线性项保证。
def compute_forcing_term(traj_pos, traj_vel, traj_acc, g, tao, alpha_y, beta_y): # 从一段示教轨迹反推 DMP 的强迫项 # traj_pos, traj_vel, traj_acc 是时间序列,tao 是时间缩放常数 s = np.exp(-alpha_y * np.linspace(0, 1, len(traj_pos)) * tao) f = tao**2 * traj_acc - alpha_y * (beta_y * (g - traj_pos) - tao * traj_vel) mask = s > 0.05 # 相位趋近于 0 时强迫项数值不稳定,直接截断 return s[mask].reshape(-1, 1), f[mask].reshape(-1, 1)这里的关键是mask截断操作。DMP 的强迫项在相位接近 0 时趋于无穷大,无论用哪种回归方法都拟合不好,直接截断到 0.05 以上是工程共识。得到 $(s, f)$ 数据对后,按 3.2 节的方式训练 GP 模型,预测时输入期望的相位序列,得到平滑的强迫项曲线。
4.3 DMP 核心参数设置参考
| 参数 | 典型值 | 说明 |
|---|---|---|
| $\alpha_y$ | 25 | 变换系统增益,越大收敛越快;过大会导致轨迹末端速度跳变 |
| $\beta_y$ | $\alpha_y / 4$ | 阻尼比相关,取 1/4 保证临界阻尼,避免末端振荡 |
| $\alpha_s$ | 2.0 | 相位系统的衰减率,控制运动总时长 |
| 高斯核数量 | 50 - 200 | 与轨迹复杂度相关,核太少细节丢失,太多出现过拟合 |
| 时间常数 $\tau$ | 1.0 - 3.0 | 缩放执行时间,1.0 表示与示教相同速度 |
这些参数在 ROS 和机器人仿真环境里都可以直接复用,不需要针对特定机器人品牌单独调整。不过真机部署时需要注意,$\alpha_x$ 和 $\tau$ 的取值要匹配机器人底层控制器的速度限制,否则 DMP 生成的加速度指令会触发驱动器报警。
4.4 在仿真环境里验证 DMP-GP 融合效果
在 Gazebo 或基于 ROS2 的仿真环境里验证 DMP-GP 融合效果,推荐的工作流是:用 MoveIt 的规划场景接口生成示教轨迹 → 用上述代码训练 GP 强制项 → 运行时由 DMP-GP 在线生成关节指令 → 通过 JointTrajectoryController 发给仿真机器人。重点关注两类指标:目标点改变后轨迹的形状保持程度(GP 的泛化能力),以及到达目标点后的残余振荡幅度(DMP 阻尼参数是否合适)。
5. 不确定性感知的控制策略与真机部署难点
5.1 用预测方差调节执行速度与安全距离
GP 输出的方差在模仿学习里不是用来好看的,它可以直接参与控制决策。一个可靠的保守策略是:预测方差的平方根被当作当前时刻轨迹信任度的倒数,方差越大,执行器速度越小。这种思路避免在示教数据稀疏的区域高速执行,防止产生碰撞风险。
实现时通常的做法是在 DMP 的相位更新率上乘一个不确定性系数。具体公式可以设计为 $\dot{s} = \alpha_s \cdot s / (1 + \lambda \sigma^2(s))$,其中 $\sigma^2(s)$ 是 GP 在相位 s 处预测的方差,$\lambda$ 是调节强度的超参数。这样在示教密集处维持原速,在示教稀疏处自动减速。与固定速度执行相比,这个策略在复杂曲面上的安全性高很多,因为它不会在知识空白区盲目全速前进。
5.2 在线更新与计算量控制
高斯过程回归的推理复杂度是 $O(N^3)$,训练一个 200 点的轨迹模型在普通工控机上耗时约 0.5 秒,这在实际控制周期(通常 1ms 到 10ms)里完全不可接受。因此在线更新不能每步都做,而是采用滑窗策略:只在检测到大幅误差积累时重新训练模型,并且把训练限制在最近的 M 个数据点上(M 一般取 100 到 300)。
机器人导航、路径规划这类任务中常提到“资源受限机器人”问题,高斯过程的计算量恰好是其中典型:预测阶段复杂度是 $O(N)$,其中 N 是训练点数量,这在树莓派级别的嵌入式平台上仍然偏重。一种可行的压缩手段是使用稀疏高斯过程,让模型只用诱导点来近似完整训练集,预测速度可以快一个数量级。
5.3 真机部署的三个关键检查点
真机部署与仿真最大的区别在于传感器噪声和通信延迟。噪声层面,编码器读数的高频抖动会直接进入强迫项反推过程,导致 GP 学习到错误的细节。解决方法是把反推强迫项之前的轨迹做零相位滤波,与 3.1 节相同的处理逻辑。延迟层面,关节控制器通常是位置或速度模式,DMP-GP 生成的目标指令需要平滑后才能发给底层,直接在目标位置后串联一阶低通滤波器就能避免指令跳变。
协作机器人的安全策略可以更直接地利用 GP 方差:当预测方差超过阈值时,机器人自动降速或停机。这一策略的思想是利用模型不确定性作为安全边界,实现算法层面的协作安全。部署前建议在两个场景做测试:一是目标点大幅改变,二是执行过程中人为拖动机械臂偏离轨迹。这两个场景能检验系统能否在方差激增时作出正确反应。
6. 模型验证的 3 个关键指标与可视化排错
6.1 位置误差、最终点误差与方差校准度
衡量一个 GP 模仿学习系统是否可用,至少要看三个指标。归一化位置 RMSE 是最基本的复现精度指标,计算方式是将预测轨迹与示教轨迹对齐后逐点计算 RMSE,再除以轨迹的空间尺度完成归一化。最终点误差单独列出来,是因为 DMP-GP 系统的末端收敛性是线性吸引子主导的,它和轨迹细节质量关系不大,单独观察能帮助定位问题出在 GP 拟合还是 DMP 参数上。
方差校准度是我国内团队经常忽略但对决策至关重要的指标。简单版本是:统计预测轨迹落在均值 ± 1 倍标准差区间内的示教数据比例,理想值应当在 68% 左右。如果这个比例远低于 68%,说明 GP 的方差过于乐观;如果远高于 68%,说明方差不必要地保守,会导致速度放缓和安全停机过于频繁。
6.2 残差分析定位核函数与超参问题
可视化排错的顺序一般不先看均值轨迹,而是先看残差。将每个示教点的真实值与 GP 预测均值相减,得到残差序列,然后按输入时间轴绘制。如果残差序列有明显的正弦形状,说明周期成分未被核函数捕捉,应该在核函数中加入周期项;如果残差集中在轨迹的某一段连续区域,说明该区域长度尺度设置不合理,局部细节无法被平滑假设覆盖;如果残差整体很大但在训练点之间保持光滑,说明噪声方差估计过低,模型被个别异常点主导。
还有一个容易被忽略的细节是方差轨迹和真实误差的相关系数。正确建模的 GP,其预测方差应当与绝对误差的时序趋势一致:误差大的区域方差也应当大。如果出现方差很小但误差很大的时段,说明模型对这部分示教数据过度自信,需要检查是否存在数据泄漏或时间轴对齐错误。
6.3 反向验证:从预测轨迹反推示教特征
更严格的做法是把训练好的 GP 模型当作一个可解释的轨迹语言模型,从中抽取“它认为重要的轨迹特征”。方法是让模型生成一条新的轨迹,然后人为地删除掉强迫项中的某些频率成分,对比删除前后轨迹的形状变化。如果删除高频成分后轨迹形状几乎不变,说明该段示教轨迹的高频信息本身就是噪声;如果删除低频成分导致轨迹整体漂移,说明模型把示教者习惯性的身体偏移当作了任务必需特征。
这种反向验证能够在做真机实验之前就发现“学到了不该学的东西”的问题。实际执行时,具体的评估指标建议用真实示教数据的留一交叉验证:训练时每次留出一条示教轨迹不参与训练,用其余轨迹训练模型,再预测被留出轨迹,计算预测均值与留出轨迹的平均偏差。相比随机切分数据,这种方式更接近实际部署场景,因为示教轨迹之间的差异才是模型真正需要泛化的对象。
本文还有配套的精品资源,点击获取