U
    ©Ê¹j¥@  ã                   @   sš  d dl mZ d dlmZmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZmZmZ d dlZd dlmZ d dlm  mZ d dlmZ d dlZd dlmZ d dlm  mZ d dlZd dl Z d dl!Z!d dl"m#Z# e$ee$e$f dœd	d
„Z%ee ej&e	e$e
f dœdd„Z'ej&e	e$e
f ejj(dœdd„Z)d0ejj(ejj(dœdd„Z*ej(ej(dœdd„Z+ej(eej& eej& eej& dœdd„Z,ej-ej.ej/ej0ej1ej2ej3ej4ej5ej6ej4ej7ej8gZ9ej:ej;gZ<ej-ej=ej.ej>ej/dd„ iZ?eej& e	e$ej(f dœdd„Z@eej& e	e$ej(f e	ej(ej(f dœd d!„ZAG d"d#„ d#ƒZBd1d&d'„ZCeBeDd(œd)d*„ZEG d+d,„ d,ƒZFdejGfejj(ee	e$e
f  eejG ejj(d-œd.d/„ZHdS )2é    N)ÚArgumentÚTarget)Úfuse_conv_bn_eval)ÚTypeÚDictÚAnyÚTupleÚIterableÚOptionalÚListÚcast)Ú	ShapeProp)Údefaultdict)ÚEnum)ÚtargetÚreturnc                 C   s&   |   dd¡�^ }}|r|d nd|fS )zp
    Splits a qualname into parent path and last atom.
    For example, `foo.bar.baz` -> (`foo.bar`, `baz`)
    Ú.é   r   Ú )Úrsplit)r   ÚparentÚname© r   úa/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/fx/experimental/optimization.pyÚ_parent_name   s    r   )ÚpatternÚnodeÚmodulesc                 C   s”   t |jƒdkrdS |jd |f}t| |ƒD ]d\}}t|tjƒsD dS |jdkrT dS t|jtƒsf dS |j|krv dS t	||j ƒ|k	r* dS q*dS )Nr   FÚcall_moduleT)
ÚlenÚargsÚzipÚ
isinstanceÚfxÚNodeÚopr   ÚstrÚtype)r   r   r   ÚnodesÚexpected_typeZcurrent_noder   r   r   Úmatches_module_pattern   s    

r*   )r   r   Ú
new_modulec                 C   s<   t | jtƒst‚t| jƒ\}}||| j< t|| ||ƒ d S ©N)r"   r   r&   ÚAssertionErrorr   Úsetattr)r   r   r+   Úparent_namer   r   r   r   Úreplace_node_module,   s    
r0   F)Úmodelr   c                 C   sî   t jt jft jt jft jt jfg}|s0t | ¡} t	 
| ¡}t| ¡ ƒ}t |j¡}|D ]Š}|jD ]~}t|||ƒr`t|jd jƒdkr†q`||jd j }||j }	|	js¨q`t||	ƒ}
t|jd ||
ƒ | |jd ¡ | |¡ q`qVt	 ||¡S )z�
    Fuses convolution/BN layers for inference purposes. Will deepcopy your
    model by default, but can modify the model inplace as well.
    r   r   )ÚnnZConv1dZBatchNorm1dÚConv2dÚBatchNorm2dZConv3dZBatchNorm3dÚcopyÚdeepcopyr#   Úsymbolic_traceÚdictÚnamed_modulesÚgraphr(   r*   r   r    Úusersr   Ztrack_running_statsr   r0   Úreplace_all_uses_withÚ
erase_nodeÚGraphModule)r1   ZinplaceÚpatternsÚfx_modelr   Ú	new_graphr   r   ÚconvZbnZ
fused_convr   r   r   Úfuse2   s.    


þ




rC   c                 C   s*   t  | ¡}G dd„ dtj jƒ}||ƒ ¡ S )z5
    Removes all dropout layers from the module.
    c                       s8   e Zd Zeeedf eeef edœ‡ fdd„Z	‡  Z
S )z&remove_dropout.<locals>.DropoutRemover.)r   r    Úkwargsr   c                    s>   t | j| tjƒr*t|ƒdks"t‚|d S tƒ  |||¡S d S )Nr   r   )r"   Z
submodulesr2   ZDropoutr   r-   Úsuperr   )Úselfr   r    rD   ©Ú	__class__r   r   r   V   s    z2remove_dropout.<locals>.DropoutRemover.call_module)Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r&   r   r   Ú__classcell__r   r   rG   r   ÚDropoutRemoverU   s   rM   )r#   r7   ÚtorchZTransformerZ	transform)r1   r@   rM   r   r   r   Úremove_dropoutO   s    
rO   )Úorig_moduler(   ÚinputsÚoutputsc                    s|   t  ¡ }i ‰ |D ]}| |j¡}|ˆ |< q|D ] }| |‡ fdd„¡}|ˆ |< q.| ‡ fdd„|D ƒ¡ | ¡  t  | |¡S )z�
    Given lists of nodes from an existing graph that represent a subgraph, returns a submodule that executes that subgraph.
    c                    s   ˆ |  S r,   r   )Úx©Úenvr   r   Ú<lambda>h   ó    z"extract_subgraph.<locals>.<lambda>c                    s   g | ]}ˆ | ‘qS r   r   )Ú.0ÚoutputrT   r   r   Ú
