如何使用 sympy 找到快速 sigmoid 函数的反函数?
How to find inverse of fast sigmoid function using sympy?
我想为变量 x 求解以下等式(灵感来自:Fast sigmoid algorithm):
0 = lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) - y
如果我使用这个 sympy,我得到一个错误:
from sympy.solvers import solve
from sympy import Symbol
x = Symbol('x', real=True)
y = Symbol('y', real=True)
lower = Symbol('lower', real=True)
upper = Symbol('upper', real=True)
solve(lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) -y, x)
错误:
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in nfloat
return type(expr)([nfloat(a, n, exponent) for a in expr])
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in <listcomp>
return type(expr)([nfloat(a, n, exponent) for a in expr])
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in nfloat
return type(expr)([nfloat(a, n, exponent) for a in expr])
TypeError: __new__() missing 1 required positional argument: 'cond'
我怎样才能用 sympy 解这个方程?
(或者如果有人能够手动求解 x
的方程:函数的反演无论如何会是什么样子?)
这似乎是 SymPy 1.4 版中的错误。在 master 上,我没有得到异常,而是得到:
In [2]: solve(lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) -y, x)
Out[2]:
⎡⎧0.5⋅lower + 0.5⋅upper - y 0.5⋅(lower + upper - 2.0⋅y) ⎧-0.5⋅lower - 0.5⋅upper + y 0.5⋅(-lower - upper + 2.0⋅y) ⎤
⎢⎪───────────────────────── for ─────────────────────────── < 0 ⎪────────────────────────── for ──────────────────────────── ≥ 0⎥
⎢⎨ lower - y lower - y , ⎨ upper - y upper - y ⎥
⎢⎪ ⎪ ⎥
⎣⎩ nan otherwise ⎩ nan otherwise ⎦
这returns两个分段解分别对应负x和正x的情况(我认为)。
虽然我对上面的结果不满意。我认为正确的结果应该是这样的:
In [46]: eqn = lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) - y
In [47]: eqn = piecewise_fold(eqn.rewrite(Piecewise))
In [48]: eqn
Out[48]:
⎧ ⎛0.5⋅x ⎞
⎪lower - y + (-lower + upper)⋅⎜───── + 0.5⎟ for x ≥ 0
⎪ ⎝x + 1 ⎠
⎨
⎪ ⎛0.5⋅x ⎞
⎪lower - y + (-lower + upper)⋅⎜───── + 0.5⎟ otherwise
⎩ ⎝1 - x ⎠
In [49]: sx1, = solve(eqn.args[0][0], x)
In [50]: sx2, = solve(eqn.args[1][0], x)
In [51]: cx1 = eqn.args[0][1].subs(x, sx1)
In [52]: sol = Piecewise((sx1, cx1), (sx2, True))
In [53]: sol
Out[53]:
⎧-0.5⋅lower - 0.5⋅upper + y -0.5⋅lower - 0.5⋅upper + y
⎪────────────────────────── for ────────────────────────── ≥ 0
⎪ upper - y upper - y
⎨
⎪0.5⋅lower + 0.5⋅upper - y
⎪───────────────────────── otherwise
⎩ lower - y
顺便说一句,我为简单的快速 sigmoid 手动派生了一个 python 函数:
from math import copysign
def inverse_fast_sigmoid(x):
assert -1.0 < x < 1.0
return copysign(
1 / (
1 - abs(x)
) - 1,
x
)
或许你可以根据自己的版本进行调整。
我想为变量 x 求解以下等式(灵感来自:Fast sigmoid algorithm):
0 = lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) - y
如果我使用这个 sympy,我得到一个错误:
from sympy.solvers import solve
from sympy import Symbol
x = Symbol('x', real=True)
y = Symbol('y', real=True)
lower = Symbol('lower', real=True)
upper = Symbol('upper', real=True)
solve(lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) -y, x)
错误:
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in nfloat
return type(expr)([nfloat(a, n, exponent) for a in expr])
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in <listcomp>
return type(expr)([nfloat(a, n, exponent) for a in expr])
File "/home/user/venv/numba/lib/python3.6/site-packages/sympy/core/function.py", line 3082, in nfloat
return type(expr)([nfloat(a, n, exponent) for a in expr])
TypeError: __new__() missing 1 required positional argument: 'cond'
我怎样才能用 sympy 解这个方程?
(或者如果有人能够手动求解 x
的方程:函数的反演无论如何会是什么样子?)
这似乎是 SymPy 1.4 版中的错误。在 master 上,我没有得到异常,而是得到:
In [2]: solve(lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) -y, x)
Out[2]:
⎡⎧0.5⋅lower + 0.5⋅upper - y 0.5⋅(lower + upper - 2.0⋅y) ⎧-0.5⋅lower - 0.5⋅upper + y 0.5⋅(-lower - upper + 2.0⋅y) ⎤
⎢⎪───────────────────────── for ─────────────────────────── < 0 ⎪────────────────────────── for ──────────────────────────── ≥ 0⎥
⎢⎨ lower - y lower - y , ⎨ upper - y upper - y ⎥
⎢⎪ ⎪ ⎥
⎣⎩ nan otherwise ⎩ nan otherwise ⎦
这returns两个分段解分别对应负x和正x的情况(我认为)。
虽然我对上面的结果不满意。我认为正确的结果应该是这样的:
In [46]: eqn = lower + (upper - lower) * (0.5 + 0.5 * x / (1 + abs(x))) - y
In [47]: eqn = piecewise_fold(eqn.rewrite(Piecewise))
In [48]: eqn
Out[48]:
⎧ ⎛0.5⋅x ⎞
⎪lower - y + (-lower + upper)⋅⎜───── + 0.5⎟ for x ≥ 0
⎪ ⎝x + 1 ⎠
⎨
⎪ ⎛0.5⋅x ⎞
⎪lower - y + (-lower + upper)⋅⎜───── + 0.5⎟ otherwise
⎩ ⎝1 - x ⎠
In [49]: sx1, = solve(eqn.args[0][0], x)
In [50]: sx2, = solve(eqn.args[1][0], x)
In [51]: cx1 = eqn.args[0][1].subs(x, sx1)
In [52]: sol = Piecewise((sx1, cx1), (sx2, True))
In [53]: sol
Out[53]:
⎧-0.5⋅lower - 0.5⋅upper + y -0.5⋅lower - 0.5⋅upper + y
⎪────────────────────────── for ────────────────────────── ≥ 0
⎪ upper - y upper - y
⎨
⎪0.5⋅lower + 0.5⋅upper - y
⎪───────────────────────── otherwise
⎩ lower - y
顺便说一句,我为简单的快速 sigmoid 手动派生了一个 python 函数:
from math import copysign
def inverse_fast_sigmoid(x):
assert -1.0 < x < 1.0
return copysign(
1 / (
1 - abs(x)
) - 1,
x
)
或许你可以根据自己的版本进行调整。