Использование функции Autograd .backward() для вычисления промежуточного значения в прямом проходе модели Pytorch

#pytorch #autograd

#pytorch #autograd

Вопрос:

Привет, я новичок в Pytorch. У меня есть простой модуль pytorch, где выход модуля представляет собой скалярную функцию потерь, которая зависит от производной некоторых полиномиальных функций. Допустим, результатом прямого прохода является: вход * производная (x ^ 2 y ^ 2) .

Один из способов реализовать это — явно записать производные от используемых полиномов и включить их в прямую модель. Итак, выход = входы * (2x 2y). Однако это ненадежно, поскольку, если я включу больше полиномов, мне придется вручную добавлять больше производных функций, что может занять много времени и привести к ошибкам.

Я хочу инициализировать полиномы, использовать Autograd для получения их производных, включить эту производную в формулу вывода. допустим, полиномиальная функция называется n . Я делаю n.backward(retain_graph=True) внутри прямого прохода. Однако, похоже, это не работает должным образом, поскольку я получаю очень разные ответы (о величине производных функции потерь по сравнению с параметрами модели), как при использовании аналитического выражения в прямом проходе.

Обратите внимание, что как выходные данные f.backward, так и аналитическое выражение производной совпадают. Таким образом, он правильно вычисляет производную от многочленов, но ему трудно связать это с конечной функцией потерь. Это означает, что вызов backward() также изменяет параметры модели, пытаясь получить производные для коэффициентов полинома. Я уверен, что это из-за моего плохого понимания pytorch, и добавление вызова f.backward() внутри прямого прохода каким-то образом портит вызов loss.backward() .

Вот упрощенный пример: проблема в том, что модель значений.learn.grad отличается при использовании аналитического метода и метода autograd .backward()

 
class Model(nn.Module):
   
    def __init__(self, grin_type='radial',loss_type='analytic', device='cpu', dtype=torch.float32): 
        super(Model, self).__init__()
        
        self.dtype=dtype
        self.device=device
        self.loss_type=loss_type
        self.grin_type=grin_type
        self.x=torch.tensor(2.,dtype = dtype, device=self.device) #mm
        
        self.learn=nn.Parameter(torch.tensor(5.,dtype = dtype, device=self.device))
        
    def forward(self,inputs,plotting=0): 
        
        
        if self.loss_type=='analytic':
        
            outputs=inputs*self.learn*(2.*self.x)
            
        elif self.loss_type=='autograd':
                                    
            self.der=self.calc_derivative(self.x)
            outputs=inputs*self.der
                    
        return outputs
    
    
    def poly_fun(self,x):
        
        return self.learn*torch.square(x)
    
    
    def calc_derivative(self,x):
        xn=x.clone().detach().requires_grad_(True)
        n=self.poly_fun(xn)
            
        dloss_dx=torch.autograd.grad(outputs=n, inputs=xn,create_graph=True)[0]*n/n
        
        return dloss_dx
       
  

Комментарии:

1. Если я правильно понимаю, попробуйте использовать x = x.detach().requires_grad_(True) , тогда вы можете использовать f = your_poly_fun(x) и f.backward() . Затем производная вашего полинома w.r.t. x должна быть сохранена x.grad . detach Здесь важно предотвратить распространение градиентов вплоть до параметров модели. Я не уверен, что этого будет полностью достаточно. Если вы опубликуете какой-нибудь минимальный пример кода, который работает с использованием выражений закрытой формы градиентов для вашего poly, это поможет.

2. Спасибо за ваш ответ. Я только что добавил упрощенный пример. Оба метода autograd для получения производной от многочлена и аналитического решения совпадают. Но при использовании метода autograd кажется, что градиенты параметров модели также меняются. Есть ли у вас какие-либо предложения по предотвращению этого?

3. Я попытался запустить ваш код, но не могу найти никакой разницы в поведении, включая градиенты и график вычислений, между предоставленными вами методами autograd и analytical.

4. Кажется, что это работает сейчас. Большое спасибо за вашу помощь.