Files
nbrightandClaude Opus 5 609d9a6972 Add SUM Parts reproduction and Seosan Myeongcheon application pipeline
Reproduces the SUM Parts (CVPR 2025) face-labeling benchmark on a single
consumer GPU, then applies it to drone-photogrammetry road survey meshes.

Verified on RTX 3060 12GB / WSL2 Ubuntu 22.04 / CUDA 11.8 / torch 2.0.1:
- CUDA extensions build (pointnet2_batch, pointops, chamfer_dist, emd,
  subsampling)
- PointNet 100 epochs reaches mIoU 17.19, matching the paper's reported 15.1
- OBJ -> PLY conversion round-trips through the model and yields per-point
  predictions

Four upstream source patches, all idempotent, originals preserved:
- numpy aliases removed in 1.24 (np.long etc.) and collections ABCs moved in
  python 3.10
- the blind test split ships label = -1, which crashed ConfusionMatrix
- mode=val referenced `epoch` before assignment

Documents the traps that cost the most time, including VRAM overflow silently
falling back to host RAM on WSL2 (25-100x slowdown, no OOM) and the colour
scale mismatch between r/g/b float32 and red/green/blue uint8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 10:29:25 +09:00

48 lines
1.5 KiB
Bash

#!/usr/bin/env bash
# SUM Parts - inspect label values in the test split
#
# test() crashed in ConfusionMatrix.update with
# RuntimeError: bincount only supports 1-d non-negative integral inputs
# which means true*num_classes + pred went negative, non-integral, or 2-D.
# Check what the files actually contain.
set -uo pipefail
DATA="${1:-$HOME/sum-parts/data/face_labeling/texsp_pcl}"
source "$HOME/miniconda3/etc/profile.d/conda.sh"
conda activate sumparts
python - "$DATA" <<'PY'
import sys
from pathlib import Path
import numpy as np
from plyfile import PlyData
root = Path(sys.argv[1])
print(f"root: {root}\n")
for split in ("test", "train"):
files = sorted((root / split).glob("*.ply"))
print(f"=== {split}: {len(files)} files ===")
for f in files:
v = PlyData.read(str(f))["vertex"]
props = [p.name for p in v.properties]
if "label" not in props:
print(f" {f.name:<34} NO LABEL FIELD props={props}")
continue
lab = np.asarray(v["label"])
u = np.unique(lab)
neg = int((lab < 0).sum())
flag = ""
if neg:
flag += f" NEGATIVE x{neg}"
if u.max() > 12:
flag += f" OUT-OF-RANGE max={u.max()}"
if not np.issubdtype(lab.dtype, np.integer):
flag += f" NON-INTEGER dtype={lab.dtype}"
print(f" {f.name:<34} n={len(lab):>8,} dtype={str(lab.dtype):<8} "
f"range=[{u.min()},{u.max()}] uniq={len(u)}{flag}")
print()
PY