U
    d1                     @   sb   d dl Z d dlZd dlmZmZ d dlmZ d dlm	Z	 d dl
mZ dd ZG dd	 d	ee	ZdS )
    N)coreschema)get_current_scope)
ModelLayer)SamplingTrainableMixinc                 C   s   | dkst d| | S )N)fp32zeOnly support fp32 for the fully connected layer in the predictor net, the provided FC precision is {})AssertionErrorformat)
fc_version r   J/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/layers/fc_with_bootstrap.pyget_fc_predictor_version   s    
r   c                	       sb   e Zd Zd fdd	Zdd Zdd	 Zd
d Zdd Zdd Zdd Z	dd Z
edd Z  ZS )FCWithBootstrapNfc_with_bootstrap   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 | _|| _|| _g | _d | _d | _d | _d | _|d k	rht|dkstd|\}}|d k	s|d k	std	|d ks:|d ks:||k s:td
i | _|d k	rT|| jd< |d k	rh|| jd< td| }|r|nd| |df}|r|nd| |df}g }t }t|D ]}|td|| d|fd|| d|f7 }| j| jd|||g|||
d| jd||g|||dg q|| _|dkr\|f}n,t|	 d j
d|d  }t||g }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maxg      ?ZUniformFill)r   r   zbootstrap_iteration_{}/indiceszbootstrap_iteration_{}/predszbootstrap_iteration_{}/w)
param_nameshapeZinitializerZ	optimizerZregularizerzbootstrap_iteration_{}/b) superr   __init__
isinstancer   Scalarr   r	   lenZfield_typesr   axisnpprod	clip_argsnum_bootstrap
input_dimsbootstrapped_FCs
batch_sizeoutput_dim_veclower_boundupper_boundmathsqrtStructrangeZget_next_blob_referenceextendZcreate_paramoutput_schemalisttuple)selfmodelinput_recordZoutput_dimsr   Zweight_initZ	bias_initZweight_optimZ
bias_optimnameZ
weight_regZbias_regZ
clip_paramr   kwargsr    Zclip_minZclip_maxZscaler!   r+   iZoutput_shape	__class__r   r   r      s      





zFCWithBootstrap.__init__c              
   C   s   t d| |dkr||d}|tdgd}|||gd}|| _|jtdgdtj	d}|jtdgd	tj	d}|j
| jgd
t jjd}	||	|gd}
|| _|
| _|j| j| j| jg| j|d   d dd}|W  5 Q R  S Q R X dS )a  
        Args:
            net: the caffe2 net to insert operator

            copied_cur_layer: blob of the bootstrapped features (make sure this
            blob has a stop_gradient on)

            iteration: the bootstrap interation to generate for. Used to correctly
            populate the output_schema

        Return:
            A blob containing the generated indices of shape: (batch_size,)
        zbootstrap_iteration_{}r   input_shapebatch_size_indexr"   r$   )Zdtyper   offsetint_batch_size)tor%   r   )Zinput_as_shapeN)r   Z	NameScoper	   ZShapeZConstr   arrayGatherr"   Zint32ZCastZDataTypeZINT32ZSubr$   r%   ZUniformIntFillr+   field_blobs)r.   netcopied_cur_layer	iterationr6   r7   r"   r$   r8   r9   r%   indicesr   r   r   _generate_bootstrapped_indices   s,      z.FCWithBootstrap._generate_bootstrapped_indicesc                 C   s4   | ||g|d|}ttj| jf|}|S )a  
            This method contains all the bootstrapping logic used to bootstrap
            the features. Only used by the train_net.

            Args:
                net: the caffe2 net to insert bootstrapping operators

                copied_cur_layer: the blob representing the current features.
                    Note, this layer should have a stop_gradient on it.

            Returns:
                bootstrapped_features: blob of bootstrapped version of cur_layer
                    with same dimensions
        zbootstrapped_features_{})r<   NextScopedBlobr	   r   r   r   Zfloat32r    )r.   r>   r?   rA   r@   bootstrapped_featuresr   r   r   _bootstrap_ops   s    
 zFCWithBootstrap._bootstrap_opsc                 C   sB   |dkr0|j | | |fd| ji| j}|S td|dS )a=  
        Args:
            net: the caffe2 net to insert operator

            features: Scalar containing blob of the bootstrapped features or
            actual cur_layer features

            params: weight and bias for FC

            outputs: the output blobs

            version: support fp32 for now.
        r   r   zunsupported FC type version {}N)ZFCr=   r   r2   	Exceptionr	   )r.   r>   featuresparamsoutputsversionZ	pred_blobr   r   r   _insert_fc_ops   s    
 zFCWithBootstrap._insert_fc_opsc           	         s   | j dk	rJ fdd|D }t||D ]\}} j|g|gf| j  q&|}| jdksbt| jdkr| j ||| j |d d  g|d dS )a0  
        Args:
            params: the weight and bias, passed by either add_ops or
            add_train_ops function

            features: feature blobs to predict on. Can be the actual cur_layer
            or the bootstrapped_feature blobs.

            version: currently fp32 support only
        Nc                    s   g | ]}  d t| qS )z
