U
    dr                     @   s   d dl mZmZmZmZmZmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZmZ d dlmZmZ d dlmZ d dlmZmZ d d	lZd d	lZd d	lZeeZG d
d dejZ d	S )    )coremodel_helperschemascopeutilsmuji)ParameterInfo)parameter_sharing_context)NetModifier)get_param_device	Optimizer)RegularizerRegularizationBy)layers)	viewitems
viewvaluesNc                       s>  e Zd ZdZdm fdd	Zdd Zdd	 Zd
d Zdd ZdnddZ	e
doddZdpddZdd Zdd Zdd Zdd Zdd Zdd  Zdqd!d"Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zed-d. Zed/d0 Zdrd1d2Zd3d4 Zed5d6 Zejd7d6 Zed8d9 Z ed:d; Z!ed<d= Z"ed>d? Z#e#jd@d? Z#edAdB Z$e$jdCdB Z$edDdE Z%dsdGdHZ&edIdJ Z'e'jdKdJ Z'edLdM Z(e(jdNdM Z(dOdP Z)dtdRdSZ*dTdU Z+dVdW Z,dXdY Z-edZd[ Z.dud\d]Z/dvd^d_Z0dwd`daZ1dxdbdcZ2dydddeZ3dfdg Z4dhdi Z5edjdk Z6e6jdldk Z6  Z7S )zLayerModelHelpera  
    Model helper for building models on top of layers abstractions.

    Each layer is the abstraction that is higher level than Operator. Layer
    is responsible for ownership of it's own parameters and can easily be
    instantiated in multiple nets possible with different sets of ops.
    As an example: one can easily instantiate predict and train nets from
    the same set of layers, where predict net will have subset of the
    operators from train net.
    FTc                    s   t t| j|d t | _g | _i | _d| _d| _i | _	i | _
d| _d| _g | _d| _g | _g | _d| _|szt| j|n| | _|st| j|n| | _t | _d| _|   | d| _d| _d| _g | _ g | _!|| _"dS )a8   TODO(amalevich): more documnetation on input args

        use_attribution:
            if True, will generate the atrribution net for feature importance
            calculation; Need to turn it to false when FC is quantized as FP16
            This attribute access will be consistent with MTML model.
        )nameNTparam_init_net)#superr   __init__set_layer_names_layers_param_to_shape_seed_sequence_seedparam_to_optimparam_to_reg_default_optimizer_loss_prediction_output_schema_post_grad_net_modifiers_final_net_modifiers_breakdown_mapr   	NewRecordnetclone_input_feature_schema_trainer_extra_schemaStruct_metrics_schema_preproc_output_schema_init_global_constantscreate_init_netr   _initialize_params%_transfer_learning_blob_name_mappingsZ$ad_hoc_diagnose_blobs_and_operationsad_hoc_plot_blobsuse_attribution)selfr   input_feature_schematrainer_extra_schemaZ
keep_blobsr3   	__class__ D/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/layer_model_helper.pyr   (   sL    
zLayerModelHelper.__init__c                 C   s
   d | _ d S N)r"   r4   r9   r9   r:   clear_output_schemag   s    z$LayerModelHelper.clear_output_schemac                 C   s
   || _ d S r;   )r0   )r4   Zinitialize_paramsr9   r9   r:   set_initialize_paramsj   s    z&LayerModelHelper.set_initialize_paramsc                 C   s4   || j jkstd|| j t||f | _ d S )Nz!Try to add metric field twice: {})r,   fieldsAssertionErrorformatr   r+   r4   r   valuer9   r9   r:   add_metric_fieldm   s    z!LayerModelHelper.add_metric_fieldc                 C   sJ   t d| | j }|D ]&}||kr| jt|t f | _qd S )Nz&Filter metric schema with white_set {})loggerinforA   r,   field_namesr   r+   Scalar)r4   Z	white_setrG   r   r9   r9   r:   filter_metrics_schemau   s
    
