簡體   English   中英

Theano sqrt返回NaN值

[英]Theano sqrt returning NaN values

在我的代碼中,我使用theano來計算歐氏距離矩陣( 此處的代碼):

import theano
import theano.tensor as T
MAT = T.fmatrix('MAT')
squared_euclidean_distances = (MAT ** 2).sum(1).reshape((MAT.shape[0], 1)) + (MAT ** 2).sum(1).reshape((1, MAT.shape[0])) - 2 * MAT.dot(MAT.T)
f_euclidean = theano.function([MAT], T.sqrt(squared_euclidean_distances))
def pdist_euclidean(mat):
    return f_euclidean(mat)

但是下面的代碼導致矩陣的某些值為NaN 我讀過這個計算時發生theano.tensor.sqrt()在這里它的建議

在sqrt中添加eps(或max(x,EP))

所以我在代碼中添加了一個eps:

import theano
import theano.tensor as T

eps = 1e-9

MAT = T.fmatrix('MAT')

squared_euclidean_distances = (MAT ** 2).sum(1).reshape((MAT.shape[0], 1)) + (MAT ** 2).sum(1).reshape((1, MAT.shape[0])) - 2 * MAT.dot(MAT.T)

f_euclidean = theano.function([MAT], T.sqrt(eps+squared_euclidean_distances))

def pdist_euclidean(mat):
    return f_euclidean(mat)

我在執行sqrt之前添加它。 我的NaN少了,但我還是得到了它們。 這個問題的正確解決方案是什么? 我也注意到如果MATT.dmatrix()那么就沒有NaN

計算歐幾里德距離時,有兩種可能的NaN來源。

  1. 浮點表示近似問題導致負距離,當它實際上只是零。 負數的平方根是未定義的(假設您對復雜解決方案不感興趣)。

    想象MAT具有價值

     [[ 1.62434536 -0.61175641 -0.52817175 -1.07296862 0.86540763] [-2.3015387 1.74481176 -0.7612069 0.3190391 -0.24937038] [ 1.46210794 -2.06014071 -0.3224172 -0.38405435 1.13376944] [-1.09989127 -0.17242821 -0.87785842 0.04221375 0.58281521]] 

    現在,如果我們分解計算,我們看到(MAT ** 2).sum(1).reshape((MAT.shape[0], 1)) + (MAT ** 2).sum(1).reshape((1, MAT.shape[0]))有價值

     [[ 10.3838024 -9.92394296 10.39763039 -1.51676099] [ -9.92394296 18.16971188 -14.23897281 5.53390084] [ 10.39763039 -14.23897281 15.83764622 -0.65066204] [ -1.51676099 5.53390084 -0.65066204 4.70316652]] 

    2 * MAT.dot(MAT.T)有價值

     [[ 10.3838024 14.27675714 13.11072431 7.54348446] [ 14.27675714 18.16971188 17.00367905 11.4364392 ] [ 13.11072431 17.00367905 15.83764622 10.27040637] [ 7.54348446 11.4364392 10.27040637 4.70316652]] 

    這兩個值的對角線應該相等(矢量和它自身之間的距離為零),從這個文本表示看起來它是真的,但實際上它們略有不同 - 差異太小而不能顯示我們打印這樣的浮點值

    當我們打印完整表達式的值(上面第二個矩陣從第一個中減去)時,這一點就變得很明顯了

     [[ 0.00000000e+00 2.42007001e+01 2.71309392e+00 9.06024545e+00] [ 2.42007001e+01 -7.10542736e-15 3.12426519e+01 5.90253836e+00] [ 2.71309392e+00 3.12426519e+01 0.00000000e+00 1.09210684e+01] [ 9.06024545e+00 5.90253836e+00 1.09210684e+01 0.00000000e+00]] 

    對角線幾乎由零組成,但第二行中的項目,第二列現在是一個非常小的負值。 然后,當您計算所有這些值的平方根時,您將在該位置獲得NaN ,因為負數的平方根未定義(對於實數)。

     [[ 0. 4.91942071 1.64714721 3.01002416] [ 4.91942071 nan 5.58951267 2.42951402] [ 1.64714721 5.58951267 0. 3.30470398] [ 3.01002416 2.42951402 3.30470398 0. ]] 
  2. 計算歐幾里德距離表達式相對於函數輸入內部變量的梯度。 這不僅發生在由於浮點近似而產生的負數(如上所述),而且如果任何輸入為零長度時也會發生。

    如果y = sqrt(x)dy/dx = 1/(2 * sqrt(x)) 因此,如果x=0或者為了您的目的,如果squared_euclidean_distances=0那么漸變將是NaN因為2 * sqrt(0) = 0並且除以零是未定義的。

第一個問題的解決方案可以通過強制它們不小於零來確保平方距離永遠不會為負:

T.sqrt(T.maximum(squared_euclidean_distances, 0.))

要解決這兩個問題(如果你需要漸變),那么你需要確保平方距離永遠不是負的或零,所以用一個小的正epsilon綁定:

T.sqrt(T.maximum(squared_euclidean_distances, eps))

第一種解決方案是有意義的,因為問題只來自近似表示。 第二個問題有點可疑,因為真實距離為零,因此,在某種意義上,漸變應該是不確定的。 您的特定用例可能會產生一些替代解決方案,該解決方案在沒有人為限制的情況下維護語義(例如,通過確保永遠不會計算梯度或使用零長度向量)。 NaN值可能是有害的:它們可以像雜草一樣傳播。

只是檢查

squared_euclidian_distances您添加了一列,一行和一個矩陣。 你確定這是你想要的嗎?

更確切地說,如果MAT具有形狀(n,p),則需要添加形狀矩陣(n,1),(1,n)和(n,n)。

Theano似乎默默地重復每個一維成員的行(相應的列)以匹配點積的行數和列數。

如果這是你想要的

在重塑時,您應該根據基本張量功能指定ndim=2 :重塑

如果形狀是Variable參數,那么您可能需要使用可選的ndim參數來聲明形狀有多少個元素,因此重構的變量將具有多少個維度。

此外,似乎squared_euclidean_distances應始終為正,除非差異中的不精確誤差將零值更改為小的負值。 如果這是真的,如果負值對你所看到的NaN負責,那么你確實可以通過用abs(...)包圍squared_euclidean_distances破壞你的結果而不會破壞你的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM