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

114 lines
3.9 KiB
Bash

#!/usr/bin/env bash
# SUM Parts - build only the CUDA extensions (rerunnable)
#
# Split out of setup_pointnext.sh so a failed compile can be retried without
# reinstalling every python dependency.
#
# ninja note: torch 2.0's cpp_extension shells out to `ninja -v` and reads its
# output through a pipe. ninja >= 1.12 dies with SIGPIPE there, which torch
# surfaces only as the useless "Error compiling objects for extension".
# Pinning ninja to 1.11.x avoids it.
set -euo pipefail
CONDA_ROOT="$HOME/miniconda3"
ENV_NAME="sumparts"
REPO="$HOME/sum-parts/semantic_segmentation/PointNeXt_bundle"
source "$CONDA_ROOT/etc/profile.d/conda.sh"
conda activate "$ENV_NAME"
export TORCH_CUDA_ARCH_LIST="8.6" # RTX 3060
export CUDA_HOME="$CONDA_PREFIX"
export PATH="$CUDA_HOME/bin:$PATH"
export MAX_JOBS="${MAX_JOBS:-4}"
echo "=== pin ninja to 1.11.x ==="
pip install --no-cache-dir "ninja==1.11.1.1"
ninja --version
# subsampling/setup.py imports numpy.distutils, which imports
# distutils.msvccompiler. setuptools removed that module in 74.0, so anything
# newer dies with "No module named 'distutils.msvccompiler'".
echo "=== pin setuptools to 69.5.1 (numpy.distutils needs it) ==="
pip install --no-cache-dir "setuptools==69.5.1"
python -c "import setuptools; print('setuptools', setuptools.__version__)"
# Skip extensions that already import cleanly, so a retry does not redo a
# 5-minute nvcc pass that already succeeded. FORCE=1 rebuilds everything.
have() { python -c "import $1" 2>/dev/null; }
# NOTE: pointnet2_batch's setup.py names the extension pointnet2_batch_cuda,
# not pointnet2_cuda as in upstream PointNet++ forks.
if [ "${FORCE:-0}" = "1" ] || ! have pointnet2_batch_cuda; then
echo "=== build pointnet2_batch ==="
cd "$REPO/openpoints/cpp/pointnet2_batch"
rm -rf build ./*.egg-info dist
python setup.py install
else
echo "=== skip pointnet2_batch (already importable) ==="
fi
echo "=== build subsampling ==="
cd "$REPO/openpoints/cpp/subsampling"
rm -rf build ./*.so
python setup.py build_ext --inplace
if [ "${FORCE:-0}" = "1" ] || ! have pointops_cuda; then
echo "=== build pointops ==="
cd "$REPO/openpoints/cpp/pointops"
rm -rf build ./*.egg-info dist
python setup.py install
else
echo "=== skip pointops (already importable) ==="
fi
# chamfer_dist and emd only matter for reconstruction tasks, but
# openpoints/models/__init__.py imports .reconstruction unconditionally, which
# imports chamfer_dist -- so even a pure segmentation run fails at import time
# without them. They are not optional in practice.
if [ "${FORCE:-0}" = "1" ] || ! have chamfer; then
echo "=== build chamfer_dist ==="
cd "$REPO/openpoints/cpp/chamfer_dist"
rm -rf build ./*.egg-info dist
python setup.py install
else
echo "=== skip chamfer_dist (already importable) ==="
fi
# emd/setup.py names the package emd_ext and the extension emd_cuda; plain
# `emd` is only the python-level alias in openpoints/cpp/emd/__init__.py.
if [ "${FORCE:-0}" = "1" ] || ! have emd_cuda; then
echo "=== build emd ==="
cd "$REPO/openpoints/cpp/emd"
rm -rf build ./*.egg-info dist
python setup.py install
else
echo "=== skip emd (already importable) ==="
fi
echo "=== verify ==="
cd "$REPO"
python - <<'PY'
import sys
print("torch :", __import__("torch").__version__,
"| cuda", __import__("torch").cuda.is_available())
ok = True
for m in ["pointnet2_batch_cuda", "pointops_cuda", "chamfer", "emd_cuda",
"torch_scatter", "plyfile"]:
try:
__import__(m)
print(f"{m:22s}: OK")
except Exception as e:
ok = False
print(f"{m:22s}: FAIL {type(e).__name__}: {e}")
try:
from openpoints.cpp.subsampling import grid_subsampling # noqa: F401
print(f"{'grid_subsampling':22s}: OK")
except Exception as e:
ok = False
print(f"{'grid_subsampling':22s}: FAIL {type(e).__name__}: {e}")
sys.exit(0 if ok else 1)
PY
echo "BUILD DONE"