z&LayerModelHelper.filter_metrics_schemaNc                 C   sX   t |ttjfs"tdt||p.tjdf}| 	t|t
|| | j| d S )Nz,expect type str or BlobReference, but got {})   )
isinstancestrr   BlobReferencer@   rA   typenpfloatrD   r   rH   r2   append)r4   blobdtyper9   r9   r:   add_ad_hoc_plot_blob|   s     z%LayerModelHelper.add_ad_hoc_plot_blobc                    s    d k	r|d kst d|d kr,t  ntj |d d  jtjkrPdn: jtjkrbdn( jtjkrtdn jtjkrdnd fdd	}n|d k	st || }|S )
Nz7Only one from array and initializer should be specifiedrS   ZGivenTensorIntFillZGivenTensorInt64FillZGivenTensorStringFillZGivenTensorBoolFillZGivenTensorFillc                    s   t jg |  j   dS )N)shapevalues)r   CreateOperatorrV   flattentolist)	blob_namearrayZop_namer9   r:   initializer   s     
zILayerModelHelper._get_global_constant_initializer_op.<locals>.initializer)r@   rO   r]   rS   int32Zint64rL   bool)r[   r]   rS   r^   initializer_opr9   r\   r:   #_get_global_constant_initializer_op   s*    
z4LayerModelHelper._get_global_constant_initializer_opc                 C   sr   t |tstd|| jks(td| | j|}|| j|< t||||}|| jksdtd| || j|< |S )Nz5name should be a string as we are using it as map keyz$%s already added in global_constantsz9there is already a initializer op associated with blob %s)	rK   rL   r@   global_constantsr'   ZNextBlobr   rb   global_constant_initializers)r4   r   r]   rS   r^   r[   ra   r9   r9   r:   add_global_constant   s*    
   
z$LayerModelHelper.add_global_constantc                 O   sp   || j kr^| j | }tj|f||}t|| j| dsZtd|t|t| j| f |S | j|f||S )NZ
debug_infozAconflict initializers for global constant %s, previous %s, now %s)	rc   r   rb   r   ZOpAlmostEqualrd   r@   rL   re   )r4   r   argskwargsr[   ra   r9   r9   r:   maybe_add_global_constant   s0    

 	z*LayerModelHelper.maybe_add_global_constantc                 C   sL   i | _ i | _| dd | dtd | dd | jdddgd	d
 d S )NONE      ?ZNANNaNZZEROg        Z
ZERO_RANGEr   r_   rU   )rc   rd   re   rP   r<   r9   r9   r:   r.      s    z'LayerModelHelper._init_global_constantsc                 C   s$   t | jD ]}|jj|g q
d S r;   )r   rd   Z_netopextend)r4   init_netra   r9   r9   r:   _add_global_constants   s    z&LayerModelHelper._add_global_constantsc                 C   s   t |}| | |S r;   )r   ZNetro   )r4   r   rn   r9   r9   r:   r/      s    

z LayerModelHelper.create_init_netc                 C   s<   || j krd S | j | }||kr8tdt |||d S )Nz~Got inconsistent shapes between shared parameters when trying to map a blob in scope {0} to {1}. ref_shape :  {2}, shape : {3})r   
ValueErrorrA   r   ZCurrentNameScope)r4   
param_namerV   Z	ref_shaper9   r9   r:   _validate_param_shape   s    

   z&LayerModelHelper._validate_param_shapec              
   C   s   || j krd S td| | j | }|d krR|| jkstd||| j|n|| jkrz|| jkstd|||nzt|trt|tstd||||t	|t	|kr|j
