로그값인 채로 확률을 더하려면
로그확률은 곱을 합으로 바꾸기 좋지만, 원래 확률의 합을 구하려면 꼴이 생겨. 가 아주 작으면 지수화한 값이 0으로 밑돌고, 아주 크면 넘칠 수 있어. 이때 쓰는 표준 도구가 log-sum-exp야.
가장 큰 값을 빼면 모든 지수의 입력이 0 이하가 돼서 넘침을 막고, 가장 큰 항은 정확히 이라 전부 0으로 밑도는 일도 피할 수 있어. 끝에 을 더하면 원래 크기로 돌아와.
softmax의 안정성도 같은 원리
softmax는 를 지수의 합으로 나눠. 순진하게 계산하면 큰 양의 logit에서 먼저 넘칠 위험이 커. 모든 logit에서 최댓값을 빼도 softmax 결과는 변하지 않으므로, 프레임워크는 이 이동을 이용해 안정적으로 계산해.
로그확률이 필요하다면 log(softmax(x))를 두 단계로 만들지 말고 log_softmax(x)를 써. 아주 작은 확률을 먼저 0으로 만든 뒤 로그를 취하는 실수를 피할 수 있어.
import numpy as np from scipy.special import logsumexp
logs = np.array([-1000, -1001, -1002])
m = np.max(logs) shifted = logs - m exp_terms = np.exp(shifted) s = np.sum(exp_terms) manual = m + np.log(s)
scipy_result = logsumexp(logs)
print("manual :", manual) print("scipy :", scipy_result) print("diff :", abs(manual - scipy_result))
출력
manual : -999.5923940355556
scipy : -999.5923940355556
diff : 0.0
언더플로우를 방지하려고 하는 기법인가보다. 에러값이 점점 작아질수록 중요한작업인듯,, 잘못하면 에러가있는데도 0으로 처리해버릴수있으니