o
    pi4                     @  s   d dl mZ d dlZd dlmZmZmZ d dlmZ ddlm	Z	 ddl	m
Z
mZ ddlmZ dd	lmZ dd
lmZ ddlmZ g ZG dd deZdS )    )annotationsN)_C_opsin_dynamic_modepir)unique_name   )base)core	framework)VarDesc)check_variable_and_dtype)_current_expected_place   )Initializerc                      s2   e Zd ZdZdd fd
dZ	ddddZ  ZS )Diraca	  Initialize the 3D/4D/5D Tensor with Dirac delta function.

    It can reserve the feature of convolution layer input, which means that
    as many channels are reserved as possible.

    In this initialize method, elements in the middle of convolution kernels will
    be set to 1 . The formula can be described as follow.

    .. math::

        X[d, d, shape[2]//2, shape[3]//2, ...]=1,  \   d=0,1...N

    where, ``N`` is the minimum value of ``in_channels`` and ``out_channels``

    Args:
        groups(int|None, optional): 0-dimension of the Tensor will be divided by groups,
            each group has the same value. Default: 1.
        name(str|None, optional): The default value is None. Normally there is no need for user to set this
            property. For more information, please refer to :ref:`api_guide_Name`.

    Returns:
        Dirac initializer instance objects.

    Examples:
        .. code-block:: python

            >>> import paddle

            >>> # 1. For kernel_size is uneven number:
            >>> attr = paddle.ParamAttr(initializer=paddle.nn.initializer.Dirac())
            >>> conv = paddle.nn.Conv1D(3, 2, 3, weight_attr=attr)
            >>> print(conv.weight)
            Parameter containing:
            Tensor(shape=[2, 3, 3], dtype=float32, place=CPUPlace, stop_gradient=False,
            [[[0., 1., 0.],
              [0., 0., 0.],
              [0., 0., 0.]],
             [[0., 0., 0.],
              [0., 1., 0.],
              [0., 0., 0.]]])
            >>> input = paddle.rand([8, 3, 10])
            >>> output = conv(input)
            >>> output == input[:, 0:2, 1:9]
            >>> print(output.shape)
            [8, 2, 8]
            >>> # It means output is almost the same with input, 2 channels are reserved

            >>> # 2. For kernel_size is even number:
            >>> attr = paddle.ParamAttr(initializer=paddle.nn.initializer.Dirac())
            >>> conv = paddle.nn.Conv1D(3, 2, 4, weight_attr=attr)
            >>> print(conv.weight)
            Parameter containing:
            Tensor(shape=[2, 3, 4], dtype=float32, place=CPUPlace, stop_gradient=False,
            [[[0., 0., 1., 0.],
              [0., 0., 0., 0.],
              [0., 0., 0., 0.]],
             [[0., 0., 0., 0.],
              [0., 0., 1., 0.],
              [0., 0., 0., 0.]]])
    r   Ngroupsintname
str | NonereturnNonec                   s.   |dkr	t |tsJ dt   || _d S )Nr   z& 'groups' must be a positive integer. )
isinstancer   super__init___groups)selfr   r   	__class__ b/home/app/PaddleOCR-VL/.venv_paddleocr/lib/python3.10/site-packages/paddle/nn/initializer/dirac.pyr   ]   s
   