clipped_%s)rC   str).0pr>   r   r   
<listcomp>  s     z,FCWithBootstrap._add_ops.<locals>.<listcomp>r   r   )r>   rG   rH   rI   rJ   )r   zipZClipr#   r   rK   r+   r=   )	r.   r>   rG   r@   rH   rJ   Zclipped_paramsrN   cpr   rO   r   _add_ops  s    
zFCWithBootstrap._add_opsc                 C   sz   t  tjddi}|d }t| jD ]N}| j|| j d |d}| j	|d |d d  }| j
|| j|||d q&dS )a}  
            Both the predict net and the eval net will call this function.

            For bootstrapping approach, the goal is to pass the cur_layer feature
            inputs through all the bootstrapped FCs that are stored under
            self.bootstrapped_FCs. Return the preds in the same output_schema
            with dummy indices (because they are not needed).
        r
   r   r   r>   r?   r@   r   )r>   rG   rH   r@   rJ   N)r   getr   __name__r)   r   rB   r0   r=   r!   rS   )r.   r>   version_infoZpredictor_fc_fp_versionr3   rA   rH   r   r   r   add_ops"  s&    
 zFCWithBootstrap.add_opsc              	   C   st   t | jD ]d}| j|| j d |d}| j|| j d ||d}| j|||| j|d |d d  dd q
d S )Nr   rT   )r>   r?   rA   r@   r   r   )rG   r@   rH   rJ   )r)   r   rB   r0   r=   rE   rS   Ztrain_param_blobs)r.   r>   r3   rA   rD   r   r   r   add_train_opsC  s&    zFCWithBootstrap.add_train_opsc                 C   s8   | j d kst| j dkr,dd t| jD S tdd S )Nr   c                 S   s    g | ]\}}|d  dkr|qS )r   r   r   )rM   idxZblobr   r   r   rP   ]  s     zBFCWithBootstrap.get_fp16_compatible_parameters.<locals>.<listcomp>z=Currently only supports functionality for output_dim_vec == 1)r#   r   	enumerater!   rF   r.   r   r   r   get_fp16_compatible_parameters[  s    z.FCWithBootstrap.get_fp16_compatible_parametersc                 C   s*   | j d kst| j dkr| jS tdd S )Nr   z5FCWithBootstrap layer only supports output_dim_vec==1)r#   r   r!   rF   r\   r   r   r   param_blobsf  s    zFCWithBootstrap.param_blobs)	NNNNr   NNNr   )rV   
__module____qualname__r   rB   rE   rK   rS   rX   rY   r]   propertyr^   __classcell__r   r   r4   r   r      s(             (!r   )r&   Znumpyr   Zcaffe2.pythonr   r   Zcaffe2.python.helpers.arg_scoper   Zcaffe2.python.layers.layersr   Z-caffe2.python.layers.sampling_trainable_mixinr   r   r   r   r   r   r   <module>   s   