gpt4 book ai didi

python - Theano sqrt 返回 NaN 值

转载 作者:太空宇宙 更新时间:2023-11-03 13:40:41 26 4
gpt4 key购买 nike

在我的代码中,我使用 theano 来计算欧氏距离矩阵(来自 here 的代码):

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()here 时会发生这种情况建议

Add an eps inside the sqrt (or max(x,EPs))

所以我在我的代码中添加了一个 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) 具有值(value)

    [[ 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 绑定(bind):

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

第一个解决方案是有道理的,因为问题仅来自近似表示。第二个更值得怀疑,因为真实距离为零,所以从某种意义上说,梯度应该是未定义的。您的特定用例可能会产生一些替代解决方案,这些解决方案可以在没有人为限制的情况下维护语义(例如,通过确保永远不会计算/使用零长度向量的梯度)。但是 NaN 值可能是有害的:它们可以像杂草一样蔓延。

关于python - Theano sqrt 返回 NaN 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31919818/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com