Files
sum-parts-test/docs/SUM-Parts-검토노트.md
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

47 KiB
Raw Permalink Blame History

SUM Parts 검토 노트

대상: tudelft3d/SUM-Parts-Benchmarks 목적: 로컬 재현 테스트 + 한국 샘플 데이터 적용 가능성 확인 작성일: 2026-08-20


1. 프로젝트 개요

SUM Parts — TU Delft 3D geoinformation, CVPR 2025. 도시 텍스처 3D 메시part-level(부품 단위) 시맨틱 세그멘테이션 벤치마크.

항목 내용
규모 2.5 km² 도시 메시
어노테이션 이중 트랙 — face 단위 + texture 픽셀 단위
클래스 21종
텍스처 메시 포맷 ASCII PLY
시맨틱 포인트클라우드 포맷 binary PLY
데이터 배포 Hugging Face gwxgrxhyz/SUM-Parts (게이트 있음, 아래 참조)
논문 arXiv:2503.15300
프로젝트 페이지 https://tudelft3d.github.io/SUMParts/
연락처 gaoweixiaocuhk@gmail.com (Weixiao Gao)

클래스 — README는 21이라 하지만, 코드상 트랙별로 다르다

README 전체 목록 (21종):

unclassified, terrain, high vegetation, water, car, boat,
wall, roof surface, facade surface, chimney, dormer, balcony,
roof installation, window, door, low vegetation,
impervious surface, road, road marking, cycle lane, sidewalk

실제 학습 코드에서는 트랙별로 분리된다 (PointNeXt openpoints/dataset/ 확인 결과):

트랙 클래스 수 목록
SUMV2_Triangle (face/메시) 13 unclassified, terrain, high_vegetation, facade_surface, water, car, boat, roof_surface, chimney, dormer, balcony, roof_installation, wall
SUMV2_Texture (텍스처 픽셀) 20 위 + window, door, low_vegetation, road, road_marking 등 세부 클래스

→ 벤치마크 재현 시 cfg의 num_classes와 데이터 트랙을 반드시 일치시켜야 한다. ignore_index: 0 (unclassified는 손실 계산에서 제외).

PLY 필드 규약

필드 의미
f:color face 단위 색상
v:color vertex(point) 단위 색상
f:label / v:label 시맨틱 라벨
h:texcoord 텍스처 좌표 (halfedge)

리포지토리 구조

  • semantic_segmentation/ — 딥러닝 베이스라인
    • KPConv (train_UrbanMesh.py, UrbanMesh.py)
    • PointNeXt_bundle (PointNet, PointNet++, PointNeXt, PointVector)
    • Open3D_ML (SparseConvUNet, RandLA-Net)
    • SPG
    • RF_MRF / SUM_RF / PSSNet → 별도 PSSNet repo의 sumv2 브랜치
  • interactive_annotation/ — SAM, SimpleClick 기반 텍스처 어노테이션 도구
  • assets/ — 문서 이미지, 설정 파일

데이터 접근 — 게이트 걸려 있음 ⚠️

HF 데이터셋이 gated: auto. 토큰만으로는 안 되고 계정별 약관 수락이 1회 필요하다. 수락 전에는 모든 다운로드가 HTTP 403.

수동 절차 (브라우저 필요, 자동화 불가)

  1. https://huggingface.co/datasets/gwxgrxhyz/SUM-Parts 접속
  2. 로그인 후 게이트 폼에서 CC BY-NC 4.0 수락
  3. 이후 캐시된 토큰으로 자동 다운로드 가능

배포 파일

파일 내용
demo.zip 소량 샘플 — 스모크 테스트용. 여기부터 시작
mesh.zip 텍스처 메시 (ASCII PLY)
pcl.zip 시맨틱 포인트클라우드 (binary PLY)

데이터 레이아웃 (PointNeXt 기준)

cfgs/sumv2_triangle/default.yamldata_root: ../../data/sumv2_tri_texpcl/

