cvxgrp / cvxpylayers

Differentiable convex optimization layers
Apache License 2.0
1.82k stars 161 forks source link

How to specify the solver in cvxpylayers #130

Open amansouri3476 opened 2 years ago

amansouri3476 commented 2 years ago

Hi!

Thank you for this great package!

I have a simple question for which I couldn't find the answer in other issues or on the web.

If I have a simple problem like the following, for which I'm using cvxpylayers (to be able to solve a batch of optimization problems), how/where can I specify the solver? In the documents, I see that the solver is specified as an argument to problem.solve(solver='mosek'). However, when using cvxpylayers, we don't invoke solve() on the problem, rather it's done internally.

Here's my problem definition:

num_slots = 5
n_mechanisms = 3
p = num_slots ** 2

w = cp.Variable((n_mechanisms, p))
C = cp.Parameter((n_mechanisms, p))
# vectorized constraints
constraints = []
constraints.extend([cp.sum(w, axis=1) == np.ones((n_mechanisms,))])
constraint = []
for k in range(num_slots):
    temp_mask = np.zeros((n_mechanisms, p))
    for i in range(n_mechanisms):
        for j in range(k*num_slots, (k+1)*num_slots):
            temp_mask[i,j] = 1.0

    temp_mask = (temp_mask == 1.0)
    constraint.append(cp.sum(w[temp_mask]))
constraint = cp.vstack(constraint)
constraints.extend([constraint <= np.ones((num_slots, 1))])
constraint = []
for k in range(num_slots):
    temp_mask = np.zeros((n_mechanisms, p))
    for i in range(n_mechanisms):
        for j in range(k, p, num_slots):
            temp_mask[i,j] = 1.0
    temp_mask = (temp_mask == 1.0)
    constraint.append(cp.sum(w[temp_mask]))

constraint = cp.vstack(constraint)
constraints.extend([constraint <= np.ones((num_slots, 1))])
constraints.extend([w >= 0.001])
constraints.extend([w <= 1.0])
# problem: objective and the problem:
objective = cp.Minimize(cp.sum(cp.multiply(w, C))**2)
problem = cp.Problem(objective, constraints)
assert problem.is_dpp()
cvxpylayer = CvxpyLayer(problem, parameters=[C], variables=[w])

Additionally, I would very much appreciate it if one could advise me as to whether my problem definition adheres to best practices for using cvxpy. I've reformulated my problem a couple of times to get speed-ups, and to me, this seems the closest form to defining a set of vectorized constraints. In fact when I remove all constraints, except for constraints.extend([w >= 0.001]), it only gets slower by about 20%, so I'm not sure if there's much room for improvement. But for my application, it is still slow, and each batch of size 128 still takes about 1s with 40 CPU cores. If I increase the problem size, it easily gets to 7s or 10s per batch which is considered very slow for my use case. I would very much appreciate any advice on speeding it up.

Many thanks for your time and support.

XFeiF commented 2 years ago

First, until 2022, CVXPY Layer supports two open-source solvers: SCS and ECOS. More details can be found in issue #51 .

Besides, CVXPY Layers uses the package diffcp to differentiate through cone programs. Right now, diffcp only supports SCS... Once diffcp supports (say) MOSEK, CVXPY Layers could support it as well.

To specify the solver, you need to pass solver_args={"solve_method":"ECOS"} to your cvxpylayer.