快速优化“病理”凸函数

时间:2016-10-12 17:58:21

标签: python numpy scipy mathematical-optimization cvxopt

我有一个简单的凸问题我试图加快解决方案。我正在解决

的argmin( theta

eq

其中 theta rt Nx1

我可以使用cvxpy轻松解决此问题

import numpy as np
from scipy.optimize import minimize
import cvxpy

np.random.seed(123)

T = 50
N = 5
R = np.random.uniform(-1, 1, size=(T, N))

cvtheta = cvxpy.Variable(N)
fn = -sum([cvxpy.log(1 + cvtheta.T * rt) for rt in R])

prob = cvxpy.Problem(cvxpy.Minimize(fn))
prob.solve()

prob.status
#'optimal'

prob.value
# -5.658335088091929

cvtheta.value
# matrix([[-0.82105079],
#         [-0.35475695],
#         [-0.41984643],
#         [ 0.66117397],
#         [ 0.46065358]])

但是对于较大的R,这会变得太慢,所以我尝试使用基于渐变的方法scipy的{​​{1}}:

fmin_cg是一个goalfun友好函数,它返回函数值和渐变。

scipy.minimize

确保功能和渐变正确:

def goalfun(theta, *args):
    R = args[0]
    N = R.shape[1]
    common = (1 + np.sum(theta * R, axis=1))**-1

    if np.any( common < 0 ):
        return 1e2, 1e2 * np.ones(N)

    fun = np.sum(np.log(common))

    thetaprime = np.tile(theta, (N, 1)).T
    np.fill_diagonal(thetaprime, np.ones(N))
    grad = np.sum(np.dot(R, thetaprime) * common[:, None], axis=0)

    return fun, grad

但解决这个问题只会产生垃圾,无论goalfun(np.squeeze(np.asarray(cvtheta.value)), R) # (-5.6583350819293603, # array([ -9.12423065e-09, -3.36854633e-09, -1.00983679e-08, # -1.49619901e-08, -1.22987872e-08])) ,迭代等等(产生method的唯一事情是Optimization terminated successfully实际上等于最佳 theta

x0

即。这个看似无害的问题x0 = np.random.rand(R.shape[1]) minimize(fun=goalfun, x0=x0, args=R, jac=True, method='CG') # fun: 3.3690101669818775 # jac: array([-11.07449021, -14.04017873, -13.38560561, -5.60375334, -2.89210078]) # message: 'Desired error not necessarily achieved due to precision loss.' # nfev: 25 # nit: 1 # njev: 13 # status: 2 # success: False # x: array([ 0.00892177, 0.24404118, 0.51627475, 0.21119326, -0.00831957]) 轻松处理,对于非凸解算器来说是完全病态的。这个问题真的很讨厌,还是我错过了什么?什么是加速这个的替代方案?

1 个答案:

答案 0 :(得分:2)

我认为问题在于theta可能使log参数变为负数。您似乎已经确定了这个问题,并且在这种情况下让goalfun返回元组(100,100*ones(N)),显然,这是一种启发式尝试,向求解器提出这个&#34;解决方案&#34;不是首选。但是,必须施加更强的条件,即这个解决方案&#34;不是可行的。当然,这可以通过提供适当的约束来完成。 (有趣的是,cvxpy似乎会自动处理此问题。)

这是一个样本运行,没有提供衍生品的麻烦。请注意使用可行的初始估算x0

np.random.seed(123)

T = 50
N = 5
R = np.random.uniform(-1, 1, size=(T, N))

def goalfun(theta, *args):
    R = args[0]
    N = R.shape[1]
    common = (1 + np.sum(theta * R, axis=1))**-1

    return np.sum(np.log(common))

def con_fun(theta, *args):
    R = args[0]

    return 1+np.sum(theta * R, axis=1)


cons = ({'type': 'ineq', 'fun': lambda x: con_fun(x, R)})

x0 = np.zeros(R.shape[1])
minimize(fun=goalfun, x0=x0, args=R, constraints=cons)
 fun: -5.658334806882614
 jac: array([ 0.0019, -0.0004, -0.0003,  0.0005, -0.0015,  0.    ])  message: 'Optimization terminated successfully.'
nfev: 92
 nit: 12
njev: 12   status: 0  success: True
   x: array([-0.8209, -0.3547, -0.4198,  0.6612,  0.4605])

请注意,当我运行此操作时,我收到invalid value encountered in log警告,表示在搜索中的某个时刻检查了theta的值,这几乎不能满足约束条件。但是,结果与cvxpy的结果相当接近。当在cvxpy公式中明确强加约束时,检查cvxpy.Problem解决方案是否会发生变化将会很有趣。