代码之家  ›  专栏  ›  技术社区  ›  politinsa

标签传播-如何避免被零除?

  •  16
  • politinsa  · 技术社区  · 7 年前

    使用时 LabelPropagation ,我经常遇到此警告(imho它应该是一个错误,因为它完全无法传播):

    /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
    

    我不知道标签“分布”是如何全部为零的,特别是当它的定义是:

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

    gamma对图_矩阵有影响(因为图_矩阵是调用内核函数的_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,而是使用中描述的方法 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 回复  |  直到 7 年前
        1
  •  5
  •   Daniel F    7 年前

    基本上你在做 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之间,并确保 EAX 将永远 1 (即元素 np.argmax(x) )这可以防止溢出和下溢(当 np.exp(x.max()) 大于或小于 float64 可以处理。

    在这种情况下,由于您不能更改算法,我将接受输入 D 并使 D_ = D - D.min() 因为这在数字上应该等同于上述,因为 W.max() 应该是 -gamma * D.min() (你只是在翻动标志)。你的算法是关于 D_

    编辑:

    正如下面@paulbrodersen推荐的,您可以基于 sklearn 实施 here :

    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 ,所以我不能测试它。

    编辑2:

    检查你的资料来源为什么你有这么大的 gamma 价值观让我怀疑你是否在使用 gamma = D.min()/3 ,这是不正确的。定义是 sigma = D.min()/3 而对 sigma 在里面 w

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

    哪个才是正确的 伽马 价值 1/sigma**2 9/D.min()**2

    推荐文章