U
    dP$                     @   s^   d dl mZ d dlmZ d dlmZ d dlmZ d dlZd dl	Z
dd ZG dd	 d	eeZdS )
    )get_current_scope)schema)
ModelLayer)SamplingTrainableMixinNc                 C   s   | dkst d| | S )N)fp32fp16znOnly support fp32 and fp16 for the fully connected layer in the predictor net, the provided FC precision is {})AssertionErrorformat)
fc_version r   ;/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/layers/fc.pyget_fc_predictor_version   s    
r   c                       s^   e Zd Zd fdd	Zedd	 Zd
d Zdd Zdd Zdd Z	dd Z
edd Z  ZS )FCNfc   F      ?c              
      s  t t| j|||f| t|tjs2td|t|	 d j
dksPtd|dksftd||| _t|	 d j
|d d  }|dkstd|d | _|d k	r:t|dkstd|\}}|d k	s|d k	std	|d ks|d ks||k std
i | _|d k	r&|| jd< |d k	r:|| jd< |d krHd}t|| }|r`|nd| |df}|rz|nd| |df}t|||| _|| _| jd kst| jdkr|r||gn||g}| jd||||	d| _| jd|g|||
d| _n~g | _g | _t| jD ]f\}}|r.||gn||g}| j| jd|||||	d | j| jd||g|||	d q|dkr|f}n,t|	 d j
d|d  }t||g }ttj|f| d| _d S )NzIncorrect input type {}r   z1FC expects limited dimensions of the input tensorr   zaxis {} should >= 1.z'FC expects input dimensions > 0, got {}   zUclip_param must be a tuple / list of length 2 and in the form of (clip_min, clip max)z8clip_min, and clip_max in clip_param cannot both be Nonez?clip_param = [clip_min, clip_max] must have clip_min < clip_maxminmaxr   ZUniformFill)r   r   w)
param_nameshapeZinitializerZ	optimizerZregularizerbzw_sub_{}zb_sub_{}output) superr   __init__
isinstancer   ZScalarr   r	   lenZfield_typesr   axisnpprod	clip_argsmathsqrtcalculate_fc_output_dimsoutput_dim_vec
transposedZcreate_paramr   r   w_vecb_vec	enumerateappendlisttupleZfloat32Zget_next_blob_referenceoutput_schema)selfmodelinput_recordZoutput_dimsZweight_initZ	bias_initZweight_optimZ
bias_optimnameZ
weight_regZbias_regZ
clip_parammax_fc_sizer   r&   Z#uniform_weight_init_scale_numeratorkwargsZ
input_dimsZclip_minZclip_maxZscaleZweight_shapeidx
output_dimZoutput_shape	__class__r   r   r      s     







 

 
  

zFC.__init__c                 C   sx   | r| dk rd S | |ks(t d| |tt| | }tt|d | d }|g|d  }||t|  |S )Nr   zwCurrently we split along the output dimension. So we need max_fc_size >= input_dim. But, max_fc_size: {}, input_dim: {}r   )r   r	   intr   floorr*   sum)r2   Z	input_dimr5   Zoutput_dim_allowedZnum_fcr%   r   r   r   r$   w   s     zFC.calculate_fc_output_dimsc                 C   s   |dkr\| j r4|j| j | |fd| ji| jS |j| j | |fd| ji| jS n<|dkr|j| j | |fd| ji| jS td	|dS )z
        Args:
            net: the caffe2 net to insert operator
            params: weight and bias for FC
            outputs: the output blobs
            version: support fp32 and fp16 for now.
        r   r   r   zunsupported FC type version {}N)
r&   ZFCTransposedr0   field_blobsr   r3   r   Z
FbFCPacked	Exceptionr	   )r.   netparamsoutputsversionr   r   r   _insert_fc_ops   s8    zFC._insert_fc_opsc                    s8  | j dk	rJ fdd|D }t||D ]\}} j|g|gf| j  q&|}| jdksbt| jdkrz|  || j | n|dtt|d  }|tt|d d }t|t|kst	g }	t
t| jD ]<}
 d|
}|  ||
 ||
 g|g|}|	| qЈ |	| j | j d d g  dS )	z
        Args:
            params : the weight and bias,
                passed by either add_ops or add_train_ops function
            version : fp16 or fp32, might support in8 in the future.
        Nc                    s   g | ]}  d t| qS )z
clipped_%s)NextScopedBlobstr).0pr=   r   r   
<listcomp>   s   
zFC._add_ops.<locals>.<listcomp>r   r   zoutput_sub_{}r   Z_concat_dims)r!   zipZClipr%   r   rA   r-   r;   r8   r   rangerB   r	   r*   ZConcat)r.   r=   r>   r@   Zclipped_paramsrE   cpr'   r(   Zoutput_blob_veciZoutput_blobZ
insert_retr   rF   r   _add_ops   s:    

   zFC._add_opsc                 C   s0   t  tjddi}|d }| || j| dS )zFBoth the predict net and the eval net will call this function
        r
   r   N)r   getr   __name__rL   param_blobs)r.   r=   version_infoZpredictor_fc_fp_versionr   r   r   add_ops   s     z
FC.add_opsc                 C   s   |  || jd d S )Nr   )rL   Ztrain_param_blobs)r.   r=   r   r   r   add_train_ops   s    zFC.add_train_opsc                 C   s*   | j d kst| j dkr | jgS | jS d S Nr   )r%   r   r   r'   r.   r   r   r   get_fp16_compatible_parameters   s    z!FC.get_fp16_compatible_parametersc                 C   s4   | j d kst| j dkr$| j| jgS | j| j S d S rS   )r%   r   r   r   r'   r(   rT   r   r   r   rO      s    zFC.param_blobs)NNNNr   NNNNr   Fr   )rN   
__module____qualname__r   staticmethodr$   rA   rL   rQ   rR   rU   propertyrO   __classcell__r   r   r6   r   r      s,                      ]
!#	r   )Zcaffe2.python.helpers.arg_scoper   Zcaffe2.pythonr   Zcaffe2.python.layers.layersr   Z-caffe2.python.layers.sampling_trainable_mixinr   r"   Znumpyr   r   r   r   r   r   r   <module>   s   