Repository navigation
[AdvCP] Add asset generation and validation utilities - #184
meaning-0f-life wants to merge 10 commits into
Conversation
| @@ -0,0 +1,93 @@ | |||
| """ | |||
There was a problem hiding this comment.
Let's move utilities within opencda/scripts directory
| # 4. Validate removal perturbation (if provided) | ||
| if args.remove_perturb is not None: | ||
| try: | ||
| _validate_remove_perturb(args.remove_perturb, car_vertex_count) |
There was a problem hiding this comment.
Removal assets are based on the 98-vertex adv-shape template, not on --car-mesh. Passing car_vertex_count to both removal checks makes the documented “validate all assets” workflow reject assets generated by these utilities for example, an 8-vertex generated car mesh together with a 98-vertex removal template. Please resolve a separate removal-template vertex count and use it for both remove-divide and remove-perturb; --advshape-template-vertices should take precedence when provided.
| @@ -0,0 +1,93 @@ | |||
| """ | |||
There was a problem hiding this comment.
Also, you need to run simulation with attacks and pin proofs how it works with new generated assets
| np.argwhere(z >= maxs[2] - eps[2]).reshape(-1), | ||
| np.argwhere(z <= mins[2] + eps[2]).reshape(-1), | ||
| np.argwhere(np.logical_and(x >= mids[0], z >= mids[2])).reshape(-1), | ||
| np.argwhere(np.logical_and(x < mids[0], z >= mids[2])).reshape(-1), |
There was a problem hiding this comment.
Generating the default car mesh produces an 8-vertex box. For that mesh, these last two groups contain only two vertices each. TriangleMesh.select_by_index() therefore returns empty meshes for them, and AdvCPCarMeshHelper.ray_intersection() currently passes those empty meshes to RaycastingScene; I reproduced an IndexError: _Map_base::at. Please generate groups that each retain at least one face (or subdivide the default mesh), and validate the resulting mesh pieces rather than only checking that an index array is non-empty.
| The AdvCP template mesh. | ||
| """ | ||
| template = box_mesh(4.9, 2.5, 2.0) | ||
| return subdivide_midpoint(template, levels=2) |
There was a problem hiding this comment.
This template is geometrically equivalent to the runtime AdvCP template, but its vertex ordering differs from the Open3D template created in _create_adv_shape_template_mesh(). The generated .pkl indices and .npy perturbations are positional, so they are applied to different runtime vertices. In a local comparison, none of the 10 generated groups matched the runtime groups. Please share the exact same template construction and vertex ordering with the consumer, or export and consume the generated template mesh itself.
| @@ -0,0 +1,93 @@ | |||
| """ | |||
There was a problem hiding this comment.
Also, you need to add new assets in PR
| """ | ||
| if blueprint is None: | ||
| return _DEFAULT_DIMENSIONS_M | ||
| return _BLUEPRINT_DIMENSIONS_M.get(blueprint, _DEFAULT_DIMENSIONS_M) |
There was a problem hiding this comment.
An unknown blueprint silently falls back to Tesla Model 3 dimensions, and the blueprint is only used to select hardcoded dimensions for a box mesh. No CARLA vehicle geometry is queried or exported. This means different CARLA blueprint values can produce the same generic box and does not provide the blueprint-based mesh generation requested in #140. Please either derive the geometry or bounding box from CARLA, or rename and document this mode as a generic box fallback and fail or warn for unknown blueprints.
| return None | ||
|
|
||
| cache_dir_value = config.get("asset_cache_dir") | ||
| if cache_dir_value is None: |
There was a problem hiding this comment.
Issue #140 describes caching as optional, but removal runtime generation is disabled entirely when asset_cache_dir is not configured. Generation and caching should be separate choices: without a cache directory, the helper should still be able to generate to the explicitly configured removal asset paths (or another documented temporary/output location).
| cache_dir = cls._resolve_absolute(cache_dir_value) | ||
| blueprint = str(config.get("vehicle_blueprint") or "vehicle.default").replace(".", "_") | ||
| mesh_name = f"car_mesh_{blueprint}.ply" | ||
| divide_name = f"car_mesh_divide_{blueprint}.pkl" |
There was a problem hiding this comment.
The cache key only includes the blueprint name, while the generated mesh also depends on car_mesh_dimensions, car_mesh_source_path, car_mesh_preserve_aspect, and the generation algorithm. Changing any of those values will silently reuse stale, incompatible assets. Please include all generation inputs, or a deterministic metadata hash and format version, in the cache identity and validate the metadata before reuse.
|
|
||
| with path.open("rb") as handle: | ||
| handle.seek(data_offset) | ||
| vertex_struct = struct.Struct("<ddd") |
There was a problem hiding this comment.
This binary PLY reader ignores the property declarations in the header and hardcodes vertices as three double values and faces as uchar plus uint32 indices. Valid external PLY files commonly use float coordinates or include normals and colors, which shifts the binary layout and causes incorrect parsing or EOF errors. Since #140 requires external .ply inputs, please parse the declared property types and order or delegate PLY loading to a format-aware library such as Open3D.
- Build the adv-shape template with Open3D's exact vertex/triangle ordering (create_box + subdivide_midpoint) and use it as the single source of truth in early_fusion_attack; share the default removal partition (advshape_default_divide) between generator and runtime. - Subdivide the default generated car mesh and validate that every divide group yields a non-empty mesh piece (generators, runtime helper and validator), preventing empty RaycastingScene inputs. - Replace the hardcoded binary PLY reader with a header-driven parser (float/double, extra properties, both byte orders, polygons). - Measure the reference bbox of car meshes missing from CAR_MESH_3D_EXAMPLES instead of borrowing car_mesh_0200's. - Add regression tests pinned to Open3D 0.18/0.19 output; apply ruff format to the asset utilities.
Keep asset_utils and runtime_assets in opencda/core/attack/advcp/utils as the library shared with the attack runtime, and move the command-line wrappers (generate_car_mesh, generate_mesh_divide, generate_remove_advshape_assets, validate_advcp_assets) to scripts/advcp, run as `python -m scripts.advcp.<name>` from the repository root. Their smoke tests move to test/ alongside the other script tests; usage examples now point at a models-repository bundle instead of the removed in-tree 3d_models directory.
Removal divide and perturbation assets are indexed against the 98-vertex adv-shape template used by the attack runtime, not against --car-mesh. The validator now resolves the template vertex count separately (--advshape-template-vertices takes precedence when given), checks both removal assets against it, and verifies that every removal group keeps template triangles. The documented "validate all assets" workflow now accepts assets produced by the generation scripts.
Blueprint-based mesh generation only looks up approximate dimensions in a small table and builds a generic box; no CARLA geometry is queried. Document it as such, and raise an actionable error for blueprints that are not in the table (pass --dimensions / car_mesh_dimensions or an external mesh instead) rather than silently using Tesla Model 3 dimensions. The CLI reports the error through argparse.
AdvCoperceptionModelManager.load_config now calls AdvCPRuntimeAssetHelper.prepare_assets, so `asset_runtime_generation: true` in the AdvCP YAML generates the car mesh and spoof divide (and, with advshape, removal assets) on demand and points the config at them. Generation and caching are now independent: - explicit asset paths: missing files are generated there; files without generation metadata are user-provided and never overwritten (a missing spoof divide is derived from a user mesh); - asset_cache_dir: assets are stored under a key hashing every generation input (blueprint, dimensions, source mesh content, preserve_aspect, subdivision, format version) and a metadata.json is checked before reuse, so changed inputs never reuse stale assets; - neither: spoof assets go to a per-process temporary directory and removal assets fall back to the identical runtime default partition. Bundle default paths are never written to. Relative paths resolve against the AdvCP YAML directory. New config keys are documented in AdvCPConfig and example.yaml.
Summary
Related to #140
Adds utility scripts under
opencda/core/attack/advcp/utils/for generating and validating the 3D assets required by AdvCP spoofing and removal attacks. This addresses the reproducibility problem raised in the original AdvCollaborativePerception repository (zqzqz/AdvCollaborativePerception#8) and extends the same capability to removal-related assets.Changes
New files
utils/generate_remove_advshape_assets.py— CLI for generating removal mesh-divide metadata (.pkl) and adversarial-shape perturbation tensors (.npy). Supports three modes:divide,perturb, andboth. Perturbations can be zero-initialised or random with configurable scale and seed.utils/validate_advcp_assets.py— CLI for validating.ply,.pkl, and.npyassets against AdvCP pipeline requirements. Checks file existence, mesh structural integrity, coordinate frame and scale, divide-index bounds, and perturbation shape/finiteness. Exits with code 0 on success or 1 with actionable error messages.test/test_advcp_asset_utils.py— 90 unit tests (84 passed, 6 skipped on Python 3.9) covering all utility functions, CLI smoke tests, and edge cases. All tests use temporary directories and do not modify the repository.Modified files
utils/__init__.py— Updated module docstring with descriptions of all submodules.utils/asset_utils.py— Added comprehensive NumPy-style docstrings toMeshDataand all 17 functions (parameters, return values, raised exceptions).utils/generate_car_mesh.py— Added module-level and function-level docstrings.utils/generate_mesh_divide.py— Added module-level and function-level docstrings.utils/runtime_assets.py— Added module-level and class-level docstrings with detailed parameter documentation forAdvCPRuntimeAssetHelperand all 6 methods.Key features
AdvCPRuntimeAssetHelperprovides on-demand asset generation during simulation, avoiding the need to commit large.ply/.pkl/.npyfiles to the repository.asset_cache_dirconfig key.car_0200.plygenerated?" problem.Usage examples