오버플로 오류없이 큰 지수 항을 안정적으로 추가하는 방법은 무엇입니까?


24

Markov Chain Monte Carlo의 가장 일반적인 문제는 지수 지수가 큰 컴퓨팅 확률과 관련이 있습니다.

ea1+ea2+...

여기서의 구성 요소 매우 큰 매우 작은 범위 일 수있다. 내 접근 방식은 가장 큰 지수 항 하여 다음과 같습니다.aK:=maxi(ai)

a=K+log(ea1K+ea2K+...)
eaea1+ea2+...

이 접근법은 a의 모든 요소 a가 크면 합리적 이지만 그렇지 않은 경우 좋은 아이디어는 아닙니다. 물론 작은 요소는 부동 소수점 합계에 기여하지 않지만 어떻게 신뢰할 수있는 요소를 다루는 지 잘 모르겠습니다. R 코드에서 내 접근 방식은 다음과 같습니다.

if ( max(abs(a)) > max(a) )
  K <-  min(a)
else
  K <- max(a)
ans <- log(sum(exp(a-K))) + K

표준 솔루션이 있어야한다는 일반적인 문제로 보이지만 그것이 무엇인지 잘 모르겠습니다. 제안 해 주셔서 감사합니다.


1
이것은 것입니다. 'logsumexp'를위한 Google.

답변:


15

데이터를 두 번만 통과하는 간단한 솔루션이 있습니다.

먼저 계산

K:=maxiai,

용어 가 있으면 를 알려줍니다Σ I E IN 전자 K .n

ieaineK.

당신은 아마도 없기 때문에 조차도 어디 근처 대형으로 , 당신의 계산에 넘쳐에 대한 걱정이 없어야 double 정밀도를 .10 20 τ : = i e a iKnn1020

τ:=ieaiKn

따라서 계산하면 솔루션은 입니다.e K ττeKτ


명확한 표기법에 감사드립니다. 그러나 이것이 본질적으로 내가 제안한 것이라고 생각합니다 (?) 가 작을 때 언더 플로 오류를 피해야한다면 @gareth가 제안한 Kahan summation 접근법이 필요 합니까? ai
cboettig

아, 이제 네가 뭘 봤는지 봤어 솔루션에 아주 작은 결과를 추가해도 변경되지 않으므로 언더 플로에 대해 걱정할 필요가 없습니다. 예외적으로 많은 수의 값이 있으면 작은 값을 먼저 합산해야합니다.
잭 폴슨

downvoter에게 : 내 대답에 무엇이 잘못되었는지 알려주시겠습니까?
잭 폴슨

아주 작은 용어 가 많은 경우 어떻게해야 합니까? 이것에 대해서는 일 수 있습니다. 이와 같은 용어가 많은 경우 큰 오류가 발생합니다. eaiK0
becko


10

두 배를 더하는 동안 정밀도를 유지하려면 Kahan Summation 을 사용해야 합니다. 이것은 캐리 레지스터를 갖는 것과 동등한 소프트웨어입니다.

이것은 대부분의 값에는 문제가 없지만 오버플로가 발생하면 IEEE 754 배정 밀도 한계에 도달합니다 . 약 입니다. 이 시점에서 새로운 표현이 필요합니다. 추가시 오버플로를 감지하고 로 평가할 지수를 크게 감지 할 수도 있습니다 . 이 시점에서 지수를 이동하고이 이동을 추적하여 double의 해석을 수정할 수 있습니다.e709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

이것은 대부분 지수 오프셋 접근 방식과 유사하지만이 버전은 기본 2에 유지되며 가장 큰 지수를 찾기 위해 초기 검색이 필요하지 않습니다. 따라서 입니다.value×2shift

#!/usr/bin/env python
from math import exp, log, ceil

doubleMAX = (1.0 + (1.0 - (2 ** -52))) * (2 ** (2 ** 10 - 1))

def KahanSumExp(expvalues):
  expvalues.sort() # gives precision improvement in certain cases 
  shift = 0 
  esum = 0.0 
  carry = 0.0 
  for exponent in expvalues:
    if exponent - shift * log(2) > 709.783:
      n = ceil((exponent - shift * log(2) - 709.783)/log(2))
      shift += n
      carry /= 2*n
      esum /= 2*n
    elif exponent - shift * log(2) < -708.396:
      n = floor((exponent - shift * log(2) - -708.396)/log(2))
      shift += n
      carry *= 2*n
      esum *= 2*n
    exponent -= shift * log(2)
    value = exp(exponent) - carry 
    if doubleMAX - esum < value:
      shift += 1
      esum /= 2
      value /= 2
    tmp = esum + value 
    carry = (tmp - esum) - value 
    esum = tmp
  return esum, shift

values = [10, 37, 34, 0.1, 0.0004, 34, 37.1, 37.2, 36.9, 709, 710, 711]
value, shift = KahanSumExp(values)
print "{0} x 2^{1}".format(value, shift)

Kahan 합계는 "보상 합계"방법 중 하나 일뿐입니다. 어떤 이유로 Kahan이 제대로 작동하지 않으면 다양한 크기와 반대 부호를 올바르게 추가하는 여러 가지 방법이 있습니다.
JM

@ JM 다른 방법의 이름을 알려 주시겠습니까? 감사.
Gareth A. Lloyd 2012

1

당신의 접근 방식은 견고합니다.

오버플로를 피하기 위해 정확히 알 필요는 없습니다 . 따라서 MCMC 샘플링을 수행하기 전에 분석적 으로 추정 할 수 있습니다 .KKK


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.