Metric#

다섯 모델이 같은 지표를 쓴다. 이 페이지는 그 지표가 각각 무엇을 말해 주는지, 어느 공간에서 계산하는지, 어떤 상황에서 믿을 만한지를 정리한다. 코드는 utils/metric.py 의 compute_submetric 과 models/base_model.py 의 검증·평가 루프에 있다.

먼저 큰 그림부터. 이 프로젝트에서 지표는 두 종류로 나뉜다.

이 프로젝트의 필드는 대체로 0 근처가 넓다. 그래서 mae 와 눈으로 보는 품질은 대체로 같이 가지만, rel_l2% 는 평가 이미지에 문제가 없어 보여도 수십 % 가 나오곤 한다. 어떤 필드에서 어떤 지표를 봐야 하는지는 해석 기준 에 정리했다.

표기#

아래 식에서 쓰는 기호다. 한 샘플의 fluid 격자점(mesh 모델이면 vertex) 집합이 이고 다. 점 에서

mesh 모델은 vertex 마다 질량 를 달아 가중 평균한다. 아래 식에서 를 로 바꿔 읽으면 된다.

지표 정의#

지표 정의 종류
mae 절대
mse 절대
rmse 절대
wmape% 상대
rel_l2% 상대
r2 상대

읽는 요령이 몇 개 있다. rmse 는 격자점 수로 나눈 진짜 RMS 다. rel_l2% 는 풀어 보면 이므로, 정답의 RMS 가 작을수록 커진다. r2 의 분모는 정답의 공간 분산이라서 정답 자체가 거의 균일한 필드에서는 값이 쉽게 나빠진다.

설정 파일의 기본값은 다섯 모델이 같다.

metric_names:      ['mae', 'mse']                                     # 검증·조기종료
test_metric_names: ['mae', 'mse', 'rmse', 'wmape%', 'rel_l2%', 'r2']  # 테스트

생성 모델(AE·EDM)은 test_metric_names 에 fid 계열이 추가된다.

계산 단위#

모델 metric 을 계산하는 공간
aicfd-grid-building-physical, aicfd-grid-indoor-physical 물리 단위 (nondim_to_physical 이후)
aicfd-mesh-nasal-physical WSS 물리 단위 (nondim_to_physical 이후)
aicfd-grid-building-rgb, aicfd-grid-nasal-rgb [0,255] 화소값 (to_img 로 [-1,1] 에서 환산)

물리량을 다루는 3종은 모든 지표를 물리 단위에서 한 번에 계산한다. 상대 지표를 nondim 공간에서 따로 구할 필요는 없다. 샘플 단위로 계산하면 샘플마다 붙는 스칼라 계수가 분자와 분모에서 상쇄돼서 두 공간의 값이 같아지기 때문이다.

nondim 공간 지표를 쓰는 곳은 조기 종료 하나뿐이다. 서로 다른 fold 와 epoch 를 견줘야 하는 판정이라, 풍속으로 정규화된 값이어야 비교가 성립한다.

샘플 단위와 집계#

지표는 샘플 하나씩 계산한 뒤 샘플끼리 평균낸다. 여기서 샘플이 무엇인지는 경로마다 물리적으로 정해져 있다.

경로 샘플 1개
2D 이미지 1장
3D 학습·검증 깊이 윈도우 1개
3D 테스트 케이스 전체 ((1,c,d,h,w) 로 접어서 전달)
mesh mesh 1개

배치 안에서 샘플별 지표를 평균한 다음, 배치를 합칠 때 샘플 수로 가중해서 다시 평균한다.

따라서 배치 크기를 바꿔도 값이 변하지 않는다.

비율 지표는 샘플 단위를 고정해야 정의가 성립한다

wmape%·rel_l2%·r2 는 비율로 정의된 지표라, 샘플마다 구한 값을 평균한 것과 여러 샘플을 합쳐 한 번에 계산한 것이 서로 다르다. 배치 전체를 한 덩어리로 모아 계산하면 배치 크기를 바꿀 때마다 값이 조금씩 달라진다. 그래서 compute_submetric 은 마스크 인자를 받지 않고 샘플 하나만 받는다. 샘플마다 잘라서 호출하는 것은 호출자가 맡는다.

