|
14 | 14 |
|
15 | 15 | from __future__ import annotations |
16 | 16 |
|
| 17 | +import warnings |
17 | 18 | from typing import TYPE_CHECKING, Literal |
18 | 19 |
|
19 | 20 | import paddle |
|
39 | 40 | _PaddingTensorMode: TypeAlias = Literal[ |
40 | 41 | "zeros", "constant", "reflect", "replicate", "circular" |
41 | 42 | ] |
| 43 | + _ReduceMode: TypeAlias = Literal["mean", "sum", "none"] |
42 | 44 |
|
43 | 45 |
|
44 | 46 | __all__ = [ |
|
48 | 50 | 'linear', |
49 | 51 | 'scaled_dot_product_attention', |
50 | 52 | 'unfold', |
| 53 | + 'smooth_l1_loss', |
51 | 54 | ] |
52 | 55 |
|
53 | 56 |
|
@@ -380,3 +383,90 @@ def to_list_if_necessary(x): |
380 | 383 | paddings=to_list_if_necessary(padding), |
381 | 384 | dilations=to_list_if_necessary(dilation), |
382 | 385 | ) |
| 386 | + |
| 387 | + |
| 388 | +@ForbidKeywordsDecorator( |
| 389 | + illegal_keys={"label", "delta", "is_huber", "name"}, |
| 390 | + func_name="paddle.compat.nn.functional.smooth_l1_loss", |
| 391 | + correct_name="paddle.nn.functional.smooth_l1_loss", |
| 392 | +) |
| 393 | +def smooth_l1_loss( |
| 394 | + input: Tensor, |
| 395 | + target: Tensor, |
| 396 | + size_average: bool | None = None, |
| 397 | + reduce: bool | None = None, |
| 398 | + reduction: _ReduceMode = 'mean', |
| 399 | + beta: float = 1.0, |
| 400 | +) -> Tensor: |
| 401 | + r""" |
| 402 | +
|
| 403 | + PyTorch compatible version of :ref:`api_paddle_nn_functional_smooth_l1_loss`. |
| 404 | +
|
| 405 | + Computes the Smooth L1 loss, aligned with ``torch.nn.functional.smooth_l1_loss``. |
| 406 | + The per-element loss is: |
| 407 | +
|
| 408 | + .. math:: |
| 409 | +
|
| 410 | + z_i = \left\{\begin{array}{rcl} |
| 411 | + 0.5 (x_i - y_i)^2 / beta & & {if |x_i - y_i| < beta} \\ |
| 412 | + |x_i - y_i| - 0.5 * beta & & {otherwise} |
| 413 | + \end{array} \right. |
| 414 | +
|
| 415 | + This equals Paddle's Huber loss divided by ``beta`` (i.e. ``is_huber=False`` with |
| 416 | + ``delta=beta``), which is the key difference from |
| 417 | + :ref:`api_paddle_nn_functional_smooth_l1_loss` whose default ``is_huber=True`` |
| 418 | + returns the raw Huber loss. |
| 419 | +
|
| 420 | + Args: |
| 421 | + input (Tensor): Input tensor, the data type is float32 or float64. |
| 422 | + target (Tensor): Label tensor with the same shape as ``input``. |
| 423 | + size_average (bool|None, optional): Deprecated (see ``reduction``). When |
| 424 | + ``size_average`` or ``reduce`` is not ``None``, it is translated into |
| 425 | + ``reduction`` with a ``DeprecationWarning``. Default is ``None``. |
| 426 | + reduce (bool|None, optional): Deprecated (see ``reduction``). Default is ``None``. |
| 427 | + reduction (str, optional): Indicate how to calculate the loss, the candidates |
| 428 | + are ``'none'`` | ``'mean'`` | ``'sum'``. Default is ``'mean'``. |
| 429 | + beta (float, optional): Specifies the threshold at which to change between L1 |
| 430 | + and L2 loss. The value must be non-negative. When ``beta == 0`` the loss |
| 431 | + degrades to the L1 loss, matching PyTorch. Default is ``1.0``. |
| 432 | +
|
| 433 | + Returns: |
| 434 | + Tensor, The tensor storing the smooth L1 loss of ``input`` and ``target``. |
| 435 | +
|
| 436 | + Examples: |
| 437 | + .. code-block:: pycon |
| 438 | +
|
| 439 | + >>> import paddle |
| 440 | +
|
| 441 | + >>> input = paddle.to_tensor([[0.5, 1.5], [2.0, 0.0]], dtype='float32') |
| 442 | + >>> target = paddle.to_tensor([[1.0, 1.0], [1.0, 0.5]], dtype='float32') |
| 443 | + >>> output = paddle.compat.nn.functional.smooth_l1_loss(input, target, beta=1.0) |
| 444 | + >>> print(output) |
| 445 | + Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True, |
| 446 | + 0.21875000) |
| 447 | + """ |
| 448 | + # Translate PyTorch's deprecated size_average / reduce into reduction. |
| 449 | + if size_average is not None or reduce is not None: |
| 450 | + reduction = ( |
| 451 | + 'none' |
| 452 | + if reduce is False |
| 453 | + else ('sum' if size_average is False else 'mean') |
| 454 | + ) |
| 455 | + warnings.warn( |
| 456 | + "'size_average' and 'reduce' args of 'smooth_l1_loss' will be " |
| 457 | + f"deprecated, please use reduction='{reduction}' instead.", |
| 458 | + DeprecationWarning, |
| 459 | + stacklevel=2, |
| 460 | + ) |
| 461 | + |
| 462 | + if beta < 0: |
| 463 | + raise ValueError( |
| 464 | + f"smooth_l1_loss does not accept negative beta, but got beta={beta}." |
| 465 | + ) |
| 466 | + |
| 467 | + if beta == 0: |
| 468 | + return paddle.nn.functional.l1_loss(input, target, reduction=reduction) |
| 469 | + |
| 470 | + return paddle.nn.functional.smooth_l1_loss( |
| 471 | + input, target, reduction=reduction, delta=beta, is_huber=False |
| 472 | + ) |
0 commit comments