U
    d3                     @   sB   d dl mZmZ d dlmZmZ dddZddd	ZdddZdS )    )core	workspace)	viewitemsviewkeysNr   Fc
           :         s  t |dkstddd |D }
dd |D }| dfdd}d	d |
| D d
d |D 7 |dk	rt| fdd jD }t j}dd |D }|	st	j
 j|\}dd tD t	d}| jdd= |dk	rddd |D } jD ]@}|t|js"| j|g t|j|s"tq"| j| t	| \}}t	|t	 \}}fddt|D }| j| d| _nd}dd |D dd |D  |  g }d _g }g }g }g }|D ]\}}t|}||d }|d } |t| }!|||df ||!|df |||!d df |||!d df ||!d |!d g || |dk	r||!d | df | jt|!d  |d }"||"ds|| | df n||"| df q|D ]"\}#}$|t|#t|$df q0|dk	r|D ]*\}#}$|t|# t|$d df qb| j j | j j dd }%|%|\}&}'}(|%|\})}*}+dd |D },|dk	r| }-g }.t |-jdkr6|-jd }|-j| |.| q|.ddd D ]~}|-j|g t|jD ]^\}/}0|0|-jkr`|0|jkrq`t	|0}0|0d  }1t|1|-jd j|/< ||0|1g|0g q`qDd!d" }2i }3|dk	rtt|%|\}4}5}6fd#d|D }7fd$d|D }8|dkr*t } fd%d|7D d&d |4D d'd |5D |6|d(d |D |8d)}3t | jdkr| |3d*< | j ||d+g f|)d,d |*D |+| fd-d|,D d.d |&D d/d |'D |(d |dkrd0nt|d1|3}9d _|9dd S )2aA  
    net: the main net operator should be added to

    cell_net: cell_net which is executed in a recurrent fasion

    inputs: sequences to be fed into the recurrent net. Currently only one input
    is supported. It has to be in a format T x N x (D1...Dk) where T is lengths
    of the sequence. N is a batch size and (D1...Dk) are the rest of dimentions

    initial_cell_inputs: inputs of the cell_net for the 0 timestamp.
    Format for each input is:
        (cell_net_input_name, external_blob_with_data)

    links: a dictionary from cell_net input names in moment t+1 and
    output names of moment t. Currently we assume that each output becomes
    an input for the next timestep.

    timestep: name of the timestep blob to be used. If not provided "timestep"
    is used.

    scope: Internal blobs are going to be scoped in a format
    <scope_name>/<blob_name>
    If not provided we generate a scope name automatically

    outputs_with_grads : position indices of output blobs which will receive
    error gradient (from outside recurrent network) during backpropagation

    recompute_blobs_on_backward: specify a list of blobs that will be
                 recomputed for backward pass, and thus need not to be
                 stored for each forward timestep.

    forward_only: if True, only forward steps are executed
       z'Only one input blob is supported so farc                 S   s   g | ]}t |d  qS r   str.0i r   ;/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/recurrent.py
<listcomp>3   s     z!recurrent_net.<locals>.<listcomp>c                 S   s   g | ]}t |d  qS r   r   r   xr   r   r   r   4   s     Z	recurrentc                    s$   d kr n}d t|t| S )Nz{}/{})formatr	   )nameZ
scope_name)op_namescoper   r   s7   s    zrecurrent_net.<locals>.sc                 S   s   g | ]}t |qS r   r   r   br   r   r   r   ?   s     c                 S   s   g | ]}t |d  qS r   r   r   r   r   r   r   @   s     Nc                    s   g | ]}| krt |qS r   )r   BlobReferencer   )known_inputsr   r   r   C   s   c                 S   s   i | ]}||d  qS )_gradr   )r   or   r   r   
<dictcomp>I   s      z!recurrent_net.<locals>.<dictcomp>c                 S   s   i | ]\}}t ||qS r   r   )r   kvr   r   r   r   O   s      ZRecurrentBackwardStepc                 S   s   h | ]}t |qS r   r   r   r   r   r   	<setcomp>X   s     z recurrent_net.<locals>.<setcomp>c                    s2   g | ]*\}}|d kr|kr|   jkr|qS r   )Protoexternal_output)r   Zblobver)cell_net	undefinedr   r   r   k   s
   simplec                 S   s   g | ]}|d  qS r   r   r
   r   r   r   r   w   s     c                 S   s   g | ]}|d  qS r   r   r   r   r   r   r   w   s    Z_statesr   r   Z_all_lastc                 S   s&   | rt |  \}}}|||fS g g g fS )N)zip)r   ar   cr   r   r   unpack_triple   s    