fluid 영역 한정#

grid 모델은 batch_dict['input']['mask'][:, :1] 의 도메인 채널로 fluid 격자점만 골라 계산한다.

dom_flag = dom_mask[i, 0].bool()        # (h,w) 또는 (d,h,w)
pred = preds_tuple[j][i][:, dom_flag]   # (c,n)

샘플 하나 안에서는 마스크가 전 채널 공통이라, 마지막 차원 불리언 인덱싱 한 번이면 끝난다. 3D 경로는 입력 dict 를 지우기 전에 케이스별 마스크를 미리 확보해 두고, latent 계열은 인코딩하기 전에 화소 해상도 마스크를 따로 챙겨 둔다.

mesh 모델은 모든 vertex 가 fluid 라 고를 것이 없다. 대신 vertex 질량으로 면적가중한다 — . 이렇게 해야 vertex 가 촘촘한 쪽으로 지표가 쏠리지 않는다.

fluid 한정이 걸리지 않는 경로도 있다. contour AE 는 Collator 가 마스크를 넘기지 않고, 도메인 AE 는 복원 대상이 마스크 자체라서 캔버스 전체로 계산한다. building 2종의 확산 계열 평가도 마찬가지로 캔버스 전체다.

해석 기준#

어떤 지표를 믿을지는 필드 이름이 아니라 값이 어떻게 분포하는지에 따라 정해진다. 크게 두 부류로 나뉜다.

값이 대부분 0 근처인 필드#

velocity, velocity-magnitude, k, WSS 가 여기 속한다. 값이 음수로 내려가지 않고, 정지 영역은 0 근처에 깔려 있고, 전단이나 제트가 있는 곳에만 값이 몰려 있다.

0 을 기준으로 부호가 갈리는 필드#

temperature(기준온도와의 차), gauge pressure 가 여기 속한다. 대부분의 값이 0 근처에 모여 있고 몇 군데에서만 값이 크게 벗어난다.

공통#

두 부류 모두 정답 크기로 나누지 않는다. 정규화가 꼭 필요하면 입구 조건에서 오는 고정 외부 스케일 (, , )을 쓴다. 정답으로 나누면 0 근처에서 분모가 무너진다.

L2 계열 지표와 눈으로 본 품질이 어긋날 수 있다

물리량 모델의 필드는 0 근처가 대부분이고 큰 값은 몇 군데뿐이다. 오차를 제곱하는 rel_l2%·rmse 는 그 몇 군데에 좌우되고, 분모가 되는 RMS 는 작아서 비율이 크게 나온다. 반대로 평가 이미지에서는 그 몇 군데가 화소 몇 개라 눈에 띄지 않는다. 그래서 평가 이미지로는 문제가 없어 보이는데 지표만 나쁘게 나오는 상황이 생긴다.

계산이 틀린 게 아니라 지표가 원래 그렇게 동작한다. 실제로 오차가 어디에 몰려 있는지는 실측 결과 에서 분해해 두었다.

조기 종료와 EMA 선택#

경로 조기 종료 기준
회귀 (물리량) nondim 공간 mae 를 채널 수로 정규화한 값
회귀 (렌더) [0,255] 화소값 mae 의 필드 합
확산 학습 공간(edm/ldm) MSE 합
mesh nondim 공간 mae 의 필드 합

post-hoc EMA 선택은 EMA 표준편차 후보를 여러 개 재구성해 각각 평가한 뒤 제일 좋은 것을 고르는 절차다. 점수는 평가 경로를 그대로 타므로 물리 단위에서 나오고, 필드마다 채널 수로 나눠 더한다. 후보끼리는 같은 fold, 같은 epoch 의 가중치를 견주는 것이라 정규화 공간을 따로 맞출 필요가 없다.