tensor([[ 2.0340e+01, 3.4694e+00, -1.7540e-02], ...
创建于:2025年4月9日
创建于:2025年4月9日
tensor([[ 2.0340e+01, 3.4694e+00, -1.7540e-02],
[ 2.0330e+01, 3.4663e+00, 1.0398e-01],
[ 2.0219e+01, 3.4660e+00, 1.1464e-01],
[ 2.0289e+01, 3.5751e+00, 4.6494e-01],
[ 2.0289e+01, 3.6878e+00, 4.6549e-01],
[ 2.0289e+01, 3.7806e+00, 4.7263e-01],
[ 2.0289e+01, 3.9498e+00, 4.6789e-01],
[ 2.0287e+01, 4.0600e+00, 4.7312e-01],
[ 2.0288e+01, 4.1288e+00, 4.7317e-01],
[ 2.0284e+01, 4.1885e+00, 4.7099e-01],
[ 2.0310e+01, 3.4638e+00, 5.7014e-01],
[ 2.0312e+01, 3.4687e+00, 6.4089e-01],
[ 2.0290e+01, 3.3495e+00, 4.6385e-01],
[ 2.0290e+01, 3.2408e+00, 4.6332e-01],
[ 2.0290e+01, 3.1480e+00, 4.6950e-01],
[ 2.0290e+01, 2.9788e+00, 4.6300e-01],
[ 2.0287e+01, 2.8686e+00, 4.6710e-01],
[ 2.0287e+01, 2.7998e+00, 4.6648e-01],
[ 2.0284e+01, 2.7401e+00, 4.6531e-01],
[ 2.0212e+01, 3.5796e+00, -1.1312e-02],
[ 2.0340e+01, 3.5701e+00, -1.4708e-02],
[ 2.0290e+01, 3.5795e+00, -1.1696e-01],
[ 2.0290e+01, 3.5798e+00, -4.4871e-01],
[ 2.0294e+01, 3.5801e+00, -8.6069e-01],
[ 2.0294e+01, 3.5801e+00, -8.6069e-01],
[ 2.0211e+01, 3.3596e+00, -1.6993e-02],
[ 2.0340e+01, 3.3687e+00, -2.0443e-02],
[ 2.0290e+01, 3.3588e+00, -1.2300e-01],
[ 2.0293e+01, 3.3566e+00, -4.5473e-01],
[ 2.0295e+01, 3.3537e+00, -8.6672e-01],
[ 2.0295e+01, 3.3537e+00, -8.6672e-01]], device='cuda:0') 通过xyz坐标分析这些关节的位置以及是哪个关节
你提供的是一个形状为 [N, 3] 的 PyTorch 张量,其中每一行代表了一个关节(joint)的空间坐标 (x, y, z)。看这些数据,可以推测你正在使用的是类似人体或机械关节模型。一般来说,此类数据经常出现在人体姿态估计或动作捕捉系统中。
~20.2到20.3之间变化,表明可能是人体或物体在一个稳定的平面位置上微小地移动或微调。2.7到4.2,呈现明显变化。这一般代表纵向变化,很可能是从头顶到脚底的方向。-0.866)到正值(例如 0.641),体现了前后或深度方向上的明显变动。根据人体三维模型的常规设定:
从这些规律出发,这些数据很可能表示了一个人的躯干或身体某区域的多个关节。
从你的数据来看:
例如:
-0.86的点可能位于身体背面(如后颈、后背)。0.64附近可能是身体前侧(如胸前或肩膀前部)。大致分布可能为:
如果是一个典型人体姿势的数据片段,它可能对应于以下典型人体关键点(参考人体关键点标准,比如COCO或SMPL):
更具体地:
该数据集可能代表一个人躯干区域的3D关节坐标:
Z轴正负体现了身体的前后深度方向分布,体现了前后姿态特征。
你可以确认一下数据来源,如是来自人体姿态捕捉或模型推理,这样的布局会非常合理。如果能提供更多上下文(例如来自于SMPL模型或某个3D人体姿态估计网络),可以进一步确定具体关节的含义。
python把这些点的坐标画出来
pythonimport torch import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # Provided tensor coords = torch.tensor([[ 2.0340e+01, 3.4694e+00, -1.7540e-02], [ 2.0330e+01, 3.4663e+00, 1.0398e-01], [ 2.0219e+01, 3.4660e+00, 1.1464e-01], [ 2.0289e+01, 3.5751e+00, 4.6494e-01], [ 2.0289e+01, 3.6878e+00, 4.6549e-01], [ 2.0289e+01, 3.7806e+00, 4.7263e-01], [ 2.0289e+01, 3.9498e+00, 4.6789e-01], [ 2.0287e+01, 4.0600e+00, 4.7312e-01], [ 2.0288e+01, 4.1288e+00, 4.7317e-01], [ 2.0284e+01, 4.1885e+00, 4.7099e-01], [ 2.0310e+01, 3.4638e+00, 5.7014e-01], [ 2.0312e+01, 3.4687e+00, 6.4089e-01], [ 2.0290e+01, 3.3495e+00, 4.6385e-01], [ 2.0290e+01, 3.2408e+00, 4.6332e-01], [ 2.0290e+01, 3.1480e+00, 4.6950e-01], [ 2.0290e+01, 2.9788e+00, 4.6300e-01], [ 2.0287e+01, 2.8686e+00, 4.6710e-01], [ 2.0287e+01, 2.7998e+00, 4.6648e-01], [ 2.0284e+01, 2.7401e+00, 4.6531e-01], [ 2.0212e+01, 3.5796e+00, -1.1312e-02], [ 2.0340e+01, 3.5701e+00, -1.4708e-02], [ 2.0290e+01, 3.5795e+00, -1.1696e-01], [ 2.0290e+01, 3.5798e+00, -4.4871e-01], [ 2.0294e+01, 3.5801e+00, -8.6069e-01], [ 2.0294e+01, 3.5801e+00, -8.6069e-01], [ 2.0211e+01, 3.3596e+00, -1.6993e-02], [ 2.0340e+01, 3.3687e+00, -2.0443e-02], [ 2.0290e+01, 3.3588e+00, -1.2300e-01], [ 2.0293e+01, 3.3566e+00, -4.5473e-01], [ 2.0295e+01, 3.3537e+00, -8.6672e-01], [ 2.0295e+01, 3.3537e+00, -8.6672e-01]]) # Plotting fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') # Extract coordinates x, y, z = coords[:, 0].cpu(), coords[:, 1].cpu(), coords[:, 2].cpu() # Plot points ax.scatter(x, y, z, c='r', marker='o') # Labeling axes ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') ax.set_title('3D Visualization of Joint Coordinates') plt.show()
当前环境似乎内存不足,导致无法成功导入torch并完成绘图。
你可以在自己本地的 Python 环境中运行以下代码,以完成可视化:
pythonimport torch import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D coords = torch.tensor([[ 2.0340e+01, 3.4694e+00, -1.7540e-02], [ 2.0330e+01, 3.4663e+00, 1.0398e-01], [ 2.0219e+01, 3.4660e+00, 1.1464e-01], [ 2.0289e+01, 3.5751e+00, 4.6494e-01], [ 2.0289e+01, 3.6878e+00, 4.6549e-01], [ 2.0289e+01, 3.7806e+00, 4.7263e-01], [ 2.0289e+01, 3.9498e+00, 4.6789e-01], [ 2.0287e+01, 4.0600e+00, 4.7312e-01], [ 2.0288e+01, 4.1288e+00, 4.7317e-01], [ 2.0284e+01, 4.1885e+00, 4.7099e-01], [ 2.0310e+01, 3.4638e+00, 5.7014e-01], [ 2.0312e+01, 3.4687e+00, 6.4089e-01], [ 2.0290e+01, 3.3495e+00, 4.6385e-01], [ 2.0290e+01, 3.2408e+00, 4.6332e-01], [ 2.0290e+01, 3.1480e+00, 4.6950e-01], [ 2.0290e+01, 2.9788e+00, 4.6300e-01], [ 2.0287e+01, 2.8686e+00, 4.6710e-01], [ 2.0287e+01, 2.7998e+00, 4.6648e-01], [ 2.0284e+01, 2.7401e+00, 4.6531e-01], [ 2.0212e+01, 3.5796e+00, -1.1312e-02], [ 2.0340e+01, 3.5701e+00, -1.4708e-02], [ 2.0290e+01, 3.5795e+00, -1.1696e-01], [ 2.0290e+01, 3.5798e+00, -4.4871e-01], [ 2.0294e+01, 3.5801e+00, -8.6069e-01], [ 2.0294e+01, 3.5801e+00, -8.6069e-01], [ 2.0211e+01, 3.3596e+00, -1.6993e-02], [ 2.0340e+01, 3.3687e+00, -2.0443e-02], [ 2.0290e+01, 3.3588e+00, -1.2300e-01], [ 2.0293e+01, 3.3566e+00, -4.5473e-01], [ 2.0295e+01, 3.3537e+00, -8.6672e-01], [ 2.0295e+01, 3.3537e+00, -8.6672e-01]]) fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection='3d') x, y, z = coords[:, 0], coords[:, 1], coords[:, 2] ax.scatter(x, y, z, c='r', marker='o') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') ax.set_title('3D Visualization of Joint Coordinates') plt.show()
在本地环境运行后,会展示出所有关节的三维空间位置图,帮助你进一步分析这些点的具体位置和关系。
def compute_humanoid_observations_max_full(body_pos, body_rot, body_vel, body_ang_vel, local_root_obs, root_height_obs):
# type: (Tensor, Tensor, Tensor, Tensor, bool, bool) -> Tensor
root_pos = body_pos[:, 0, :]
root_rot = body_rot[:, 0, :]
textroot_h = root_pos[:, 2:3] heading_rot_inv = torch_utils.calc_heading_quat_inv(root_rot) if (not root_height_obs): root_h_obs = torch.zeros_like(root_h) else: root_h_obs = root_h heading_rot_inv_expand = heading_rot_inv.unsqueeze(-2) heading_rot_inv_expand = heading_rot_inv_expand.repeat((1, body_pos.shape[1], 1)) flat_heading_rot_inv = heading_rot_inv_expand.reshape(heading_rot_inv_expand.shape[0] * heading_rot_inv_expand.shape[1], heading_rot_inv_expand.shape[2]) root_pos_expand = root_pos.unsqueeze(-2) local_body_pos = body_pos - root_pos_expand flat_local_body_pos = local_body_pos.reshape(local_body_pos.shape[0] * local_body_pos.shape[1], local_body_pos.shape[2]) flat_local_body_pos = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_local_body_pos) local_body_pos = flat_local_body_pos.reshape(local_body_pos.shape[0], local_body_pos.shape[1] * local_body_pos.shape[2]) local_body_pos = local_body_pos[..., 3:] # remove root pos 移除展平后的前三个数 flat_body_rot = body_rot.reshape(body_rot.shape[0] * body_rot.shape[1], body_rot.shape[2]) # This is global rotation of the body flat_local_body_rot = quat_mul(flat_heading_rot_inv, flat_body_rot) flat_local_body_rot_obs = torch_utils.quat_to_tan_norm(flat_local_body_rot) local_body_rot_obs = flat_local_body_rot_obs.reshape(body_rot.shape[0], body_rot.shape[1] * flat_local_body_rot_obs.shape[1]) if not (local_root_obs): root_rot_obs = torch_utils.quat_to_tan_norm(root_rot) # If not local root obs, you override it. local_body_rot_obs[..., 0:6] = root_rot_obs flat_body_vel = body_vel.reshape(body_vel.shape[0] * body_vel.shape[1], body_vel.shape[2]) flat_local_body_vel = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_body_vel) local_body_vel = flat_local_body_vel.reshape(body_vel.shape[0], body_vel.shape[1] * body_vel.shape[2]) flat_body_ang_vel = body_ang_vel.reshape(body_ang_vel.shape[0] * body_ang_vel.shape[1], body_ang_vel.shape[2]) flat_local_body_ang_vel = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_body_ang_vel) local_body_ang_vel = flat_local_body_ang_vel.reshape(body_ang_vel.shape[0], body_ang_vel.shape[1] * body_ang_vel.shape[2]) obs_list = [] if root_height_obs: obs_list.append(root_h_obs) obs_list += [local_body_pos, local_body_rot_obs, local_body_vel, local_body_ang_vel] obs = torch.cat(obs_list, dim=-1) return obs 解释
这个函数compute_humanoid_observations_max_full是一个用于计算类人角色(humanoid)状态观测信息的函数,通常用于强化学习中人体运动控制或仿真任务。
给定类人模型的位置(body_pos)、旋转四元数(body_rot)、速度(body_vel)、角速度(body_ang_vel),该函数返回一个统一的张量(obs),代表该角色的观测状态。
这个观测状态会以角色根节点(通常为躯干或臀部)为参照系,并把所有信息转化为局部坐标系(相对根节点的本地坐标系)。
body_pos:[batch_size, num_joints, 3]
表示每个关节的空间位置坐标。
body_rot:[batch_size, num_joints, 4]
每个关节的旋转,用**四元数(quaternion)**表示。
body_vel:[batch_size, num_joints, 3]
每个关节的线性速度。
body_ang_vel:[batch_size, num_joints, 3]
每个关节的角速度。
local_root_obs:布尔值
是否使用根节点局部旋转的观测信息。
root_height_obs:布尔值
是否使用根节点高度(通常为臀部的高度)作为观测信息。
pythonroot_pos = body_pos[:, 0, :] root_rot = body_rot[:, 0, :]
pythonroot_h = root_pos[:, 2:3] # 提取高度(Z轴一般表示垂直高度) if (not root_height_obs): root_h_obs = torch.zeros_like(root_h) else: root_h_obs = root_h
heading_rot_inv)pythonheading_rot_inv = torch_utils.calc_heading_quat_inv(root_rot)
pythonheading_rot_inv_expand = heading_rot_inv.unsqueeze(-2).repeat((1, body_pos.shape[1], 1)) flat_heading_rot_inv = heading_rot_inv_expand.reshape(-1, 4)
pythonlocal_body_pos = body_pos - root_pos.unsqueeze(-2) flat_local_body_pos = local_body_pos.reshape(-1, 3) flat_local_body_pos = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_local_body_pos)
pythonlocal_body_pos = flat_local_body_pos.reshape(body_pos.shape[0], -1) local_body_pos = local_body_pos[..., 3:] # 去除根节点位置(前三个数),因为根节点本地位置始终是零
pythonflat_body_rot = body_rot.reshape(-1, 4) flat_local_body_rot = quat_mul(flat_heading_rot_inv, flat_body_rot)
pythonflat_local_body_rot_obs = torch_utils.quat_to_tan_norm(flat_local_body_rot) local_body_rot_obs = flat_local_body_rot_obs.reshape(body_rot.shape[0], -1)
local_root_obs的值来决定是否要替换根节点旋转为全局表示:pythonif not local_root_obs: root_rot_obs = torch_utils.quat_to_tan_norm(root_rot) local_body_rot_obs[..., 0:6] = root_rot_obs
pythonflat_body_vel = body_vel.reshape(-1, 3) flat_local_body_vel = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_body_vel) local_body_vel = flat_local_body_vel.reshape(body_vel.shape[0], -1) flat_body_ang_vel = body_ang_vel.reshape(-1, 3) flat_local_body_ang_vel = torch_utils.my_quat_rotate(flat_heading_rot_inv, flat_body_ang_vel) local_body_ang_vel = flat_local_body_ang_vel.reshape(body_ang_vel.shape[0], -1)
pythonobs_list = [] if root_height_obs: obs_list.append(root_h_obs) obs_list += [local_body_pos, local_body_rot_obs, local_body_vel, local_body_ang_vel] obs = torch.cat(obs_list, dim=-1)
最终输出obs张量形状类似:
[batch_size, observation_dim]
此函数广泛用于强化学习领域,尤其是在基于物理引擎的仿真(如IsaacGym, DeepMimic)中,用于生成状态观测(state observation),为学习控制策略提供清晰、统一的输入。
总结:
compute_humanoid_observations_max_full函数将全局关节状态(位置、旋转、速度、角速度)统一转为局部坐标系下的单一观测张量,这种表示更利于强化学习算法进行学习与泛化。
def compute_imitation_observations_max_full(root_pos, root_rot, body_pos, body_rot, body_vel, body_ang_vel, ref_body_pos, ref_body_rot, ref_body_vel, ref_body_ang_vel, time_steps, ref_episodic_offset = None, ref_vel_in_task_obs = True):
# type: (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor,Tensor, Tensor,Tensor,Tensor, int, Tensor, bool) -> Tensor
# Adding pose information at the back
# Future tracks in this obs will not contain future diffs.
obs = []
B, J, _ = body_pos.shape
textheading_inv_rot = torch_utils.calc_heading_quat_inv(root_rot) heading_rot = torch_utils.calc_heading_quat(root_rot) heading_inv_rot_expand = heading_inv_rot.unsqueeze(-2).repeat((1, J, 1)).repeat_interleave(time_steps, 0) heading_rot_expand = heading_rot.unsqueeze(-2).repeat((1, J, 1)).repeat_interleave(time_steps, 0) ##### Body position and rotation differences diff_global_body_pos = ref_body_pos.view(B, time_steps, J, 3) - body_pos.view(B, 1, J, 3) diff_local_body_pos_flat = torch_utils.my_quat_rotate(heading_inv_rot_expand.view(-1, 4), diff_global_body_pos.view(-1, 3)) diff_global_body_rot = torch_utils.quat_mul(ref_body_rot.view(B, time_steps, J, 4), torch_utils.quat_conjugate(body_rot[:, None].repeat_interleave(time_steps, 1))) diff_local_body_rot_flat = torch_utils.quat_mul(torch_utils.quat_mul(heading_inv_rot_expand.view(-1, 4), diff_global_body_rot.view(-1, 4)), heading_rot_expand.view(-1, 4)) # Need to be change of basis ##### linear and angular Velocity differences diff_global_vel = ref_body_vel.view(B, time_steps, J, 3) - body_vel.view(B, 1, J, 3) diff_local_vel = torch_utils.my_quat_rotate(heading_inv_rot_expand.view(-1, 4), diff_global_vel.view(-1, 3)) diff_global_ang_vel = ref_body_ang_vel.view(B, time_steps, J, 3) - body_ang_vel.view(B, 1, J, 3) diff_local_ang_vel = torch_utils.my_quat_rotate(heading_inv_rot_expand.view(-1, 4), diff_global_ang_vel.view(-1, 3)) ##### body pos + Dof_pos This part will have proper futuers. local_ref_body_pos = ref_body_pos.view(B, time_steps, J, 3) - root_pos.view(B, 1, 1, 3) # preserves the body position local_ref_body_pos = torch_utils.my_quat_rotate(heading_inv_rot_expand.view(-1, 4), local_ref_body_pos.view(-1, 3)) local_ref_body_rot = torch_utils.quat_mul(heading_inv_rot_expand.view(-1, 4), ref_body_rot.view(-1, 4)) local_ref_body_rot = torch_utils.quat_to_tan_norm(local_ref_body_rot) if ref_episodic_offset is not None: # import ipdb; ipdb.set_trace() diff_global_body_pos_offset= ref_episodic_offset.unsqueeze(1).unsqueeze(2).expand(-1, 1, J, -1) diff_local_body_pos_flat = diff_local_body_pos_flat.view(B, 1, J, 3) + diff_global_body_pos_offset local_ref_body_pos_offset = ref_episodic_offset.repeat(J,1)[:J * ref_episodic_offset.shape[0], :] local_ref_body_pos += local_ref_body_pos_offset.repeat_interleave(time_steps, 0) # make some changes to how futures are appended. obs.append(diff_local_body_pos_flat.view(B, time_steps, -1)) # 1 * timestep * J * 3 obs.append(torch_utils.quat_to_tan_norm(diff_local_body_rot_flat).view(B, time_steps, -1)) # 1 * timestep * J * 6 obs.append(diff_local_vel.view(B, time_steps, -1)) # timestep * J * 3 obs.append(diff_local_ang_vel.view(B, time_steps, -1)) # timestep * J * 3 obs.append(local_ref_body_pos.view(B, time_steps, -1)) # timestep * J * 3 obs.append(local_ref_body_rot.view(B, time_steps, -1)) # timestep * J * 6 obs = torch.cat(obs, dim=-1).view(B, -1) return obs 解释
你提供的函数compute_imitation_observations_max_full是一个用于生成模仿学习(imitation learning)观测的函数。它的主要目的是计算当前角色状态与参考状态(目标状态)之间的差异,并且将这些差异以局部坐标系下的观测表示。这种表示形式常见于深度模仿学习、动作跟踪、动作模仿等任务。
给定角色的当前姿态(位置、旋转、速度、角速度)以及参考(目标)姿态,函数计算二者之间的差值,生成局部空间下的观察状态张量。通常用于:
root_pos, root_rot:[B, 3],[B, 4]
当前角色的根节点位置与旋转(四元数)。
body_pos, body_rot:[B, J, 3], [B, J, 4]
当前角色的各个关节位置与旋转。
body_vel, body_ang_vel:[B, J, 3]
当前角色关节的线速度与角速度。
ref_body_pos, ref_body_rot:[B, timesteps, J, 3], [B, timesteps, J, 4]
参考(目标)关节在未来timesteps步内的目标位置与旋转。
ref_body_vel, ref_body_ang_vel:[B, timesteps, J, 3]
参考关节的目标速度和角速度。
time_steps:int
需要预测的未来步数。
ref_episodic_offset:[B, 3] (可选)
一种位置偏移,用于对参考轨迹整体进行位移调整。
ref_vel_in_task_obs:bool
是否在观测中加入参考速度信息。
pythonheading_inv_rot = torch_utils.calc_heading_quat_inv(root_rot) heading_rot = torch_utils.calc_heading_quat(root_rot)
pythonheading_inv_rot_expand = heading_inv_rot.unsqueeze(-2).repeat((1, J, 1)).repeat_interleave(time_steps, 0) heading_rot_expand = heading_rot.unsqueeze(-2).repeat((1, J, 1)).repeat_interleave(time_steps, 0)
pythondiff_global_body_pos = ref_body_pos - body_pos.unsqueeze(1) diff_local_body_pos_flat = torch_utils.my_quat_rotate(heading_inv_rot_expand, diff_global_body_pos.view(-1, 3))
pythondiff_global_body_rot = quat_mul(ref_body_rot, quat_conjugate(body_rot.unsqueeze(1).repeat_interleave(time_steps, 1))) diff_local_body_rot_flat = quat_mul(quat_mul(heading_inv_rot_expand, diff_global_body_rot.view(-1,4)), heading_rot_expand)
这里diff_local_body_rot_flat表示将旋转差值统一到角色的局部坐标系(相对角色自身朝向)内的旋转差异。
pythondiff_global_vel = ref_body_vel - body_vel.unsqueeze(1) diff_local_vel = torch_utils.my_quat_rotate(heading_inv_rot_expand, diff_global_vel.view(-1,3))
pythondiff_global_ang_vel = ref_body_ang_vel - body_ang_vel.unsqueeze(1) diff_local_ang_vel = torch_utils.my_quat_rotate(heading_inv_rot_expand, diff_global_ang_vel.view(-1,3))
pythonlocal_ref_body_pos = ref_body_pos - root_pos.unsqueeze(1).unsqueeze(1) local_ref_body_pos = torch_utils.my_quat_rotate(heading_inv_rot_expand, local_ref_body_pos.view(-1, 3))
pythonlocal_ref_body_rot = quat_mul(heading_inv_rot_expand, ref_body_rot.view(-1,4)) local_ref_body_rot = torch_utils.quat_to_tan_norm(local_ref_body_rot)
ref_episodic_offset非空,将用于整体偏移轨迹(用于跨episode位置连续处理):pythonif ref_episodic_offset is not None: diff_local_body_pos_flat += ref_episodic_offset.unsqueeze(1).unsqueeze(2) local_ref_body_pos += ref_episodic_offset.repeat(J,1).repeat_interleave(time_steps, 0)
pythonobs.append(diff_local_body_pos_flat.view(B, time_steps, -1)) obs.append(torch_utils.quat_to_tan_norm(diff_local_body_rot_flat).view(B, time_steps, -1)) obs.append(diff_local_vel.view(B, time_steps, -1)) obs.append(diff_local_ang_vel.view(B, time_steps, -1)) obs.append(local_ref_body_pos.view(B, time_steps, -1)) obs.append(local_ref_body_rot.view(B, time_steps, -1)) obs = torch.cat(obs, dim=-1).view(B, -1)
最终输出张量的维度:
[B, time_steps * (J*(3+6+3+3+3+6))]
代表批次内每个样本:
最终观测通常会输入深度模仿学习策略(例如 PPO 或 SAC)进行策略学习。
compute_imitation_observations_max_full函数广泛应用于模仿学习场景,尤其在物理引擎仿真中(如IsaacGym、DeepMimic),它能有效地编码当前与目标状态之间的差异,供强化学习策略以高效、局部的方式来学习如何跟踪或模仿动作轨迹。
def _draw_debug_vis(self):
""" Draws visualizations for dubugging (slows down simulation a lot).
Default behaviour: draws height measurement points
"""
self.gym.clear_lines(self.viewer)
self.gym.refresh_rigid_body_state_tensor(self.sim)
# import ipdb; ipdb.set_trace()
for env_id in range(self.num_envs):
if self.cfg.motion.teleop:
if self.cfg.motion.realtime_vr_keypoints:
for vr_keypoint_idx in range(self.realtime_vr_keypoints_pos.shape[0]):
color_inner = [1, 0.651, 0]
color_inner = tuple(color_inner)
sphere_geom_marker = gymutil.WireframeSphereGeometry(0.04, 20, 20, None, color=color_inner)
sphere_pose = gymapi.Transform(gymapi.Vec3(self.realtime_vr_keypoints_pos[vr_keypoint_idx, 0], self.realtime_vr_keypoints_pos[vr_keypoint_idx, 1], self.realtime_vr_keypoints_pos[vr_keypoint_idx, 2]), r=None)
gymutil.draw_lines(sphere_geom_marker, self.gym, self.viewer, self.envs[env_id], sphere_pose)
else:
for pos_id, pos_joint in enumerate(self.marker_coords[env_id]): # idx 0 torso (duplicate with 11)
textcolor_inner = (0.3, 0.3, 0.3) if not self.cfg.motion.visualize_config.customize_color \ else self.cfg.motion.visualize_config.marker_joint_colors[pos_id % len(self.cfg.motion.visualize_config.marker_joint_colors)] color_inner = tuple(color_inner) sphere_geom_marker = gymutil.WireframeSphereGeometry(0.04, 20, 20, None, color=color_inner) # sphere_geom3 = gymutil.WireframeSphereGeometry(0.05, 4, 4, None, color=(1., 1.0, 1.0)) if self.cfg.domain_rand.randomize_motion_ref_xyz: # import ipdb; ipdb.set_trace() # pos_joint[0] += self.ref_episodic_offset[env_id][0] # pos_joint[1] += self.ref_episodic_offset[env_id][1] # pos_joint[2] += self.ref_episodic_offset[env_id][2] # import ipdb; ipdb.set_trace() if pos_id == 22: pos_joint += self.ref_episodic_offset[env_id] sphere_pose = gymapi.Transform(gymapi.Vec3(pos_joint[0], pos_joint[1], pos_joint[2]), r=None) gymutil.draw_lines(sphere_geom_marker, self.gym, self.viewer, self.envs[env_id], sphere_pose) 解释这些东西
你提供的函数 _draw_debug_vis 主要用于在仿真环境中进行可视化调试,它属于一个仿真或强化学习环境(如IsaacGym环境)的一部分。
该函数在仿真界面内绘制一些可视化的球形标记,用来展示角色的一些关键位置(例如关节或传感器标记点),用于直观地调试角色的动作轨迹或实时状态。
下面详细解释函数内各部分的作用:
pythonself.gym.clear_lines(self.viewer) self.gym.refresh_rigid_body_state_tensor(self.sim)
pythonfor env_id in range(self.num_envs):
pythonif self.cfg.motion.teleop: if self.cfg.motion.realtime_vr_keypoints: for vr_keypoint_idx in range(self.realtime_vr_keypoints_pos.shape[0]): color_inner = [1, 0.651, 0] # 橙色标记点 sphere_geom_marker = gymutil.WireframeSphereGeometry(0.04, 20, 20, None, color=color_inner) sphere_pose = gymapi.Transform( gymapi.Vec3( self.realtime_vr_keypoints_pos[vr_keypoint_idx, 0], self.realtime_vr_keypoints_pos[vr_keypoint_idx, 1], self.realtime_vr_keypoints_pos[vr_keypoint_idx, 2] ), r=None ) gymutil.draw_lines(sphere_geom_marker, self.gym, self.viewer, self.envs[env_id], sphere_pose)
teleop(远程操控模式)且启用了realtime_vr_keypoints(实时VR关键点),就绘制VR跟踪到的关键点位置。pythonelse: for pos_id, pos_joint in enumerate(self.marker_coords[env_id]): color_inner = (0.3, 0.3, 0.3) if not self.cfg.motion.visualize_config.customize_color \ else self.cfg.motion.visualize_config.marker_joint_colors[pos_id % len(self.cfg.motion.visualize_config.marker_joint_colors)] sphere_geom_marker = gymutil.WireframeSphereGeometry(0.04, 20, 20, None, color=color_inner)
pythonif self.cfg.domain_rand.randomize_motion_ref_xyz: if pos_id == 22: pos_joint += self.ref_episodic_offset[env_id]
ref_episodic_offset用于在不同episode间调整轨迹,使轨迹或位置随机化,便于增强鲁棒性。pythonsphere_pose = gymapi.Transform(gymapi.Vec3(pos_joint[0], pos_joint[1], pos_joint[2]), r=None) gymutil.draw_lines(sphere_geom_marker, self.gym, self.viewer, self.envs[env_id], sphere_pose)
textdef _reward_teleop_body_position_extend(self): body_pos = self._rigid_body_pos body_rot = self._rigid_body_rot offset = self.env_origins + self.env_origins_init_3Doffset motion_times = (self.episode_length_buf ) * self.dt + self.motion_start_times # next frames so +1 # motion_res = self._get_state_from_motionlib_cache(self.motion_ids, motion_times, offset=offset) motion_res = self._get_state_from_motionlib_cache_trimesh(self.motion_ids, motion_times, offset= offset) ref_body_pos_extend = motion_res['rg_pos_t'] if self.cfg.asset.local_upper_reward: diff = ref_body_pos_extend[:, [0]] - body_pos[:, [0]] ref_body_pos_extend[:, 11:] -= diff extend_curr_pos = torch_utils.my_quat_rotate(body_rot[:, self.extend_body_parent_ids].reshape(-1, 4), self.extend_body_pos[:, ].reshape(-1, 3)).view(self.num_envs, -1, 3) + body_pos[:, self.extend_body_parent_ids] body_pos_extend = torch.cat([body_pos, extend_curr_pos], dim=1) diff_global_body_pos = ref_body_pos_extend - body_pos_extend diff_global_body_pos_lower = diff_global_body_pos[:, :11] diff_global_body_pos_upper = diff_global_body_pos[:, 11:] diff_body_pos_dist_lower = (diff_global_body_pos_lower**2).mean(dim=-1).mean(dim=-1) diff_body_pos_dist_upper = (diff_global_body_pos_upper**2).mean(dim=-1).mean(dim=-1) diff_body_pos_dist_lower = diff_body_pos_dist_lower diff_body_pos_dist_upper = diff_body_pos_dist_upper r_body_pos_lower = torch.exp(-diff_body_pos_dist_lower / self.cfg.rewards.teleop_body_pos_lowerbody_sigma) r_body_pos_upper = torch.exp(-diff_body_pos_dist_upper / self.cfg.rewards.teleop_body_pos_upperbody_sigma) r_body_pos = r_body_pos_lower * self.cfg.rewards.teleop_body_pos_lowerbody_weight + r_body_pos_upper * self.cfg.rewards.teleop_body_pos_upperbody_weight return r_body_pos 详细解释这个
你提供的函数 _reward_teleop_body_position_extend 是一个专门为远程操控动作模仿(Teleoperation-based imitation)强化学习任务设计的奖励函数。它通过比较仿真角色的身体位置与一个参考动作轨迹(例如来自运动捕捉库的数据)之间的差异,计算角色当前姿势与目标姿势之间的匹配程度。
下面详细分步解释函数的每个关键步骤:
此函数计算角色的身体位置(包含额外扩展的辅助点)与参考运动轨迹之间的差异,并转化为奖励值,以指导策略学习模仿轨迹。
具体而言,角色的每个关节位置都会与参考关节位置比较,差距越小,奖励越高。
body_pos [num_envs, num_joints, 3]:角色当前每个关节的三维位置。body_rot [num_envs, num_joints, 4]:角色当前每个关节的旋转四元数。offset:环境的原点坐标修正值,用于将参考轨迹放到仿真环境的合适位置上。motion_res:从参考轨迹库获取的当前时刻的参考姿势信息(例如从运动捕捉或动画库获取)。ref_body_pos_extend [num_envs, num_joints + extend_joints, 3]:扩展后的参考姿势(包含额外的关键点)。extend_curr_pos:额外扩展点的位置,用于更精细地捕捉角色姿势特征。self.extend_body_parent_ids:每个额外扩展点的父节点关节索引,用于正确计算扩展点的全局位置。pythonoffset = self.env_origins + self.env_origins_init_3Doffset motion_times = (self.episode_length_buf) * self.dt + self.motion_start_times motion_res = self._get_state_from_motionlib_cache_trimesh(self.motion_ids, motion_times, offset=offset) ref_body_pos_extend = motion_res['rg_pos_t']
motion_res取到rg_pos_t(目标的关节位置),作为计算参考。pythonif self.cfg.asset.local_upper_reward: diff = ref_body_pos_extend[:, [0]] - body_pos[:, [0]] ref_body_pos_extend[:, 11:] -= diff
local_upper_reward选项,则对上半身参考轨迹进行位置修正:
pythonextend_curr_pos = torch_utils.my_quat_rotate( body_rot[:, self.extend_body_parent_ids].reshape(-1, 4), self.extend_body_pos.reshape(-1, 3) ).view(self.num_envs, -1, 3) + body_pos[:, self.extend_body_parent_ids] body_pos_extend = torch.cat([body_pos, extend_curr_pos], dim=1)
body_pos_extend,包含原有关节和额外的扩展点。pythondiff_global_body_pos = ref_body_pos_extend - body_pos_extend diff_global_body_pos_lower = diff_global_body_pos[:, :11] diff_global_body_pos_upper = diff_global_body_pos[:, 11:]
pythondiff_body_pos_dist_lower = (diff_global_body_pos_lower**2).mean(dim=-1).mean(dim=-1) diff_body_pos_dist_upper = (diff_global_body_pos_upper**2).mean(dim=-1).mean(dim=-1)
pythonr_body_pos_lower = torch.exp(-diff_body_pos_dist_lower / self.cfg.rewards.teleop_body_pos_lowerbody_sigma) r_body_pos_upper = torch.exp(-diff_body_pos_dist_upper / self.cfg.rewards.teleop_body_pos_upperbody_sigma)
teleop_body_pos_lowerbody_sigma 和 teleop_body_pos_upperbody_sigma 控制误差对奖励衰减的敏感度。
pythonr_body_pos = (r_body_pos_lower * self.cfg.rewards.teleop_body_pos_lowerbody_weight + r_body_pos_upper * self.cfg.rewards.teleop_body_pos_upperbody_weight)
teleop_body_pos_lowerbody_weight与teleop_body_pos_upperbody_weight),融合上下半身的奖励,形成最终综合的身体位置奖励。最终输出一个奖励值r_body_pos:
广泛用于:
_reward_teleop_body_position_extend 函数是一种精细化的奖励设计,精确地评估了仿真角色与参考轨迹间的姿势匹配度,通过明确区分上下半身以及扩展点位置,提供了更加详细的模仿奖励信号,从而有利于策略更精确地模仿参考动作轨迹。
同名的conda环境 覆盖了之前安装的环境怎么办
如果你使用了同名的conda环境,覆盖了之前安装的环境,默认情况下,原有环境数据会被覆盖,无法自动恢复。不过,这里给你一些恢复或补救的方法:
先确认旧环境是否真的已经被覆盖:
bashconda env list
检查列表中是否只剩一个该环境名称。
conda可能会自动保留历史环境的快照。尝试以下方法:
bashconda list --revisions -n 你的环境名
你会看到类似:
bash2024-04-01 10:00:00 (rev 1) 2024-04-08 11:00:00 (rev 2)
如果有旧的revisions,比如上面的rev 1是旧的,可以尝试回滚:
bashconda install --revision 1 -n 你的环境名
这样或许可以恢复到之前的状态。
如果你曾导出过原环境文件(.yml文件),可以使用:
bashconda env update --name 你的环境名 --file old_environment.yml --prune
这样就能从你之前的.yml环境文件恢复环境。
建议在重建后,及时备份:
bashconda env export > backup_environment.yml
以后新建环境,最好确认是否已存在同名环境:
bashconda env list
或者在创建环境前,先备份原环境:
bashconda env export -n 你的环境名 > old_env_backup.yml
环境覆盖后数据恢复概率较低,因此定期导出环境文件(备份)是非常必要的习惯。
conda怎么复制环境
你可以使用以下方法快速复制一个已有的 conda 环境:
假如你有一个名为env_old的环境,想复制为env_new:
bashconda create --name env_new --clone env_old
1. 导出现有环境配置文件
bashconda activate env_old conda env export > env_old.yml
2. 使用环境配置文件创建新环境
bashconda env create -n env_new -f env_old.yml
1. 导出纯包列表(无版本号):
bashconda activate env_old conda list --export > packages.txt
2. 创建新环境并安装这些软件包:
bashconda create -n env_new --file packages.txt
conda create --name env_new --clone env_oldconda env export + conda env create。这样可以方便地复制和管理你的 conda 环境。
git clone --recursive https://github.com/DekuLiuTesla/CityGaussian.git
怎么克隆V1-original的版本
如果你想克隆一个特定的分支(比如仓库中的V1-original分支),可以这样操作:
bashgit clone --recursive --branch V1-original https://github.com/DekuLiuTesla/CityGaussian.git
git clone:可以进入克隆好的文件夹中,然后切换到指定分支:
bashcd CityGaussian git checkout V1-original git submodule update --init --recursive
在仓库文件夹中运行:
bashgit branch
你应该看到类似的输出:
text* V1-original main
其中前面有*号的即为当前所在的分支。
这样你就能确保得到的是仓库中指定的V1-original版本了。