cvxgrp / cvxpylayers

Differentiable convex optimization layers
Apache License 2.0
1.79k stars 159 forks source link

A tensor must be provided for each CVXPY parameter #94

Closed AadharshAadhithya closed 3 years ago

AadharshAadhithya commented 3 years ago
class MyNN(nn.Module):

  def __init__(self,n,m,p):
    super().__init__()
    torch.manual_seed(0)
    self.z = cp.Variable(n)
    self.P = cp.Parameter((n,n))
    self.q = cp.Parameter(n)
    self.G = cp.Parameter((m,n))
    self.h = cp.Parameter(m)
    self.A = cp.Parameter((p,n))
    self.b = cp.Parameter(p)
    self.objective = cp.Minimize(0.5*cp.sum_squares(self.P @ self.z) + self.q @ self.z ) #if isinstance(self.z, cp.Variable) else 0.5*torch.sum((self.P @ self.z)**2) + self.q@self.z)
    self.constraints = [self.G@self.z-self.h <= 0 , self.A@self.z == self.b]
    self.problem = cp.Problem(self.objective, self.constraints) 
    self.net = nn.Sequential(
        nn.Linear(2, 100), 
        nn.Sigmoid(), 
        nn.Linear(100, 3), 
        nn.Softmax(),
      CvxpyLayer(self.problem, parameters=[self.P,self.q,self.G,self.h,self.A,self.b], variables=[self.z]),
    )

  def forward(self, X):
    return self.net(X)

This is my class, when i Try to train the network using ,


