วิธีเพิ่มคำที่อธิบายใหญ่ ๆ ได้อย่างน่าเชื่อถือโดยไม่มีข้อผิดพลาดล้น


24

ปัญหาที่พบบ่อยมากในมาร์คอฟเชนมอนติคาร์โลนั้นเกี่ยวข้องกับความน่าจะเป็นในการคำนวณซึ่งเป็นผลรวมของเทอมใหญ่ ๆ

ea1+ea2+...

ซึ่งองค์ประกอบของได้ตั้งแต่ขนาดเล็กมากที่จะมีขนาดใหญ่มาก แนวทางของฉันคือการแยกคำที่ใหญ่ที่สุดเพื่อให้:aK:=maxi(ai)

E 'อี1 + e 2 + . .

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

วิธีการนี้มีความสมเหตุสมผลหากองค์ประกอบทั้งหมดของaมีขนาดใหญ่ แต่ไม่ใช่ความคิดที่ดีเช่นนั้นหากไม่ใช่ แน่นอนว่าองค์ประกอบเล็ก ๆ นั้นไม่ได้มีส่วนช่วยในการบวกจำนวนจุดลอยตัว แต่ฉันไม่แน่ใจว่าจะจัดการกับพวกเขาได้อย่างไร ในรหัส R วิธีการของฉันดูเหมือนว่า:

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

ดูเหมือนว่าเป็นปัญหาที่พบได้บ่อยพอที่ควรจะมีวิธีแก้ไขปัญหามาตรฐาน แต่ฉันไม่แน่ใจว่ามันคืออะไร ขอบคุณสำหรับคำแนะนำใด ๆ


1
นี่คือสิ่งที่ Google สำหรับ 'logsumexp'

คำตอบ:


15

มีวิธีแก้ปัญหาที่ตรงไปตรงมาโดยมีเพียงสองผ่านผ่านข้อมูล:

คำนวณอันดับแรก

K:=maxiai,

ซึ่งจะบอกคุณว่าหากมีคำศัพท์คำดังนั้น Σฉันอีฉันn E Kn

ieaineK.

เนื่องจากคุณไม่มีใกล้ที่ใด ๆ แม้แต่ใหญ่เท่ากับคุณจึงไม่ต้องกังวลกับการคำนวณของ ในความแม่นยำสองเท่า .10 20 τ : = Σฉันอีฉัน - Knn1020

τ:=ieaiKn

ดังนั้นการคำนวณแล้ววิธีการแก้ปัญหาของคุณมี\อีK ττeKτ


ขอบคุณสำหรับโน้ตชัดเจน - (?) แต่ผมเชื่อว่านี่เป็นหลักสิ่งที่ผมได้นำเสนอถ้าผมจำเป็นต้องหลีกเลี่ยงข้อผิดพลาด underflow เมื่อบางมีขนาดเล็กฉันฉันต้องรวบรวมวิธีการบวก Kahan เสนอโดย@gareth ? ai
cboettig

อาตอนนี้ฉันเห็นสิ่งที่คุณได้รับ คุณไม่จำเป็นต้องกังวลเกี่ยวกับอันเดอร์โฟล์เนื่องจากการเพิ่มผลลัพธ์เล็กน้อยให้กับโซลูชันของคุณไม่ควรเปลี่ยนแปลง หากมีจำนวนมากเป็นพิเศษคุณควรรวมค่าเล็กก่อน
Jack Poulson

สำหรับผู้ลงคะแนนเสียง: คุณจะช่วยให้ฉันรู้ว่าคำตอบของฉันผิดหรือเปล่า?
Jack Poulson

ถ้าคุณมีศัพท์จำนวนน้อยมาก อาจเป็นไปได้ว่าสำหรับสิ่งเหล่านี้ หากมีคำมากมายเช่นนี้คุณจะมีข้อผิดพลาดขนาดใหญ่ eaiK0
becko


10

เพื่อความแม่นยำในขณะที่คุณเพิ่มคู่กันคุณต้องใช้Kahan Summationซอฟต์แวร์นี้เทียบเท่ากับการพกพาลงทะเบียน

นี้จะปรับค่ามากที่สุด แต่ถ้าคุณได้รับล้นแล้วคุณจะตีขอบเขตของมาตรฐาน IEEE 754 แม่นยำสองซึ่งจะเกี่ยวกับ{} ณ จุดนี้คุณต้องแสดงภาพใหม่ คุณสามารถตรวจสอบล้นได้ตลอดเวลานอกจากนี้โดยและยังตรวจสอบเลขยกกำลังที่มีขนาดใหญ่เพื่อที่จะประเมินผลโดย ณ จุดนี้คุณสามารถแก้ไขการตีความของคู่โดยขยับเลขชี้กำลังและติดตามการเปลี่ยนแปลงนี้e709.783doubleMax - sumSoFar < valueToAddexponent > 709.783

สิ่งนี้ส่วนใหญ่คล้ายกับวิธีการ offseting แบบเลขชี้กำลังของคุณ แต่เวอร์ชันนี้ถูกเก็บไว้ในฐาน 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 ไม่ทำงานค่อนข้างถูกต้องมีวิธีอื่น ๆ อีกมากมายสำหรับการเพิ่มเงื่อนไขของขนาดที่แตกต่างกันและสัญญาณตรงข้ามอย่างถูกต้อง
JM

@JM คุณสามารถให้ฉันชื่อวิธีอื่น ๆ ฉันจะค่อนข้าง intrested เพื่ออ่านเป็นพวกเขา ขอบคุณ
Gareth A. Lloyd

1

แนวทางของคุณแข็งแกร่ง

คุณไม่จำเป็นต้องรู้แน่นอนเพียงแค่ดีพอที่จะหลีกเลี่ยงการล้น ดังนั้นคุณอาจประเมินเชิงวิเคราะห์ก่อนที่คุณจะทำการสุ่มตัวอย่าง MCMCเคKK


0

มีแพ็คเกจ R ที่ให้การติดตั้ง "log-sum-exp trick" อย่างรวดเร็วและมีประสิทธิภาพ

http://www.inside-r.org/packages/cran/matrixStats/docs/logSumExp

ฟังก์ชัน logSumExp ยอมรับเวกเตอร์ตัวเลข lX และเอาต์พุตบันทึก (ผลรวม (exp (lX))) ในขณะที่หลีกเลี่ยงปัญหาอันเดอร์โฟล์และโอเวอร์โฟลว์โดยใช้วิธีที่คุณอธิบาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.