LabelPropagation-如何避免被零除?

时间:2018-08-28 12:23:41

标签: python numpy machine-learning scikit-learn

在使用LabelPropagation时,我经常遇到此警告(恕我直言,这应该是一个错误,因为它完全使传播失败了):

  

/usr/local/lib/python3.5/dist-packages/sklearn/semi_supervised/label_propagation.py:279:RuntimeWarning:true_divide中遇到无效值     self.label_distributions_ / =规范化器

因此,在尝试了RBF内核后,我发现参数gamma会产生影响。

编辑:

问题来自these lines

        if self._variant == 'propagation':
            normalizer = np.sum(
                self.label_distributions_, axis=1)[:, np.newaxis]
            self.label_distributions_ /= normalizer

我不知道label_distributions_如何全为零,尤其是当其定义为:

self.label_distributions_ = safe_sparse_dot(
graph_matrix, self.label_distributions_)

Gamma对graph_matrix有影响(因为graph_matrix是_build_graph()调用内核函数的结果)。好。但是还是。出了什么问题

旧帖子(编辑前)

我提醒您如何为传播计算图权重:W = exp(-gamma * D),D是数据集所有点之间的成对距离矩阵。

问题是:np.exp(x) 如果x非常小,则返回0.0
假设我们有两个点ij这样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

实际上,我不是手动设置伽玛,而是使用this paper(第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]: 

1 个答案:

答案 0 :(得分:5)

基本上,您正在执行softmax函数,对吧?

防止softmax上溢/下溢的一般方法是(来自here

# Instead of this . . . 
def softmax(x, axis = 0):
    return np.exp(x) / np.sum(np.exp(x), axis = axis, keepdims = True)

# Do this
def softmax(x, axis = 0):
    e_x = np.exp(x - np.max(x, axis = axis, keepdims = True))
    return e_x / e_x.sum(axis, keepdims = True)

此边界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实现here构建一个“安全的” rbf内核:

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)

不幸的是,我只有v0.18,它不接受LabelPropagation的用户定义的内核函数,因此我无法对其进行测试。

EDIT2:

检查您的来源以了解为什么拥有如此大的gamma值使我想知道您是否使用gamma = D.min()/3,这是不正确的。定义为sigma = D.min()/3,而sigmaw的定义为

w = exp(-d**2/sigma**2)  # Equation (1)

这将产生正确的gamma1/sigma**29/D.min()**2