Shape issue with 3D patches

Shape issue with 3D patches  

  By: Telcrome on June 30, 2025, 9:18 a.m.

Hi!

I encountered an error with "Check Task 10" after successful feature extraction: "Only zero batch or zero channel inputs are supported, but got input shape: [10, 64, 0, 0, 0]"

Could you help me identify the issue with the patches that I sent to the adapter? Are there constraints to the patch size or embedding sizes?

Would the adapter give specific error messages for other issues? For example, I was unsure about how to set the 'patch spacing' field.

Result ID is c475e71d-29a3-4e33-bcf6-361ff73430c0.

Re: Shape issue with 3D patches  

  By: lphilipp on June 30, 2025, 10:58 a.m.

Hi,

The constrains for the 3D dense radiology tasks are currently that the adaptor method expects a 3D input and due to time and memory limits, the patch size should not be too big (or too small) - but that does not seem to be the issue here.

If you do not use any specific resampling per patch, you can set the patch spacing to the image spacing, like in src/unicorn_baseline/vision/radiology/main.py -> extract_features_segmentation.

Regarding the error you encountered, it looks like the patch is empty. You can download the encoded patch-neural-representation.json from Grand Challenge when navigating to Submit -> Submissions -> your algorithm run -> Result or navigate to your algorithm page -> Results after running your algorithm on the leaderboard. Let me know if this helps, otherwise I am happy to assist you further.

Re: Shape issue with 3D patches  

  By: Telcrome on June 30, 2025, 4:20 p.m.

After increasing the patchsize from 8x8x8 to 64x64x64 and adding a field "patch-spacing" with the "image-spacing", the adapter does not error for task 10, but for task 11 I get "AssertionError: Coordinates don't match!" for several patch sizes.

Perhaps I am not approaching the issue of sending my features to the platform correctly. My model outputs voxel features, where each voxel or small group of voxels is represented by an embedding of size C. Currently, I am trying to average the voxel features to obtain patch features.

Do you have an idea how I could verify my patch representations? I used SimpleITK for metadata handling to be able to reuse as much of the baseline code as possible. I adapted it like:

# voxel_features_original are voxel features (C, spatials...) with the exact same shape as sitk_image (no padding)
for x, y, z in itertools.product(
    *[range(0, voxel_features_original.shape[dim + 1], patch_size[dim]) for dim in range(3)]
):
    patch = voxel_features_original[
        :,
        x : x + patch_size[0],
        y : y + patch_size[1],
        z : z + patch_size[2],
    ]
    patches.append(patch)
    matrix_coordinates = (x, y, z)
    coordinates.append(sitk_image.TransformIndexToPhysicalPoint(matrix_coordinates))
patch_and_coords = [
    {
        "coordinates": coordinates[i],
        "features": torch.mean(patches[i], dim=(1, 2, 3)).tolist(),
    }
    for i in range(len(patches))
]
return [
    {
        "title": image_input["interface"]["slug"],
        "patches": patch_and_coords,
        "meta": {
            "patch-size": list(patch_size),
            "patch-spacing": list(sitk_image.GetSpacing()),
            "image-size": list(sitk_image.GetSize()),
            "image-origin": list(sitk_image.GetOrigin()),
            "image-spacing": list(sitk_image.GetSpacing()),
            "image-direction": list(sitk_image.GetDirection()),
        },
    }
]

Re: Shape issue with 3D patches  

  By: lphilipp on July 2, 2025, 8:06 a.m.

The coordinates extracted during encoding need to match the coordinates that are extracted for the groundtruth in the evaluation script: This is where the coordinates for the labels are extracted (follows the same logic as the baseline): src/unicorn_eval/adaptors/segmentation.py -> def extract_patch_labels

This is where the coordinates are checked: src/unicorn_eval/adaptors/segmentation.py -> def construct_data_with_labels

You can implement your own patch-extraction strategy for the evaluation adaptor, but you’ll need to contribute it to the project to make it available on grand-challenge.

Regarding the verification of your patch representations: Locally run extract_patch_labels.py on a few sample images. Compare the output coordinates with those produced by your extractor to confirm they’re identical.

If your preprocessing resamples the images or patches, please verify that the correct spacing is written to the patch-neural-representation.json, as mentioned before, you can download that file from grand-challenge or test it locally. Task 10 images have already been resampled to a common spacing/size, whereas Task 11 images have not. That difference could explain why the code works for Task 10 but fails for Task 11.

 Last edited by: lphilipp on July 2, 2025, 8:08 a.m., edited 1 time in total.