Градиенты высшего порядка в pytorch

Я реализовал следующую функцию Якоби в pytorch. Если я не ошибся, он вычисляет якобиан любого тензора относительно любые размерные входы:

import torch
import torch.autograd as ag

def nd_range(stop, dims = None):
    if dims == None:
        dims = len(stop)
    if not dims:
        yield ()
        return
    for outer in nd_range(stop, dims - 1):
        for inner in range(stop[dims - 1]):
            yield outer + (inner,)


def full_jacobian(f, wrt):    
    f_shape = list(f.size())
    wrt_shape = list(wrt.size())
    fs = []


    f_range = nd_range(f_shape)
    wrt_range = nd_range(wrt_shape)

    for f_ind in f_range:
        grad = ag.grad(f[tuple(f_ind)], wrt, retain_graph=True, create_graph=True)[0]
        for i in range(len(f_shape)):
            grad = grad.unsqueeze(0)
        fs.append(grad)

    fj = torch.cat(fs, dim=0)
    fj = fj.view(f_shape + wrt_shape)
    return fj

Вдобавок к этому я попытался реализовать рекурсивную функцию для вычисления производных n-го порядка:

def nth_derivative(f, wrt, n):
    if n == 1:
        return full_jacobian(f, wrt)
    else:        
        deriv = nth_derivative(f, wrt, n-1)
        return full_jacobian(deriv, wrt)

Я провел простой тест:

op = torch.ger(s, s)
deep_deriv = nth_derivative(op, s, 5)

К сожалению, мне удалось получить гессиан ... но не производные более высокого порядка. Я знаю, что многие производные более высокого порядка должны быть равны 0, но я бы предпочел, чтобы pytorch мог это вычислить аналитически.

Одно из исправлений заключалось в изменении расчета градиента на:

try:
            grad = ag.grad(f[tuple(f_ind)], wrt, retain_graph=True, create_graph=True)[0]
        except:
            grad = torch.zeros_like(wrt)

Это общепринятый правильный способ справиться с этим? Или есть вариант получше? Или у меня изначально совершенно неправильная причина моей проблемы?


person user650261    schedule 14.05.2018    source источник
comment
К сожалению, забыл добавить эту функцию. Сделаю так сейчас.   -  person user650261    schedule 16.05.2018
comment
вы никогда не используете wrt_range в своем якобиане   -  person lurscher    schedule 20.10.2019


Ответы (2)


Вы можете просто повторить вызов grad функции:

import torch
from torch.autograd import grad

def nth_derivative(f, wrt, n):

    for i in range(n):

        grads = grad(f, wrt, create_graph=True)[0]
        f = grads.sum()

    return grads

x = torch.arange(4, requires_grad=True).reshape(2, 2)
loss = (x ** 4).sum()

print(nth_derivative(f=loss, wrt=x, n=3))

выходы

tensor([[  0.,  24.],
        [ 48.,  72.]])
person Alex    schedule 16.05.2018
comment
Не самое чистое решение, но оно сработает. Влияет ли такой итерационный метод на производительность? - person user650261; 16.05.2018
comment
Влияет ли такой итерационный метод на производительность? это очень расплывчатый вопрос. Это может или не может, в зависимости от остальной части вашего кода. Если у вас нет проблем с производительностью и вы не определили это как узкое место, не переживайте. Если процитировать Дональда Кнута, преждевременная оптимизация является корнем всех зол. - person Alex; 16.05.2018
comment
@ user650261 И что вы имеете в виду, говоря «Не самое чистое решение»? - person Alex; 16.05.2018
comment
Является ли основная идея этого подхода простым созданием нового вычислительного графа каждый раз, когда вы берете производную (а затем берете производную на этом новом вычислительном графике / функции)? - person information_interchange; 21.03.2020
comment
@information_interchange yes: create_graph (bool, optional) - Если True, будет построен график производной, позволяющий вычислять производные продукты более высокого порядка. - person iacob; 31.03.2021

Для производной второго порядка вы можете использовать функцию PyTorch hessian:

torch.autograd.functional.hessian()

Для производных более высокого порядка вы можете многократно вызывать jacobian или grad, сохраняя вычислительный граф:

create_graph (bool, необязательно) - Если True, будет построен график производной, позволяющий вычислять производные продукты более высокого порядка.

person iacob    schedule 31.03.2021