<listcomp>j   s     z$extract_subgraph.<locals>.<listcomp>)r#   ÚGraphÚplaceholderr   Z	node_copyrY   Úlintr>   )rP   r(   rQ   rR   rA   ÚinputÚnew_noder   r   rT   r   Úextract_subgraph^   s    

r`   c                 C   s
   t  | ¡S r,   )Ú	th_mkldnnZMkldnnBatchNorm)ÚaÚ_r   r   r   rV   {   rW   rV   )r(   r   c                 C   s€   i }| D ]r}|j dkrt|jtƒs&t‚||j }t|ƒtkrtt|ƒ |tjƒ}t|t	j
ƒs`t‚t |¡||< t|||ƒ q|S )zÈ
    For each node, if it's a module that can be preconverted into MKLDNN,
    then we do so and create a mapping to allow us to convert from the MKLDNN
    version of the module to the original.
    r   )r%   r"   r   r&   r-   r'   Ú
mkldnn_maprN   Úfloatr2   ÚModuler5   r6   r0   )r(   r   Úold_modulesr   Ú
cur_moduler+   r   r   r   Úmodules_to_mkldnn   s    

ri   )r(   r   rg   c                 C   sJ   | D ]@}|j dkrt|jtƒs"t‚||j }||krt|||| ƒ qdS )za
    Maps each module that's been changed with `modules_to_mkldnn` back to its
    original.
    r   N)r%   r"   r   r&   r-   r0   )r(   r   rg   r   rh   r   r   r   Úreset_modules‘   s    

rj   c                   @   s   e Zd Zejdœdd„ZdS )ÚMklSubgraph©Úfx_graphc                 C   s   || _ g | _g | _g | _d S r,   )rm   r(   Ústart_nodesÚ	end_nodes)rF   rm   r   r   r   Ú__init__ž   s    zMklSubgraph.__init__N)rI   rJ   rK   r#   r[   rp   r   r   r   r   rk   �   s   rk   é
   r   c                    s(   d‰d‰t tdœ‡ ‡‡‡‡fdd„}|S )aW  
    This generates a heuristic that can be passed into `optimize_for_inference` that
    determines whether a subgraph should be run in MKL by running it with the example_inputs.

    Example usage:
        heuristic = gen_mkl_autotuner(example_inputs, iters=10)
        fast_model = optimization.optimize_for_inference(model, heuristic)
    N©r:   r   c                    s¸   | j }ˆd kr,| jj‰| jj‰tˆƒ ˆ¡ dd„ |D ƒ‰ tttj	 dd„ | j
D ƒƒ}tˆ| j||ƒ‰‡‡fdd„}|‡ ‡fdd„ƒ}tˆjjtˆ ¡ ƒˆƒ |‡ ‡fdd„ƒ}||k S )	Nc                 S   s   g | ]}t  |j¡‘qS r   )rN   ZrandnÚshape©rX   r   r   r   r   rZ   ·   s     z@gen_mkl_autotuner.<locals>.use_mkl_heuristic.<locals>.<listcomp>c                 S   s   g | ]}|j d  ‘qS )r   )r    rt   r   r   r   rZ   ¸   s     c                    s<   t ˆƒD ]
}| ƒ  qt ¡ }t ˆ ƒD ]
}| ƒ }q$t ¡ | S r,   )ÚrangeÚtime)Úfrc   ÚbeginÚout)ÚitersÚwarmupr   r   Ú	benchmark»   s    z?gen_mkl_autotuner.<locals>.use_mkl_heuristic.<locals>.benchmarkc                      s   dd„ ˆdd„ ˆ D ƒŽ D ƒS )Nc                 S   s   g | ]}|  ¡ ‘qS r   )Úto_dense©rX   Úir   r   r   rZ   Ã   s     zRgen_mkl_autotuner.<locals>.use_mkl_heuristic.<locals>.<lambda>.<locals>.<listcomp>c                 S   s   g | ]}|  ¡ ‘qS r   )Ú	to_mkldnnr~   r   r   r   rZ   Ã   s     r   r   ©Zsample_inputsÚ	submoduler   r   rV   Ã   rW   z>gen_mkl_autotuner.<locals>.use_mkl_heuristic.<locals>.<lambda>c                      s   ˆˆ Ž S r,   r   r   r�   r   r   rV   Æ   rW   )rn   rm   Zowning_modulerg   r   Ú	propagater   r   r#   r$   ro   r`   r(   rj   r:   r8   r9   )r:   Zinput_nodesZoutput_argsr|   Zmkl_timeZno_mkl_time©Úexample_inputsr@   rz   rg   r{   r�   r   Úuse_mkl_heuristic°   s    z,gen_mkl_autotuner.<locals>.use_mkl_heuristic)rk   Úbool)r…   rz   r{   r†   r   r„   r   Úgen_mkl_autotuner¤   s    	rˆ   rr   c                 C   s   t | jƒdkS )z¿
    This is a heuristic that can be passed into `optimize_for_inference` that
    determines whether a subgraph should be run in MKL by checking if there
    are more than 2 nodes in it
    é   )r   r(   )r:   r   r   r   Úuse_mkl_lengthÊ   s    rŠ   c                   @   sB   e Zd Zdd„ Zedœdd„Zeedœdd„Zeed	œd