|j
kstd|||t	|t	||j
|j
ntd|d S )Nzr{} shares the same parameter with another parameter. Validating if the same optimizer has been specified for them.a9  Optim for {} is None which will fall back to use default_optimizer. However, the optimizer that has been specified for this shared parameter is {} which is different from default_optimizer {}. Please check the optimizers specified for parameters shared with {} and the default_optimizer to ensure the consistency.zOptim for {} is NoOptim. However, the optimizer for the parameters shared with {} is {} which is different from NoOptim. Please check the optimizer specified for other parameters in the shared group to ensure consistency.zOptim for {} is an instance of Optimizer. However, the optimizer for the parameters shared with {} is {} which is not an instance of Optimizer. Please check the optimizer specified for other  parameters in the shared group to ensure consistency.a  Optim for {} is an instance of Optimizer. However, the optimizer for the parameters shared with {} is {}. This optimizer either doesn't have the same type as the current optimizer: {} vs {}, or its attributes such as learning rate are different from that of current optimizer which is {} vs {}. Please check the optimizer specified for other parameters in the shared group to ensure consistency.zJoptim should be either None, NoOptim, or an instance of Optimizer, Got {} )r   rE   rF   rA   r   r@   NoOptimrK   r   rN   
attributesrp   )r4   rq   ZoptimZ	ref_optimr9   r9   r:   _validate_param_optim   sX    

   	
  
   	      z&LayerModelHelper._validate_param_optimc                 C   s   t |tjrt|}nt |tr,t|}ntdt|}t|dkrPi }nt|dks`tt	
|d }|d k	rd|kst|d|i d }	| jrtj|d g |f|}	tj||	|||d}
| || | || || j|< |
S )NzUnsupported type for param_namerJ      rV   r   )	parameterr^   	optimizerps_paramregularizer)rK   r   rM   rL   r	   Zget_parameter_namerp   lenr@   copydeepcopyupdater0   rX   r   LayerParameterrr   ru   r   )r4   rq   rV   r^   rx   ry   rz   Z
param_blobZinit_op_argsra   paramr9   r9   r:   create_param3  sF    



zLayerModelHelper.create_paramc                 C   sF   t |}|}d}|| jkr6|d t| }|d7 }q| j| |S )Nr   _auto_rJ   )r   Z
ScopedNamer   rL   add)r4   prefix	base_namer   indexr9   r9   r:   next_layer_namec  s    


z LayerModelHelper.next_layer_namec                 C   s   | j | | D ]}t|jtjs*t|jp4| j	| j
t|j< | j|j t|tjr~td|j |j| j|j< qt|trtd qtd|q|| j| j |jS )NzAdd parameter regularizer {0}z6regularization is unsupported for ParameterInfo objectz@unknown object type besides ParameterInfo and LayerParameter: {})r   rQ   get_parametersrK   rw   r   rM   r@   rx   default_optimizerr   rL   paramsr   r   rE   rF   rA   rz   r   r   rp   Zadd_operatorsr'   r   output_schema)r4   layerr   r9   r9   r:   	add_layern  s$    

zLayerModelHelper.add_layerc                 C   s.   g }| j D ]}| D ]}||j qq
|S r;   )r   r   rQ   rw   )r4   Zparam_blobsr   r   r9   r9   r:   get_parameter_blobs  s
    
z$LayerModelHelper.get_parameter_blobsc                 C   sD   || j kstd|| j t|ts4td|| j | d S Nz{0} is already in {1}z#{} has to be a NetModifier instance)r#   r@   rA   rK   r
   rQ   r4   modifierr9   r9   r:   add_post_grad_net_modifiers  s    z,LayerModelHelper.add_post_grad_net_modifiersc                 C   sD   || j kstd|| j t|ts4td|| j | d S r   )r$   r@   rA   rK   r
   rQ   r   r9   r9   r:   add_final_net_modifiers  s    z(LayerModelHelper.add_final_net_modifiersc                 C   s   | j S r;   )r   r<   r9   r9   r:   seed  s    zLayerModelHelper.seedc                 C   s   | j S r;   )r   r<   r9   r9   r:   sequence_seed  s    zLayerModelHelper.sequence_seedc                 C   s   || _ || _d S r;   )r   r   )r4   r   r   r9   r9   r:   
store_seed  s    zLayerModelHelper.store_seedc                 C   s   | j r|| j | j d S r;   )r   Zset_rand_seedr   )r4   r'   r9   r9   r:   
apply_seed  s    zLayerModelHelper.apply_seedc                 C   s   | j S r;   r   r<   r9   r9   r:   r     s    z"LayerModelHelper.default_optimizerc                 C   s
   || _ d S r;   r   )r4   rx   r9   r9   r:   r     s    c                 C   s   | j S r;   )r)   r<   r9   r9   r:   r5     s    z%LayerModelHelper.input_feature_schemac                 C   s   | j S r;   )r*   r<   r9   r9   r:   r6     s    z%LayerModelHelper.trainer_extra_schemac                 C   s   | j S )z
        Returns the schema that represents model output that should be used for
        metric reporting.

        During the training/evaluation this schema will be appended to the
        schema that represents model output.
        )r,   r<   r9   r9   r:   metrics_schema  s    	zLayerModelHelper.metrics_schemac                 C   s   | j d k	st| j S r;   r"   r@   r<   r9   r9   r:   r     s    zLayerModelHelper.output_schemac                 C   s   | j d kst|| _ d S r;   r   r4   r   r9   r9   r:   r     s    c                 C   s   | j d k	st| j S r;   r-   r@   r<   r9   r9   r:   preproc_output_schema  s    z&LayerModelHelper.preproc_output_schemac                 C   s   | j d kst|| _ d S r;   r   r   r9   r9   r:   r     s    c                 C   s   | j std| j S )Nzmodel prediction is empty)r!   r@   r<   r9   r9   r:   
prediction  s    zLayerModelHelper.predictionrj   c                 C   s$   |d k	st d| j||f d S )Nz#Added prediction should not be None)r@   r!   rQ   )r4   r   Zweightr9   r9   r:   add_prediction  s    zLayerModelHelper.add_predictionc                 C   s   | j S r;   )r1   r<   r9   r9   r:   $transfer_learning_blob_name_mappings  s    z5LayerModelHelper.transfer_learning_blob_name_mappingsc                 C   s   |d k	st d|| _d S )Nz7Transfer learning blob name mappings should not be None)r@   r1   )r4   Zblob_name_mappingsr9   r9   r:   r     s    c                 C   s   | j d k	st| j S r;   r    r@   r<   r9   r9   r:   loss  s    zLayerModelHelper.lossc                 C   s   | j d kst|| _ d S r;   r   )r4   r   r9   r9   r:   r     s    c                 C   s
   | j d k	S r;   )r    r<   r9   r9   r:   has_loss  s    zLayerModelHelper.has_lossunnamedc                 C   s   |d k	st dt|tjs0t|tjs0t d| jd krLt||f| _njt| jtjrltd| jf| _|d }d}|}|| jkr|t| }|d7 }q|t||f}| j| | _d S )NzAdded loss should not be Nonez)Added loss should be a scalar or a structr   r   r   rJ   )r@   rK   r   rH   r+   r    rL   )r4   r   r   Zprefix_baser   r   Zloss_structr9   r9   r:   add_loss  s&     


zLayerModelHelper.add_lossc                 C   s   |d k	st d|t|tjsBt|tjsBt d|t|| jd kr^t||f| _n0|| jjksxt d|| jt||f | _d S )Nz)Added output schema {} should not be NonezPAdded output schema {} should be a scalar or a struct.
            Now it is {}.z%Output Schema Field {} already exists)	r@   rA   rK   r   rH   r+   rN   r"   r?   rB   r9   r9   r:   add_output_schema  s$    

 
z"LayerModelHelper.add_output_schemac                 C   s    t | j|}|  j|7  _d S r;   )r   r&   r'   r*   )r4   r6   Ztrainer_extra_recordr9   r9   r:   add_trainer_extra_schema)  s    z)LayerModelHelper.add_trainer_extra_schemac                    sr   dd }dd }  dr"t t r> fdd}|S | r`|   fdd}|S td	 d S )
Nc                 S   s$   t | rdS | drdS dS d S )NTFunctionalLayerF)r   
IsOperator
startswithr   r9   r9   r:   is_functional_layer.  s
    

