o
    IhCT                     @   s   d Z ddlZddlZddlmZ ddlZddlmZ ddgZG dd dejj	Z
G dd	 d	ejj	ZG d
d dejj	ZG dd dejj	ZdS )z
We will recreate all the RNN modules as we require the modules to be decomposed
into its building blocks to be able to observe.
    N)Optional)TensorLSTMCellLSTMc                
       s   e Zd ZdZejjZdgZ			dddde	de	d	e
d
df fddZ	ddedeeeef  d
eeef fddZ	dde	de
d
eeef fddZdd ZedddZedddZ  ZS ) r   a  A quantizable long short-term memory (LSTM) cell.

    For the description and the argument types, please, refer to :class:`~torch.nn.LSTMCell`

    `split_gates`: specify True to compute the input/forget/cell/output gates separately
    to avoid an intermediate tensor which is subsequently chunk'd. This optimization can
    be beneficial for on-device inference latency. This flag is cascaded down from the
    parent classes.

    Examples::

        >>> import torch.ao.nn.quantizable as nnqa
        >>> rnn = nnqa.LSTMCell(10, 20)
        >>> input = torch.randn(6, 10)
        >>> hx = torch.randn(3, 20)
        >>> cx = torch.randn(3, 20)
        >>> output = []
        >>> for i in range(6):
        ...     hx, cx = rnn(input[i], (hx, cx))
        ...     output.append(hx)
    split_gatesTNFr   	input_dim
hidden_dimbiasreturnc          	         s  ||d}t    || _|| _|| _|| _|sAtjj|d| fd|i|| _	tjj|d| fd|i|| _
tjjj | _nAtj | _	tj | _
tj | _dD ],}tjj||fd|i|| j	|< tjj||fd|i|| j
|< tjjj | j|< qUtj | _tj | _tj | _tj | _tjjj | _tjjj | _tjjj | _tjjj | _d| _d| _tj| _tj| _d S )Ndevicedtype   r
   )inputforgetcelloutput)      ?r   )super__init__
input_sizehidden_sizer
   r   torchnnLinearigateshgatesao	quantizedFloatFunctionalgates
ModuleDictSigmoid
input_gateforget_gateTanh	cell_gateoutput_gatefgate_cxigate_cgatefgate_cx_igate_cgateogate_cyinitial_hidden_state_qparamsinitial_cell_state_qparamsquint8hidden_state_dtypecell_state_dtype)	selfr   r	   r
   r   r   r   factory_kwargsg	__class__ W/var/www/vscode/kcb/lib/python3.10/site-packages/torch/ao/nn/quantizable/modules/rnn.pyr   ,   sj   


zLSTMCell.__init__xhiddenc                 C   sr  |d u s|d d u s|d d u r|  |jd |j}|\}}| jsQ| |}| |}| j||}|dd\}}	}
}| 	|}| 
|	}	| |
}
| |}nAi }t| j | j | j D ]\\}}}}|||||||< qb| 	|d }| 
|d }	| |d }
| |d }| j|	|}| j||
}| j||}|}t|}| j||}||fS )Nr      r   r   r   r   r   )initialize_hiddenshapeis_quantizedr   r   r   r!   addchunkr$   r%   r'   r(   zipitemsvaluesr)   mulr*   r+   r   tanhr,   )r2   r9   r:   hxcxr   r   r!   r$   r%   r'   out_gategatekeyr)   r*   r+   cytanh_cyhyr7   r7   r8   forwardf   s<    





zLSTMCell.forward
batch_sizer>   c           	      C   sj   t || jft || jf}}|r1| j\}}| j\}}t j|||| jd}t j|||| jd}||fS )Nscale
zero_pointr   )r   zerosr   r-   r.   quantize_per_tensorr0   r1   )	r2   rO   r>   hch_scaleh_zpc_scalec_zpr7   r7   r8   r<      s   



zLSTMCell.initialize_hiddenc                 C      dS )NQuantizableLSTMCellr7   r2   r7   r7   r8   	_get_name      zLSTMCell._get_namec                 C   s(  |du |du ks
J |j d }|j d }| |||du|d}|sJtj||j_|dur4tj||j_tj||j_|durHtj||j_|S t||g||g|j|jgD ]9\}	}
}t|	j	ddd|
 D ]\}}tj||_qi|
durt|
j	ddd|
 D ]\}}tj||_qqX|S )zUses the weights and biases to create a new LSTM cell.

        Args:
            wi, wh: Weights for the input and hidden layers
            bi, bh: Biases for the input and hidden layers
        Nr;   )r   r	   r
   r   r   r   )dim)r=   r   r   	Parameterr   weightr
   r   rA   r@   rC   )clswiwhbibhr   r   r   r   wbr!   w_chunkrI   b_chunkr7   r7   r8   from_params   s2   