z$recurrent_net.<locals>.unpack_triplec                 S   s   g | ]}t |d  qS r   r   r   r   r   r   r      s     Z_accumc                 S   s,   dd t |  D dd t |  D  S )Nc                 S   s   g | ]}t |qS r   r   r   r   r   r   r      s     z;recurrent_net.<locals>.map_to_dual_list.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   r   r   r   r   r   r      s     )listkeysvalues)mr   r   r   map_to_dual_list   s    z'recurrent_net.<locals>.map_to_dual_listc                    s   g | ]}| kr|qS r   r   r   )backward_mapping_keysr   r   r      s      c                    s    g | ]}|krt  | qS r   r   r   )backward_mappingr3   r   r   r      s   c                    s   g | ]}  |qS r   index)r   p
all_inputsr   r   r      s     c                 S   s   g | ]}t |qS r   r   r   lr   r   r   r      s     c                 S   s   g | ]}t |qS r   r   r:   r   r   r   r      s     c                 S   s   g | ]}t |qS r   r   r   r   r   r   r      s    )parambackward_link_internalbackward_link_externalbackward_link_offsetoutputs_with_gradsrecompute_blobs_on_backwardparam_gradsZbackward_step_netZstep_workspacesc                 S   s   g | ]}t |qS r   r   )r   r+   r   r   r   r   
  s     c                    s   g | ]}  |qS r   r5   r
   r8   r   r   r     s    c                 S   s   g | ]}t |qS r   r   r:   r   r   r   r     s     c                 S   s   g | ]}t |qS r   r   r:   r   r   r   r     s     timestep)	alias_src	alias_dstalias_offsetrecurrent_statesZinitial_recurrent_state_idslink_internallink_externallink_offsetZenable_rnn_executorZstep_netrC   )lenAssertionErrorZNextNameappendr	   r"   Zexternal_inputr.   r#   r   ZGradientRegistryZGetBackwardPassopr   ZNet
isdisjointsetoutputextendissubsetZget_ssaZget_undefined_blobstypegetremove	enumerateinputr   ZSumr   RecurrentNetwork):netr%   inputsZinitial_cell_inputslinksrC   r   r@   rA   Zforward_onlyZinput_blobsZinitial_input_blobsr   Z
referencesZinner_outputsZinner_outputs_mapZbackward_opsZbackward_cell_netrN   Zbackward_ssaZbackward_blob_versionsZssaZblob_versionsZ	scratchesZall_outputsZforward_linksZbackward_linksaliasesrG   Z
cell_input_stateZstates_gradZcell_outputZrecurrent_input_gradZinput_tZ
input_blobr-   rH   rI   rJ   rD   rE   rF   Zrecurrent_inputsproto	operatorsjZoutput_blobZ
accum_blobr2   Zbackward_argsr=   r>   r?   paramsrB   resultsr   )r9   r4   r3   r%   r   r   r   r&   r   recurrent_net   s@   &

 









 
 









re   c                    sP   ddl m  jdkst fdd}|d k	r:|d| |d k	rL|d| d S )Nr   )
caffe2_pb2>   RecurrentNetworkGradientrY   c                    s*      }d|  |_||_j|g d S )Nzrnn_executor.)ZArgumentr   r   argrR   )r   r    r+   rf   rnn_opr   r   add_arg%  s    
z(set_rnn_executor_config.<locals>.add_argnum_threadsmax_cuda_streams)Zcaffe2.protorf   rT   rL   )rj   rl   rm   rk   r   ri   r   set_rnn_executor_config!  s    
rn   rnnc              	   C   sv   d}g }|   jD ]^}|jdkr|d t| }|d }|jd }ttjd|g|g|d |t	|
 7 }q|S )a  
    Retrieves blobs from step workspaces (which contain intermediate recurrent
    network computation for each timestep) and puts them in the global
    workspace. This allows access to the contents of this intermediate
    computation in python. Returns the list of extracted blob names.

    net: the net from which the step workspace blobs should be extracted

    prefix: prefix to append to extracted blob names when placing them in the
    global workspace
    r   rY   r^   r)   ZRecurrentNetworkBlobFetcher)prefix)r"   rN   rT   r	   rQ   r   ZRunOperatorOncer   ZCreateOperatorZ	FetchBlobtolist)rZ   rp   countZoutput_listrN   Z	blob_nameZscratch_workspaces_blob_namer   r   r   retrieve_step_blobs1  s"    

rs   )NNr   NF)NN)ro   )	Zcaffe2.pythonr   r   Zfuture.utilsr   r   re   rn   rs   r   r   r   r   <module>   s           
  
