chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle.base import core, framework
|
||||
from paddle.base.backward import gradients_with_optimizer # noqa: F401
|
||||
from paddle.utils.download import check_and_create_dir
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Sequence
|
||||
|
||||
from paddle import Tensor
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
@framework.dygraph_only
|
||||
def backward(
|
||||
tensors: Tensor | Sequence[Tensor],
|
||||
grad_tensors: Tensor | Sequence[Tensor | None] | None = None,
|
||||
retain_graph: bool = False,
|
||||
create_graph: bool = False,
|
||||
*,
|
||||
dump_backward_graph_path: str | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Compute the backward gradients of given tensors.
|
||||
|
||||
Args:
|
||||
tensors(list of Tensors): the tensors which the gradient to be computed. The tensors can not contain the same tensor.
|
||||
|
||||
grad_tensors(list of Tensors of None, optional): the init gradients of the `tensors`` .If not None, it must have the same length with ``tensors`` ,
|
||||
and if any of the elements is None, then the init gradient is the default value which is filled with 1.0.
|
||||
If None, all the gradients of the ``tensors`` is the default value which is filled with 1.0.
|
||||
Defaults to None.
|
||||
|
||||
retain_graph(bool, optional): If False, the graph used to compute grads will be freed. If you would
|
||||
like to add more ops to the built graph after calling this method( :code:`backward` ), set the parameter
|
||||
:code:`retain_graph` to True, then the grads will be retained. Thus, setting it to False is much more memory-efficient.
|
||||
Defaults to False.
|
||||
dump_backward_graph_path(str, optional): Specifies the directory path for storing the debug file.
|
||||
If this parameter is specified, the backward-related graph (in dot format)
|
||||
and the debugging call stack information will be generated in this directory.
|
||||
Returns:
|
||||
NoneType: None
|
||||
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> x = paddle.to_tensor([[1, 2], [3, 4]], dtype='float32', stop_gradient=False)
|
||||
>>> y = paddle.to_tensor([[3, 2], [3, 4]], dtype='float32')
|
||||
|
||||
>>> grad_tensor1 = paddle.to_tensor([[1, 2], [2, 3]], dtype='float32')
|
||||
>>> grad_tensor2 = paddle.to_tensor([[1, 1], [1, 1]], dtype='float32')
|
||||
|
||||
>>> z1 = paddle.matmul(x, y)
|
||||
>>> z2 = paddle.matmul(x, y)
|
||||
|
||||
>>> paddle.autograd.backward([z1, z2], [grad_tensor1, grad_tensor2], True)
|
||||
>>> print(x.grad)
|
||||
Tensor(shape=[2, 2], dtype=float32, place=Place(cpu), stop_gradient=False,
|
||||
[[12., 18.],
|
||||
[17., 25.]])
|
||||
|
||||
|
||||
>>> x.clear_grad()
|
||||
|
||||
>>> paddle.autograd.backward([z1, z2], [grad_tensor1, None], True)
|
||||
>>> print(x.grad)
|
||||
Tensor(shape=[2, 2], dtype=float32, place=Place(cpu), stop_gradient=False,
|
||||
[[12., 18.],
|
||||
[17., 25.]])
|
||||
|
||||
>>> x.clear_grad()
|
||||
|
||||
>>> paddle.autograd.backward([z1, z2])
|
||||
>>> print(x.grad)
|
||||
Tensor(shape=[2, 2], dtype=float32, place=Place(cpu), stop_gradient=False,
|
||||
[[10., 14.],
|
||||
[10., 14.]])
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def check_tensors(
|
||||
in_out_list: Sequence[Tensor] | Tensor, name: str
|
||||
) -> Sequence[Tensor]:
|
||||
assert in_out_list is not None, f"{name} should not be None"
|
||||
|
||||
if isinstance(in_out_list, (list, tuple)):
|
||||
assert len(in_out_list) > 0, f"{name} cannot be empty"
|
||||
for each_var in in_out_list:
|
||||
assert isinstance(each_var, paddle.Tensor), (
|
||||
f"Elements of {name} must be paddle.Tensor"
|
||||
)
|
||||
return in_out_list
|
||||
else:
|
||||
assert isinstance(in_out_list, paddle.Tensor), (
|
||||
f"{name} must be Tensor or list of Tensor"
|
||||
)
|
||||
return [in_out_list]
|
||||
|
||||
tensors = check_tensors(tensors, "tensors")
|
||||
|
||||
assert len(tensors) == len(set(tensors)), (
|
||||
"The argument 'tensors' of paddle.autograd.backward contains duplicate paddle.Tensor object."
|
||||
)
|
||||
|
||||
if grad_tensors is not None:
|
||||
if not isinstance(grad_tensors, (list, tuple)):
|
||||
grad_tensors = [grad_tensors]
|
||||
|
||||
for each_tensor in grad_tensors:
|
||||
if each_tensor is not None:
|
||||
assert isinstance(each_tensor, paddle.Tensor), (
|
||||
"The argument 'grad_tensors' of paddle.autograd.backward is invalid, it can be 'None', 'paddle.Tensor' or 'list[None/paddle.Tensor]'."
|
||||
)
|
||||
else:
|
||||
grad_tensors = []
|
||||
|
||||
if len(grad_tensors) > 0:
|
||||
assert len(tensors) == len(grad_tensors), (
|
||||
"The length of grad_tensors must be equal to tensors"
|
||||
)
|
||||
|
||||
assert isinstance(retain_graph, bool), "retain_graph must be True or False"
|
||||
check_and_create_dir(dump_backward_graph_path)
|
||||
core.eager.run_backward(
|
||||
tensors,
|
||||
grad_tensors,
|
||||
retain_graph,
|
||||
create_graph,
|
||||
dump_backward_graph_path,
|
||||
)
|
||||
Reference in New Issue
Block a user