z9LayerModelHelper.__getattr__.<locals>.is_functional_layerc                 S   s8   t | r| S | dr(| tdd  S td|  d S )Nr   z)%s cannot be resolved as functional layer)r   r   r   r{   rp   r   r9   r9   r:   resolve_functional_layer6  s    

z>LayerModelHelper.__getattr__.<locals>.resolve_functional_layer__c                     sF   t j f| |}|ddr(|  |ddr<|  |S )Noutput_to_metricsFparams_to_metricsr   Zcreate_layergetZexport_output_for_metricsZexport_params_for_metricsr   )rf   rg   	new_layerr   r4   r9   r:   wrapperE  s    z-LayerModelHelper.__getattr__.<locals>.wrapperc                     sj    fdd}d|kr |d< t jdf| d|i|}|ddrL|  |ddr`|  |S )	Nc                    s    |   | | f| d S r;   )__getattr__Zfield_blobs)r'   Z	in_recordZ
out_recordrg   r   r9   r:   apply_operatorT  s
    zELayerModelHelper.__getattr__.<locals>.wrapper.<locals>.apply_operatorr   Z
Functionalfunctionr   Fr   r   )rf   rg   r   r   r   r9   r:   r   S  s$    z)Trying to create non-registered layer: {})r   AttributeErrorr   Zlayer_existsrA   )r4   r   r   r   r   r9   r   r:   r   -  s    


zLayerModelHelper.__getattr__c                 C   s   | j S r;   )r   r<   r9   r9   r:   r   p  s    zLayerModelHelper.layersc                 C   s   t d t| jD ]p\}}|d kr&qt d|| t|tsFt||||d tj	d}t | |d k	r| 
tj|dt| qd S )Nzapply regularizer on lossz)add regularizer {0} for param {1} to lossZgradZby)rR   )rE   rF   r   r   rA   rK   r   r@   r   ZON_LOSSr   r   rH   rL   )r4   	train_nettrain_init_netblob_to_devicer   rz   Zadded_loss_blobr9   r9   r:   apply_regularizers_on_losst  s    



z+LayerModelHelper.apply_regularizers_on_lossc           	   
   C   s   t d t }|pi }t| jD ]\}}|d kr6q$t|tsDtt d	|| t
||t|||d}t|$ |||||t|tjd W 5 Q R X q$d S )Nz!apply regularizer after optimizerz.add regularizer {0} for param {1} to optimizerZparam_to_deviceZdefault_devicer   )rE   rF   r   OnCPUr   r   rK   r   r@   rA   r   r   rL   r   DeviceScoper   ZAFTER_OPTIMIZER)	r4   r   r   grad_mapr   CPUr   rz   devicer9   r9   r:   "apply_regularizers_after_optimizer  s,    
   z3LayerModelHelper.apply_regularizers_after_optimizerc                    s:    fdd| j  D }| jD ]}||||||d qd S )Nc                    s   i | ]}| kr| | qS r9   r9   ).0r   r   r9   r:   
<dictcomp>  s     zBLayerModelHelper.apply_post_grad_net_modifiers.<locals>.<dictcomp>r   modify_output_record)r   keysr#   )r4   trainer_nettrainer_init_netr   r   r   Zparam_grad_mapr   r9   r   r:   apply_post_grad_net_modifiers  s    

z.LayerModelHelper.apply_post_grad_net_modifiersc                 C   s"   | j D ]}||||||d qd S )Nr   )r$   )r4   r   r   r   r   r   r   r9   r9   r:   apply_final_net_modifiers  s
    
z*LayerModelHelper.apply_final_net_modifiersc           	   
   C   s   t  }|pi }t| jD ]t\}}|d k	s2tdt||t|||d}|d k	r`|jd d = t	