loss_fn = torch.nn.MSELoss
opt = optim.SGD(fn.parameters(), lr=0.7)
fit_v2(X_train, Y_train, fn, opt, loss_fn)```

I get the following error.... 
ValueError: A tensor must be provided for each CVXPY parameter; received 1 tensors, expected 6

Here is the call stack ... 

ValueError                                Traceback (most recent call last)
<ipython-input-79-fe49acf49523> in <module>()
      2 loss_fn = torch.nn.MSELoss
      3 opt = optim.SGD(fn.parameters(), lr=0.7)
----> 4 fit_v2(X_train, Y_train, fn, opt, loss_fn)

6 frames
<ipython-input-66-650e0265a609> in fit_v2(x, y, model, opt, loss_fn, epochs)
      3 
      4   for epoch in range(epochs):
----> 5     loss = loss_fn()(model(x.float() ), y.float())
      6     mlflow.log_metric('train_loss',loss.data.item()/len(x)*1000)
      7 

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

<ipython-input-76-3899e00e40d0> in forward(self, X)
     23 
     24   def forward(self, X):
---> 25     return self.net(X)

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/container.py in forward(self, input)
    115     def forward(self, input):
    116         for module in self:
--> 117             input = module(input)
    118         return input
    119 

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

/usr/local/lib/python3.6/dist-packages/cvxpylayers/torch/cvxpylayer.py in forward(self, solver_args, *params)
    136             raise ValueError('A tensor must be provided for each CVXPY '
    137                              'parameter; received %d tensors, expected %d' % (
--> 138                                  len(params), len(self.param_ids)))
    139         info = {}
    140         f = _CvxpyLayerFn(

ValueError: A tensor must be provided for each CVXPY parameter; received 1 tensors, expected 6
sbarratt commented 3 years ago

Aadharsh,

Thank you for you question. As built, a CvxpyLayer isn't a Module, so isn't suitable to be called within nn.sequential. Also, you need two versions of each parameter: one for cvxpy, and one as a pytorch tensor with a numerical value. Please modify your code to something along the lines of the following:

class MyNN(nn.Module):

def __init__(self,n,m,p):
    super().__init__()
    torch.manual_seed(0)
    z = cp.Variable(n)
    self.P = cp.Parameter((n,n))
    self.q = cp.Parameter(n)
    self.G = cp.Parameter((m,n))
    self.h = cp.Parameter(m)
    self.A = cp.Parameter((p,n))
    self.b = cp.Parameter(p)
    self.nn_output = cp.Parameter(3)

    scale_factor = 1e-4
    self.Ptch = torch.nn.Parameter(scale_factor*torch.randn(n,n))
    self.qtch = torch.nn.Parameter(scale_factor*torch.randn(n))
    self.Gtch = torch.nn.Parameter(scale_factor*torch.randn(m,n))
    self.htch = torch.nn.Parameter(scale_factor*torch.randn(m))
    self.Atch = torch.nn.Parameter(scale_factor*torch.randn(p,n))
    self.btch = torch.nn.Parameter(scale_factor*torch.randn(p))

    self.objective = cp.Minimize(0.5*cp.sum_squares(self.P @ self.z) + self.q @ self.z )
    self.constraints = [self.G@self.z-self.h <= 0 , self.A@self.z == self.b]
    raise NotImplementedError # include nn_output somehow in the cvxpy problem.
    self.problem = cp.Problem(self.objective, self.constraints) 
    self.net = nn.Sequential(
        nn.Linear(2, 100), 
        nn.Sigmoid(), 
        nn.Linear(100, 3), 
        nn.Softmax()
    )
    self.cvxpylayer = CvxpyLayer(self.problem, parameters=[self.P,self.q,self.G,self.h,self.A,self.b,self.nn_output], variables=[self.z])

def forward(self, X):
    nn_output = self.net(X)
    output = self.cvxpylayer(self.Ptch, self.qtch, self.Gtch, self.htch, self.Atch, self.btch, nn_output)[0]
    return output

However, this doesn't really make sense. The output of the network is a 3-vector in the probability simplex, and there is no parameter in your cvxpylayer that is a 3-vector, and the output of the layer is not 3-dimensional or in the simplex. I have added a cvxpy parameter called nn_output which is 3-dimensional and should be included in your cvxpylayer.

Please let me know if this makes sense.

AadharshAadhithya commented 3 years ago

Aadharsh,

Thank you for you question. As built, a CvxpyLayer isn't a Module, so isn't suitable to be called within nn.sequential. Also, you need two versions of each parameter: one for cvxpy, and one as a pytorch tensor with a numerical value. Please modify your code to something along the lines of the following:

class MyNN(nn.Module):

def __init__(self,n,m,p):
    super().__init__()
    torch.manual_seed(0)
    z = cp.Variable(n)
    self.P = cp.Parameter((n,n))
    self.q = cp.Parameter(n)
    self.G = cp.Parameter((m,n))
    self.h = cp.Parameter(m)
    self.A = cp.Parameter((p,n))
    self.b = cp.Parameter(p)
    self.nn_output = cp.Parameter(3)

    scale_factor = 1e-4
    self.Ptch = torch.nn.Parameter(scale_factor*torch.randn(n,n))
    self.qtch = torch.nn.Parameter(scale_factor*torch.randn(n))
    self.Gtch = torch.nn.Parameter(scale_factor*torch.randn(m,n))
    self.htch = torch.nn.Parameter(scale_factor*torch.randn(m))
    self.Atch = torch.nn.Parameter(scale_factor*torch.randn(p,n))
    self.btch = torch.nn.Parameter(scale_factor*torch.randn(p))

    self.objective = cp.Minimize(0.5*cp.sum_squares(self.P @ self.z) + self.q @ self.z )
    self.constraints = [self.G@self.z-self.h <= 0 , self.A@self.z == self.b]
    raise NotImplementedError # include nn_output somehow in the cvxpy problem.
    self.problem = cp.Problem(self.objective, self.constraints) 
    self.net = nn.Sequential(
        nn.Linear(2, 100), 
        nn.Sigmoid(), 
        nn.Linear(100, 3), 
        nn.Softmax()
    )
    self.cvxpylayer = CvxpyLayer(self.problem, parameters=[self.P,self.q,self.G,self.h,self.A,self.b,self.nn_output], variables=[self.z])

def forward(self, X):
    nn_output = self.net(X)
    output = self.cvxpylayer(self.Ptch, self.qtch, self.Gtch, self.htch, self.Atch, self.btch, nn_output)[0]
    return output

However, this doesn't really make sense. The output of the network is a 3-vector in the probability simplex, and there is no parameter in your cvxpylayer that is a 3-vector, and the output of the layer is not 3-dimensional or in the simplex. I have added a cvxpy parameter called nn_output which is 3-dimensional and should be included in your cvxpylayer.

Please let me know if this makes sense.

thank::you()

@sbarratt tysm for clearing this up. The Parameters was initialized during Initialization , with m,n,p = 3 . fn = MyNet(3,3,3) . Hope This initialization is meaningful ..... Really appreciate your help . 😊

AadharshAadhithya commented 3 years ago

also , any suggestions , on how to add nn.output() into cp.Problem()

sbarratt commented 3 years ago

I think it depends on what you want the layer to do? What problem are you solving? Why did you turn to a cvxpylayer?

On Wed, Feb 24, 2021 at 7:05 PM Aadharsh Aadhithya notifications@github.com wrote:

also , any suggestions , on how to add nn.output() into cp.Problem()

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/cvxgrp/cvxpylayers/issues/94#issuecomment-784878870, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB7LUGPZOW2F2JKKXVZIIR3TASXK7ANCNFSM4YCR4V6A .

AadharshAadhithya commented 3 years ago

@sbarratt , we just wanted to try the use of cvxpy layers in a state space with obstacles, and see how the model learns constraints .. In particular , We wanted to Describe the IK of 3 planar manipulator although , we can do this just with a neural network . We wanted to keep an obstacle in the space , and see how the layer learns the constraints from the data, hence the 3 output of our network corresponds to the link variables of our manipulator , and the inputs are end effector's position coordinates , we might slowly want to build up to reinforcement learning , but for now , this is what we are doing with cvxpylayer... ! we , Really appreciate your help.. 😊

sbarratt commented 3 years ago

Is the space that the IK coordinates have to sit in convex?

On Wed, Feb 24, 2021 at 10:31 PM Aadharsh Aadhithya < notifications@github.com> wrote:

@sbarratt https://github.com/sbarratt , we just wanted to try the use of cvxpy layers in a state space with obstacles, and see how the model learns constraints .. In particular , We wanted to Describe the IK of 3 planar manipulator although , we can do this just with a neural network https://doi.org/10.1016/j.protcy.2013.12.451 . We wanted to keep an obstacle in the space , and see how the layer learns the constraints from the data, hence the 3 output of our network corresponds to the link variables of our manipulator , and the inputs are end effector's position coordinates , we might slowly want to build up to reinforcement learning , but for now , this is what we are doing with cvxpylayer... ! we , Really appreciate your help.. 😊

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cvxgrp/cvxpylayers/issues/94#issuecomment-785012556, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB7LUGOLR3TTFWLDOV4HXWLTATPRLANCNFSM4YCR4V6A .

AadharshAadhithya commented 3 years ago

@sbarratt , It Can Be Convex ...... at least locally to our solution point

AadharshAadhithya commented 3 years ago

got it, Thanks for the help and the amazing work here. Im closing this issue.