Python 标签传播-如何避免被零除?
在使用时,我经常遇到此警告(我认为这应该是一个错误,因为它完全无法传播): /usr/local/lib/python3.5/dist-packages/sklearn/semi_-supervised/label_-propagation.py:279:RuntimeWarning:true_divide中遇到无效值 self.label_分布u/=normalizer 因此,在对RBF核进行了几次尝试之后,我发现参数Python 标签传播-如何避免被零除?,python,numpy,machine-learning,scikit-learn,Python,Numpy,Machine Learning,Scikit Learn,在使用时,我经常遇到此警告(我认为这应该是一个错误,因为它完全无法传播): /usr/local/lib/python3.5/dist-packages/sklearn/semi_-supervised/label_-propagation.py:279:RuntimeWarning:true_divide中遇到无效值 self.label_分布u/=normalizer 因此,在对RBF核进行了几次尝试之后,我发现参数gammar有影响 编辑: 问题来自: 我不明白label_distribu
gammar
有影响
编辑:
问题来自:
我不明白label_distributions_uu怎么可能全为零,尤其是当它的定义是:
self.label_distributions_ = safe_sparse_dot(
graph_matrix, self.label_distributions_)
Gamma对graph_矩阵有影响(因为graph_矩阵是调用核函数的_build_graph()的结果)。好啊但仍然如此。有点不对劲
旧帖子(编辑前)
我提醒您如何计算传播的图权重:W=exp(-gamma*D),D数据集所有点之间的成对距离矩阵
问题是:np.exp(x)
如果x非常小,则返回0.0
假设我们有两个点,i
和j
,使得dist(i,j)=10
>>> np.exp(np.asarray(-10*40, dtype=float)) # gamma = 40 => OKAY
1.9151695967140057e-174
>>> np.exp(np.asarray(-10*120, dtype=float)) # gamma = 120 => NOT OKAY
0.0
实际上,我不是手动设置gamma,而是使用(第2.4节)中描述的方法
那么,如何避免被零除以获得适当的传播呢?
我能想到的唯一方法是规范化每个维度的数据集,但我们会丢失数据集的一些几何/拓扑属性(例如,2x10矩形变成1x1正方形)
可复制示例: 在这个例子中,最糟糕的是:即使gamma=20,它也会失败
In [11]: from sklearn.semi_supervised.label_propagation import LabelPropagation
In [12]: import numpy as np
In [13]: X = np.array([[0, 0], [0, 10]])
In [14]: Y = [0, -1]
In [15]: LabelPropagation(kernel='rbf', tol=0.01, gamma=20).fit(X, Y)
/usr/local/lib/python3.5/dist-packages/sklearn/semi_supervised/label_propagation.py:279: RuntimeWarning: invalid value encountered in true_divide
self.label_distributions_ /= normalizer
/usr/local/lib/python3.5/dist-packages/sklearn/semi_supervised/label_propagation.py:290: ConvergenceWarning: max_iter=1000 was reached without convergence.
category=ConvergenceWarning
Out[15]:
LabelPropagation(alpha=None, gamma=20, kernel='rbf', max_iter=1000, n_jobs=1,
n_neighbors=7, tol=0.01)
In [16]: LabelPropagation(kernel='rbf', tol=0.01, gamma=2).fit(X, Y)
Out[16]:
LabelPropagation(alpha=None, gamma=2, kernel='rbf', max_iter=1000, n_jobs=1,
n_neighbors=7, tol=0.01)
In [17]:
基本上你在做一个
softmax
功能,对吗
防止softmax
溢出/下溢的一般方法是(从)
这将e_x
限制在0和1之间,并确保e_x
的一个值始终为1
(即元素np.argmax(x)
)。这可以防止溢出和下溢(当np.exp(x.max())
大于或小于float64
可以处理的值时)
在这种情况下,由于您无法更改算法,因此我将接受输入D
,并使D_=D-D.min()
,因为这在数字上应该与上面的相同,因为W.max()
应该是-gamma*D.min()
(因为您只是在翻转符号)。执行有关D的算法
编辑:
正如下面@PaulBrodersen所建议的,您可以基于sklearn
实现构建一个“安全”的rbf内核:
然后在传播中使用它
LabelPropagation(kernel = rbf_kernel_safe, tol = 0.01, gamma = 20).fit(X, Y)
不幸的是,我只有v0.18
,它不接受LabelPropagation
的用户定义内核函数,所以我无法测试它
EDIT2:
检查源代码以了解为什么有如此大的gamma
值,我想知道您是否使用了gamma=D.min()/3
,这是不正确的。定义是sigma=D.min()/3
,而w
中sigma
的定义是
w = exp(-d**2/sigma**2) # Equation (1)
这将使正确的gamma
值1/sigma**2
或9/D.min()**2
可能使用阈值对RBF内核进行编码,以避免返回0。但是如果我这样做,D=15处的点的影响将小于D=100处的2点。(类似于1e-99对2*1e-99)通常我会说降低伽马值,但这不会有帮助,因为你用algo找到它。人们倾向于使用gamme=1/n_特性。20对伽马来说真是太大了。我不确定你在做唇形繁殖时会不会碰到它。使用Gamma1/n_功能显然不适用于像卫星这样的数据集,如sklearn.datasets.make_卫星(1000,noise=0.06)
我认为大于10的值非常大,但这当然取决于你的数据。至于np.exp(x)
对于非常小的x为零,请尝试以下操作:np.exp(np.asarray(-10*120,dtype=np.float128))
为什么不更改实现?您可以从LabelPropagation
继承,并覆盖\u get\u kernel
以使用自定义的rbf\u kernel
,其中在sklearn实现中添加一行K-=K.max()
。免责声明:我还没有测试过这些。谢谢你的编辑,我正在考虑做我自己的内核。别担心,我使用了gamma=9/D.min()**2,如果D.min()<1,那么这个值就大了。老实说,那篇论文中对gamma
的启发似乎更像是一种对给定数据集有效的方法gamma>>1
很快就会得到一个二进制label\u分布
矩阵(只有1和0),如果任何一行被驱动到所有0(因为一个点远离其他点)正如您所描述的,您的方法将失败。今天我有时间尝试,修改后的内核允许我使用比经典rbf内核更大的gamma。谢谢你!
def rbf_kernel_safe(X, Y=None, gamma=None):
X, Y = sklearn.metrics.pairwise.check_pairwise_arrays(X, Y)
if gamma is None:
gamma = 1.0 / X.shape[1]
K = sklearn.metrics.pairwise.euclidean_distances(X, Y, squared=True)
K *= -gamma
K -= K.max()
np.exp(K, K) # exponentiate K in-place
return K
LabelPropagation(kernel = rbf_kernel_safe, tol = 0.01, gamma = 20).fit(X, Y)
w = exp(-d**2/sigma**2) # Equation (1)