zDirac.__init__varpaddle.Tensorblockpir.Block | Nonec                 C  s  t |tjr| rJ d| |}t |tjtjjtj	j
fs"J t |tjtjfs-J t|dg dd t|jdv sAJ d|jd | j dksOJ dt rg|jt	jjkrat	jj}|}n.|j}|}n(|jtjjkrtjj}|jtd	d
|jdg|j|tjjdd}n|j}|}d}t rtj   t! }t"#||jt$t%d|| W d   n1 sw   Y  n't rt! }t"&|jt%d||}n|j'di d|it%d|j|jddd |j}|d | j }t(||d }	g }
g }g }d}t)|D ]}|*d| ||9 }q t+| jD ]I}t+|	D ]A}|,d d}t-|D ]-\}}|dkr;||||  | 7 }q&|dkrH||| 7 }q&||| d | 7 }q&|
,| qqt rtj   t".|dg}|/| W d   n	1 sw   Y  n6t rt".|dg}n)|jtd	|jdg||jtjjddd}|j'dd|iddgi||ddd t rtj0t|
gt	jj1d}d|_2n|jtdddd }t rtj    t3 }t"4|t|
gtjj1|
t!  |/| W d   n	1 s	w   Y  n)t r$t"4|t|
gt	jj1|
t!  n|j'd!d|itjj1t|
g|
d"dd# t rMtj0t|gt	jjd}d|_2n|jtd$ddd }t rtj    t3 }t"4|t|gtjj|t!  |/| W d   n	1 sw   Y  n)t rt"4|t|gt	jj|t!  n|j'd!d|itjjt|g|d"dd# t rtj  4 t"5|||d}|/| t".||}|/| |jtjjkrt"6||j}|/| W d   n	1 sw   Y  nyt r!t"5|||d}t".||}|jt	jjkrt"6||jS |S |j'd%|||d&d'did|idd}|jtd	|jdg||jtjjddd}|j'dd|id|i||ddd |jtjjkrv|j'd(d|id|i|j|jd)dd t7 s}||_8|S )*a  Initialize the input tensor with dirac initializer.

        Args:
            var(Tensor): Tensor that needs to be initialized.
            block(Block|None, optional): The block in which initialization ops
                   should be added. Used in static graph only, default None.

        Returns:
            The most critical OP(scatter) in this initializer, which contains 7~8 ops in total.
        zBCurrently, dirac initializer not support lazy init for dist param.Out)Zfloat16Zbfloat16Zfloat32Zfloat64r   )r         z=Only Tensor with 3/4/5 dimensions can be initialized by Diracr   z.Tensor 0-dimension must be divisible by groups.ZdiractmpF)r   shapedtypetypepersistableNZfill_constant)valuer*   r)   T)r+   inputsoutputsattrsstop_gradientr   g      ?   XShape)r   r*   r)   r+   r,   r1   Zreshape2Xr)   )r$   r4   )r+   r.   r0   r/   r1   )r*   Zscatter_index)r   r,   r1   Zassign_value)r*   r)   values)r+   r/   r0   r1   Zscatter_valuescatter)r5   ZIdsZUpdates	overwritecast)Zin_dtype	out_dtype)9r   r
   ZEagerParamBaseZis_distZ_check_blockVariablepaddler   Valuer	   ZParameterMetaZBlockr   lenr)   r   Zin_pir_moder*   ZDataTypeZFLOAT32r   ZVarTypeZFP32Z
create_varr   generatejoinr   ZDENSE_TENSORZin_dygraph_moder   ZdygraphZno_gradr   r   Zfull_strfloatfullZ	append_opminreversedinsertrangeappend	enumerateZreshapeZ_share_underline_tensor_toZzerosZINT64r1   Z_create_tensorZassign_value_r7   r9   r   op)r   r    r"   r:   Zout_varrJ   ZplaceZorigin_shapeZnum_per_groupZ	min_shapeZidx_listZ
value_liststridesproddimijoffsetkZstrideZtmp_outZx_shapeZindex_tensorZ
tmp_tensorZvalue_tensorZtmp_reshape_outZtmp_cast_outr   r   r   __call__d   s  





















zDirac.__call__)r   N)r   r   r   r   r   r   )N)r    r!   r"   r#   r   r!   )__name__
__module____qualname____doc__r   rR   __classcell__r   r   r   r   r      s
    =r   )
__future__r   r<   r   r   r   Zpaddle.utilsr    r   r	   r
   Z	base.corer   Zbase.data_feederr   Zbase.frameworkr   Zinitializerr   __all__r   r   r   r   r   <module>   s   