Skip to content

Commit 4fc8882

Browse files
committed
fix in evaluation: consistent with training losses, updated docs
1 parent 8dc1398 commit 4fc8882

10 files changed

+79
-135
lines changed

monoforce/docs/DATA.md

+1-5
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ Colored point cloud | Front-facing camera |
5050
![](./imgs/rgb_cloud.png) | ![](./imgs/camera_fisheye_front.png) | ![](./imgs/camera_up.png)
5151

5252
To explore the data, please follow the tutorial
53-
at [../examples/explore_data_rgb_rigid_terrain.ipynb](../examples/explore_data_rgb_rigid_terrain.ipynb)
54-
or run the module:
55-
```commandline
56-
python -m monoforce.datasets.rough
57-
```
53+
at [../examples/explore_data_rgb_rigid_terrain.ipynb](../examples/explore_data_rgb_rigid_terrain.ipynb).
5854

5955
### Data Sample
6056

monoforce/docs/DPHYS.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Run the differentiable physics simulation with a robot model and the provided da
66
python scripts/robot_control
77
```
88

9-
![](./imgs/hm_learning.gif)
10-
119
Terrain properties optimization from the ground-truth trajectories followed by the robot:
1210
```commandline
1311
python scripts/fit_terrain
1412
```
13+
14+
![](./imgs/hm_learning.gif)

monoforce/docs/INSTALL.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@ catkin build
2626

2727
### Model Weights
2828

29-
The pretrained weights for the LSS terrain encoder can be downloaded from:
30-
- RobinGas: [lss_robingas_husky.pt](https://drive.google.com/file/d/1h1VieiIdGZB1Ml3QdIlh8ZJA67sJej4m/view?usp=sharing),
31-
[lss_robingas_tradr.pt](https://drive.google.com/file/d/1jpsgXN-44Bbu9hfAWd5Z3te1DWp3s8cX/view?usp=sharing),
32-
[lss_robingas_husky_oru.pt](https://drive.google.com/file/d/12v6EAvaw0LqdINYFyHYr0t5mlZn-VN6c/view?usp=sharing),
33-
- RELLIS-3D: [lss_rellis3d.pt](https://drive.google.com/file/d/1kK75mUxHn-4GadU4k8-c43hA9t3bZxw1/view?usp=sharing).
29+
The pretrained weights for the terrain encoder are available at:
30+
[]().
3431

35-
Once downloaded put the weights to `monoforce/config/weights/lss` folder.
32+
Once downloaded, please, put the weights to
33+
`monoforce/config/weights/${MODEL_NAME}` folder,
34+
where `${MODEL_NAME}` is the name is one of the models: `lss, lidarbev, bevfusion`.
3635

3736
## Docker
3837

monoforce/docs/TERRAIN_ENCODER.md

-8
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,3 @@ To train the LSS model, please run:
1919
cd scripts/
2020
python train
2121
```
22-
23-
### Weights
24-
25-
The pretrained weights for the LSS terrain encoder can be downloaded from
26-
[Google Drive](https://drive.google.com/drive/folders/1n0KoUEQ0FIznf-qMKshk0C956CJenIhd?usp=sharing).
27-
28-
Once downloaded put the weights to
29-
`monoforce/monoforce/config/weights/lss` folder.

monoforce/examples/bevfusion.ipynb

+24-17
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,20 @@
33
{
44
"metadata": {
55
"ExecuteTime": {
6-
"end_time": "2024-11-25T12:39:10.061779Z",
7-
"start_time": "2024-11-25T12:39:08.313307Z"
6+
"end_time": "2024-12-17T10:38:44.003902Z",
7+
"start_time": "2024-12-17T10:38:42.182608Z"
88
}
99
},
1010
"cell_type": "code",
1111
"source": [
1212
"import sys\n",
1313
"sys.path.append('../src/')\n",
1414
"import torch\n",
15-
"import numpy as np\n",
1615
"from torch.utils.data import DataLoader\n",
1716
"from monoforce.models.terrain_encoder.bevfusion import BEVFusion\n",
1817
"from monoforce.utils import read_yaml, position\n",
1918
"from monoforce.datasets.rough import ROUGH, rough_seq_paths\n",
20-
"from monoforce.dphys_config import DPhysConfig\n",
21-
"from monoforce.transformations import transform_cloud"
19+
"from monoforce.dphys_config import DPhysConfig"
2220
],
2321
"id": "b7a7dacb0d156951",
2422
"outputs": [
@@ -45,8 +43,8 @@
4543
{
4644
"metadata": {
4745
"ExecuteTime": {
48-
"end_time": "2024-11-25T12:39:10.087675Z",
49-
"start_time": "2024-11-25T12:39:10.062753Z"
46+
"end_time": "2024-12-17T10:38:44.149683Z",
47+
"start_time": "2024-12-17T10:38:44.004928Z"
5048
}
5149
},
5250
"cell_type": "code",
@@ -62,14 +60,23 @@
6260
" points)"
6361
],
6462
"id": "dacf9fbbbc81fec7",
65-
"outputs": [],
63+
"outputs": [
64+
{
65+
"name": "stderr",
66+
"output_type": "stream",
67+
"text": [
68+
"/home/ruslan/miniconda3/envs/mf/lib/python3.9/site-packages/torch/functional.py:504: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at /opt/conda/conda-bld/pytorch_1666643016022/work/aten/src/ATen/native/TensorShape.cpp:3190.)\n",
69+
" return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined]\n"
70+
]
71+
}
72+
],
6673
"execution_count": 2
6774
},
6875
{
6976
"metadata": {
7077
"ExecuteTime": {
71-
"end_time": "2024-11-25T12:39:10.105485Z",
72-
"start_time": "2024-11-25T12:39:10.088532Z"
78+
"end_time": "2024-12-17T10:38:44.193210Z",
79+
"start_time": "2024-12-17T10:38:44.150482Z"
7380
}
7481
},
7582
"cell_type": "code",
@@ -86,7 +93,7 @@
8693
"name": "stdout",
8794
"output_type": "stream",
8895
"text": [
89-
"Dataset length: 335\n"
96+
"Dataset length: 349\n"
9097
]
9198
}
9299
],
@@ -95,8 +102,8 @@
95102
{
96103
"metadata": {
97104
"ExecuteTime": {
98-
"end_time": "2024-11-25T12:39:11.121161Z",
99-
"start_time": "2024-11-25T12:39:10.106441Z"
105+
"end_time": "2024-12-17T10:38:45.200218Z",
106+
"start_time": "2024-12-17T10:38:44.194312Z"
100107
}
101108
},
102109
"cell_type": "code",
@@ -121,8 +128,8 @@
121128
{
122129
"metadata": {
123130
"ExecuteTime": {
124-
"end_time": "2024-11-25T12:39:14.271963Z",
125-
"start_time": "2024-11-25T12:39:11.122171Z"
131+
"end_time": "2024-12-17T10:38:48.136932Z",
132+
"start_time": "2024-12-17T10:38:45.200914Z"
126133
}
127134
},
128135
"cell_type": "code",
@@ -142,8 +149,8 @@
142149
{
143150
"metadata": {
144151
"ExecuteTime": {
145-
"end_time": "2024-11-25T12:39:15.973490Z",
146-
"start_time": "2024-11-25T12:39:14.273103Z"
152+
"end_time": "2024-12-17T10:38:49.838240Z",
153+
"start_time": "2024-12-17T10:38:48.137920Z"
147154
}
148155
},
149156
"cell_type": "code",

monoforce/examples/trajectory_shooting_with_torch_diff_physics.ipynb

+35-36
Large diffs are not rendered by default.

monoforce/scripts/eval.py

+5-43
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from monoforce.datasets.rough import ROUGH, rough_seq_paths
1717
from monoforce.models.terrain_encoder.utils import ego_to_cam, get_only_in_img_mask, denormalize_img
1818
from monoforce.utils import read_yaml, write_to_csv, append_to_csv
19+
from monoforce.losses import physics_loss, hm_loss
1920
import matplotlib as mpl
2021

2122

@@ -80,45 +81,6 @@ def __init__(self,
8081
# self.ds = Fusion(path=self.path, lss_cfg=self.lss_config, dphys_cfg=self.dphys_cfg, is_train=False)
8182
self.loader = torch.utils.data.DataLoader(self.ds, batch_size=1, shuffle=False)
8283

83-
def hm_loss(self, height_pred, height_gt, weights=None):
84-
assert height_pred.shape == height_gt.shape, 'Height prediction and ground truth must have the same shape'
85-
if weights is None:
86-
weights = torch.ones_like(height_gt)
87-
assert weights.shape == height_gt.shape, 'Weights and height ground truth must have the same shape'
88-
89-
# remove nan values
90-
mask_valid = ~torch.isnan(height_gt)
91-
height_gt = height_gt[mask_valid]
92-
height_pred = height_pred[mask_valid]
93-
weights = weights[mask_valid]
94-
95-
# compute weighted loss
96-
loss = torch.nn.functional.mse_loss(height_pred * weights, height_gt * weights, reduction='mean')
97-
assert not torch.isnan(loss), 'Terrain Loss is nan'
98-
99-
return loss
100-
101-
def physics_loss(self, states_pred, states_gt, pred_ts, gt_ts):
102-
# unpack the states
103-
X, Xd, R, Omega = states_gt
104-
X_pred, Xd_pred, R_pred, Omega_pred = states_pred
105-
106-
# find the closest timesteps in the trajectory to the ground truth timesteps
107-
ts_ids = torch.argmin(torch.abs(pred_ts.unsqueeze(1) - gt_ts.unsqueeze(2)), dim=2)
108-
109-
# get the predicted states at the closest timesteps to the ground truth timesteps
110-
batch_size = X.shape[0]
111-
X_pred_gt_ts = X_pred[torch.arange(batch_size).unsqueeze(1), ts_ids]
112-
113-
# remove nan values
114-
mask_valid = ~torch.isnan(X_pred_gt_ts)
115-
X_pred_gt_ts = X_pred_gt_ts[mask_valid]
116-
X = X[mask_valid]
117-
loss = torch.nn.functional.mse_loss(X_pred_gt_ts, X)
118-
assert not torch.isnan(loss), 'Physics Loss is nan'
119-
120-
return loss
121-
12284
def run(self, vis=False, save=False):
12385
if save:
12486
# create output folder
@@ -168,12 +130,12 @@ def run(self, vis=False, save=False):
168130
# friction_pred = torch.ones_like(terrain_pred)
169131

170132
# evaluation losses
171-
terrain_loss = self.hm_loss(height_pred=terrain_pred[0, 0], height_gt=hm_terrain[0, 0])
133+
loss_terrain = hm_loss(height_pred=terrain_pred[0, 0], height_gt=hm_terrain[0, 0], weights=hm_terrain[0, 1])
172134
states_gt = [Xs, Xds, Rs, Omegas]
173135
state0 = tuple([s[:, 0] for s in states_gt])
174136
states_pred, _ = self.dphysics(z_grid=terrain_pred.squeeze(1), state=state0,
175137
controls=controls, friction=friction_pred.squeeze(1))
176-
physics_loss = self.physics_loss(states_pred, states_gt, pred_ts=control_ts, gt_ts=traj_ts)
138+
loss_physics = physics_loss(states_pred=states_pred, states_gt=states_gt, pred_ts=control_ts, gt_ts=traj_ts)
177139

178140
# visualizations
179141
terrain_pred = terrain_pred[0, 0].cpu()
@@ -187,7 +149,7 @@ def run(self, vis=False, save=False):
187149
# hm_points = hm_points[:, terrain_mask]
188150

189151
plt.clf()
190-
plt.suptitle(f'Terrain Loss: {terrain_loss.item():.4f}, Physics Loss: {physics_loss.item():.4f}')
152+
plt.suptitle(f'Terrain Loss: {loss_terrain.item():.4f}, Physics Loss: {loss_physics.item():.4f}')
191153
for imgi, img in enumerate(imgs[0]):
192154
cam_pts = ego_to_cam(hm_points, rots[0, imgi], trans[0, imgi], intrins[0, imgi])
193155
mask = get_only_in_img_mask(cam_pts, H, W)
@@ -251,7 +213,7 @@ def run(self, vis=False, save=False):
251213
if save:
252214
plt.savefig(f'{self.output_folder}/{i:04d}.png')
253215
append_to_csv(f'{self.output_folder}/losses.csv',
254-
f'{i:04d}.png, {terrain_loss.item():.4f},{physics_loss.item():.4f}\n')
216+
f'{i:04d}.png, {loss_terrain.item():.4f},{loss_physics.item():.4f}\n')
255217

256218
plt.close(fig)
257219

monoforce/scripts/eval.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ROBOT=marv
66

77
source $HOME/workspaces/traversability_ws/devel/setup.bash
88
# loop through data sequences
9-
for SEQ_I in {0..27};
9+
for SEQ_I in {0..18};
1010
do
1111
echo "Evaluating sequence ${SEQ_I}"
1212
./eval.py --model_path ${WEIGHTS} --robot ${ROBOT} --seq_i ${SEQ_I} --vis #--save

monoforce/scripts/robot_control.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def motion():
2525

2626
# control inputs: linear velocity and angular velocity, v in m/s, w in rad/s
2727
controls = torch.stack([
28-
torch.tensor([[1.0, 0.0]] * int(dphys_cfg.traj_sim_time / dphys_cfg.dt)), # [v] m/s, [w] rad/s for each time step
28+
torch.tensor([[1.0, 1.0]] * int(dphys_cfg.traj_sim_time / dphys_cfg.dt)), # [v] m/s, [w] rad/s for each time step
2929
]).to(device)
3030
B, N_ts, _ = controls.shape
3131
assert controls.shape == (B, N_ts, 2), f'controls shape: {controls.shape}'
@@ -44,14 +44,12 @@ def motion():
4444
# heightmap defining the terrain
4545
x_grid, y_grid = dphys_cfg.x_grid, dphys_cfg.y_grid
4646
# z_grid = torch.sin(x_grid) * torch.cos(y_grid)
47-
# z_grid = torch.exp(-(x_grid - 2) ** 2 / 4) * torch.exp(-(y_grid - 0) ** 2 / 2)
48-
z_grid = torch.zeros_like(x_grid)
49-
# z_grid = torch.from_numpy(np.load('./gen/terrain_optimization/z_grid.npy'))
50-
z_grid[80:81, 0:100] = 1.0 # add a wall
47+
z_grid = torch.exp(-(x_grid - 2) ** 2 / 4) * torch.exp(-(y_grid - 0) ** 2 / 2)
48+
# z_grid = torch.zeros_like(x_grid)
49+
# z_grid[80:81, 0:100] = 1.0 # add a wall
5150

5251
x_grid, y_grid, z_grid = x_grid.to(device), y_grid.to(device), z_grid.to(device)
5352
friction = dphys_cfg.friction
54-
# friction = torch.from_numpy(np.load('./gen/terrain_optimization/friction.npy'))
5553
friction = friction.to(device)
5654

5755
# repeat the heightmap for each rigid body
@@ -201,7 +199,7 @@ def shoot_multiple():
201199
# simulate the rigid body dynamics
202200
with torch.no_grad():
203201
t0 = time()
204-
states, forces = dphysics(z_grid=z_grid, controls=controls, state=state0)
202+
states, forces = dphysics(z_grid=z_grid, controls=controls, state=state0, vis=False)
205203
t1 = time()
206204
Xs, Xds, Rs, Omegas = states
207205
print(f'Simulation took {(t1-t0):.3f} [sec] on device: {device}')

monoforce/src/monoforce/datasets/rough.py

+1-10
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,9 @@
3333
os.path.join(data_dir, 'ROUGH/24-08-14-monoforce-long_drive'),
3434
os.path.join(data_dir, 'ROUGH/marv_2024-09-26-13-46-51'),
3535
os.path.join(data_dir, 'ROUGH/marv_2024-09-26-13-54-43'),
36-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-12-34-53'),
37-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-13-01-40'),
38-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-13-17-08'),
39-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-13-29-39'),
40-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-13-43-21'),
41-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-13-57-57'),
42-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-14-12-29'),
43-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-14-22-10'),
44-
# os.path.join(data_dir, 'ROUGH/marv_2024-10-05-14-28-15'),
4536
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-16-42'),
4637
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-26-47'),
47-
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-35-05'), # some problem with numpy arrays instead of torch tensors
38+
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-35-05'),
4839
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-52-07'),
4940
os.path.join(data_dir, 'ROUGH/marv_2024-10-31-15-56-33'),
5041

0 commit comments

Comments
 (0)