⚠️ 이 상대경로는 main.py의 작업 디렉토리 기준이다. main.pyexamples/segmentation/에서 실행되므로 ../../ = **PointNeXt_bundle/**이지 repo 루트가 아니다. 착각하면 Totally 0 samples in train set으로 조용히 실패한다.

PointNeXt_bundle/data/sumv2_tri_texpcl/
├── train/*.ply
├── val/*.ply
├── test/*.ply
└── processed/          # presample 캐시, 자동 생성

여기서는 데이터를 <repo>/data에 두고 심볼릭 링크로 연결했다 (scripts/link_data.sh).

demo.zip 실제 구조 (train/val/test 아님 — 타일 1장짜리 쇼케이스):

data/
├── mesh/
│   ├── textured_mesh/      demo.ply + demo.jpg
│   ├── face_label/         demo_face_label.ply + .jpg
│   ├── pixel_label/        demo_pixel_label.ply + .png
│   └── full_pixel_label/   demo_full_pixel_label.ply + .png
└── pcl/
    ├── face_labeling_pcl/     demo_{texsp,fdcen,poisson,rand}_pcl.ply
    └── texture_labeling_pcl/  demo_{texsp,poisson,rand}_pcl.ply

cfg 디렉토리명 sumv2_tri_texpcl = triangle 트랙 + texsp 샘플러pcl/face_labeling_pcl/demo_texsp_pcl.ply

PLY vertex 속성 (실측 + read_ply_with_plyfilelib 확인):

속성 실제 배포본 필수 비고
x, y, z float32
nx, ny, nz 로더가 무시
r, g, b red,green,blue 아님. 로더는 둘 다 받는다
label int32
sp_id texsp 파일만 슈퍼픽셀 ID
object_index 로더는 지원하나 demo엔 없음

실측 라벨 분포

트랙 라벨 값 클래스 수
face_labeling_pcl {0..10, 12} 13 SUMV2_Triangle 일치
texture_labeling_pcl {0..9, 11..19} 20 SUMV2_Texture 일치

타일 규모: 252 × 252 × 40 m, 47만 포인트 (fdcen만 21만). 좌표 원점 (7749, 5499, -1.6)저자도 전체 CRS 좌표가 아닌 로컬 미터계로 배포한다.

한국 데이터 변환 시 이 스키마만 맞추면 된다. 텍스처 불필요.

주요 학습 하이퍼파라미터 (sumv2_triangle 기본값)

항목
voxel_size 0.02
voxel_max (train) 64000
loop 30 (학습셋 30회 반복 → epoch 수는 적어도 됨)
epochs 100
batch_size 2 (PointNeXt-XL 기준. PointNet: 6, PointNet++: 10)
ignore_index 0 (unclassified 제외)
optimizer adamw, lr 0.01, cosine
cls_weighed_loss True (클래스 불균형 보정)

제공 모델 cfg: pointnet.yaml, pointnet++msg.yaml, pointnext-xl.yaml, pointvector-xl.yaml

평가

현재는 각 데이터에 내장된 GT 라벨로 자체 평가. 논문과 동일한 fine-grained 테스트셋 평가는 예측 결과를 저자 이메일로 보내면 로컬에서 채점해 줌. 자동 평가 코드는 HF에 추가 예정.

시각화

  • Mapple (권장) — f:color, v:color, 라벨 범례 표시 가능
  • MeshLab — face color/texture는 보이나 스칼라(라벨)는 처리 못 함

2. 라이선스 검토

두 개가 따로 논다. 분리해서 봐야 한다.

대상 라이선스 배포 조건
코드 (GitHub repo) GPL-3.0 파생 코드 배포 시 소스 공개 + GPL-3.0 승계. 비공개 상용 제품에 혼합 불가
데이터셋 (HF SUM-Parts) CC BY-NC 4.0 비상업 한정. 출처 표기 필수. 재배포/개변 허용

결론

  • 로컬 실험/학습 목적 → 제약 없음. 그냥 쓰면 된다.
  • 논문 / 오픈소스 릴리즈 → 가능. 단 코드는 GPL-3.0으로 내고, SUM Parts(2025) + SUM(2021) 둘 다 인용.
  • 상업 이용 → 저자에게 별도 허락 필요 (gaoweixiaocuhk@gmail.com).

주의 3가지

  1. 학습 가중치 — NC 데이터로 뽑은 weight는 NC로 취급하는 게 안전. 상업 배포 금지 쪽으로 본다.
  2. 베이스라인별 개별 라이선스 — KPConv/PointNeXt/Open3D-ML은 대개 MIT, SPG는 별도 확인 필요. vendoring 시 각 LICENSE 동봉.
  3. 데이터 자체를 repo에 커밋 금지 — HF 링크 + 다운로드 스크립트만 둔다.

법률 자문 아님. 최종 확인은 repo LICENSE 파일 + HF 데이터셋 카드 원문.

인용

@InProceedings{Gao_2025_CVPR,
    author    = {Gao, Weixiao and Nan, Liangliang and Ledoux, Hugo},
    title     = {SUM Parts: Benchmarking Part-Level Semantic Segmentation of Urban Meshes},
    booktitle = {Proceedings of CVPR},
    month     = {June},
    year      = {2025},
    pages     = {24474-24484}
}

3. 실행 환경 판단

왜 Windows 네이티브로 안 되나

railway-client 프로젝트의 SAM 3.1은 Windows에서 잘 돈다. 이유는 순수 PyTorch, 컴파일 없음. SUM 베이스라인은 성격이 다르다 — nvcc + 컴파일러커스텀 CUDA 커널을 직접 빌드해야 한다.

하려는 것 Windows 네이티브
interactive_annotation/ (SAM, SimpleClick) 가능
PLY 로드 / 변환 / 시각화 가능
KPConv / PointNeXt / SPG 학습 pointnet2_ops, cut-pursuit 등 Windows 패치 필요

결론: WSL2가 이미 설치돼 있으므로 그대로 사용. 학습만 WSL, 데이터 변환/어노테이션은 Windows. /mnt/d/로 파일 공유되니 복사 불필요.

실측 환경

Windows 호스트

항목
OS Windows 10 Enterprise 19045
GPU RTX 3060 12GB, 드라이버 610.47
Python 3.11.9
MSVC Visual Studio Professional 2022
CUDA Toolkit (nvcc) 없음
WSL Ubuntu-22.04 (v2), docker-desktop

WSL2 / Ubuntu-22.04

항목 상태
GPU 패스스루 RTX 3060 12GB 인식됨
gcc / g++ 11.4.0
git 2.34.1
Python (시스템) 3.10.12
디스크 / 251G 중 192G 여유
디스크 /mnt/d 7.3T 중 2.9T 여유
RAM 31G
nvcc 없음 설치 필요
conda 없음 설치 필요
sudo 암호 필요 (NOPASSWD 아님) ⚠️ apt 사용 불가

최종 구성 (검증 완료)

nvcc   : 11.8.89   (~/miniconda3/envs/sumparts/bin/nvcc)
torch  : 2.0.1+cu118
cuda   : available → NVIDIA GeForce RTX 3060
numpy  : 1.26.4
python : 3.10

업스트림 install.sh와 다르게 간 이유

원본은 python 3.7 / torch 1.12.1 / cu113 / cudatoolkit=11.3 전제. py3.7은 EOL이고 requirements.txt 핀(setuptools==59.5.0, protobuf==3.19.4, tensorboard==2.8.0 등)이 py3.10에서 해결되지 않는다. 그래서:

항목 원본 여기 이유
python 3.7 3.10 3.7 EOL
torch 1.12.1+cu113 2.0.1+cu118 드라이버 610.47 / sm_86 대응
채널 anaconda defaults conda-forge + nvidia ToS/상용 라이선스 회피
deepspeed 설치 제외 sumv2 학습 경로에서 미사용, 빌드 무거움
mkdocs-* 설치 제외 문서 전용
chamfer_dist, emd 확장 빌드 제외 reconstruction 태스크 전용
plyfile 누락됨 추가 데이터 로더가 import 하는데 requirements.txt에 없음
setuptools 59.5.0 <80 80+에서 python setup.py install 제거됨

빌드 대상 CUDA 확장 3종: pointnet2_batch, subsampling, pointops. TORCH_CUDA_ARCH_LIST=8.6 고정 (RTX 3060) — 전 아키텍처 빌드 방지.

Anaconda 채널 회피 (중요)

기본 miniconda는 repo.anaconda.com/pkgs/main, pkgs/r을 쓰는데, 이 채널은 ToS 수락이 필요하고 일정 규모 이상 조직에는 상용 라이선스 의무가 붙는다. conda createCondaToSNonInteractiveError로 막힌다.

→ 수락하지 않고 우회. --override-channels -c conda-forge + CUDA는 nvidia 채널. conda config --remove channels defaults + channel_priority strict.

sudo 제약 대응

sudo 암호가 필요해 apt install cuda-toolkit을 자동화할 수 없다. → conda 경로로 우회. 둘 다 sudo 없이 설치된다.

  • miniconda → ~/miniconda3 (홈 디렉토리, sudo 불필요)
  • CUDA Toolkit → conda install -c nvidia cuda-toolkit (env 내부 설치, sudo 불필요)

배치 원칙

대상 위치 이유
코드 / conda env WSL ext4 (~) /mnt/d는 9p 파일시스템이라 CUDA 확장 빌드가 매우 느림
데이터셋 /mnt/d 용량 크고 Windows 도구와 공유 필요

3-1. 빌드 트러블슈팅 기록

CUDA 확장 3종(pointnet2_batch, subsampling, pointops) 빌드에서 걸린 것들. 전부 최신 툴체인 × 2022년 코드베이스 충돌이다.

① Anaconda ToS 차단

CondaToSNonInteractiveError: Terms of Service have not been accepted for the
following channels: https://repo.anaconda.com/pkgs/main, .../pkgs/r

수락하면 넘어가지만 상용 라이선스 의무가 붙는다. → --override-channels -c conda-forge + nvidia 채널로 회피. defaults 미사용.

② ninja SIGPIPE

subprocess.CalledProcessError: Command '['ninja', '-v']' died with <Signals.SIGPIPE: 13>.
RuntimeError: Error compiling objects for extension

컴파일 에러가 아니다. torch 2.0의 cpp_extensionninja -v 출력을 파이프로 읽는데 ninja ≥1.12가 거기서 SIGPIPE로 죽는다. torch가 원인을 뭉개고 "Error compiling objects"로만 표시해 오해하기 쉽다.

pip install ninja==1.11.1.1

③ setuptools에서 distutils.msvccompiler 제거

ModuleNotFoundError: No module named 'distutils.msvccompiler'

openpoints/cpp/subsampling/setup.py:2numpy.distutils.misc_util를 import 하는데, numpy.distutils는 내부적으로 distutils.msvccompiler를 찾는다. 이 모듈은 setuptools 74.0에서 제거됨. (초기 핀 <80은 79.0.1을 뽑아서 여전히 실패)

pip install setuptools==69.5.1 (단, numpy<2 도 함께 필요. numpy 2에는 numpy.distutils 자체가 없다.)

④ WSL 인스턴스 사망

Wsl/Service/CreateInstance/E_FAIL

컴파일 도중 WSL VM이 통째로 내려갔다. 컴파일 에러와 무관.

wsl --shutdown 후 재접속으로 복구. 재발 시 MAX_JOBS 낮춰서 병렬 컴파일 부하 감소.

⑤ 확장 모듈 이름 (함정)

pointnet2_batch/setup.py가 만드는 모듈명은 **pointnet2_batch_cuda**다. 업스트림 PointNet++ 포크들의 pointnet2_cuda가 아니다. 검증 스크립트에서 이걸 틀리면 빌드는 다 성공했는데 ModuleNotFoundError로 실패한 것처럼 보인다.

확장 import 이름
pointnet2_batch pointnet2_batch_cuda
pointops pointops_cuda
subsampling from openpoints.cpp.subsampling import grid_subsampling

unzip 미설치

exit 127. sudo 암호가 필요해 apt install unzip을 못 한다. → python zipfile로 압축 해제.

wandb가 모듈 스코프에서 import 됨

main.py:8: import argparse, yaml, os, logging, numpy as np, csv, wandb, glob
ModuleNotFoundError: No module named 'wandb'

wandb.use_wandb=False로 꺼도 소용없다. import 자체가 조건 없이 실행되므로 설치는 필수. → pip install wandb + WANDB_MODE=disabled (로그인 요구 차단).

⑧ chamfer_dist / emd는 "선택"이 아니다

openpoints/cpp/chamfer_dist/__init__.py:10: import chamfer
ModuleNotFoundError: No module named 'chamfer'

기능상 reconstruction 전용이 맞다. 하지만 openpoints/models/__init__.py:9.reconstruction조건 없이 importmaskedpointvit.py:10chamfer_dist. 세그멘테이션만 돌려도 import 체인에 걸린다. 빌드 필수.

(deepspeed 제외는 유효 — import 체인에 없음.)

⑨ emd 모듈명도 다르다

emd/setup.py: setup(name='emd_ext', ext_modules=[CUDAExtension(name='emd_cuda', ...)]) → import 이름은 emd_cuda. emdopenpoints/cpp/emd/__init__.py의 파이썬 별칭일 뿐.

data_root 상대경로 기준점

[SUMV2_Triangle]: Totally 0 samples in train set.

예외 없이 조용히 0개. data_root: ../../data/...main.py의 cwd 기준이고, main.pyexamples/segmentation/에서 돈다 → ../../ = PointNeXt_bundle/. repo 루트가 아니다.

scripts/link_data.shPointNeXt_bundle/data<repo>/data 심볼릭 링크.

⑪ 샘플 수 < batch_size → 엉뚱한 예외

0it [00:00, ?it/s]
AttributeError: 'int' object has no attribute 'diag'
  at openpoints/utils/metrics.py:84  ->  return self.value.diag()

메시지가 원인을 전혀 안 가리킨다. 실제 원인은 dataloader의 drop_last: 타일 1장 × loop=1 = 샘플 1개인데 pointnet batch_size=6배치 0개 → 혼동행렬이 int 0으로 남아 .diag() 호출에서 터진다.

dataset.train.loop를 키우고 batch_size=1. 데이터가 적을 때 반드시 걸리는 함정.

⑫ Git Bash에서 WSL 호출 시 경로 변환

bash: C:/Program Files/Git/mnt/d/.../smoke_train.sh: No such file or directory

Git Bash(MSYS)가 /mnt/d/...를 Windows 경로로 자동 변환한다. → WSL 호출은 PowerShell에서 하거나 MSYS_NO_PATHCONV=1.

⑬ numpy 제거 별칭

sumv2_triangle.py:134: label = label.astype(np.long)
AttributeError: module 'numpy' has no attribute 'long'

np.long / np.int / np.float / np.bool / np.object / np.strnumpy 1.24에서 제거됐다. 원본은 numpy 1.20 전제.

numpy를 내리는 건 불가 — torch 2.0.1은 numpy<2를 요구하고, numpy 1.20에는 py3.10 휠이 없다. → 소스 패치. scripts/patch_numpy_aliases.sh (8개 파일)

별칭 치환
np.long np.int64
np.int int
np.float float
np.bool bool
np.object object
np.str str

\b 경계 필수 — 안 그러면 np.int32, np.float32까지 망가진다.

⑭ collections ABC 이동

point_transformer_gpu.py:282: isinstance(self.angle, collections.Iterable)
AttributeError: module 'collections' has no attribute 'Iterable'

Python 3.10에서 collections.abc로 이동. 같은 패치 스크립트가 처리한다.

⑮ BatchNorm은 배치 1을 거부

ValueError: Expected more than 1 value per channel when training,
            got input size torch.Size([1, 512])

⑪ 해결하려고 batch_size=1로 내렸더니 이번엔 BN이 막는다. 양쪽에서 조인다: 너무 크면 drop_last로 배치 0개, 너무 작으면 BN 거부. → batch_size=2 (BN 하한) + loop로 타일 반복해 온전한 배치 확보.

⑯ WSL 크래시가 남긴 0바이트 패키지 ★

가장 찾기 어려웠던 것.

main.py:666: all_logits = scatter(all_logits, idx_points, dim=0, reduce='mean')
TypeError: 'module' object is not callable

from torch_scatter import scatter가 함수가 아니라 서브모듈을 반환. 이유:

torch_scatter/__init__.py        0 bytes
torch_scatter/scatter.py         0 bytes
torch_scatter/_scatter_cuda.so   0 bytes

④의 WSL VM 사망 당시 pip이 열고 있던 파일이 전부 빈 껍데기로 디스크에 남았다. gdown/*.py 전부, vtkmodules/*.so 다수도 동일.

고약한 이유: import가 성공한다. 모듈이 비어있을 뿐이라 에러가 한참 뒤 호출 지점에서 엉뚱한 메시지로 터진다. 설치 로그에도 Successfully installed로 남아 있다.

탐지:

find <site-packages> -type f \( -name '*.py' -o -name '*.so' \) -size 0 ! -name '__init__.py'

__init__.py는 원래 빈 경우가 많으니 제외. 잔여 정상 케이스: torch/cuda/error.py, torch/ao/.../observation_type.py, sklearn/_built_with_meson.py.

scripts/repair_env.sh로 크래시 당시 배치 전체 강제 재설치.

교훈: VM/컨테이너가 설치 도중 죽으면 그 시점 패키지들을 무조건 재설치해라. pip은 손상을 감지하지 못한다.

무시해도 되는 경고

warning: 'T* at::Tensor::data() const' is deprecated:
         Tensor.data<T>() is deprecated. Please use Tensor.data_ptr<T>() instead.
warning: There are no g++ version bounds defined for CUDA version 11.8

전부 경고. 빌드 실패 원인 아니다.

재실행 전략

빌드 단계만 scripts/build_ext.sh로 분리했다. 의존성 재설치 없이 컴파일만 재시도 가능하고, 이미 import 되는 확장은 건너뛴다 (FORCE=1이면 전부 재빌드).


3-2. 실학습 가능성 — RTX 3060 12GB 실측 (2026-08-20)

결론: 가능하다. 단 XL 계열은 voxel_max를 낮춰야 한다.

데이터 규모

항목
pcl.zip 4.66 GB
mesh.zip 0.52 GB
demo.zip 0.12 GB
타일 수 train 24 / val 8 / test 8 (총 40)

디스크 192GB 여유 → 저장은 문제 없음.

★ WSL2의 함정 — VRAM 초과가 OOM을 내지 않는다

WSL2의 NVIDIA 드라이버는 VRAM을 넘으면 호스트 RAM으로 흘린다(system memory fallback). 네이티브 Linux라면 torch.cuda.OutOfMemoryError로 즉시 죽을 설정이 여기서는 조용히 완주한다 — 25~100배 느리게.

peak VRAM 15.47 GB on a 12 GB card    <- 물리적으로 불가능한 수치가 보고된다

"돌아간다"는 사실만 보고 설정을 확정하면 20일짜리 학습을 시작하게 된다. 반드시 peak VRAM을 카드 용량과 대조해야 한다.

voxel_max 스윕 (pointnext-xl, batch_size 2)

voxel_max pts/batch peak VRAM s/iter 판정
24000 48,000 6.17 G 0.434
32000 64,000 8.03 G 0.635
40000 80,000 9.88 G 1.169
48000 96,000 11.75 G 29.169 폴백
64000 (cfg 기본값) 128,000 15.47 G 46.980 폴백

경계가 선명하다. 40000 → 48000 사이에서 25배 절벽. 정상 구간 안에서도 s/iter가 초선형으로 증가한다(0.434 → 0.635 → 1.169).

모델별 실측

cfg params bs 설정 peak VRAM s/iter 적합
pointnet 3.6M 2 voxel_max 64000 (원본) 6.01 G 0.291
pointnet++msg 3.0M 2 voxel_max 64000 (원본) 4.16 G 0.675
pointnext-xl 41.6M 2 voxel_max 32000 8.03 G 0.635
pointvector-xl 24.1M 2 voxel_max 24000 6.46 G 0.402
pointnext-xl 41.6M 2 voxel_max 64000 15.47 G 46.980
pointvector-xl 24.1M 2 voxel_max 64000 16.49 G 13.113

batch_size는 네 cfg 모두 default.yaml2를 그대로 쓴다. default.yaml 주석의 "PointNet: 6, PointNet++: 10"은 실제 설정에 반영돼 있지 않다.

학습 시간 추정

반복 횟수 = train 24타일 × loop 30 ÷ batch_size 2 = 360 iter/epoch × epochs 100 = 36,000 iter

모델 설정 학습 시간 (val 제외)
pointnet 원본 2.9 h
pointnet++msg 원본 6.8 h
pointnext-xl voxel_max 32000 6.4 h
pointvector-xl voxel_max 24000 4.0 h
pointnext-xl 원본 64000 470 h ≈ 20일

val_freq: 1이라 매 epoch 8타일 검증이 붙는다 → 1~3시간 추가. val_freq: 5로 올리면 대부분 회수된다.

남는 제약

  • XL 계열은 논문 설정 재현 불가. voxel_max 64000 → 32000은 샘플당 포인트를 절반으로 줄이는 것이고, 컨텍스트 윈도우가 좁아진다. 논문 수치와 직접 비교하면 안 된다.
  • 작은 모델 2개(pointnet, pointnet++msg)는 원본 설정 그대로 학습 가능하다. 재현성이 중요하면 이쪽부터.
  • 측정은 5~8 iteration 평균이며 warm-up 2회는 제외했다. 장시간 학습의 열/클럭 변동은 반영 안 됨.

스크립트

파일 역할
scripts/bench_models.py 모델별 peak VRAM + s/iter 측정, VRAM 초과 여부 판정
scripts/run_bench.sh 벤치 실행 래퍼
scripts/sweep_voxel_max.sh voxel_max 스윕으로 VRAM 한계 탐색
scripts/check_hf_sizes.py HF 아카이브 크기 조회
scripts/list_archive.sh 아카이브 내용·타일 수 확인 (압축 해제 없이)
scripts/verify_archives.sh 다운로드 아카이브 무결성 검사
scripts/check_alloc_conf.sh PYTORCH_CUDA_ALLOC_CONF 유효성 사전 검증
scripts/epoch_timing.sh epoch별 소요 시간 → 감속 시작 지점 특정
scripts/iter_rate.sh 초기 vs 최근 반복 속도 비교
scripts/verify_speed.sh 현재 속도가 정상 범위인지 판정
scripts/diag_run.sh 실행 실패 시 로그 일괄 덤프

무인 실행 스크립트

파일 역할
scripts/launch_overnight.sh setsid nohup 분리 실행. RESUME_CKPT로 이어하기
scripts/train_watchdog.sh 크래시 시 최신 체크포인트에서 자동 재개 (최대 8회)
scripts/check_training.sh 진행 epoch·GPU·best miou·워치독 이벤트
scripts/stop_training.sh 워치독 먼저 종료 후 학습 중단
scripts/monitor_training.sh 진행·감속·크래시·완료 이벤트 스트림
scripts/train_full.sh 단발 실학습 (워치독 없이)
scripts/prepare_full_split.sh valvalidate 심볼릭 링크
scripts/show_layout.sh 전개된 데이터 레이아웃 확인

3-2-1. 실학습 중 발생한 무증상 10배 감속 ★★

벤치마크에서 발견한 "VRAM 초과가 OOM을 안 낸다"가 실제 학습에서 재현됐다. 다만 원인이 예상과 달랐다.

증상

epoch  1-10   ~103 s/epoch     (벤치 예측 105 s와 일치)
epoch 11     +1011 s           ← 20:45부터 급변
epoch 12-20  ~1100 s/epoch

반복당 속도: 0.29 s/it → 3.14 s/it (10.7배). 남은 80 epoch에 24시간.

에러 없음. 경고 없음. GPU 사용률 100%, 클럭 1942MHz 만빵, 온도 51°C, 스로틀 전무. 로그만 보면 완벽하게 정상이다.

오진과 정정

처음엔 데스크톱 앱(브라우저·Electron)이 VRAM을 잠식했다고 봤다. nvidia-smi에 Brave, Edge, WebView2, VS Code 등이 잔뜩 잡혀 있었기 때문이다.

학습을 죽이고 재측정해서 뒤집혔다:

상태 Dedicated (VRAM) Shared (호스트 RAM)
학습 중 11,715 MB 18,967 MB
학습 종료 후 1,245 MB 468 MB

데스크톱 앱은 1.2GB뿐. 11.7GB + 19GB를 전부 학습 프로세스가 잡고 있었다. 벤치 측정값 6.01GB의 약 2배로 불어난 것.

교훈: 남 탓하기 전에 의심 대상을 죽여보고 기준선을 재라. 30초면 된다.

진단 경로

단계 관측 배제/확정
GPU 스로틀 51°C, HW Slowdown: Not Active 열/전력 배제
WSL 자원 swap 0, IO wait 0, load 1.16 메모리·디스크 배제
프로세스 main python CPU 99.8% 단일 스레드 CUDA 동기화 스핀 = GPU 대기
전력 61.7W (3060 TDP 170W) 연산 아님 → 전송 대기
반복 속도 초기 0.29 s/it → 3.14 s/it epoch 간 오버헤드 아닌 반복 자체 감속
Perf 카운터 Shared Usage 18,967 MB 시스템 메모리 폴백 확정

전력 소비가 가장 빠른 판별 지표였다. 사용률 100%인데 전력이 낮으면 연산이 아니라 대기다.

# 폴백 여부 직접 확인 (nvidia-smi로는 안 보인다)
(Get-Counter '\GPU Adapter Memory(*)\Shared Usage','\GPU Adapter Memory(*)\Dedicated Usage').CounterSamples

기여 요인 — cfg의 검증 설정

train: { voxel_max: 64000 }
val:   { voxel_max: null }     # ← 타일 전체(47만 포인트)를 통째로

학습 스텝은 상한이 있는데 검증만 무제한이다. 이 거대한 일시 할당이 캐싱 할당자 풀을 부풀린다. 감속 시작이 epoch 10 검증 직후인 것과 일치한다.

핵심: PyTorch 캐싱 할당자는 한 번 shared로 넘어간 풀을 되돌리지 않는다. VRAM이 비어도 자동 회복 없음 → 프로세스 재시작이 유일한 복구 경로.

조치

항목
할당자 PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.7,max_split_size_mb:128
검증 상한 dataset.val.voxel_max=64000 (학습과 동일)
재개 epoch 20 체크포인트 (진행분 손실 없음)

복구 확인

반복 속도 : 3.56 it/s = 0.28 s/it   (벤치 0.291과 일치)
GPU 전력  : 61.7W → 140.08W

⚠️ expandable_segments는 torch 2.0에서 못 쓴다

첫 시도에서 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True를 썼다가 즉시 크래시.

RuntimeError: Unrecognized CachingAllocator option: expandable_segments

torch 2.1부터 지원한다. 이 환경은 2.0.1. 게다가 traceback이 model.to(device)를 가리켜 모델 문제처럼 보인다.

scripts/check_alloc_conf.sh실행 전 2초 만에 검증하도록 만들었다.

워치독은 이때 "재시도해도 새 체크포인트가 안 생긴다 = 학습 진입 전 실패"를 감지하고 무한 재시도 없이 정상 중단했다. 설계 의도대로 동작.

남는 편차 — 명시

dataset.val.voxel_max를 64000으로 제한했으므로 val_miou는 서브샘플된 타일 기준이다. 체크포인트 선택 신호로만 유효하다. 최종 test는 test()가 전체 타일을 슬라이딩 윈도우로 처리하므로 보고 수치에는 영향이 없다.

감시에 반영

침묵이 성공으로 오인되지 않도록 scripts/monitor_training.sh속도 회귀 감지를 추가했다. 1.5 s/it을 넘으면 GPU 메모리·전력과 함께 즉시 알린다. 크래시만 감시하면 이런 무증상 감속은 영원히 못 잡는다.


3-4. 실학습 결과 — pointnet 100 epoch (2026-08-21)

완주

epoch 100/100 완료   01:56:58
Best ckpt @E90
  val_oa    49.12
  val_macc  25.47
  val_miou  17.19
항목
모델 pointnet (3.6M params)
데이터 face_labeling/texsp_pcl, train 24 / val 8 / test 8
설정 voxel_max 64000(원본), batch_size 2, val_freq 5, cosine LR 0.01→1.2e-5
소요 20:08 시작 → 01:57 완료. 순수 학습 시간 약 3.4h (감속 사고 3h 별도)
속도 102초/epoch, 0.28 s/it (벤치 0.291과 일치)

수렴 추이

epoch train_miou best val_miou
10 12.80 2.77
20 15.79 8.04
31 17.56 8.49
40 17.86 10.40
50 18.89 15.62
60 19.22 16.04
70 19.09 16.93
80 19.62 16.93
90 17.19 ← best
100 19.95 17.19

train 19.95 / val 17.19 — 격차가 작아 과적합 징후 없다.

★ test 세트는 라벨이 없다 (블라인드)

학습 직후 test 단계에서 크래시:

main.py:672  cm.update(pred, label)
metrics.py:74  RuntimeError: bincount only supports 1-d non-negative integral inputs

원인 조사 결과 우리 설정 문제가 아니었다:

split 라벨 값
train 24타일 0 ~ 12 정상
val 8타일 0 ~ 12 정상
test 8타일 전부 -1 (dtype int32, uniq=1)

README와 일치한다:

"For fine-grained test set evaluation consistent with the paper, send predictions to our email for local assessment."

의도적인 블라인드 테스트셋이고 -1은 자리표시자다. 업스트림 코드가 if label is not None만 검사하고 -1을 안 걸러서, true × num_classes + pred가 음수가 되어 torch.bincount가 거부한 것.

로컬에서 test_miou는 원천적으로 계산 불가. 논문 수치와 직접 대조하려면 예측 결과를 저자에게 보내야 한다 (gaoweixiaocuhk@gmail.com).

업스트림 버그 패치 2건

# 증상 원인 패치
A bincount ... non-negative 블라인드 test의 -1 라벨 미처리 patch_unlabeled_test.sh — 전부 음수면 "정답 없음"으로 간주, 예측만 생성
B UnboundLocalError: 'epoch' (mode=val) epoch이 학습 루프 안에서만 바인딩되는데 val 경로가 참조 patch_val_mode.shepoch = best_epoch 선바인딩

둘 다 멱등이고 원본은 main.py.orig로 보존한다. 라벨 있는 데이터의 채점 동작은 바뀌지 않는다.

워치독 동작 검증

학습 완주 후 test 크래시로 rc=1이 되자 워치독이 재개를 시도했고, 2회째에 **"새 체크포인트가 생기지 않음 = 학습 진입 전 실패"**를 감지해 중단했다. 무한 재시도 없이 설계대로 동작했다.

남는 편차

학습 중 dataset.val.voxel_max를 64000으로 제한했다(§3-2-1). 따라서 위 val_miou 17.19서브샘플된 검증셋 기준이다. voxel_max: null(전체 타일)로 다시 평가한 수치는 scripts/final_eval.sh 결과로 별도 기록한다.


3-3. WSL2 안정화

VM이 2회 사망했다.

# 시점 상황
1 CUDA 확장 컴파일 중 Wsl/Service/CreateInstance/E_FAIL. pip 진행 중 파일들이 0바이트로 남음 (§3-1 ⑯)
2 GPU 벤치(VRAM 만재) + 4.7GB 다운로드 동시 두 작업 동시 exit 253

.wslconfig가 없어 WSL2가 호스트 64GB의 50%(≈32GB)를 동적으로 잡고 있었다.

적용한 설정 (C:\Users\nbright\.wslconfig)

[wsl2]
memory=24GB          # 동적 50% → 고정 상한
swap=16GB            # 스파이크 시 VM 사망 대신 페이지아웃
processors=8         # cfg의 num_workers: 6 감안
vmIdleTimeout=60000  # 연속 실행 시 VM 부팅 비용 회피

pageReporting은 뺐다 — 기본값이 true이고, 명시하면 WSL 2.7.12가 파싱 경고를 낸다.

적용 후 확인: Mem 23GB / Swap 16GB / 8 cpus, GPU 정상 인식, 경고 없음.

운용 규칙: GPU 만재 작업과 대용량 다운로드를 동시에 돌리지 않는다.

wsl --shutdown은 WSL 배포판만 종료한다. Windows 네이티브 프로세스는 영향 없다.


4. 한국 데이터 적용 계획

두 갈래 경로

A. 포인트 클라우드 경로 (권장, 스모크 테스트용)

포인트 기반 방법(KPConv/PointNeXt/RandLA-Net)은 xyz + rgb + label만 필요. 텍스처 불필요.

한국 메시(OBJ+texture) → face 샘플링 → binary PLY (v:color, v:label)
  • SUM으로 학습한 모델 → 한국 타일 zero-shot 추론
  • 라벨 없으면 전부 0(unclassified)로 채워도 추론은 동작

B. 메시 경로 (텍스처 기반 21클래스 풀 파이프라인)

h:texcoord + f:label 포함 ASCII PLY 필요. 변환 공수 큼. 후순위.

확보된 실데이터 — 서산 명천 (2026-08)

D:\MyProject_대용량샘플\02. 데이터\01. 서산 명천_08월

├── 01. 드론원본이미지   JPG 8,120장 (132 GB) + PPK(.obs/.nav/.MRK)
│     고고도 120m / 저고도 70m × 수직 / 경사, 1구역(미션1)·2구역(미션7)
├── 02. 본태모델        ★ OBJ 6개 (3.0 GB) + JPG 텍스처 144장 (908 MB)
├── 03. 지오이드모델     .tif 2.8 GB
├── 04. 카메라파라미터    .txt 6개
└── 05. 정사영상        .tif 25.8 GB + .tfw + .dwg

본태모델 = ContextCapture 계열 OBJ, 블록 6개

구역 블록 OBJ 크기
구역1(미션1) BlockYBY / BlockYYA / BlockYYX 645 / 433 / 464 MB
구역2(미션7) BlockBXY / BlockYBA / BlockYBX 497 / 355 / 634 MB

metadata.xml — 좌표계 (결정적)

<SRS>EPSG:5186+9999</SRS>
<SRSOrigin>154113.37472199186,466558.57182090241,151.18628846539363</SRSOrigin>  <!-- 구역1 -->
<SRSOrigin>155184.79128718161,469705.02542312664,149.57080945797654</SRSOrigin>  <!-- 구역2 -->

좌표가 이미 로컬 미터계 + 원점 오프셋. SUM Parts 배포 관례와 동일. 재투영 작업 불필요. (단 원본 easting/northing이나 경위도를 그대로 넣으면 cfg의 반경·voxel 설정이 전부 미터 기준이라 조용히 망가진다.)

메시 실측 (scripts/inspect_obj.py)

BlockYBA BlockYYA SUM Parts demo
vertex 2,287,325 2,699,696
face 4,553,583 5,377,777
UV 3,121,900 3,886,962
vertex color
머티리얼 17 21
extent 465×487×28 m 439×404×46 m 252×252×40 m
면적 0.227 km² 0.177 km²
밀도 20.1 face/m² 30.3 face/m²

적합 판정 근거

  • 텍스처 메시 + UV 완비 → SUM Parts와 동일 모달리티
  • 좌표계 관례 일치
  • 블록이 SUM 타일(252m)의 약 4배 면적 → 블록당 4타일, 6블록 = 약 24타일 확보 가능

주의 2가지

  1. 멀티머티리얼 — 블록당 텍스처 아틀라스 17~21장. trimesh.load(force='mesh')로 합치면 텍스처가 전부 날아가 결과가 회색이 된다. Scene으로 받아 머티리얼별로 샘플링해야 함.
  2. vertex color 없음 — 텍스처가 유일한 색상 소스. 폴백 경로가 없다.

왜 PLY로 변환하나 (OBJ/GLB 아니고)

포맷 선택이 아니라 모델 요구사항이다.

# openpoints/dataset/sumv2_triangle/sumv2_triangle.py
self.data_list = glob.glob(os.path.join(data_root, split, "*.ply"))
plydata = PlyData.read(filename)
labels = plydata['vertex']['label']
  • 데이터로더가 *.ply만 glob한다. OBJ/GLB는 스캔조차 안 함
  • 네트워크 입력은 포인트 클라우드지 메시가 아니다
  • OBJ/GLB에는 포인트별 label 스칼라를 담을 표준 필드가 없다. SUM Parts 저자가 텍스처 메시조차 PLY로 배포하는 이유도 같다 (f:label, v:label)

원본 OBJ는 읽기만 하고 손대지 않는다. PLY는 모델 입력용 중간 산출물이다.

BlockYBA.obj (원본 불변) → 면적가중 샘플링 → tile.ply → 모델 → 예측

다른 한국 데이터 후보 (참고)

  • V-World 3D (국토지리정보원) — 3D 건물 / 지형
  • 서울 S-Map — 3D 서울, 텍스처 메시

4-1. POC 결과 (2026-08-20) — 통과

범위를 의도적으로 타일 1장으로 제한. "우리 데이터가 이 파이프라인을 통과하는가"만 확인. 성능 측정 아님.

입력: 구역2(미션7)/BlockYBA, 중앙 252m bbox (300, 720) ~ (552, 972)

[17:10:12] loaded 17 geometry group(s), 4,553,583 faces total
[17:10:13] cropped surface area: 14,609 m^2 across 283,099 faces
           geom  0..16 : 머티리얼별 면적 비례 샘플링
[17:10:19] extent: [137.84 178.07 19.48] m   origin: [299.6 794.32 -67.58]
[17:10:19] wrote seosan_BlockYBA_tile0.ply (470,000 points, label=0, colour=sum)

스키마 대조 (scripts/check_ply.py)

변환 결과 SUM demo 판정
properties x,y,z,r,g,b,label x,y,z,nx,ny,nz,r,g,b,label,sp_id OK (법선·sp_id는 로더가 무시)
colour float32 [0,1] float32 [0,1] 일치
label dtype int32 int32
extent 137.8 × 178.1 × 19.5 m 252.2 × 252.2 × 39.7 m 노선형 vs 정사각 타일
density 19.1 pts/m² 7.4 pts/m² 2.6× 조밀

추론 (scripts/poc_infer.sh)

Successful Loading the ckpt from ..._ckpt_best.pth
length of test dataset: 1
Test on 0-th cloud [2]/[3]: 100%
test_oa nan, test_macc 0.00, test_miou 0.00
POC INFER DONE  (exit=0)

test_oa = nan정상이다. 전 포인트 라벨이 0이고 ignore_index: 0이라 채점 대상이 없다.

예측 산출물 (scripts/check_pred.py)

visualization/seosan_BlockYBA_tile0_pred.ply    13 MB
points     : 470,000
properties : ['x','y','z','red','green','blue','label']
palette fit: exact

class        points    share
wall        470,000  100.00%

470,000 포인트 전부에 클래스 예측이 붙었다. 전부 wall인 건 1 epoch 모델(val_miou 0.21)이 사실상 단일 클래스만 뱉기 때문이며, 예상된 결과다.

결론: 배관은 뚫렸다. OBJ → 샘플링 → PLY → 모델 → 포인트별 예측 → 시각화 PLY. 모델 품질에 대해서는 이 POC가 아무것도 말해주지 않는다.

POC에서 드러난 것 3가지

① 색상 스케일 — 조용히 망가지는 함정 ★

첫 변환에서 red,green,blue uint8 [0,255]로 썼다. SUM 배포본은 r,g,b **float32 [0,1]**이다.

로더는 정규화하지 않는다:

rgb = np.stack([...'r','g','b'...]).astype(np.float32)
if np.max(rgb) > 1:
    rgb = rgb          # ← no-op. 읽으면 정규화할 것 같지만 아무것도 안 한다

cfg의 활성 transform도 [PointsToTensor, PointCloudScaling, PointCloudRotation, PointCloudJitter] 뿐 — NumpyChromaticNormalize는 주석 처리돼 있다.

파일에 든 값이 그대로 네트워크에 들어간다. 255배 큰 색상 특징을 주게 되고, 에러 없이 결과만 무의미해진다. --colour-style sum이 기본값인 이유.

② 블록은 정사각형이 아니다 — 노선을 따라 뻗은 형태

252×252m bbox로 잘랐는데 실제 표면적은 14,609 m² (bbox 면적 63,504 m²의 23%). 결과 extent도 137×178m. 도로 프로젝트라 노선을 따라 길게 뻗은 형태다. 도시 전역을 덮는 SUM Parts와 형상이 다르다.

→ 균등 격자로 타일링하면 빈 타일이 대량 발생한다. 노선 축을 따라 자르는 전략이 필요하다. 앞서 "블록당 4타일 × 6블록 = 24타일" 추정은 낙관적이며, 실제로는 더 적다.

③ 멀티머티리얼 처리 필수

trimesh.load(..., force='mesh')로 합치면 머티리얼별 텍스처가 전부 유실되어 결과가 회색으로 나온다. Scene으로 받아 geometry(=머티리얼)별로 UV 샘플링해야 한다. BlockYBA는 17개, BlockYYA는 21개 그룹.

다음 단계에서 필요한 것

POC는 배관만 확인했다. 의미 있는 결과를 내려면:

  1. 제대로 학습된 체크포인트 — SUM Parts 전체 데이터(mesh.zip/pcl.zip)로 학습. 현재는 demo 타일 1장 1 epoch짜리뿐이다.
  2. 노선 축 기반 타일링 — 빈 타일 회피
  3. 한국 타일 라벨링 — zero-shot 성능을 측정하려면 GT가 필요하다. 최소 2~3타일. SAM 기반 어노테이션 도구(interactive_annotation/)가 repo에 있다.
  4. 클래스 정의 대조 — SUM 13클래스(terrain/roof/facade/chimney/dormer...)는 도시 건물 중심. 도로 프로젝트에서 필요한 건물/수목/차량/지면은 SUM 13클래스를 합치면 그대로 나온다 (§4-2).

예상 결과

SUM Parts는 헬싱키 항공 메시 기반. 한국 도시는 지붕 형태(평지붕 + 옥탑), 건물 밀도, 도로 표시가 다르다. → zero-shot mIoU 큰 폭 하락 예상. 그게 정상이며, 그 수치 자체가 저자에게 보낼 메일의 근거가 된다. 타일 2~3장 라벨링해 fine-tune 하면 크게 개선될 것.


5. 진행 순서

  1. 환경 조사
  2. WSL2 환경 셋업 (miniconda, conda env py3.10, CUDA 11.8, torch 2.0.1+cu118)
  3. repo clone ~/sum-parts
  4. PointNeXt CUDA 확장 빌드 (3종 전부 import 확인)
  5. HF 게이트 수락 (브라우저 수동)
  6. demo.zip 다운로드 + 압축 해제 + 스키마 검증
  7. 1 epoch 스모크 테스트 파이프라인 생존 확인
  8. 한국 실데이터 조사 서산 명천, ContextCapture OBJ 6블록
  9. 한국 타일 → PLY 변환 BlockYBA 타일 1장, 470k 포인트
  10. POC 추론 배관 관통 확인 (§4-1)
  11. 제대로 된 학습 ← 다음. pcl.zip 전체 받아 실학습
  12. 노선 축 기반 타일링 + 한국 타일 라벨링
  13. Zero-shot 평가 + Mapple 시각화
  14. 결과 정리 후 저자에게 메일

스모크 테스트 결과 (2026-08-20)

cfg=pointnet epochs=1 loop=4 bs=2

Train Epoch [1/1] Loss 3.474 Acc 0.08
Best ckpt @E1   val_oa 2.48  val_macc 8.33  val_miou 0.21
Test [0]/[1] cloud
Best ckpt @E1  test_oa 2.48  test_macc 8.33  test_miou 0.21
save results in log/.../ALo5iXF6AAHrWkAghKA8nv.csv
exit=0

체인 전 구간 통과: PLY 로드 → grid subsample → CUDA ops → forward/backward → 검증 → 체크포인트 저장 → 재로드 → 테스트 추론 → CSV 저장.

⚠️ 수치는 무의미하다. 1 epoch, 타일 1장, train/val/test 모두 같은 타일. 파이프라인 생존만 확인한 것이고, 어떤 성능 주장에도 쓸 수 없다.

검증된 스택

python  3.10
nvcc    11.8.89
torch   2.0.1+cu118    cuda available: True (RTX 3060)
numpy   1.26.4
ninja   1.11.1.1       (1.12+ 금지)
setuptools 69.5.1      (74+ 금지)
torch-scatter 2.1.2+pt20cu118

pointnet2_batch_cuda  : OK
pointops_cuda         : OK
grid_subsampling      : OK
plyfile / torch_scatter : OK

스크립트

파일 역할
scripts/setup_env.sh conda env + CUDA + torch
scripts/setup_pointnext.sh python 의존성 → build_ext.sh 호출
scripts/build_ext.sh CUDA 확장 빌드만 (재실행 가능, FORCE=1로 전체 재빌드)
scripts/repair_env.sh WSL 크래시로 0바이트가 된 패키지 재설치
scripts/patch_numpy_aliases.sh 제거된 numpy 별칭 / collections ABC 소스 패치
scripts/verify_env.py 컴파일 확장 + import 체인 일괄 점검
scripts/download_data.sh HF 데이터 다운로드 + 압축 해제
scripts/prepare_demo_split.sh demo 타일을 train/val/test로 배치
scripts/link_data.sh PointNeXt_bundle/data 심볼릭 링크
scripts/smoke_train.sh 1 epoch 파이프라인 생존 테스트
scripts/inspect_obj.py 대용량 OBJ 스트리밍 통계 (vertex/face/UV/bbox/머티리얼)
scripts/mesh_to_ply.py 멀티머티리얼 텍스처 메시 → SUM 스키마 PLY (bbox 크롭 지원)
scripts/check_ply.py PLY를 SUM 스키마와 대조 검증
scripts/poc_korea.sh 서산 명천 타일 1장 변환 + 검증
scripts/poc_infer.sh 변환된 타일로 추론
scripts/check_pred.py 예측 PLY의 클래스 분포 복원 (팔레트 역매핑)
scripts/poc_check_pred.sh 최신 예측 PLY 자동 탐색 후 검사

실행 순서 (처음부터 재현 시)

bash scripts/setup_env.sh            # conda env + CUDA 11.8 + torch 2.0.1
bash scripts/setup_pointnext.sh      # 의존성 + CUDA 확장 빌드
bash scripts/patch_numpy_aliases.sh  # 소스 현대화 패치
bash scripts/download_data.sh        # HF 게이트 수락 후
bash scripts/prepare_demo_split.sh
bash scripts/link_data.sh
python scripts/verify_env.py         # 전부 OK 확인
bash scripts/smoke_train.sh

WSL이 중간에 죽으면 bash scripts/repair_env.sh 먼저 돌리고 재개.


6. 메모

  • VSCode에서 WSL 전환: 좌하단 >< 버튼 → "Connect to WSL"
  • 다만 Windows 셸에서 wsl -d Ubuntu-22.04 -- bash -lc "<cmd>" 로 직접 실행도 가능 (전환 불필요)
  • Downloads교각.hmeg, 교량.hmeg, sss.obj 등 자체 3D 데이터 존재 → 한국 샘플 후보로 검토 가치 있음