&  zLSTMCell.from_paramsc                 C   s   t || jks	J t|dsJ d| j|j|j|j|j|d}|j|_|j|j	_|j|j
_|rH|j	 D ]}|j|_q5|j
 D ]}|j|_qA|S )Nqconfigz$The float module must have 'qconfig'r   )type_FLOAT_MODULEhasattrrl   	weight_ih	weight_hhbias_ihbias_hhrm   r   r   rC   )rc   otheruse_precomputed_fake_quantr   observedr4   r7   r7   r8   
from_float   s$   



zLSTMCell.from_floatTNNN)F)NNF)FF)__name__
__module____qualname____doc__r   r   r   ro   __constants__intboolr   r   r   tuplerN   r<   r^   classmethodrl   rx   __classcell__r7   r7   r5   r8   r      sN    	;

,

$c                
       sl   e Zd ZdZ			ddddededed	df fd
dZddedee	eef  fddZ
edd Z  ZS )_LSTMSingleLayerzA single one-directional LSTM layer.

    The difference between a layer and a cell is that the layer can process a
    sequence, while the cell only expects an instantaneous value.
    TNFr   r   r	   r
   r   c                   s2   ||d}t    t||f||d|| _d S Nr   )r
   r   )r   r   r   r   )r2   r   r	   r
   r   r   r   r3   r5   r7   r8   r      s   


z_LSTMSingleLayer.__init__r9   r:   c                 C   sN   g }|j d }t|D ]}| || |}||d  qt|d}||fS )Nr   )r=   ranger   appendr   stack)r2   r9   r:   resultseq_leniresult_tensorr7   r7   r8   rN      s   
z_LSTMSingleLayer.forwardc                 O   s2   t j|i |}| |j|j|j|jd}||_|S )Nr   )r   rl   r   r   r
   r   r   )rc   argskwargsr   layerr7   r7   r8   rl     s   z_LSTMSingleLayer.from_paramsry   rz   )r{   r|   r}   r~   r   r   r   r   r   r   rN   r   rl   r   r7   r7   r5   r8   r      s&    
	 	r   c                       sz   e Zd ZdZ					ddddededed	ed
eddf fddZddedee	eef  fddZ
edddZ  ZS )
_LSTMLayerz#A single bi-directional LSTM layer.TFNr   r   r	   r
   batch_firstbidirectionalr   c          
         sb   ||d}	t    || _|| _t||f||d|	| _| jr/t||f||d|	| _d S d S r   )r   r   r   r   r   layer_fwlayer_bw)
r2   r   r	   r
   r   r   r   r   r   r3   r5   r7   r8   r     s,   

z_LSTMLayer.__init__r9   r:   c                 C   s  | j r	|dd}|d u rd\}}n|\}}d }| jrE|d u r"d }n|d }|d }|d u r1d }n|d }|d }|d urE|d urE||f}|d u rP|d u rPd }ntj|tj|f}| ||\}	}t| dr| jr|d}
| 	|
|\}}|d}t
|	|g|	 d }|d u r|d u rd }d }n=|d u rtj|\}}n0|d u rtj|\}}n#t|d |d gd}t|d |d gd}n
|	}tj|\}}| j r|dd |||ffS )Nr   r;   )NNr   )r   	transposer   r   jit_unwrap_optionalr   rp   flipr   catr`   r   
transpose_)r2   r9   r:   hx_fwcx_fw	hidden_bwhx_bwcx_bw	hidden_fw	result_fw
x_reversed	result_bwr   rU   rV   r7   r7   r8   rN   *  sT   


z_LSTMLayer.forwardr   c                 K   sP  t |ds|dusJ |d|j}|d|j}|d|j}|d|j}|d|j}	|dd	}
| |||||	|
d
}t|d||_t|d| }t|d| }t|d| d}t|d| d}t	j
|||||
d
|_|jrt|d| d}t|d| d}t|d| dd}t|d| dd}t	j
|||||
d
|_|S )z
        There is no FP equivalent of this class. This function is here just to
        mimic the behavior of the `prepare` within the `torch.ao.quantization`
        flow.
        rm   Nr   r   r
   r   r   r   Fr   weight_ih_lweight_hh_l	bias_ih_l	bias_hh_l_reverse)rp   getr   r   r
   r   r   getattrrm   r   rl   r   r   )rc   ru   	layer_idxrm   r   r   r   r
   r   r   r   r   rd   re   rf   rg   r7   r7   r8   rx   `  s@   

z_LSTMLayer.from_float)TFFNNrz   )r   N)r{   r|   r}   r~   r   r   r   r   r   r   rN   r   rx   r   r7   r7   r5   r8   r     s2    
 6r   c                       s   e Zd ZdZejjZ							dddded	ed
