You can define cX as an nn.Parameter, which would make them trainable.
Also, you can wrap them in an nn.Module, which could make handling them easier:
class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.c0 = nn.Parameter(torch.randn(1, 1))
        self.c1 = nn.Parameter(torch.randn(1, 1))
        self.c2 = nn.Parameter(torch.randn(1, 1))
        self.c3 = nn.Parameter(torch.randn(1, 1))
        
    def forward(self, x, y):
        out = self.c0 * torch.cos(self.c1 * y) + self.c2 + self.c3 * x**2
        return out

model = MyModel()
x, y = torch.randn(1, 1), torch.randn(1, 1)
out = model(x, y)
out.backward()
for name, param in model.named_parameters():
    print(name, param.grad)