U
    yhVC                     @   s   d dl Z d dlmZmZ d dl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 )    N)OptionalTuple)TensorLSTMCellLSTMc                       s   e Zd ZdZejjZdeee	dd fddZ
deeeeef  eeef ddd	Zdee	eeef d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`

    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)
    TN	input_dim
hidden_dimbiasreturnc                    s  ||d}t    || _|| _|| _tjj|d| fd|i|| _tjj|d| fd|i|| _	tj
jj | _t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
   )      ?r   )super__init__
input_sizehidden_sizer
   torchnnZLinearigateshgatesaoZ	quantizedZFloatFunctionalgatesZ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   factory_kwargs	__class__ U/var/www/html/venv/lib/python3.8/site-packages/torch/ao/nn/quantizable/modules/rnn.pyr   &   s(    

  zLSTMCell.__init__)xhiddenr   c                 C   s   |d ks |d d ks |d d kr4|  |jd |j}|\}}| |}| |}| j||}|dd\}}	}
}| |}| 	|	}	| 
|
}
| |}| j|	|}| j||
}| j||}|}t|}| j||}||fS )Nr      r   )initialize_hiddenshapeis_quantizedr   r   r   addchunkr   r   r   r   r   mulr    r!   r   tanhr"   )r(   r.   r/   hxcxr   r   r   r   r   r   Zout_gater   r    r!   cyZtanh_cyhyr,   r,   r-   forwardB   s$     






zLSTMCell.forwardF)
batch_sizer3   r   c           	      C   sj   t || jft || jf }}|rb| 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(   r=   r3   hcZh_scaleZh_zpZc_scaleZc_zpr,   r,   r-   r1   \   s    "

zLSTMCell.initialize_hiddenc                 C   s   dS )NZQuantizableLSTMCellr,   r(   r,   r,   r-   	_get_namee   s    zLSTMCell._get_namec                 C   s   |dk|dkkst |jd }|jd }| |||dk	d}tj||j_|dk	rbtj||j_tj||j_|dk	rtj||j_|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
        Nr0   )r   r	   r
   )	AssertionErrorr2   r   r   	Parameterr   weightr
   r   )clswiwhbibhr   r   cellr,   r,   r-   from_paramsh   s    

zLSTMCell.from_paramsc                 C   s\   t || jkstt|ds$td| |j|j|j|j}|j	|_	|j	|j
_	|j	|j_	|S )Nqconfigz$The float module must have 'qconfig')type_FLOAT_MODULErF   hasattrrO   Z	weight_ihZ	weight_hhZbias_ihZbias_hhrP   r   r   )rI   otherZuse_precomputed_fake_quantobservedr,   r,   r-   
from_float}   s     

zLSTMCell.from_float)TNN)N)F)NN)F)__name__
__module____qualname____doc__r   r   r   rR   intboolr   r   r   r   r<   r1   rE   classmethodrO   rV   __classcell__r,   r,   r*   r-   r      s       (	c                       sX   e Zd ZdZdeeedd fddZdeee	eef  d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.
    TNr   c                    s0   ||d}t    t||fd|i|| _d S Nr   r
   )r   r   r   rN   r'   r*   r,   r-   r      s    

z_LSTMSingleLayer.__init__r.   r/   c                 C   sN   g }|j d }t|D ]"}| || |}||d  qt|d}||fS )Nr   )r2   rangerN   appendr   stack)r(   r.   r/   resultZseq_leniZresult_tensorr,   r,   r-   r<      s    
z_LSTMSingleLayer.forwardc                 O   s(   t j||}| |j|j|j}||_|S )N)r   rO   r   r   r
   rN   )rI   argskwargsrN   layerr,   r,   r-   rO      s    z_LSTMSingleLayer.from_params)TNN)N)rW   rX   rY   rZ   r[   r\   r   r   r   r   r<   r]   rO   r^   r,   r,   r*   r-   r_      s       	r_   c                       s^   e Zd ZdZdeeeeedd fddZdeee	eef  dd	d
Z
edddZ  ZS )
_LSTMLayerz#A single bi-directional LSTM layer.TFN)r   r	   r
   batch_firstbidirectionalr   c           	         sZ   ||d}t    || _|| _t||fd|i|| _| jrVt||fd|i|| _d S r`   )r   r   rk   rl   r_   layer_fwlayer_bw)	r(   r   r	   r
   rk   rl   r   r   r)   r*   r,   r-   r      s    