d„ZdS )Ú	UnionFindc                 C   s   d g| | _ dg| | _d S )Nr   ©r   Úsize)rF   Únr   r   r   rp   Ó   s    zUnionFind.__init__)Úvc                 C   s   || j |< d| j|< d S )Nr   rŒ   )rF   r�   r   r   r   Úmake_set×   s    
zUnionFind.make_set)r�   r   c                 C   sB   | j | }||kr|S |d k	s"t‚|  |¡| j |< tt| j | ƒS r,   )r   r-   Úfindr   Úint)rF   r�   Zparr   r   r   r‘   Û   s    
zUnionFind.find)rb   Úbc                 C   sf   |   |¡|   |¡ }}||kr"|S | j| | j| k r@|| }}|| j|< | j|  | j| 7  < d S r,   )r‘   r�   r   )rF   rb   r“   r   r   r   Újoinã   s    

zUnionFind.joinN)rI   rJ   rK   rp   r’   r�   r‘   r”   r   r   r   r   r‹   Ò   s   r‹   )r1   Úpass_configÚtracerr   c              
      s*  dddt idœ}|dkri }| |¡ |d r6t| ƒ} |d rFt| ƒ} |d dkrV| S t|d tƒsltd	ƒ‚d|d kr€td
ƒ‚|d d }|ƒ }| t 	| ¡¡‰ t
 |jˆ ¡}t|  ¡ ƒ}G dd„ dtƒ}tˆ jƒD �]V}	|j}
|	jdk�rV||	j }t|ƒtk�rˆ|j}
t| ¡ dƒ}|dk	�rˆ|jtjk�s:tdƒ‚|jt d¡k�sˆtdƒ‚n2|	jdk�rˆ|	jtk�rv|j}
n|	jtk�rˆ|j}
|
|jkrÖ|
|jk�r¶t dd„ |	j!D ƒƒ�s¶qÖˆ  "|	¡� t
 #|	j!‡ fdd„¡}W 5 Q R X t$t%t
j&j' |ƒ|	_!ˆ  (|	¡�( ˆ  )dd|	f¡}|	 *|¡ |	f|_!W 5 Q R X qÖt+tˆ jƒ|ƒ}|ˆ _,ˆ jD ]„}	|	jdk�rL|	jdk�rL|	j!d }t|	j-ƒ}|D ]2}|jdk�r€|jdk�r€| *|¡ ˆ  .|¡ �q€t/|	j-ƒdk�rLˆ  .|	¡ �qLt/ˆ jƒ}t0|ƒ‰‡fdd„‰t1ˆ jƒD ]ê\}}	|	jdk�r,|	jdk�r,||	_2ˆ 3|¡ n¶|	jdk�rn|	jdk�rnˆ|	j!d ƒdk	�s\t‚ˆ|	j!d ƒ|	_4nt‡fdd„|	j5D ƒ}t/|ƒdk�r”�qút dd„ |D ƒƒ�r¬t‚t6|ƒ}|d |	_7|dd… D ]}ˆ 8|d |¡ �qÊ�qút9‡ fd d„ƒ}ˆ jD ]r}	t:|	d!ƒ�r$|ˆ ;|	j7¡ j <|	¡ t:|	d"ƒ�rH|ˆ ;|	j2¡ j= <|	¡ t:|	d#ƒ�rü|ˆ ;|	j4¡ j> <|	¡ �qü| ?¡ D ]P}||ƒ�sx|j=|j> D ]$}	|	j!d }|	 *|¡ ˆ  .|	¡ �q’t@|j||ƒ �qxd}ˆ jD ]&}	|	jdk�sð|	jdk�rÔ|d7 }�qÔtA BtC¡ Dd$|› �¡ ˆ  E¡  t
 | ˆ ¡}|S )%a  
    Performs a set of optimization passes to optimize a model for the
    purposes of inference. Specifically, the passes that are run are:
    1. Conv/BN fusion
    2. Dropout removal
    3. MKL layout optimizations

    The third optimization takes a function `use_mkl_heuristic` that's used
    to determine whether a subgraph should be explicitly run in MKL layout.

    Note: As FX does not currently handle aliasing, this pass currently
    assumes nothing aliases. If that isn't true, use at your own risk.
    TÚ	heuristic)Úconv_bn_fuserO   Úmkldnn_layout_optimizeNr˜   rO   r™   Fz+mkldnn_layout_optimize config is not a dictz4Heuristic not found in mkldnn_layout_optimize configc                   @   s   e Zd ZdZdZdZdS )z*optimize_for_inference.<locals>.MklSupportr   r‰   é   N)rI   rJ   rK   ÚNOÚYESÚUNKNOWNr   r   r   r   Ú
