Adds STATUS.md as the handoff document: benchmark numbers, the bare-earth
metrics that actually matter for this project, the Korean-data domain gap that
retraining will not fix, and what to do on the 24 GB machine.
The memory problem was in how a prediction's colours were turned back into
class indices. Every consumer built an (N, 13, 3) float64 temporary:
d = ((rgb[:, None, :] - COLOR_MAP[None, :, :]) ** 2).sum(axis=2)
That is ~250 MB of intermediates per 800k-point tile, several live at once, and
a full 4.7M-point block pushes it into gigabytes. main.py writes exact palette
entries, so an exact hash lookup resolves nearly every point with no large
temporary; only leftovers fall back to a chunked distance search. Peak RSS on a
470k-point tile drops to 61 MB. Extracted to sumparts_palette.py and shared by
coarse_eval.py and split_by_class.py.
Also from this round:
- patch_cm_mutation.sh: ConfusionMatrix.update() rewrote the caller's pred
tensor in place, folding every ignore_index point into class num_classes-1.
test() saves its visualization from that same tensor afterwards, so an
unlabelled tile came out 100% wall and the model looked degenerate when it
was not.
- patch_class_mask.sh: SUMPARTS_MASK_CLASSES drops known-absent classes from
the argmax. Measured on Seosan and it does not help - the runner-up for
"water" is "wall", not "terrain" - but the experiment is worth keeping.
- split_by_class.py now writes .ply alongside .obj. A vertex-only OBJ has zero
faces and most viewers render nothing, which is why the first export looked
broken.
- verify_outputs.sh reads exported files back with a parser, so "here are your
files" can be checked rather than asserted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
247 lines
8.8 KiB
Markdown
247 lines
8.8 KiB
Markdown
# 현재 상태 — 2026-08-21
|
|
|
|
3060 머신에서 여기까지 왔다. 이 문서는 **3090으로 옮겨서 이어가기 위한 인수인계**다.
|
|
|
|
목표: 드론 사진측량 메시에서 **구조물을 제거한 지형(bare earth)** 추출.
|
|
부수적으로 건물·수목·차량 분리.
|
|
|
|
---
|
|
|
|
## 한 줄 요약
|
|
|
|
SUM Parts 벤치마크는 재현했다. **지면 precision 95.24%로 목표 용도에 충분하다.**
|
|
문제는 벤치마크가 아니라 **한국 데이터에서의 도메인 갭**이다.
|
|
|
|
---
|
|
|
|
## 1. 완료된 것
|
|
|
|
| 항목 | 결과 |
|
|
|---|---|
|
|
| WSL2 환경 (CUDA 11.8 + torch 2.0.1 + 확장 5종) | ✅ |
|
|
| SUM Parts 데이터 (train 24 / val 8 / test 8) | ✅ |
|
|
| PointNet 100 epoch | mIoU 17.19 (논문 15.1 — **재현 확인**) |
|
|
| **PointVector 100 epoch** | **mIoU 51.83 / OA 80.41** |
|
|
| 서산 OBJ → PLY 변환 | ✅ 타일 1장 |
|
|
| 서산 추론 | ✅ 13클래스 예측 |
|
|
| 클래스별 분리 출력 | ✅ `D:\AI_Test\sum-part\` |
|
|
|
|
---
|
|
|
|
## 2. SUM 벤치마크 성적 (PointVector, voxel_max 24000)
|
|
|
|
### 4클래스 통합
|
|
|
|
| 클래스 | IoU | precision | recall |
|
|
|---|---|---|---|
|
|
| ground | 60.69% | **95.24%** | 62.59% |
|
|
| vegetation | 90.70% | 95.11% | 95.14% |
|
|
| building | 86.10% | 88.01% | 97.54% |
|
|
| vehicle | 51.05% | 78.81% | 59.17% |
|
|
| **mIoU 72.14% / OA 89.72%** | | | |
|
|
|
|
### bare earth (지면 vs 나머지) ← 실제 목표 지표
|
|
|
|
```
|
|
지면 정확히 유지 523,983
|
|
비지면 섞여 들어옴 26,217 ← 지형을 오염시킴
|
|
지면 놓침 268,755 ← 구멍, 보간 가능
|
|
|
|
precision 95.24%
|
|
recall 66.10%
|
|
IoU 63.98%
|
|
F1 78.04%
|
|
```
|
|
|
|
**오염원 분해**
|
|
|
|
| 출처 | 비중 |
|
|
|---|---|
|
|
| facade_surface | **49.90%** ← 절반이 건물 외벽 |
|
|
| high_vegetation | 17.42% |
|
|
| water | 12.04% |
|
|
| car | 7.83% |
|
|
| wall (옹벽) | 7.54% |
|
|
| roof_surface | 5.05% |
|
|
|
|
건물 외벽 하단 — 지면과 만나는 경계에서 새는 것으로 보인다.
|
|
**후처리로 상당 부분 잡을 수 있다**: 지면 예측 중 수직으로 튀는 포인트 제거.
|
|
|
|
> precision 95.24%는 목표 용도(구조물 제거 지형도)에 **이미 쓸 만하다.**
|
|
> recall 66.10%로 지면 34%를 놓치지만, 구멍은 보간으로 메운다.
|
|
|
|
---
|
|
|
|
## 3. ★ 미해결 — 한국 데이터 도메인 갭
|
|
|
|
서산 타일 1장 추론 결과:
|
|
|
|
| 클래스 | 비율 | 판정 |
|
|
|---|---|---|
|
|
| terrain | 24.29% | 타당 |
|
|
| **unclassified** | **21.70%** | ❌ 모델이 판단 못 함 |
|
|
| **water** | **21.11%** | ❌ **물 없다고 확인됨** |
|
|
| high_vegetation | 7.85% | 타당 |
|
|
| wall | 6.48% | ? |
|
|
| roof_surface | 6.11% | ? |
|
|
| **boat** | **5.07%** | ❌ **배 있을 리 없다** |
|
|
| facade_surface | 0.10% | ❌ 지붕 6%인데 벽 0.1%는 모순 |
|
|
|
|
**신뢰 불가 47.9%.**
|
|
|
|
### 원인
|
|
|
|
닫힌 집합 분류기다. 13개 중 반드시 하나를 고르고 **"모르겠음"이 없다.**
|
|
학습 어휘에 없는 것을 만나면 특징 공간에서 가장 가까운 것으로 간다.
|
|
|
|
헬싱키에서 배운 `water` = 어둡고 평평하고 균질하고 수평. 서산 포장면이 그 설명에 맞는다.
|
|
`boat`는 물 위에 있는 것이라 따라온다. **일관성 있는 착각이다.**
|
|
|
|
비율 매칭은 아니다 — SUM val의 water는 11.17%인데 서산 예측은 21.11%로 2배다.
|
|
|
|
### 시도했고 실패한 것: 클래스 마스킹
|
|
|
|
`water`·`boat` 로짓을 `-inf`로 죽여 2순위로 넘기는 실험.
|
|
|
|
```
|
|
wall +63,783 (6.48% → 20.05%) ← 절반 이상이 여기로
|
|
unclassified +33,867
|
|
terrain +13,656 ← 11%만 회복
|
|
```
|
|
|
|
**실패.** 2순위가 `terrain`이 아니라 `wall`이었다.
|
|
모델이 그 영역을 수직 구조물로 읽고 있다는 뜻이고, 도메인 갭이 얕지 않다는 증거다.
|
|
마스킹은 되돌렸다 (`SUMPARTS_MASK_CLASSES` 환경변수로 언제든 다시 켤 수 있다).
|
|
|
|
---
|
|
|
|
## 4. 발견한 업스트림 버그 4건 (전부 패치됨, 멱등, 원본 보존)
|
|
|
|
| # | 증상 | 원인 | 패치 |
|
|
|---|---|---|---|
|
|
| A | `bincount ... non-negative` | 블라인드 test셋 라벨이 전부 `-1` | `patch_unlabeled_test.sh` |
|
|
| B | `UnboundLocalError: 'epoch'` | `mode=val`이 학습 루프 변수 참조 | `patch_val_mode.sh` |
|
|
| C | `np.long` / `collections.Iterable` | numpy 1.24 / python 3.10에서 제거·이동 | `patch_numpy_aliases.sh` |
|
|
| D | **예측이 전부 한 클래스로 나옴** | `ConfusionMatrix.update()`가 **입력을 제자리 변조** | `patch_cm_mutation.sh` |
|
|
|
|
**D가 가장 위험했다.** `ignore_index`에 해당하는 포인트의 예측을
|
|
`num_classes-1`(=wall)로 덮어쓰는데, `main.py`가 그 다음에 시각화를 저장한다.
|
|
라벨이 없는 우리 타일은 전 포인트가 `ignore_index`라 **100% wall로 저장됐다.**
|
|
모델이 퇴화한 것처럼 보였지만 멀쩡했다.
|
|
|
|
---
|
|
|
|
## 5. 메모리 문제 (3090에서 겪은 것)
|
|
|
|
팔레트 색상 → 클래스 복원에서 `(N, 13, 3)` 배열을 통째로 만들고 있었다.
|
|
|
|
```python
|
|
d = ((rgb[:, None, :] - COLOR_MAP[None, :, :]) ** 2).sum(axis=2)
|
|
```
|
|
|
|
80만 포인트면 임시 배열 하나가 250 MB이고 여러 개가 동시에 존재한다.
|
|
전체 블록(470만 포인트)이면 GB 단위로 뛴다.
|
|
|
|
**수정 완료** — `sumparts_palette.py`로 분리하고 해시 조회 + 청크 폴백으로 바꿨다.
|
|
|
|
```
|
|
개선 후 peak RSS: 61 MB (470k 포인트 처리)
|
|
```
|
|
|
|
`coarse_eval.py`, `split_by_class.py`가 이 모듈을 쓴다.
|
|
|
|
---
|
|
|
|
## 6. 실측 성능표 (RTX 3060 12GB)
|
|
|
|
| 모델 | voxel_max | peak VRAM | s/iter | 100 epoch | 논문 mIoU |
|
|
|---|---|---|---|---|---|
|
|
| pointnet | 64000 | 6.01 G | 0.291 | 2.9h | 15.1% |
|
|
| pointnet++msg | 64000 | 4.16 G | 0.675 | 6.8h | 33.1% |
|
|
| pointvector-xl | 24000 | 6.46 G | 0.402 | **4.1h** | 70.0% |
|
|
| pointvector-xl | 64000 | **16.49 G** | 13.113 | ❌ 12GB 불가 | |
|
|
| pointnext-xl | 32000 | 8.03 G | 0.635 | 6.4h | 65.3% |
|
|
| pointnext-xl | 64000 | **15.47 G** | 46.980 | ❌ 12GB 불가 | |
|
|
|
|
> **WSL2에서 VRAM 초과는 OOM을 내지 않는다.** 호스트 RAM으로 흘려서
|
|
> 조용히 완주한다 — 25~100배 느리게. peak VRAM과 **전력(W)**으로 판정할 것.
|
|
> 사용률 100%인데 전력이 낮으면 연산이 아니라 PCIe 전송 대기다.
|
|
|
|
---
|
|
|
|
## 7. 3090에서 할 일
|
|
|
|
### 우선순위 1 — 논문 설정 재학습
|
|
|
|
`voxel_max 64000`은 16.5 GB가 필요해 12 GB 카드에서 불가능했다. 24 GB면 된다.
|
|
|
|
기대 효과:
|
|
|
|
| | 현재 (24000) | 재학습 (64000) 기대 |
|
|
|---|---|---|
|
|
| SUM terrain IoU | 60.69% | ~85% |
|
|
| 지면 precision | 95.24% | ~96% |
|
|
| 지면 recall | 66.10% | ~85% |
|
|
| **서산 물 오분류 21%** | — | **그대로** |
|
|
|
|
**주의**: `voxel_max`는 중립적 손잡이가 아니다. 64000으로 학습하면
|
|
**추론도 64000 청크로 해야** 성능이 나온다 → 서산 추론도 3090에서 돌려야 한다.
|
|
|
|
### 우선순위 2 — 서산 예측 육안 확인
|
|
|
|
`D:\AI_Test\sum-part\unseen\*.ply`에 42.82%가 들어 있다.
|
|
**이게 뭔지 모르면 나머지가 전부 추측이다.**
|
|
|
|
### 우선순위 3 — 도메인 갭 대응
|
|
|
|
재학습으로 안 고쳐진다. 선택지:
|
|
|
|
1. **SAM 3.1 자동 라벨링 + 파인튜닝** — 드론 원본 8,120장 + 카메라 포즈(PPK) 보유.
|
|
SAM 3의 텍스트 프롬프트로 명명된 마스크 → 포즈로 3D 투영 → 면 투표.
|
|
사람 몫은 전수 라벨링이 아니라 **1~2타일 검증**이다.
|
|
2. **후처리** — 지면 예측 중 수직 이상치 제거로 건물 외벽 오염(49.9%) 감소.
|
|
|
|
---
|
|
|
|
## 8. 산출물 위치
|
|
|
|
```
|
|
D:\AI_Test\sum-part\
|
|
├── ground\ 114,159 pts (24.29%)
|
|
├── building\ 93,076 pts (19.80%)
|
|
├── tree\ 36,876 pts ( 7.85%)
|
|
├── vehicle\ 24,631 pts ( 5.24%)
|
|
└── unseen\ 201,258 pts (42.82%) ← unclassified + water
|
|
```
|
|
|
|
각 폴더에 `.ply`와 `.obj`가 있다. **`.ply`를 열어라** —
|
|
OBJ는 면이 없어서 대부분의 뷰어가 아무것도 안 보여준다.
|
|
색상은 클래스 색이 아니라 **드론 사진 텍스처**라, 그 클래스로 분류된 게 실제로 뭔지 보인다.
|
|
|
|
```
|
|
D:\MYCLAUDE_PROJECT\sum-parts-test\output\
|
|
├── seosan_pred_viewer.ply 클래스 색
|
|
└── seosan_rgb_viewer.ply 사진 색
|
|
```
|
|
|
|
---
|
|
|
|
## 9. 제약
|
|
|
|
- **test 세트는 블라인드다.** 라벨이 전부 `-1`이라 로컬 채점 불가.
|
|
논문 수치와 직접 대조하려면 예측을 저자(gaoweixiaocuhk@gmail.com)에게 보내야 한다.
|
|
- **어노테이션 도구는 비공개다.** 저자가 유료 서비스로 판매 중.
|
|
- **학습 가중치도 비공개다.** 직접 학습이 유일한 경로.
|
|
- **라이선스**: 데이터 CC BY-NC 4.0, 코드 GPL-3.0. 상업 이용은 저자 허락 필요.
|
|
|
|
---
|
|
|
|
## 10. 문서
|
|
|
|
| 문서 | 용도 |
|
|
|---|---|
|
|
| [SETUP.md](SETUP.md) | 1단계 — 환경 구축 (GPU 불필요, ~80분) |
|
|
| [TRAIN.md](TRAIN.md) | 2단계 — 학습 (GPU 필요) |
|
|
| [docs/pipeline.html](docs/pipeline.html) | 전체 6단계 공정 정의 |
|
|
| [docs/SUM-Parts-검토노트.md](docs/SUM-Parts-검토노트.md) | 트러블슈팅 상세, 데이터 스키마 실측 |
|