운영 절차#
데이터 재생성, 재평가처럼 실행이 따르는 작업. 개념 설명은 전처리 에 있다.
공통 주의#
- h5 읽기에는
import hdf5plugin이 필요하다 (zstd/blosc2 압축). outputs/는 git 무시 대상이라 gitignore 를 따르는 검색 도구에 잡히지 않는다. 얼려둔 설정, 학습 상태 파일, 결과 csv 를 찾을 때는 일반grep이나 파이썬으로 따로 훑어야 한다.
aicfd-grid-building-physical 데이터 재생성#
양자화 범위를 실제 분포에 맞게 좁히는 작업이다. 현재 범위는 보간 안전장치가 없던 시절 기준이라 넉넉해서, 범위를 좁히면 uint16 한 단계가 나타내는 물리값 간격이 작아져서 양자화 오차가 줄어든다. 순서를 지키지 않으면 보간 아티팩트가 남은 분포에서 임계값을 정하게 되므로, 단계를 건너뛰지 않는다.
1. fp32 재생성#
# 전량 재생성하려면 완료 기록 파일부터 비운다
rm -f <데이터 경로>/regen_done.txt
python scripts/preprocess/preprocess.py
clip 임계값을 다시 잡으려면 잘리지 않은 fp32 가 있어야 해서 이 단계부터 시작한다.
건너뛰기 판단은 regen_done.txt(완료된 케이스만 기록) 기준이다. 저장이 원자적이고 완료 기록 전에 죽은 케이스만
다시 처리하므로, 중간에 끊겨도 다시 실행하면 이어서 진행되고 잃는 것이 없다.
2. O(1) 분포 측정#
clip 임계값은 데이터 분포를 기준으로 정한다. 그래서 임계값을 계산하기 전에, 보간 아티팩트가 분포의 상단 꼬리를 왜곡하고 있지 않은지부터 확인한다. fluid 영역에서 필드별 값의 분포를 본다. building 의 은 velocity , pressure , k 다.
| 확인 | 정상 |
|---|---|
| 격자 최댓값 대 원본 점군 최댓값 | 같다. 경계 행·열에 몰림이 없다 |
| p99 / p99.9 / p99.95 / p99.99 / max | 완만하게 증가하고 값이 도메인 내부에 분포한다 |
| 원본 표준편차 대 p99.9 윈저화 표준편차 | 차이가 작다 |
위험 신호는 두 가지가 같이 나타나는 경우다. 하나는 p99.9 와 최댓값 사이가 갑자기 벌어지는 것(꼬리가 완만하지 않고 몇 개 화소만 멀리 튀어 있다는 뜻), 다른 하나는 그 화소들이 도메인 경계 행·열에 몰려 있는 것이다. 둘이 겹치면 실제 현상이 아니라 보간 아티팩트가 남아 있는 것이므로, 임계값을 정하기 전에 보간 단계부터 고쳐야 한다.
3. clip 임계값 결정#
building 은 clip 임계값과 저장 범위가 같은 숫자다 (전처리 — O(1) clip). 그래서 이 단계에서 정하는 것은 필드별 저장 범위 하나뿐이다. 2 단계에서 본 최소·최대와 quantile 을 놓고, 실제로 일어난 극단값은 남기고 보간 blowup 만 걸러낼 수 있을 만큼 범위를 넉넉하게 정한다. 잘려 나가는 화소가 필드당 0.01~0.05% 를 넘으면 임계값 문제가 아니라 분포 문제이므로 2 단계로 돌아간다.
aicfd-grid-indoor-physical 은 같은 자리에서 규칙을 쓴다.
데이터가 작아 clip 과 저장 범위를 따로 둘 수 있어서다. building 에 그대로 옮겨 쓰는 숫자가 아니다.
4. 양자화 범위 재산정#
3 단계에서 정한 범위를 clipper.py 와 compressor.py 의 MINMAX_DICT 에 함께 넣는다.
두 스크립트가 같은 dict 를 들고 있어 한쪽만 고치면 clip 과 양자화가 어긋난다.
범위는 clip 을 지난 값의 실제 최소·최대를 감싸야 하고(solid=0 도 그 안에 들어간다),
좁을수록 uint16 한 칸이 나타내는 물리량이 작아져 정밀도가 올라간다.
범위 변경은 재학습을 수반한다
양자화 범위는 dequantization 계수라서, 바꾸면 기존 checkpoint 및 함께 얼려둔 설정과 호환되지 않는다. 재전처리·재양자화·재학습이 모두 필요하다. 학습·평가 코드 자체는 물리 단위로 동작하므로 수정할 것이 없다.
5. uint16 재생성#
python scripts/preprocess/compressor.py # 기존 uint16 을 지운 뒤 실행
제대로 됐는지 확인하려면 dequantization 해서 2 단계를 다시 측정한다. 포화 화소(==0, ==65535)가
거의 없어야 하고, 윈저화 표준편차가 안정적이어야 한다. 마지막으로 정규화 통계 캐시(nondim_ref_*.npy)를 지운다.
그래야 다음 학습이 옛 데이터 기준 통계를 재사용하지 않고 새로 계산한다.
재평가#
retest.py 는 얼려둔 outputs/*/.hydra/config.yaml 의 test_metric_names 를 읽어
evaluate_one_epoch 에 위임한다. 지표 이름을 하드코딩하지 않으므로 기존 checkpoint 를 무효화하지 않는다.
--save-eval-plots false 로 실행하면 평가 이미지·PLY 를 재생성하지 않는다.
얼려둔 설정에 지표 이름을 추가하면 재개가 깨진다
과거 학습의 train_state.yaml 에 없는 지표 이름을 얼려둔 설정에 넣으면 재개 시 길이가 맞지 않아 실패한다.
또한 그 학습이 "무엇을 측정했는지"를 사후에 바꾸는 일이 된다. 과거 학습에서 새 지표가 필요하면 전체 재평가를 돌린다.
결과 진단#
지표가 이상해 보일 때 위에서부터 순서대로 확인한다. 대부분은 1~2번에서 원인이 드러난다.
- 오차 에너지 분해 — (mesh 는 )를 정답 크기 분위 구간별로 나눠 본다. 상위 1% 가 대부분을 차지한다면 몇 개 안 되는 극단점이 지표 값을 거의 다 결정하고 있는 상황이다.
- 샘플별 값 대 전체 합산 값 — 재평가는 샘플 평균이다. 둘이 크게 다르면 소수 슬라이스나 mesh 가 튄 것이다.
- 양자화 포화 — 포화 화소 수가 0 이 아니면 fp32 가 저장 범위를 넘고 있다.
- 정규화 통계 — 학습 공간의 표준편차가 1 에서 크게 벗어나면 통계 캐시가 옛 데이터 기준일 수 있다.
해석 기준은 Metric — 해석 참고.