.. _cn_api_fluid_clip_GradientClipByNorm:

GradientClipByNorm
-------------------------------

.. py:class:: paddle.fluid.clip.GradientClipByNorm(clip_norm, need_clip=None)

:alias_main: paddle.nn.GradientClipByNorm
:alias: paddle.nn.GradientClipByNorm,paddle.nn.clip.GradientClipByNorm
:old_api: paddle.fluid.clip.GradientClipByNorm






将输入的多维Tensor :math:`X` 的L2范数限制在 ``clip_norm`` 范围之内。

- 如果L2范数大于 ``clip_norm`` ，则该 Tensor 会乘以一个系数进行压缩

- 如果L2范数小于或等于 ``clip_norm`` ，则不会进行任何操作。

输入的 Tensor 不是从该类里传入， 而是默认会选择 ``Program`` 中全部的梯度，如果 ``need_clip`` 不为None，则可以只选择部分参数进行梯度裁剪。

该类需要在初始化 ``optimizer`` 时进行设置后才能生效，可参看 ``optimizer`` 文档(例如： :ref:`cn_api_fluid_optimizer_SGDOptimizer` )。

裁剪公式如下：

.. math::

  Out=
  \left\{
  \begin{aligned}
  &  X & & if (norm(X) \leq clip\_norm)\\
  &  \frac{clip\_norm∗X}{norm(X)} & & if (norm(X) > clip\_norm) \\
  \end{aligned}
  \right.


其中 :math:`norm（X）` 代表 :math:`X` 的L2范数

.. math::
  \\norm(X) = (\sum_{i=1}^{n}|x_i|^2)^{\frac{1}{2}}\\

参数:
 - **clip_norm** (float) - 所允许的二范数最大值。
 - **need_clip** (function, optional) - 类型: 函数。用于指定需要梯度裁剪的参数，该函数接收一个 ``Parameter`` ，返回一个 ``bool`` (True表示需要裁剪，False不需要裁剪)。默认为None，此时会裁剪网络中全部参数。

**代码示例1：静态图**
 
.. code-block:: python
            
    import paddle
    import paddle.fluid as fluid
    import numpy as np
                
    main_prog = fluid.Program()
    startup_prog = fluid.Program()
    with fluid.program_guard(
            main_program=main_prog, startup_program=startup_prog):
        image = fluid.data(
            name='x', shape=[-1, 2], dtype='float32')
        predict = fluid.layers.fc(input=image, size=3, act='relu') #可训练参数: fc_0.w.0, fc_0.b.0
        loss = fluid.layers.mean(predict)
        
        # 裁剪网络中全部参数：
        clip = fluid.clip.GradientClipByNorm(clip_norm=1.0)
        
        # 仅裁剪参数fc_0.w_0时：
        # 为need_clip参数传入一个函数fileter_func，fileter_func接收参数的类型为Parameter，返回类型为bool
        # def fileter_func(Parameter):
        # # 可以较为方便的通过Parameter.name判断（name可以在fluid.ParamAttr中设置，默认为fc_0.w_0、fc_0.b_0）
        #   return Parameter.name=="fc_0.w_0"
        # clip = fluid.clip.GradientClipByNorm(clip_norm=1.0, need_clip=fileter_func)

        sgd_optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.1, grad_clip=clip)
        sgd_optimizer.minimize(loss)

    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    x = np.random.uniform(-100, 100, (10, 2)).astype('float32')
    exe.run(startup_prog)
    out = exe.run(main_prog, feed={'x': x}, fetch_list=loss)


**代码示例2：动态图**

.. code-block:: python

    import paddle
    import paddle.fluid as fluid
    
    with fluid.dygraph.guard():
        linear = fluid.dygraph.Linear(10, 10)  #可训练参数: linear_0.w.0, linear_0.b.0
        inputs = fluid.layers.uniform_random([32, 10]).astype('float32')
        out = linear(fluid.dygraph.to_variable(inputs))
        loss = fluid.layers.reduce_mean(out)
        loss.backward()

        # 裁剪网络中全部参数：
        clip = fluid.clip.GradientClipByNorm(clip_norm=1.0)

        # 仅裁剪参数linear_0.w_0时：
        # 为need_clip参数传入一个函数fileter_func，fileter_func接收参数的类型为ParamBase，返回类型为bool
        # def fileter_func(ParamBase):
        # # 可以通过ParamBase.name判断（name可以在fluid.ParamAttr中设置，默认为linear_0.w_0、linear_0.b_0）
        #   return ParamBase.name == "linear_0.w_0"
        # # 注：linear.weight、linear.bias能分别返回dygraph.Linear层的权重与偏差，也可以此来判断
        #   return ParamBase.name == linear.weight.name
        # clip = fluid.clip.GradientClipByNorm(clip_norm=1.0, need_clip=fileter_func)

        sgd_optimizer = fluid.optimizer.SGD(
          learning_rate=0.1, parameter_list=linear.parameters(), grad_clip=clip)
        sgd_optimizer.minimize(loss)