【问题标题】:Sigmoid function returns 1 for large positive inputsSigmoid 函数为大的正输入返回 1
【发布时间】:2019-02-24 15:35:39
【问题描述】:

我在 Python 中编写了以下函数来计算标量、向量或矩阵的 sigmoid 函数。

def sigmoid(z):
    sig = 1.0/(1.0 + np.exp(-z))
    return sig

对于相对较大的 z 正值,e^-z 返回一个接近零 (0) 的非常小的值,因此 sig 的值四舍五入为 1。我的最终目标是确定逻辑回归算法的成本函数。由于 sigmoid 正好返回 1,log(1-1) 返回 'nan'。如何解决问题,使我的 sigmoid() 函数返回正确的值,而不是将 e^-z 舍入为 0?

当我使用均值和标准差对输入特征进行归一化时,效果很好。但是有没有办法让它在更大的 z 值下工作?

另外,我在 Matlab 上尝试了同样的方法,它在没有规范化的情况下运行良好。

>>> Z = np.array([[60, 100],[20, 80]])
>>> Z
array([[ 60, 100],
       [ 20,  80]])
>>> np.exp(-Z)
array([[8.75651076e-27, 3.72007598e-44],
       [2.06115362e-09, 1.80485139e-35]])
>>> 1.0/(1.0 + np.exp(-Z))
array([[1., 1.],
       [1., 1.]])

【问题讨论】:

  • 它从不四舍五入,你能举个例子吗?具体来说,使函数 roundz 的输入值是多少?
  • 函数返回 1 并没有“错误”,只是你已经达到了机器精度限制。您的成本函数应该受到“保护”,要么具有 sigmoid 的最小值 (log(1 - max(sigmoid(z), EPSILON))),要么在有条件的基础上定义它,这样如果 sigmoid(z) == 1(或 sigmoid(z) > 1 - EPSILON)则成本为零。
  • @EPo:嗨,从控制台添加了一个 sn-p。我不确定我做错了什么或解释错了什么。
  • @jdehesa:您好,感谢您的解释,这是有道理的!我会试试这个。
  • 查看question,了解如何稳健地实施 sigmoid。

标签: python machine-learning logistic-regression sigmoid


【解决方案1】:

我通过使用 np.minimumnp.maximum 包装 sigmoid 函数克服了这个问题:

def sigmoid(x):
    sig = 1 / (1 + np.exp(-x))     # Define sigmoid function
    sig = np.minimum(sig, 0.9999)  # Set upper bound
    sig = np.maximum(sig, 0.0001)  # Set lower bound
    return sig

结果我的损失开始看起来像这样

但训练和测试损失都很好地收敛了,我在使用逻辑回归的小数据集上获得了约 90% 的准确率。

【讨论】:

    【解决方案2】:

    正如 jdehesa 已经提到的,您的问题在于精度限制。你可以在这里阅读更多: https://docs.python.org/2/tutorial/floatingpoint.html

    您可以尝试使用避免舍入的 Decimal 类:

    from decimal import Decimal
    import numpy as np
    import math
    
    def sigmoid(z):
        sig = Decimal(1.0)/(Decimal(1.0) + Decimal(np.exp(-z)))
        return sig
    
    
    math.log(Decimal(1)-sigmoid(60))
    >>> -59.97257293350302
    

    但这只能在一定程度上起作用(我看到它已经失败了 80 次)。我做了一些阅读,如果您真的需要更高的精度,您可以通过将以下值从默认值 28 增加来更改 Decimal 对象的精度:

    from decimal import *
    getcontext().prec = 28 
    

    更多细节在这里:

    https://docs.python.org/2/library/decimal.html

    不过,在大多数情况下,使用逻辑检查手动处理小结果的建议可能是最好的。

    【讨论】:

    • 嗨安德鲁,感谢您的建议,这些很有帮助!但是,我可以按照@jdehesa 的建议解决这个问题。在返回 sig 之前添加以下内容:sig[sig == 1.0] = 0.9999 和 sig[sig == 0.0] = 0.0001。
    猜你喜欢
    • 2017-03-20
    • 1970-01-01
    • 2018-06-19
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多