ede	de	de
de	de	ddf fddZddedeeeef  fddZdd ZedddZedd Z  ZS ) r   aX  A quantizable long short-term memory (LSTM).

    For the description and the argument types, please, refer to :class:`~torch.nn.LSTM`

    Attributes:
        layers : instances of the `_LSTMLayer`

    .. note::
        To access the weights and biases, you need to access them per layer.
        See examples below.

    Examples::

        >>> import torch.ao.nn.quantizable as nnqa
        >>> rnn = nnqa.LSTM(10, 20, 2)
        >>> input = torch.randn(5, 3, 10)
        >>> h0 = torch.randn(2, 3, 20)
        >>> c0 = torch.randn(2, 3, 20)
        >>> output, (hn, cn) = rnn(input, (h0, c0))
        >>> # To get the weights:
        >>> # xdoctest: +SKIP
        >>> print(rnn.layers[0].weight_ih)
        tensor([[...]])
        >>> print(rnn.layers[0].weight_hh)
        AssertionError: There is no reverse path in the non-bidirectional layer
    r;   TF        Nr   r   r   
num_layersr
   r   dropoutr   r   r   c
                   s  ||	d t    |_|_|_|_|_t|_|_	d_
t|tjr>d|  kr4dkr>n tdt|trBtd|dkrZtd |dkrZtd| d|  tjjjfdj	d	 g}| fd
dtd|D  tj|_d S )Nr   Fr   r;   zbdropout should be a number in range [0, 1] representing the probability of an element being zeroedz|dropout option for quantizable LSTM is ignored. If you are training, please, use nn.LSTM version followed by `prepare` step.zdropout option adds dropout after all but last recurrent layer, so non-zero dropout expects num_layers greater than 1, but got dropout=z and num_layers=r   r   r   c                 3   s4    | ]}t jjjfd jd V  qdS )Fr   N)r   r   r
   r   .0_r3   r2   r   r7   r8   	<genexpr>  s    

z LSTM.__init__.<locals>.<genexpr>)r   r   r   r   r   r
   r   floatr   r   training
isinstancenumbersNumberr   
ValueErrorwarningswarnr   extendr   r   r   
ModuleListlayers)r2   r   r   r   r
   r   r   r   r   r   r   r   r5   r   r8   r     sb   




zLSTM.__init__r9   r:   c                    s  | j r	|dd}|d}| jrdnd}|d u rEtj||| jtj|jd	d |j
r8tjdd|jdfddt| jD }n5tj|}t|d trx|d | j||| j|d | j||| j  fd	dt| jD }n|}g }g }t| jD ]!\}	}
|
|||	 \}\}}|tj| |tj| qt|}t|}|d
|jd |jd
 }|d
|jd |jd
 }| j r|dd}|||ffS )Nr   r;      )r   r   r   rP   c                    s   g | ]}  fqS r7   r7   r   )rS   r7   r8   
<listcomp>  s    z LSTM.forward.<locals>.<listcomp>c                    s(   g | ]}|  d  |  d fqS )r   )squeeze)r   idx)rG   rF   r7   r8   r     s    )r   r   sizer   r   rS   r   r   r   squeeze_r>   rT   r   r   r   r   r   r   r   reshape	enumerater   r   r   r=   )r2   r9   r:   max_batch_sizenum_directionshxcxhidden_non_opthx_listcx_listr   r   rU   rV   	hx_tensor	cx_tensorr7   )rG   rF   rS   r8   rN     sV   




zLSTM.forwardc                 C   r[   )NQuantizableLSTMr7   r]   r7   r7   r8   r^   +  r_   zLSTM._get_namec              
   C   s   t || jsJ t|ds|sJ | |j|j|j|j|j|j|j	|d}t
|d||_t|jD ]}tj|||d|d|j|< q0|jrR|  tjjj|dd}|S |  tjjj|dd}|S )Nrm   r   F)r   r   T)inplace)r   ro   rp   r   r   r   r
   r   r   r   r   rm   r   r   rx   r   r   trainr   r   quantizationprepare_qatevalprepare)rc   ru   rm   r   rw   r   r7   r7   r8   rx   .  s0   

zLSTM.from_floatc                 C   s   t d)NzuIt looks like you are trying to convert a non-quantizable LSTM module. Please, see the examples on quantizable LSTMs.)NotImplementedError)rc   ru   r7   r7   r8   from_observedK  s   zLSTM.from_observed)r;   TFr   FNNrz   )NF)r{   r|   r}   r~   r   r   r   ro   r   r   r   r   r   r   r   rN   r^   r   rx   r   r   r7   r7   r5   r8   r     sJ     J7)r~   r   r   typingr   r   r   __all__r   Moduler   r   r   r   r7   r7   r7   r8   <module>   s     O* 