o
    ZhCT                     @   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nnZLinearigateshgatesaoZ	quantizedZFloatFunctionalgatesZ
ModuleDictZSigmoid
input_gateforget_gateZTanh	cell_gateoutput_gatefgate_cxigate_cgatefgate_cx_igate_cgateogate_cyinitial_hidden_state_qparamsinitial_cell_state_qparamsZquint8hidden_state_dtypecell_state_dtype)	selfr   r	   r
   r   r   r   factory_kwargsg	__class__ R/var/www/auris/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&   )r+   r2   r3   hxcxr   r   r   r   r    r!   Zout_gategatekeyr#   r$   r%   cyZtanh_cyhyr0   r0   r1   forwardf   s<    





zLSTMCell.forward
batch_sizer7   c           	      C   sj   t || jft || jf}}|r1| j\}}| j\}}t j|||| jd}t j|||| jd}||fS )NscaleZ
zero_pointr   )r   zerosr   r'   r(   quantize_per_tensorr)   r*   )	r+   rF   r7   hcZh_scaleZh_zpZc_scaleZc_zpr0   r0   r1   r5      s   



zLSTMCell.initialize_hiddenc                 C      dS )NZQuantizableLSTMCellr0   r+   r0   r0   r1   	_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
        Nr4   )r   r	   r
   r   r   r   )dim)r6   r   r   	Parameterr   weightr
   r   r:   r9   r<   )clswiwhbibhr   r   r   r   wbr   Zw_chunkrA   Zb_chunkr0   r0   r1   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hasattrr[   Z	weight_ihZ	weight_hhZbias_ihZbias_hhr\   r   r   r<   )rT   otherZuse_precomputed_fake_quantr   observedr-   r0   r0   r1   
from_float   s$   



zLSTMCell.from_floatTNNN)F)NNF)FF)__name__
__module____qualname____doc__r   r   r   r^   Z__constants__intboolr   r   r   tuplerE   r5   rO   classmethodr[   rb   __classcell__r0   r0   r.   r1   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   )r+   r   r	   r
   r   r   r   r,   r.   r0   r1   r      s   


z_LSTMSingleLayer.__init__r2   r3   c                 C   sN   g }|j d }t|D ]}| || |}||d  qt|d}||fS )Nr   )r6   ranger   appendr   stack)r+   r2   r3   resultZseq_leniZresult_tensorr0   r0   r1   rE      s   
z_LSTMSingleLayer.forwardc                 O   s2   t j|i |}| |j|j|j|jd}||_|S )Nr   )r   r[   r   r   r
   r   r   )rT   argskwargsr   layerr0   r0   r1   r[     s   z_LSTMSingleLayer.from_paramsrc   rd   )re   rf   rg   rh   ri   rj   r   r   r   rk   rE   rl   r[   rm   r0   r0   r.   r1   rn      s&    
	 	rn   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 ro   )r   r   ry   rz   rn   layer_fwlayer_bw)
r+   r   r	   r
   ry   rz   r   r   r   r,   r.   r0   r1   r     s,   

z_LSTMLayer.__init__r2   r3   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   r4   )NNr|   )ry   	transposerz   r   jit_unwrap_optionalr{   r_   flipr|   catrQ   rr   Z
transpose_)r+   r2   r3   Zhx_fwZcx_fwZ	hidden_bwZhx_bwZcx_bwZ	hidden_fwZ	result_fwZ
x_reversedZ	result_bwrs   rK   rL   r0   r0   r1   rE   *  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.
        r\   Nr   r   r
   ry   rz   r   Fr   Zweight_ih_lZweight_hh_lZ	bias_ih_lZ	bias_hh_lZ_reverse)r_   getr   r   r
   ry   rz   getattrr\   rn   r[   r{   r|   )rT   r`   Z	layer_idxr\   rv   r   r   r
   ry   rz   r   rw   rU   rV   rW   rX   r0   r0   r1   rb   `  s@   

z_LSTMLayer.from_float)TFFNNrd   )r   N)re   rf   rg   rh   ri   rj   r   r   r   rk   rE   rl   rb   rm   r0   r0   r.   r1   rx     s2    
 6rx   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
    r4   TF        Nr   r   r   
num_layersr
   ry   dropoutrz   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   r4   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=ry   rz   r   c                 3   s4    | ]}t jjjfd jd V  qdS )Fr   N)rx   r   r
   rz   .0_r,   r+   r   r0   r1   	<genexpr>  s    

z LSTM.__init__.<locals>.<genexpr>)r   r   r   r   r   r
   ry   floatr   rz   training
isinstancenumbersNumberrj   
ValueErrorwarningswarnrx   extendrp   r   r   Z
ModuleListlayers)r+   r   r   r   r
   ry   r   rz   r   r   r   r   r.   r   r1   r     sb   




zLSTM.__init__r2   r3   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   r4      )r   r   r   rG   c                    s   g | ]}  fqS r0   r0   r   )rI   r0   r1   
<listcomp>  s    z LSTM.forward.<locals>.<listcomp>c                    s(   g | ]}|  d  |  d fqS )r   )Zsqueeze)r   idx)r@   r?   r0   r1   r     s    )ry   r}   sizerz   r   rI   r   r   r   Zsqueeze_r7   rJ   r   rp   r   r~   r   r   r   Zreshape	enumerater   rq   rr   r6   )r+   r2   r3   Zmax_batch_sizeZnum_directionsZhxcxZhidden_non_optZhx_listZcx_listr   rw   rK   rL   Z	hx_tensorZ	cx_tensorr0   )r@   r?   rI   r1   rE     sV   




zLSTM.forwardc                 C   rM   )NZQuantizableLSTMr0   rN   r0   r0   r1   rO   +  rP   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 )Nr\   r   F)ry   r   T)Zinplace)r   r^   r_   r   r   r   r
   ry   r   rz   r   r\   rp   rx   rb   r   r   trainr   r   ZquantizationZprepare_qatevalprepare)rT   r`   r\   r   ra   r   r0   r0   r1   rb   .  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)rT   r`   r0   r0   r1   from_observedK  s   zLSTM.from_observed)r4   TFr   FNNrd   )NF)re   rf   rg   rh   r   r   r   r^   ri   rj   r   r   r   r   rk   rE   rO   rl   rb   r   rm   r0   r0   r.   r1   r     sJ     J7)rh   r   r   typingr   r   r   __all__r   Moduler   rn   rx   r   r0   r0   r0   r1   <module>   s     O* 