| |||||t| W 5 Q R X qd S )Nz1default optimizer must have been set in add_layerr   )r   r   r   r   r@   r   r   rL   Z
extra_infor   r   )	r4   r   r   r   r   r   r   rx   r   r9   r9   r:   apply_optimizers  s*    
   z!LayerModelHelper.apply_optimizersc                 C   s
   | j d S )Nri   )rc   r<   r9   r9   r:   _GetOne  s    zLayerModelHelper._GetOnec                 O   s   d S r;   r9   )r4   rf   rg   r9   r9   r:   rs     s    zLayerModelHelper.NoOptimc                 C   s   | j S r;   )r%   r<   r9   r9   r:   breakdown_map  s    zLayerModelHelper.breakdown_mapc                 C   sN   t |tsttdd |D s$tt| ttt|ksDt|| _	d S )Nc                 s   s   | ]}t |tV  qd S r;   )rK   rL   )r   kr9   r9   r:   	<genexpr>  s     z1LayerModelHelper.breakdown_map.<locals>.<genexpr>)
rK   dictr@   allsortedrW   listranger{   r%   )r4   r   r9   r9   r:   r     s     )FT)N)NNN)NNN)NNN)T)rj   )r   )N)N)NF)NF)N)8__name__
__module____qualname____doc__r   r=   r>   rD   rI   rT   staticmethodrb   re   rh   r.   ro   r/   rr   ru   r   r   r   r   r   r   propertyr   r   r   r   r   setterr5   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rs   r   __classcell__r9   r9   r7   r:   r      s     ?
     '     
<    
0 



















C
 
 
!  
  
 

r   )!Zcaffe2.pythonr   r   r   r   r   r   Z%caffe2.python.modeling.parameter_infor   Z(caffe2.python.modeling.parameter_sharingr	   Z#caffe2.python.modeling.net_modifierr
   Zcaffe2.python.optimizerr   r   Zcaffe2.python.regularizerr   r   Zcaffe2.python.layersr   Zfuture.utilsr   r   loggingZnumpyrO   r|   	getLoggerr   rE   ZModelHelperr   r9   r9   r9   r:   <module>   s    
