scipy-optimize-minimize 不执行优化 - CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL
scipy-optimize-minimize does not perform the optimization - CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL
我正在尝试最小化定义如下的函数:
utility(decision) = decision * (risk - cost)
其中变量采用以下形式:
decision = binary array
risk = array of floats
cost = constant
我知道解决方案将采用以下形式:
decision = 1 if (risk >= threshold)
decision = 0 otherwise
因此,为了最小化这个函数,我可以假设我将函数效用转换为仅依赖于这个阈值。我对 scipy 的直接翻译如下:
def utility(threshold,risk,cost):
selection_list = [float(risk[i]) >= threshold for i in range(len(risk))]
v = np.array(risk.astype(float)) - cost
total_utility = np.dot(v, selection_list)
return -1.0*total_utility
result = minimize(fun=utility, x0=0.2, args=(r,c),bounds=[(0,1)], options={"disp":True} )
这给了我以下结果:
fun: array([-17750.44298655]) hess_inv: <1x1 LbfgsInvHessProduct with
dtype=float64>
jac: array([0.])
message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 2
nit: 0 status: 0 success: True
x: array([0.2])
但是,我知道结果是错误的,因为在这种情况下它必须等于 cost。最重要的是,无论我使用什么 x0,结果总是 returns 它。查看结果,我发现 jacobian=0 并且没有正确计算 1 次迭代。
更彻底地研究函数。我绘制它并观察到它在边界的限制上不是凸的,但我们可以清楚地看到最小值 0.1。但是,无论我将边界调整多少只在凸起部分,结果仍然是一样的。
我该怎么做才能最小化这个功能?
错误消息告诉您梯度在某个点太小,因此在数值上与零相同。这可能是由于您在计算 selection_list
时所做的阈值处理。你说 float(risk[i]) >= threshold
,几乎所有地方的导数都是 0。因此,几乎每个起始值都会给您收到警告。
一个解决方案可能是对阈值操作应用一些平滑。因此,您可以使用连续函数代替 float(risk[i]) >= threshold
:
def g(x):
return 1./(1+np.exp(-x))
有了这个函数,您可以将阈值操作表示为
g((risk[i] - threshold)/a)
,其中一个参数a
。 a
越大,这个修改后的误差函数就越接近您目前所做的。在 a=20
左右,您可能会拥有与现在几乎相同的东西。因此,您将导出一系列解决方案,从 a=1
开始,然后将该解决方案作为 a=2
相同问题的起始值,将该解决方案作为 a=2
问题的起始值=20=],等等。在某些时候,您会注意到更改 a
不会再更改解决方案,您就完成了。
我正在尝试最小化定义如下的函数:
utility(decision) = decision * (risk - cost)
其中变量采用以下形式:
decision = binary array
risk = array of floats
cost = constant
我知道解决方案将采用以下形式:
decision = 1 if (risk >= threshold)
decision = 0 otherwise
因此,为了最小化这个函数,我可以假设我将函数效用转换为仅依赖于这个阈值。我对 scipy 的直接翻译如下:
def utility(threshold,risk,cost):
selection_list = [float(risk[i]) >= threshold for i in range(len(risk))]
v = np.array(risk.astype(float)) - cost
total_utility = np.dot(v, selection_list)
return -1.0*total_utility
result = minimize(fun=utility, x0=0.2, args=(r,c),bounds=[(0,1)], options={"disp":True} )
这给了我以下结果:
fun: array([-17750.44298655]) hess_inv: <1x1 LbfgsInvHessProduct with
dtype=float64>
jac: array([0.])
message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 2
nit: 0 status: 0 success: True
x: array([0.2])
但是,我知道结果是错误的,因为在这种情况下它必须等于 cost。最重要的是,无论我使用什么 x0,结果总是 returns 它。查看结果,我发现 jacobian=0 并且没有正确计算 1 次迭代。
更彻底地研究函数。我绘制它并观察到它在边界的限制上不是凸的,但我们可以清楚地看到最小值 0.1。但是,无论我将边界调整多少只在凸起部分,结果仍然是一样的。
我该怎么做才能最小化这个功能?
错误消息告诉您梯度在某个点太小,因此在数值上与零相同。这可能是由于您在计算 selection_list
时所做的阈值处理。你说 float(risk[i]) >= threshold
,几乎所有地方的导数都是 0。因此,几乎每个起始值都会给您收到警告。
一个解决方案可能是对阈值操作应用一些平滑。因此,您可以使用连续函数代替 float(risk[i]) >= threshold
:
def g(x):
return 1./(1+np.exp(-x))
有了这个函数,您可以将阈值操作表示为
g((risk[i] - threshold)/a)
,其中一个参数a
。 a
越大,这个修改后的误差函数就越接近您目前所做的。在 a=20
左右,您可能会拥有与现在几乎相同的东西。因此,您将导出一系列解决方案,从 a=1
开始,然后将该解决方案作为 a=2
相同问题的起始值,将该解决方案作为 a=2
问题的起始值=20=],等等。在某些时候,您会注意到更改 a
不会再更改解决方案,您就完成了。