Saklı Markov modelleri ile çalışırken “underflow”, yani değerlerin bilgisayarda saklanamayacak derecede küçülüp pratikte sıfır olması temel bir uygulama sorunu olarak karşımıza çıkar. Çünkü hesaplamalarda alttakine benzer bir işlem yapmamız gerekir:

$$\log\sum\limits_k e^{x_k}$$

$e^{x_k}$ değerlerinin -1000lerde seyrettiğini düşünün. $e^{1000}$ gibi bir sayıyı açıkça hesaplamaya çalışırsak sıfır elde ederiz.

Probleme tane tane değil, tümden bakalım. Elimizde 3 tane değer olsun: -1000, -1005 ve -1010. Bunları işleyelim. $e^{1005}$,  $e^{1000}$’e göre oldukça küçük.  $e^{1010}$ ise daha da küçük. Burada baskın olan  $e^{1000}$ değeri. Yani, en büyük değer baskın görünüyor. En büyük değere $y$ diyelim ve bunu hesaba katarak sihirli değneğimizi kullanalım:

\begin{align}
\log\sum\limits_k e^{x_k}
& = \log\left[\left(\sum\limits_k e^{x_k}\right)e^{-y} e^y \right] \\
& = \log\left[\left(\sum\limits_k e^{x_k}\right)e^{-y}\right] + y \\
& = \log\left[\sum\limits_k e^{x_k - y}\right] + y
\end{align}

Yani öncelikle tüm değerlerden en büyüğünü çıkartacağız (yeni dizilimin en büyük değeri 0 olacak) ve işlemi yaptıktan sonra bu değeri geri ekleyeceğiz.

Fonksiyonumuz çok basit:

import numpy as np

def logSumExp(x):
    maxX = np.max(x)
    r = maxX + np.log(np.sum(np.exp(x-maxX)))
    return r

Deneyelim:

r = logSumExp(np.array([-1213, -1214]))  # sonuç: -1212.6867383124818
r2 =  np.log(np.sum(np.exp(np.array([-1213, -1214]))))  # sonuç: -Inf

Yöntemimiz sonucu başarıyla hesapladı. Açıkça yaptığımızda ise underflow oldu ve log(0) hesabı yüzünden -sonsuz sonucu döndü.

Not: Kaynak olarak şu videoya bakabilirsiniz.