z_LSTMLayer.__init__ra   c                 C   s  | j r|dd}|d kr$d\}}n|\}}d }| jr|d krDd }n|d }|d }|d krbd }n|d }|d }|d k	r|d k	r||f}|d kr|d krd }ntj|tj|f}| ||\}	}t| dr| jr|d}
| 	|
|\}}|d}t
|	|g|	 d }|d kr6|d kr6d }d }nh|d krRtj|\}}nL|d krntj|\}}n0t|d |d gd}t|d |d gd}n|	}tj|\}}| j r|dd |||ffS )Nr   r0   )NNrn   )rk   	transposerl   r   jit_unwrap_optionalrm   rS   fliprn   catdimrd   Z
transpose_)r(   r.   r/   Zhx_fwZcx_fwZ	hidden_bwZhx_bwZcx_bwZ	hidden_fwZ	result_fwZ
x_reversedZ	result_bwre   rB   rC   r,   r,   r-   r<      sP    




z_LSTMLayer.forwardr   c                 K   s:  t |ds|dk	st|d|j}|d|j}|d|j}|d|j}|d|j}	| |||||	}
t|d||
_	t|d| }t|d	| }t|d
| d}t|d| d}t
|||||
_|jr6t|d| d}t|d	| d}t|d
| dd}t|d| dd}t
|||||
_|
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.
        rP   Nr   r   r
   rk   rl   Zweight_ih_lZweight_hh_lZ	bias_ih_lZ	bias_hh_lZ_reverse)rS   rF   getr   r   r
   rk   rl   getattrrP   r_   rO   rm   rn   )rI   rT   Z	layer_idxrP   rh   r   r   r
   rk   rl   ri   rJ   rK   rL   rM   r,   r,   r-   rV      s(    z_LSTMLayer.from_float)TFFNN)N)r   N)rW   rX   rY   rZ   r[   r\   r   r   r   r   r<   r]   rV   r^   r,   r,   r*   r-   rj      s           4rj   c                
       s~   e Zd ZdZejjZdeeee	e	e
e	dd fdd	Zdeeeeef  d
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
    r0   TF        N)r   r   
num_layersr
   rk   dropoutrl   r   c
                    s(  ||	d}
t    || _|| _|| _|| _|| _t|| _|| _	d| _
|rPdnd}t|tjrd|  krtdkrn n
t|trtd|dkrtd |dkrtd| d	|  t| j| j| jfd| j	d
|
g}td|D ],}|t| j| j| jfd| j	d
|
 qtj|| _d S )Nr   F   r0   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=)rk   rl   )r   r   r   r   rx   r
   rk   floatry   rl   training
isinstancenumbersNumberr\   
ValueErrorwarningswarnrj   rb   rc   r   r   Z
ModuleListlayers)r(   r   r   rx   r
   rk   ry   rl   r   r   r)   num_directionsr   ri   r*   r,   r-   r   %  sJ    


$


zLSTM.__init__ra   c                    s  | j r|dd}|d}| jr&dnd}|d krtj||| jtj|jd	d |j
rptjdd|jdfddt| jD }njtj|}t|d tr|d | j||| j|d | j||| j  fd	dt| jD }n|}g }g }t| jD ]D\}	}
|
|||	 \}\}}|tj| |tj| qt|}t|}|d
|jd |jd
 }|d
|jd |jd
 }| j r|dd}|||ffS )Nr   r0   rz   )r   r   r   r>   c                    s   g | ]}  fqS r,   r,   ).0_)r@   r,   r-   
<listcomp>]  s     z LSTM.forward.<locals>.<listcomp>c                    s(   g | ] }|  d  |  d fqS )r   )Zsqueeze)r   idx)r9   r8   r,   r-   r   g  s     )rk   ro   sizerl   r   r@   r   r{   r   Zsqueeze_r3   rA   r   rb   rx   rp   rq   r}   r   Zreshape	enumerater   rc   rd   r2   )r(   r.   r/   Zmax_batch_sizer   ZhxcxZhidden_non_optZhx_listZcx_listr   ri   rB   rC   Z	hx_tensorZ	cx_tensorr,   )r9   r8   r@   r-   r<   O  sT    
 
 

zLSTM.forwardc                 C   s   dS )NZQuantizableLSTMr,   rD   r,   r,   r-   rE   ~  s    zLSTM._get_namec                 C   s   t || jstt|ds"|s"t| |j|j|j|j|j|j	|j
}t|d||_t|jD ]}tj|||dd|j|< q\|jr|  tjjj|dd}n|  tjjj|dd}|S )NrP   F)rk   T)Zinplace)r}   rR   rF   rS   r   r   rx   r
   rk   ry   rl   rv   rP   rb   rj   rV   r   r|   trainr   r   ZquantizationZprepare_qatevalprepare)rI   rT   rP   rU   r   r,   r,   r-   rV     s&      
zLSTM.from_floatc                 C   s   t dd S )NzuIt looks like you are trying to convert a non-quantizable LSTM module. Please, see the examples on quantizable LSTMs.)NotImplementedError)rI   rT   r,   r,   r-   from_observed  s    zLSTM.from_observed)r0   TFrw   FNN)N)N)rW   rX   rY   rZ   r   r   r   rR   r[   r\   r{   r   r   r   r   r<   rE   r]   rV   r   r^   r,   r,   r*   r-   r     s.               */)r~   typingr   r   r   r   r   __all__r   Moduler   r_   rj   r   r,   r,   r,   r-   <module>   s   vb