• 文档 >
  • torch.func >
  • torch.func API 参考 >
  • torch.func.functionalize
快捷键

torch.func.functionalize

torch.func.functionalize(func, *, remove='mutations')[source]

functionalize 是一个转换,可以用来从函数中移除(中间)突变和别名,同时保留函数的语义。

返回一个与 func 具有相同语义的新函数,但移除了所有中间突变。对中间张量 intermediate.foo_() 执行的每个就地操作: intermediate_updated = intermediate.foo() ,都替换为其就地等效操作。

将函数式化用于将 PyTorch 程序发送到无法轻松表示突变或别名操作的后端或编译器。

参数:
  • func (Callable) – 一个接受一个或多个参数的 Python 函数。

  • remove (str) – 可选字符串参数,可以是值‘mutations’或‘mutations_and_views’。如果传入‘mutations’,则所有突变操作都将替换为其非突变等效操作。如果传入‘mutations_and_views’,则此外,所有别名操作也将替换为其非别名等效操作。默认值:‘mutations’。

返回值:

返回一个新的“功能化”函数。它接受与 func 相同的输入,并且具有相同的行为,但函数中对中间张量进行的任何突变(以及可选的别名)将被移除。

返回类型:

可调用

functionalize 还会移除对函数输入进行的突变(和视图)。但是为了保持语义,functionalize 将在转换完成后“修复”突变,通过检测是否有任何张量输入“应该”被突变,并在必要时将新数据复制回输入。

示例:

>>> import torch
>>> from torch.fx.experimental.proxy_tensor import make_fx
>>> from torch.func import functionalize
>>>
>>> # A function that uses mutations and views, but only on intermediate tensors.
>>> def f(a):
...     b = a + 1
...     c = b.view(-1)
...     c.add_(1)
...     return b
...
>>> inpt = torch.randn(2)
>>>
>>> out1 = f(inpt)
>>> out2 = functionalize(f)(inpt)
>>>
>>> # semantics are the same (outputs are equivalent)
>>> print(torch.allclose(out1, out2))
True
>>>
>>> f_traced = make_fx(f)(inpt)
>>> f_no_mutations_traced = make_fx(functionalize(f))(inpt)
>>> f_no_mutations_and_views_traced = make_fx(functionalize(f, remove='mutations_and_views'))(inpt)
>>>
>>> print(f_traced.code)



def forward(self, a_1):
    add = torch.ops.aten.add(a_1, 1);  a_1 = None
    view = torch.ops.aten.view(add, [-1])
    add_ = torch.ops.aten.add_(view, 1);  view = None
    return add

>>> print(f_no_mutations_traced.code)



def forward(self, a_1):
    add = torch.ops.aten.add(a_1, 1);  a_1 = None
    view = torch.ops.aten.view(add, [-1]);  add = None
    add_1 = torch.ops.aten.add(view, 1);  view = None
    view_1 = torch.ops.aten.view(add_1, [2]);  add_1 = None
    return view_1

>>> print(f_no_mutations_and_views_traced.code)



def forward(self, a_1):
    add = torch.ops.aten.add(a_1, 1);  a_1 = None
    view_copy = torch.ops.aten.view_copy(add, [-1]);  add = None
    add_1 = torch.ops.aten.add(view_copy, 1);  view_copy = None
    view_copy_1 = torch.ops.aten.view_copy(add_1, [2]);  add_1 = None
    return view_copy_1


>>> # A function that mutates its input tensor
>>> def f(a):
...     b = a.view(-1)
...     b.add_(1)
...     return a
...
>>> f_no_mutations_and_views_traced = make_fx(functionalize(f, remove='mutations_and_views'))(inpt)
>>> #
>>> # All mutations and views have been removed,
>>> # but there is an extra copy_ in the graph to correctly apply the mutation to the input
>>> # after the function has completed.
>>> print(f_no_mutations_and_views_traced.code)



def forward(self, a_1):
    view_copy = torch.ops.aten.view_copy(a_1, [-1])
    add = torch.ops.aten.add(view_copy, 1);  view_copy = None
    view_copy_1 = torch.ops.aten.view_copy(add, [2]);  add = None
    copy_ = torch.ops.aten.copy_(a_1, view_copy_1);  a_1 = None
    return view_copy_1
functionalize 有几个“故障模式”值得关注:
  1. 与其他 torch.func 转换一样,functionalize()不适用于直接使用.backward()的函数。对于 torch.autograd.grad 也是如此。如果您想使用 autograd,可以直接使用 functionalize(grad(f))计算梯度。

  2. 与其他 torch.func 转换类似,functionalize()不适用于全局状态。如果你对一个接受非局部状态视图/变体的函数调用 functionalize(f),功能化将简单地无操作,并将视图/变体调用直接传递到后端。一种解决方法是将任何非局部状态创建包装在一个更大的函数中,然后调用 functionalize。

  3. resize_()有一些限制:只有当被调整大小的张量不是视图时,functionalize 才能在使用 resize_()的程序上工作。

  4. as_strided()有一些限制:functionalize 无法处理 as_strided()调用产生的具有重叠内存的张量。

最后,一个有助于理解功能化的思维模型是,大多数用户编写的 PyTorch 程序都是使用公共的 torch API。当执行时,torch 运算符通常会被分解成我们内部的 C++ “ATen” API。功能化的逻辑完全发生在 ATen 的层面。功能化知道如何将 ATen 中的每个别名运算符映射到其非别名等效运算符(例如 tensor.view({-1}) -> at::view_copy(tensor, {-1}) ),以及如何将 ATen 中的每个可变运算符映射到其非可变等效运算符(例如 tensor.add_(1) -> at::add(tensor, -1) ),同时跟踪别名和可变操作,以便知道何时进行修复。有关哪些 ATen 运算符是别名或可变的详细信息,请参阅 https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/native_functions.yaml。


© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源并获得您的疑问解答

查看资源