Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type error in DropPointsByClass #113

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.5.0
hooks:
# list of supported hooks: https://pre-commit.com/hooks.html
- id: trailing-whitespace
Expand All @@ -12,26 +12,26 @@ repos:

# python code formatting
- repo: https://github.com/psf/black
rev: 20.8b1
rev: 24.2.0
hooks:
- id: black
args: [--line-length, "99"]

# python import sorting
- repo: https://github.com/PyCQA/isort
rev: 5.8.0
rev: 5.13.2
hooks:
- id: isort

# yaml formatting
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.3.0
rev: v4.0.0-alpha.8
hooks:
- id: prettier
types: [yaml]

# python code analysis
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
rev: 7.0.0
hooks:
- id: flake8
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# CHANGELOG
### 3.8.2
- fix: type error in edge case when dropping points in transforms

### 3.8.1
- fix: propagate input las format to output las (in particular epsg which comes either from input or config)

Expand Down
7 changes: 4 additions & 3 deletions myria3d/pctl/transforms/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def subsample_data(data, num_nodes, choice):
continue
elif torch.is_tensor(item) and item.size(0) == num_nodes and item.size(0) != 1:
data[key] = item[choice]
elif isinstance(item, np.ndarray) and item.shape[0] == num_nodes and item.shape[0] != 1:
data[key] = item[choice]

return data


Expand Down Expand Up @@ -234,7 +237,5 @@ def __call__(self, data):
if points_to_drop.sum() > 0:
points_to_keep = torch.logical_not(points_to_drop)
data = subsample_data(data, num_nodes=data.num_nodes, choice=points_to_keep)
# Here we also subsample these idx since we do not need to interpolate these points back
if "idx_in_original_cloud" in data:
data.idx_in_original_cloud = data.idx_in_original_cloud[points_to_keep]

return data
2 changes: 1 addition & 1 deletion package_metadata.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__: "3.8.1"
__version__: "3.8.2"
__name__: "myria3d"
__url__: "https://github.com/IGNF/myria3d"
__description__: "Deep Learning for the Semantic Segmentation of Aerial Lidar Point Clouds"
Expand Down
28 changes: 28 additions & 0 deletions tests/myria3d/models/test_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import hydra
from pytorch_lightning import LightningDataModule
from tests.conftest import make_default_hydra_cfg

from myria3d.models.model import Model


def test_model_get_batch_tensor_by_enumeration():
config = make_default_hydra_cfg(
overrides=[
"predict.src_las=tests/data/toy_dataset_src/862000_6652000.classified_toy_dataset.100mx100m.las",
"datamodule.epsg=2154",
"work_dir=./../../..",
"datamodule.subtile_width=1",
"datamodule.hdf5_file_path=null",
]
)

datamodule: LightningDataModule = hydra.utils.instantiate(config.datamodule)
datamodule._set_predict_data(config.predict.src_las)

model = Model(
neural_net_class_name="PyGRandLANet",
neural_net_hparams=dict(num_features=2, num_classes=7),
)
for batch in datamodule.predict_dataloader():
# Check that no error is raised ("TypeError: object of type 'numpy.int64' has no len()")
_ = model._get_batch_tensor_by_enumeration(batch.idx_in_original_cloud)
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import numpy as np
import pytest
import torch_geometric
import torch
import torch_geometric

from myria3d.pctl.transforms.transforms import TargetTransform, DropPointsByClass
from myria3d.pctl.transforms.transforms import DropPointsByClass, TargetTransform


def test_TargetTransform_with_valid_config():
Expand All @@ -12,10 +12,12 @@ def test_TargetTransform_with_valid_config():
# 1 becomes 0, and 6 becomes 1.
classification_dict = {1: "unclassified", 6: "building"}
tt = TargetTransform(classification_preprocessing_dict, classification_dict)

y = np.array([1, 1, 2, 2, 6, 6])
data = torch_geometric.data.Data(x=None, y=y)
assert np.array_equal(tt(data).y, np.array([0, 0, 0, 0, 1, 1]))
idx = np.arange(6)
data = torch_geometric.data.Data(x=None, y=y, idx_in_original_cloud=idx)
out_data = tt(data)
assert np.array_equal(out_data.y, np.array([0, 0, 0, 0, 1, 1]))
assert np.array_equal(out_data.idx_in_original_cloud, idx)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you testing that the idx in original cloud are not modified?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, after all I'm not sure it is useful, but I did it to be consistent with the test I added for DropPointsByClass



def test_TargetTransform_throws_type_error_if_invalid_classification_dict():
Expand All @@ -34,11 +36,16 @@ def test_DropPointsByClass():
# points with class 65 are droped.
y = torch.Tensor([1, 65, 65, 2, 65])
x = torch.rand((5, 3))
data = torch_geometric.data.Data(x=x, y=y)
idx = np.arange(5) # Not a tensor
data = torch_geometric.data.Data(x=x, y=y, idx_in_original_cloud=idx)
drop_transforms = DropPointsByClass()
transformed_data = drop_transforms(data)
assert torch.equal(transformed_data.y, torch.Tensor([1, 2]))
assert transformed_data.x.size(0) == 2
print(type(transformed_data.idx_in_original_cloud))
assert isinstance(transformed_data.idx_in_original_cloud, np.ndarray)
assert transformed_data.idx_in_original_cloud.size == 2
assert np.all(transformed_data.idx_in_original_cloud == np.array([0, 3]))

# No modification
x = torch.rand((3, 3))
Expand All @@ -47,3 +54,15 @@ def test_DropPointsByClass():
transformed_data = drop_transforms(data)
assert torch.equal(data.x, transformed_data.x)
assert torch.equal(data.y, transformed_data.y)

# Keep one point only
y = torch.Tensor([1, 65, 65, 65, 65])
x = torch.rand((5, 3))
idx = np.arange(5) # Not a tensor
data = torch_geometric.data.Data(x=x, y=y, idx_in_original_cloud=idx)
transformed_data = drop_transforms(data)
assert torch.equal(transformed_data.y, torch.Tensor([1]))
assert transformed_data.x.size(0) == 1
assert isinstance(transformed_data.idx_in_original_cloud, np.ndarray)
assert transformed_data.idx_in_original_cloud.shape[0] == 1
assert np.all(transformed_data.idx_in_original_cloud == np.array([0]))