Как применить границы переменной при выполнении оптимизации в Pytorch?

Я пытаюсь использовать 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 с помощью экспоненциальной функции, но тогда вам придется масштабировать функцию, чтобы избежать бесконечности положительных значений, и мне нужна некоторая гибкость с возможностью установки ограничения.


person Capeboom    schedule 05.12.2019    source источник
comment
clamp в порядке, вам просто нужно сделать это внутри with torch.no_grad():   -  person minhle_r7    schedule 18.01.2020
comment
clamp в порядке, вам просто нужно сделать это внутри with torch.no_grad(): и использовать x[:]=x.clamp( вместо x=x.clamp(   -  person 1943 Yonv    schedule 16.09.2020


Ответы (1)


У меня с тобой такая же проблема. Я тоже хочу применить границы к переменной в PyTorch. И я решил эту проблему с помощью приведенного ниже Way3.

Ваш пример - небольшой комплиекс, но я все еще учу английский. Ниже я привожу более простой пример.

Например, есть обучаемая переменная v, ее границы (-1, 1)

v = torch.tensor((0.5, ), require_grad=True)
v_loss = xxxx
optimizer.zero_grad()
v_loss.backward()
optimizer.step()

Путь1. RuntimeError: листовая переменная, для которой требуется градиент, была использована в операции на месте.

v.clamp_(-1, 1)             

Путь2. RuntimeError: попытка вернуться по графику во второй раз, но буферы уже освобождены.

v = torch.clamp(v, -1, +1)  # equal to v = v.clamp(-1, +1)  

Путь3. NotError. Решил эту проблему в Way3.

with torch.no_grad():
    v[:] = v.clamp(-1, +1)  # You must use v[:]=xxx instead of v=xxx
person 1943 Yonv    schedule 16.09.2020