从BC到Difussion Policy:机器人动作生成算法入门
第 1 讲:为什么需要 Diffusion Policy?
1.1 普通 BC 方法
普通的行为克隆是单步回归(模型每次只根据当前观测,预测“下一步的动作”),容易将多种可行的动作平均掉。
行为克隆的伪代码:
obs_t=当前图像+当前关节角
action_t=model(obs_t)
其中模型action输出的只是一瞬间的动作--关节1转多少度、关节2转多少度
loss=mse(pred_action,expert_action)
1.2 BC 的局限性
为什么单步回归会将多种动作平均掉:通常来说会用MSE或者L2 loss训练,那么根据下面的公式,我们可以假设一个单一维度的动作来验证:
MSE:Mean Squared Error–均方误差:将每一个预测误差先平方,再求平均
M S E = 1 N ∑ i = 1 N ( y i − y ^ i ) 2 MSE = \frac{1}{N}\sum_{i=1}^{N}(y_i - \hat{y}_i)^2 MSE=N1i=1∑N(yi−y^i)2
L2 loss:把所有维度误差平方后加起来,相比MSE少➗了N
L = ∣ ∣ y − y ^ ∣ ∣ 2 − − − − − − − ∣ ∣ y − y ^ ∣ ∣ 2 = ∑ i ( y i − y ^ i ) 2 L = ||y - \hat y||^2 -------||y-\hat y||^2 = \sum_i (y_i - \hat y_i)^2 L=∣∣y−y^∣∣2−−−−−−−∣∣y−y^∣∣2=i∑(yi−y^i)2
为什么叫L2
因为它来自数学里的范数(Norm)
L1 norm:
∣ ∣ x ∣ ∣ 1 = ∣ x 1 ∣ + ∣ x 2 ∣ + . . . ||x||_1 = |x_1|+|x_2|+... ∣∣x∣∣1=∣x1∣+∣x2∣+...
L2 norm:
∣ ∣ x ∣ ∣ 2 = x 1 2 + x 2 2 + . . . ||x||_2 = \sqrt{x_1^2+x_2^2+...} ∣∣x∣∣2=x12+x22+...
平方后的 L2:
∣ ∣ x ∣ ∣ 2 2 = x 1 2 + x 2 2 + . . . ||x||_2^2 = x_1^2+x_2^2+... ∣∣x∣∣22=x12+x22+...
所以:
L2 loss = 误差向量的欧几里得长度平方
几何上就是:
预测点和真实点之间的平方距离。
当训练数据中存在一半往左,一半往右的动作,模型为了让mse误差最小,根据这个公式就会预测其中的平均值,这就是BC的局限性所在。
1.3 多模态动作问题
在同一个任务下,抓杯子可以从左侧抓、右侧抓;插孔可以从左侧绕、右侧绕,这些都可以是正确动作,所以不是一个状态一个正确答案,而是一个状态对应多个合理动作,这种现象就叫动作分布是多模态/多峰的
1.4 Diffusion Policy 的引入
单步回归就是模型根据当前观测预测下一步的动作,比如输入当前图像和关节状态,输入当前时刻的关节动作。对于动作分布的多模态现象,单步回归中的MSE或者L2这类回归损失训练,会输出平均值–选择障碍物这种情况
但是在机器人动作中,平均值不一定是合理动作,所以说普通的单步回归,容易将多模态动作分布平均掉,DP和FL的优势在于他们学习的是动作分布,可以生成不同合理的动作序列,而不是只输出一个平均动作
BC
action=model(obs)
DP
noise-->denoise-->action_chunk
FL
noise-->沿速度场流动-->action_chunk
第 2 讲:DDPM 基础原理
参考材料:
DDPM论文:https://arxiv.org/abs/2006.11239
HuggingFace-DDPM:https://huggingface.co/docs/diffusers/api/schedulers/ddpm
DDPM 全称是 Denoising Diffusion Probabilistic Models-去噪扩散概率模型,是 Ho 等人在 2020 年提出的一类扩散生成模型。它的基本思想是:前向过程逐步破坏数据,反向过程学习把噪声还原成数据。
在本课程中,我们最终关心的不是图像生成,而是机器人动作生成。所以这一讲虽然从图像扩散讲起,但每个概念都会对应到机器人动作序列中。
2.1 扩散模型基本思想

