我正在尝试使用 Pytorch 进行非凸优化,试图最大化我的目标(因此在 SGD 中最小化)。我想绑定我的因变量 x > 0,并且我的 x 值的总和小于 1000。
我认为我已经以斜坡惩罚的形式正确实施了惩罚,但我正在努力解决 x 变量的边界问题。在 Pytorch 中,您可以使用设置边界,clamp
但在这种情况下似乎不合适。我认为这是因为 optim 需要在引擎盖下释放渐变。完整的工作示例:
import torch
from torch.autograd import Variable
import numpy as np
def objective(x, a, b, c): # Want to maximise this quantity (so minimise in SGD)
d = 1 / (1 + torch.exp(-a * (x)))
# Checking constraint
exceeded_limit = constraint(x).item()
#print(exceeded_limit)
obj = torch.sum(d * (b * c - x))
# If overlimit add ramp penalty
if exceeded_limit < 0:
obj = obj - (exceeded_limit * 10)
print("Exceeded limit")
return - obj
def constraint(x, limit = 1000): # Must be > 0
return limit - x.sum()
N = 1000
# x is variable to optimise for
x = Variable(torch.Tensor([1 for ii in range(N)]), requires_grad=True)
a = Variable(torch.Tensor(np.random.uniform(0,100,N)), requires_grad=True)
b = Variable(torch.Tensor(np.random.rand(N)), requires_grad=True)
c = Variable(torch.Tensor(np.random.rand(N)), requires_grad=True)
# Would like to include the clamp
# x = torch.clamp(x, min=0)
# Non-convex methodf
opt = torch.optim.SGD([x], lr=.01)
for i in range(10000):
# Zeroing gradients
opt.zero_grad()
# Evaluating the objective
obj = objective(x, a, b, c)
# Calculate gradients
obj.backward()
opt.step()
if i%1000==0: print("Objective: %.1f" % -obj.item())
print("\nObjective: {}".format(-obj))
print("Limit: {}".format(constraint(x).item()))
if torch.sum(x<0) > 0: print("Bounds not met")
if constraint(x).item() < 0: print("Constraint not met")
任何关于如何强加边界的建议都将受到赞赏,无论是使用钳位还是其他方式。或者一般建议使用 Pytorch 进行非凸优化。这是我正在解决的问题的一个更简单且按比例缩小的版本,因此如果可能的话,我试图找到一个轻量级的解决方案。我正在考虑使用一种解决方法,例如使用指数函数转换 x 变量,但是您必须缩放函数以避免正值变为无限,并且我希望能够设置约束具有一定的灵活性。