【4】Humanoid Gym初学之 ---- 关于仿真Issac-GYM出现Tensor出现Nan报错的解决方案及分析过程
报错问题:出现了一个Nan
num_envs很小的情况下没问题,一旦大于50就有nan然后被强行停止函数的运行
Traceback (most recent call last):
File "train.py", line 43, in <module>
train(args)
File "train.py", line 39, in train
ppo_runner.learn(num_learning_iterations=train_cfg.runner.max_iterations, init_at_random_ep_len=True)
File "/home/yyds/桌面/Gym5_human/humanoid-gym-main/humanoid/algo/ppo/on_policy_runner.py", line 129, in learn
actions = self.alg.act(obs, critic_obs)
File "/home/yyds/桌面/Gym5_human/humanoid-gym-main/humanoid/algo/ppo/ppo.py", line 93, in act
self.transition.actions = self.actor_critic.act(obs).detach()
File "/home/yyds/桌面/Gym5_human/humanoid-gym-main/humanoid/algo/ppo/actor_critic.py", line 133, in act
self.update_distribution(observations)
File "/home/yyds/桌面/Gym5_human/humanoid-gym-main/humanoid/algo/ppo/actor_critic.py", line 114, in update_distribution
self.distribution = Normal(mean, mean*0. + self.std)
File "/home/yyds/.local/lib/python3.8/site-packages/torch/distributions/normal.py", line 50, in __init__
super(Normal, self).__init__(batch_shape, validate_args=validate_args)
File "/home/yyds/.local/lib/python3.8/site-packages/torch/distributions/distribution.py", line 55, in __init__
raise ValueError(
ValueError: Expected parameter loc (Tensor of shape (128, 10)) of distribution Normal(loc: torch.Size([128, 10]), scale: torch.Size([128, 10])) to satisfy the constraint Real(), but found invalid values:
tensor([[-0.0894, -0.0036, -0.0296, ..., -0.0120, 0.0645, 0.0829],
[-0.0959, 0.0003, -0.0248, ..., -0.0023, 0.0624, 0.0635],
[-0.1045, 0.0304, -0.0236, ..., -0.0096, 0.0812, 0.0747],
...,
[-0.0886, 0.0052, 0.0767, ..., 0.0252, -0.0141, 0.1679],
[-0.1043, 0.0212, -0.0588, ..., 0.0114, 0.0969, 0.0459],
[-0.0986, 0.0268, 0.0214, ..., -0.0173, 0.0592, 0.0900]],
device='cuda:0')
分析1
发现出现了这样的一个初始化,会不会和初始化有了一定程度的关系?
初步排查是这里的值存在Nan
而这个函数又被act函数引用
其又被一个内部类的函数应用
传入的参数为:
obs和critic_obs
那么我么就寻找obs这个变量的来源:
找到了这个函数:
返回类型为tensor类型的:
由于其用装饰函数修饰,必须要在子类中实现,所以我们查看它的子类在哪里集成了这个类:
这里env继承了这个类,但下面就走不通了,我们得另找其他路径来解决问题。。
找到了这个函数的定义了,在base_task文件中,返回的是obs_buf这个变量
那么我们继续查找这个变量
发现和下面的这两个变量紧密相关:
self.num_envs 环境数目
self.num_obs 观测值数目
说明它有环境数目行,观测值那么多列
整个目录又来base_task下面
被继承
被我们所继承
但我们还是不清楚obs_buf为什么会有一行,也就是有一个观测体会没有观测值?(也就是前面图片的变量,忘了前面图片找去)
我们进行了如下的查找,找到了这个obs_buf内容都是什么
我们询问copilot相关内容都是什么:
以及特权观察信息
二者分别对应了这里:
def compute_observations(self):
phase = self._get_phase()
self.compute_ref_state()
sin_pos = torch.sin(2 * torch.pi * phase).unsqueeze(1)
cos_pos = torch.cos(2 * torch.pi * phase).unsqueeze(1)
stance_mask = self._get_gait_phase()
contact_mask = self.contact_forces[:, self.feet_indices, 2] > 5.
self.command_input = torch.cat(
(sin_pos, cos_pos, self.commands[:, :3] * self.commands_scale), dim=1)
q = (self.dof_pos - self.default_dof_pos) * self.obs_scales.dof_pos
dq = self.dof_vel * self.obs_scales.dof_vel
diff = self.dof_pos - self.ref_dof_pos
self.privileged_obs_buf = torch.cat((
self.command_input, # 2 + 3
(self.dof_pos - self.default_joint_pd_target) * \
self.obs_scales.dof_pos, # 12
self.dof_vel * self.obs_scales.dof_vel, # 12
self.actions, # 12
diff, # 12
self.base_lin_vel * self.obs_scales.lin_vel, # 3
self.base_ang_vel * self.obs_scales.ang_vel, # 3
self.base_euler_xyz * self.obs_scales.quat, # 3
self.rand_push_force[:, :2], # 3
self.rand_push_torque, # 3
self.env_frictions, # 1
self.body_mass / 30., # 1
stance_mask, # 2
contact_mask, # 2
), dim=-1)
obs_buf = torch.cat((
self.command_input, # 5 = 2D(sin cos) + 3D(vel_x, vel_y, aug_vel_yaw)
q, # 12D
dq, # 12D
self.actions, # 12D
self.base_ang_vel * self.obs_scales.ang_vel, # 3
self.base_euler_xyz * self.obs_scales.quat, # 3
), dim=-1)
if self.cfg.terrain.measure_heights:
heights = torch.clip(self.root_states[:, 2].unsqueeze(1) - 0.5 - self.measured_heights, -1, 1.) * self.obs_scales.height_measurements
self.privileged_obs_buf = torch.cat((self.obs_buf, heights), dim=-1)
if self.add_noise:
obs_now = obs_buf.clone() + torch.randn_like(obs_buf) * self.noise_scale_vec * self.cfg.noise.noise_level
else:
obs_now = obs_buf.clone()
self.obs_history.append(obs_now)
self.critic_history.append(self.privileged_obs_buf)
obs_buf_all = torch.stack([self.obs_history[i]
for i in range(self.obs_history.maxlen)], dim=1) # N,T,K
self.obs_buf = obs_buf_all.reshape(self.num_envs, -1) # N, T*K
self.privileged_obs_buf = torch.cat([self.critic_history[i] for i in range(self.cfg.env.c_frame_stack)], dim=1)
也就是常见的那些观测值,那这样的话就跟我的urdf文件就有很大的关系了。
分析2
对urdf文件进行细致的分析。。
初步猜想是由于导出时的转动惯量造成的,所以我接下来进一步的分析。
然后我们来到了urdf的文件中:
我看到了这俩货:
effort和velocity
初步检查是关节电机的两个参数,我用的是达妙的电机,所以将力矩effort设置为20N/m,velocity角速度我设置为20.7rad/s,两个都设置为20。
分析3 质量
我看到有一个初始化质量的阶段,因此我怀疑是不是初始化随机智联的时候,将质量变为了负数?
然后我发现了这里
嗯嗯,应该是初始化的baseline的质量超了,或者减去5变为负数了,所以停止了。
分析4 其他?
我以为我完事儿了,没想到我把num_envs调整到512训练的时候,发现还是有腾空而起的现象,我还得进一步看看到底是咋回事儿。
发现
最终我发现,除了质量超了之外,还有一点很关键,就是urdf模型的转动惯量,由于SW有BUG,导致自动导出的转动惯量都很小,主轴的都跟偏轴的差不多了,这可不行,所以我直接重新配置转动惯量(一个一个打入的,累死)。。。
保证IXX IYY IZZ这些主轴的比其他的大得多就不会出现导入乱飞等。。。。
本文作者:泪水下的笑靥
本文链接:https://www.cnblogs.com/myleaf/p/18523125
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具