Numpy线性代数范数表现异常(错误)

3

我有一个包含数百万个元素的大向量 F,在计算范数时表现不一致。

np.linalg.norm(F,2.000001)=3225.96..
np.linalg.norm(F,2)=inf
np.linalg.norm(F,1.999999)=3226.01..
np.linalg.norm(F,1)=inf
---------
np.linalg.norm(F)=inf
np.linalg.norm(F/12)=inf
np.linalg.norm(F/13)=246.25
---------
np.sum(F*F)=inf
np.sum(F*F/169)=60639
np.sum(F*F/144)=inf
---------
np.all(np.isfinite(F))=True
np.max(np.abs(F))=11
---------
F.dtype=dtype('float16')

除了某些笨拙的解决方案外,有人知道发生了什么吗?

1
np.sum(F*F)会得到什么?如果去掉第二个参数np.linalg.norm(F)呢?np.max(F)是什么?np.isfinite(F).all()又是什么? - Eric
@Eric,我按照你要求的方式,以更清晰的格式添加了计算。 - ShakesBeer
1
F.dtype 是什么? - Eric
dtype('float16') - ShakesBeer
1
哎呀... float16。可能不是规范优化的目标。 - sascha
3
@莎士比亚 numpy.array([11 * 11 * 1e6], dtype='float16') 是无穷大。 - kennytm
2个回答

3

根据评论中的描述,您的问题是float16过于小而无法表示中间结果——它的最大值为65504。一个简单得多的测试案例如下:

np.linalg.norm(np.float16([1000]))

为了避免溢出,你可以将数值除以最大值,然后再乘回去:
def safe_norm(x):
    xmax = np.max(x)
    return np.linalg.norm(x / xmax) * xmax

或许有人认为对于float16,np.linalg.norm应该默认执行此操作。


Eric,在我接受之前,您能否解释一下为什么使用$p=1.999$或$p=2.0001$的$L_p$范数有效,但默认情况下的$p=2$却无效? - ShakesBeer
@Shakespeare:np.linalg.norm(F,1.999999)的数据类型是什么?它与“p=2”的情况有何区别? - Eric
它是float64。谢谢,亲切的陌生人。 - ShakesBeer
@Shakespeare:Numpy 的类型检测出现了一些奇怪的问题,但如果你使用 np.linalg.norm(..., np.float16(1.9999)),它会如预期般失败。 - Eric
哦,那很有趣。也许值得向NumPy团队提出这个问题? - ShakesBeer
2
你现在正在和一个聊天。我已经提交了一个问题(https://github.com/numpy/numpy/issues/8775)来与其他Numpy的人讨论这个问题。 - Eric

0

Numpy目前似乎没有解决方案。因此,为了完整起见,我提供另一种(相当明显的)解决方案来计算范数

def calcNorm(vector):
    if (vector.dtype == np.float16):
        vector = vector.astype(np.float32)
    return np.linalg.norm(vector)

或者,就像我需要的那样,在规范化向量的用例中:

def normalize(vector):
    prevType = vector.dtype
    if (vector.dtype == np.float16):
        vector = vector.astype(np.float32)
    norm = np.linalg.norm(vector)
    if (norm != 0 and np.isfinite(norm)):
        vector /= norm
    return vector.astype(prevType)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接