MklSupport  s   rž   r   z)this pass is only for torch.float modulesÚcpuz!this pass is only for CPU modulesZcall_functionc                 s   s   | ]}|j d kV  qdS )r}   N)r   )rX   Úargr   r   r   Ú	<genexpr>3  s     z)optimize_for_inference.<locals>.<genexpr>c                    s   ˆ   d| f¡S )Nr€   )Úcall_method©rŽ   rl   r   r   rV   6  rW   z(optimize_for_inference.<locals>.<lambda>r¢   r}   r   r€   c                    s0   t | dƒrˆ  | j¡S t | dƒr,ˆ  | j¡S d S )NÚcolorÚstart_color)Úhasattrr‘   r¤   r¥   r£   )Úufr   r   Ú	get_colorS  s
    

z)optimize_for_inference.<locals>.get_colorc                    s,   g | ]$}t |tjƒrˆ |ƒd k	rˆ |ƒ‘qS r,   )r"   r#   r$   r~   )r¨   r   r   rZ   n  s       z*optimize_for_inference.<locals>.<listcomp>c                 s   s   | ]}|d kV  qd S r,   r   r~   r   r   r   r¡   r  s     r   c                      s   t ˆ ƒS r,   )rk   r   rl   r   r   rV   y  rW   r¤   r¥   Ú	end_colorzmkldnn conversions: )FrŠ   ÚupdaterC   rO   r"   r8   ÚRuntimeErrorÚtracer5   r6   r#   r>   Úrootr9   r   Úlistr(   r›   r%   r   r'   Úmkldnn_supportedrœ   ÚnextÚ
parametersZdtyperN   re   r-   ZdeviceÚmkldnn_supported_unknownr�   Úanyr    Zinserting_beforeZmap_argr   r   r   r   Zinserting_afterZcreate_noder<   ri   rg   r;   r=   r   r‹   Ú	enumerater¥   r�   r©   Zall_input_nodesÚsortedr¤   r”   r   r¦   r‘   Úappendrn   ro   Úvaluesrj   ÚloggingÚ	getLoggerrI   Úinfor]   )r1   r•   r–   Zdefault_pass_configr†   Z
cur_tracerr@   r   rž   r   Zsupports_mkldnnrh   Zsample_parameterZmkldnn_argsZdense_xrg   Zprv_noder;   ÚuserZ	num_nodesZcur_idxZ
cur_colorsZother_colorZmkldnn_graphsr:   ZprvZmkldnn_conversionsÚresultr   )rm   r¨   r§   r   Úoptimize_for_inferenceì   sÌ    ý
	


 











r½   )F)rq   r   )IZtorch.fxr#   Ztorch.fx.noder   r   Ztorch.nn.utils.fusionr   Útypingr   r   r   r   r	   r
   r   r   rN   Ztorch.nnr2   Ztorch.nn.functionalZ
functionalÚFZtorch.fx.passes.shape_propr   r5   Úcollectionsr   Ztorch.utils.mkldnnÚutilsZmkldnnra   Úoperatorrv   r¸   Úenumr   r&   r   r$   r*   rf   r0   rC   rO   r`   r3   ZLinearr4   ZReLUZ	MaxPool2dZ	AvgPool2dZAdaptiveAvgPool2dZreluZ	transposeZsigmoidZ
avg_pool2dZadaptive_avg_pool2dr¯   ÚaddÚmulr²   ZMkldnnConv2dZMkldnnLinearrd   ri   rj   rk   rˆ   r‡   rŠ   r‹   ZTracerr½   r   r   r   r   Ú<module>   sp   (	  (          ý	   ý .
&ýü