DDPM的本质就是,先人为地把真实数据破坏成噪声,再训练模型学会如何从噪声恢复数据。
前向扩散过程,也就是加噪过程:清晰图片 → 有一点噪声 → 有很多噪声 → 纯噪声
反向去噪过程,也就是生成过程:纯噪声 → 去掉一点噪声→ 更清晰 → 生成图片
DDPM 本来是生成图片的方法,但它的核心不是“图片”,而是“从噪声中生成数据”。
如果数据是图片,它就生成图片;如果数据是机器人动作序列,它就可以生成动作。
真实动作序列 → 加噪 → 随机动作噪声
随机动作噪声 → 去噪 → 生成动作序列
2.2 前向加噪过程
DDPM 原论文中,前向过程被定义为一个固定的马尔可夫加噪过程,也就是逐步往数据里加入高斯噪声
前向加噪过程的作用是:把干净数据 x0 逐步变成噪声 xT
x 0 → x 1 → x 2 → . . . → x T x_0 → x_1 → x_2 → ... → x_T x0→x1→x2→...→xT
x0 是原始干净数据
x1 是加了一点噪声的数据
xt 是第 t 步加噪后的数据
xT 接近纯高斯噪声
DDPM 里最常用的加噪公式(核心公式)是:
x t = α ˉ t x 0 + 1 − α ˉ t ϵ x_t = \sqrt{\bar{\alpha}_t}x_0 + \sqrt{1-\bar{\alpha}_t}\epsilon xt=αˉtx0+1−αˉtϵ
x0 是原始干净的数据
xt 是第 t 步加噪后的数据
ϵ是随机高斯噪声
t是扩散时间步数
αˉt是噪声调度系数
当 t 很小时:xt更像 x0
当 t 很大时:xt 更像 noise
2.3 反向去噪过程
前向过程是:干净数据 → 噪声 ;
反向过程是:噪声 → 干净数据
也就是:
x T → x T − 1 → x T − 2 → . . . → x 0 x_T→ x_{T-1} → x_{T-2} → ... → x_0 xT→xT−1→xT−2→...→x0
#推理时,我们没有真实数据 x0,所以只能从随机噪声开始
x = torch.randn(shape)
#然后不断调用模型预测噪声,并更新当前样本:
for t in reversed(range(T)):
pred_noise = model(x, t)
x = denoise_step(x, pred_noise, t)
#最后得到
x ≈ 生成出来的数据
DDPM 的反向过程就是训练一个模型去近似从 xt 到 x_{t-1} 的去噪过程。Hugging Face 的 Diffusers 文档中,DDPMScheduler 也正是用于处理训练加噪和推理去噪中的调度步骤。
为什么推理时从高斯噪声开始?
因为 DDPM 训练时已经学会了:从任意噪声程度的 xt 中预测 noise。所以推理时可以从最严重的噪声开始,也就是:xT ≈ 纯高斯噪声,然后一步步去噪,最终生成一个符合训练数据分布的新样本。
放到机器人里就是:随机动作噪声 → 去噪 → 合理动作序列
这也是 Diffusion Policy 能生成多种动作的原因之一:每次初始噪声不同,最终生成的动作序列也可能不同
第 3 讲:Diffusion Policy 基本原理
参考材料
DP论文:https://arxiv.org/abs/2303.04137
DP代码:https://diffusion-policy.cs.columbia.edu/?utm_source=chatgpt.com
上一讲我们讲的是:DDPM:从噪声中生成数据
这一讲要理解的是:Diffusion Policy:在机器人观测条件下,从噪声中生成机器人未来一段动作序列action chunk
在了解完DDPM基本实现后,继续回答一个问题:如何把图像扩散模型改造成机器人策略模型?

3.1 从图像扩散到动作扩散
model(xt,t)
图像扩散模型的目标是:从随机噪声中生成一张符合数据分布的图片。
model(obs,xt,t)
而动作扩散的核心是:根据当前观测(新增条件下),把机器人动作序列当成 DDPM 中的 x0来生成连续的动作序列
两者本质上都是对一类数据在去噪,只不过一个在像素空间中,一个在连续动作空间中。
3.2 DP 的输入与输出
DP的输入:
Diffusion Policy 和普通 DDPM 的最大区别是:DP 是条件生成模型(基于当前观测obs)
p r e d n o i s e = m o d e l ( o b s , x t , t ) pred_{noise} = model(obs, x_t, t) prednoise=model(obs,xt,t)
Obs:图像、关节角度信息、语言指令、历史观测信息
xt:xt.shape = [B, pred_horizon, action_dim]
-------根据数据的形状可以看出,xt代表第 b 条样本中,未来第 t 步机器人要执行的 7 维动作指令。
- B:batch size,批量样本数
- pred_horizon:预测动作序列长度
- action_dim:每一步动作的维度 t:扩散时间步
DP的输出:
#DP的输入
pred_noise = model(obs, xt, t)
#xt输入形状
xt.shape = [B, pred_horizon, action_dim]
#DP的输出
#pred_noise形状与xt一样
pred_noise.shape = [B, pred_horizon, action_dim]
#训练时计算loss:
loss = F.mse_loss(pred_noise, noise)
#推理时更新动作序列:
x = scheduler.step(pred_noise, t, x)
3.3 条件去噪过程
p r e d n o i s e = m o d e l ( o b s , x t , t ) pred_{noise}=model(obs,x_t,t) prednoise=model(obs,xt,t)
所谓条件去噪:相对DDPM多出来的obs就是条件
xt:是一段被污染的动作
t:告诉模型当前动作被污染得多严重
obs:告诉模型当前目标在哪里,障碍物在哪里,机器人自己在哪里
总结:在当前观测条件下,判断这段带噪声动作里哪些部分应该被去掉
学习过程 :
#输入真实动作x0
x0 = batch["action_chunk"]
#生成随机噪声,并添加到x0上得到xt
noise = torch.randn_like(x0)
xt = noise_scheduler.add_noise(x0, noise, t)
#将obs,xt,t输入模型,让模型预测噪声
pred_noise = model(obs, xt, t)
#监督pred_noise接近noise
loss = F.mse_loss(pred_noise, noise)
推理过程
#输入随机的噪声,其中x与真实动作形状一样
x = torch.randn([B, pred_horizon, action_dim])
#逐步去除噪声
for t in scheduler.timesteps:
pred_noise = model(obs, x, t)
x = scheduler.step(pred_noise, t, x).prev_sample
#输出最终去噪后的动作序列
action_chunk = x
第4讲:DDPM 图片项目生成
第5讲:DP-PushT项目
第6讲:DP-2D轨迹项目
第7讲:DP与其他算法对比
第8讲:常见面试问答与总结
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)