U
    f}`                     @   sh   d dl Zd dlZddlmZ d dlmZ dadada	G dd deZ
G dd deZG d	d
 d
eZdS )    N   )	Explainer)LooseVersionc                   @   s$   e Zd ZdZdddZdd	d
ZdS )GradientExplainerah   Explains a model using expected gradients (an extension of integrated gradients).

    Expected gradients an extension of the integrated gradients method (Sundararajan et al. 2017), a
    feature attribution method designed for differentiable models based on an extension of Shapley
    values to infinite player games (Aumann-Shapley values). Integrated gradients values are a bit
    different from SHAP values, and require a single reference value to integrate from. As an adaptation
    to make them approximate SHAP values, expected gradients reformulates the integral as an expectation
    and combines that expectation with sampling reference values from the background dataset. This leads
    to a single combined expectation of gradients that converges to attributions that sum to the
    difference between the expected model output and the current output.
    N2   r   c           	      C   s   t |tkr8|\}}z|  d}W qZ   d}Y qZX n"z|  d}W n   d}Y nX |dkrvt|||||| _n|dkrt||||| _dS )a   An explainer object for a differentiable model using a given background dataset.

        Note that the complexity of the method scales linearly with the number of background data
        samples. Passing the entire training dataset as `data` will give very accurate expected
        values, but be unreasonably expensive. The variance of the expectation estimates scale by
        roughly 1/sqrt(N) for N background data samples. So 100 samples will give a good estimate,
        and 1000 samples a very good estimate of the expected values.

        Parameters
        ----------
        model : if framework == 'tensorflow', (input : [tf.Tensor], output : tf.Tensor)
             A pair of TensorFlow tensors (or a list and a tensor) that specifies the input and
            output of the model to be explained. Note that SHAP values are specific to a single
            output value, so the output tf.Tensor should be a single dimensional output (,1).

            if framework == 'pytorch', an nn.Module object (model), or a tuple (model, layer),
                where both are nn.Module objects
            The model is an nn.Module object which takes as input a tensor (or list of tensors) of
            shape data, and returns a single dimensional output.
            If the input is a tuple, the returned shap values will be for the input of the
            layer argument. layer must be a layer in the model, i.e. model.conv2

        data :
            if framework == 'tensorflow': [numpy.array] or [pandas.DataFrame]
            if framework == 'pytorch': [torch.tensor]
            The background dataset to use for integrating out features. GradientExplainer integrates
            over these samples. The data passed here must match the input tensors given in the
            first argument.
        Zpytorch
tensorflowN)typetupleZnamed_parameters_TFGradientExplainer	explainer_PyTorchGradientExplainer)	selfmodeldatasession
batch_sizelocal_smoothingabZ	framework r   ?/tmp/pip-target-lpfmz8o1/lib/python/shap/explainers/gradient.py__init__   s      
zGradientExplainer.__init__   maxc                 C   s   | j |||||S )a   Return the values for the model applied to X.

        Parameters
        ----------
        X : list,
            if framework == 'tensorflow': numpy.array, or pandas.DataFrame
            if framework == 'pytorch': torch.tensor
            A tensor (or list of tensors) of samples (where X.shape[0] == # samples) on which to
            explain the model's output.

        ranked_outputs : None or int
            If ranked_outputs is None then we explain all the outputs in a multi-output model. If
            ranked_outputs is a positive integer then we only explain that many of the top model
            outputs (where "top" is determined by output_rank_order). Note that this causes a pair
            of values to be returned (shap_values, indexes), where phi is a list of numpy arrays for each of
            the output ranks, and indexes is a matrix that tells for each sample which output indexes
            were choses as "top".

        output_rank_order : "max", "min", "max_abs", or "custom"
            How to order the model outputs when using ranked_outputs, either by maximum, minimum, or
            maximum absolute value. If "custom" Then "ranked_outputs" contains a list of output nodes.

        rseed : None or int
            Seeding the randomness in shap value computation  (background example choice, 
            interpolation between current and background example, smoothing).

        Returns
        -------
        For a models with a single output this returns a tensor of SHAP values with the same shape
        as X. For a model with multiple outputs this returns a list of SHAP value tensors, each of
        which are the same shape as X. If ranked_outputs is None then this list of tensors matches
        the number of model outputs. If ranked_outputs is a positive integer a pair is returned
        (shap_values, indexes), where shap_values is a list of tensors with a length of
        ranked_outputs, and indexes is a matrix that tells for each sample which output indexes
        were chosen as "top".
        )r   shap_values)r   Xnsamplesranked_outputsoutput_rank_orderrseedr   r   r   r   K   s    %zGradientExplainer.shap_values)Nr   r   )r   Nr   N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   
   s   
4r   c                   @   s0   e Zd ZdddZdd Zdd
dZdd ZdS )r
   Nr   r   c                 C   s  t d kr,dd la tt jtdk r,td td krjz(dd lattjtdk rZtd W n   Y nX tt|	dr|j
| _|jd j| _ntt|	dr|j
| _|jd j| _nntt|	d	r|j
| _|jd j| _nDtt|	d
r|d | _|d | _nds,ttt|d t| jtksDtdt| jjdk s^tdd| _t| jjdkr|d| _d| _t| jtkrd| _| jg| _t|tkr|g}|| _i | _|| _|| _|d kr
td k	rtjjjd k	rtj }nt jj }|d krt  n|| _d | _| jj ! D ]}d|j"kr4|j#d | _q4| jsfd g| _$ndd t%| jjd D | _$d S )Nr   z1.4.0z>Your TensorFlow version is older than 1.4.0 and not supported.z2.1.0z9Your Keras version is older than 2.1.0 and not supported.z$keras.engine.sequential.Sequential'>zkeras.models.Sequential'>zkeras.engine.training.Model'>ztuple'>r   Fz) is not currently a supported model type!z9The model output to be explained must be a single tensor!   z4The model output must be a vector or a single value!TZkeras_learning_phasec                 S   s   g | ]}d qS Nr   .0ir   r   r   
<listcomp>   s     z1_TFGradientExplainer.__init__.<locals>.<listcomp>)&tfr   r   __version__warningswarnkerasstrr   endswithinputsmodel_inputsZlayersoutputmodel_outputAssertionErrorlistlenshapemulti_outputmulti_inputr   Z_num_vinputsr   r   backendZtensorflow_backendZ_SESSIONZget_sessionget_default_sessionr   keras_phase_placeholdergraphZget_operationsnameoutputs	gradientsrange)r   r   r   r   r   r   opr   r   r   r   u   sf    




z_TFGradientExplainer.__init__c                 C   sJ   | j | d kr@| jr&| jd d |f n| j}t || j| j |< | j | S r&   )rB   r:   r5   r+   r3   )r   r)   outr   r   r   gradient   s    z_TFGradientExplainer.gradientr   r   c              
      s  j s"t tkstd g nt tks6tdtjt ksPtdjj }|d k	rjr|dkrt	
| }nH|dkrt	
|}n4|dkrt	
t	|}n|dkr|}ndstd	|d
kr|d d d |f }n&t	t	tj d jd df}g } fddtt D  fddtt D }	|d krft	jdd}t|jd D ],}
t	j| g }g }tt D ]2}|t	 | j |t	 | j qt d jd D ]}tD ]}t	jjd jd }t	j }tt D ]}jdkrZ | | t	jj | | j j  }n | | }|| d| j| |   | |< |j| |  |	| |< q q|||
f }g tdjD ]Bfddtt D }|j| q̇fddtt D }tt D ]J}|| |	|  }|d|| |< |dt	|jd  || |< q6q|j s|d n| qtjs|d S |d k	r||fS |S d S )N%Expected a single tensor model input! Expected a list of model inputs!z7Number of model inputs does not match the number given!r   minmax_absZcustomFz6output_rank_order must be max, min, max_abs or custom!)r   rI   rJ   r   r   c                    s*   g | ]"}t f | jd d  qS r   Nnpzerosr9   r(   lr   r   r   r   r*      s     z4_TFGradientExplainer.shap_values.<locals>.<listcomp>c                    s*   g | ]"}t f | jd d  qS rK   rL   rO   rQ   r   r   r*      s         .Ac                    s(   g | ] }|  t  j  qS r   )rI   r   rO   r   r   samples_inputr   r   r   r*     s     c                    s&   g | ] t  fd dD dqS )c                    s   g | ]}|  qS r   r   r(   grP   r   r   r*     s     z?_TFGradientExplainer.shap_values.<locals>.<listcomp>.<listcomp>r   rM   Zconcatenater(   gradsrW   r   r*     s     ) r;   r   r7   r6   r8   r3   runr5   r:   rM   ZargsortabsZtilearangerB   r9   rC   randomrandintseedappendrN   choicer   uniformr   Zrandnr   rF   meanvarsqrt)r   r   r   r   r   r   model_output_valuesmodel_output_ranksoutput_phissamples_deltar)   phisphi_varskjrindtrP   xfindbatchgradsamplesr   )r   r   r[   r   rT   r   r   r      sr    &

*&"  *
z _TFGradientExplainer.shap_valuesc                 C   s0   t t||}| jd k	r"d|| j< | j||S )Nr   )dictzipr>   r   r\   )r   rE   r3   r   Z	feed_dictr   r   r   r\   .  s    

z_TFGradientExplainer.run)Nr   r   )r   Nr   N)r    r!   r"   r   rF   r   r\   r   r   r   r   r
   s   s   
I
jr
   c                   @   s<   e Zd ZdddZdd Zedd Zd	d
 ZdddZdS )r   r   r   c           
   	   C   sl  t d kr,dd l a tt jtdk r,td d| _t|tkrDd| _t|tkrV|g}|| _|| _	|| _
d | _d | _d| _t|tkrd| _|\}}| }| | || _t  D || }| jj}t|tkrdd |D | _n|  g| _W 5 Q R X n|| _| | _d}| j| j }	|	jd dkr6d}|| _| jsNd g| _nd	d t|	jd D | _d S )
Nr   z0.4z9Your PyTorch version is older than 0.4 and not supported.FTc                 S   s   g | ]}|   qS r   )clonedetachr'   r   r   r   r*   `  s     z6_PyTorchGradientExplainer.__init__.<locals>.<listcomp>r   c                 S   s   g | ]}d qS r&   r   r'   r   r   r   r*   p  s     )torchr   r,   r-   r.   r;   r   r7   r3   r   r   layerinput_handleinterimr	   evaladd_handlesno_gradtarget_inputr   ry   rz   r   r9   r:   rB   rC   )
r   r   r   r   r   r|   _interim_inputsr:   rA   r   r   r   r   7  sJ    




z"_PyTorchGradientExplainer.__init__c                    s~   | j   dd |D }| j | }dd |d d |f D  | jd k	rh| jj} fdd|D }| j`n fdd|D }|S )Nc                 S   s   g | ]}|  qS r   )Zrequires_grad_r(   rr   r   r   r   r*   t  s     z6_PyTorchGradientExplainer.gradient.<locals>.<listcomp>c                 S   s   g | ]}|qS r   r   )r(   valr   r   r   r*   v  s     c                    s&   g | ]}t j |d    qS r   r{   Zautogradru   cpunumpy)r(   inputselectedr   r   r*   y  s     c                    s&   g | ]}t j |d    qS r   r   r   r   r   r   r*   |  s     )r   Z	zero_gradr}   r|   r   )r   idxr2   r   rA   r   r[   r   r   r   rF   r  s    


z"_PyTorchGradientExplainer.gradientc                 C   s.   z| ` W n tk
r   Y nX t| d| d S )Nr   )r   AttributeErrorsetattr)r   r   r4   r   r   r   get_interim_input  s
    z+_PyTorchGradientExplainer.get_interim_inputc                 C   s   | | j}|| _d S r&   )Zregister_forward_hookr   r}   )r   r|   r}   r   r   r   r     s    z%_PyTorchGradientExplainer.add_handlesr   Nr   c                    s>  j s"t tkstd g nt tks6td|d k	rވjrt  j  }W 5 Q R X |dkr~tj|dd\}}nJ|dkrtj|dd\}}n.|dkrtjt	|dd\}}ndstd	|d d d |f }n8t
 d
 jd
 tjf td
tj  }jd kr:jdkr:j  d
 jd
 }	g }
 fddtt D fddttjD }|d krtjd
d}t|jd D ]H}tj| g }g }ttjD ]R|t|	fj jdd    |t|	fj jdd    qt d
 jd
 D ]}tD ]tjjd
 jd
 }tj }tt D ]}jd
krʈ | |    tj! | | j | j"d# j  }n | |    }|| d| j$| |         | < jd kr||j| |     % & || < q|jdkrHt  jfddtt D  }jj'}j`'t|t(krt|t(krtt|D ]}|| % & || < qn|% & |d
 < W 5 Q R X qH|||f }g td
j)D ]8fddtt D }*|| qfddttjD }ttjD ]J}|| ||  }|+d
|| |< |,d
t-|jd
  || |< qq:|
tjdkr|d
 n| qjd k	rj.  d _js$|
d
 S |d k	r6|
|fS |
S d S )NrG   rH   r   T)Z
descendingrI   FrJ   z/output_rank_order must be max, min, or max_abs!r   c                    s4   g | ],}t jf | jd d   | jdqS )r   Ndevice)r{   rN   r9   r   rO   rQ   r   r   r*     s     z9_PyTorchGradientExplainer.shap_values.<locals>.<listcomp>c                    s,   g | ]$}t  fj| jd d  qS rK   )rM   rN   r   r9   rO   )r   r   r   r   r*     s     rR   r   r   c                    s   g | ]}|    d qS r   )Z	unsqueezerO   )rn   rT   r   r   r*     s     c                    s0   g | ](}|  t  j    qS r   )rI   r   ry   rz   rO   rS   r   r   r*     s     c                    s&   g | ] t  fd dD dqS )c                    s   g | ]}|  qS r   r   rU   rW   r   r   r*     s     zD_PyTorchGradientExplainer.shap_values.<locals>.<listcomp>.<listcomp>r   rX   rY   rZ   rW   r   r*     s     )/r;   r   r7   r6   r:   r{   r   r   sortr]   Zonesr9   r8   rB   intr^   r}   r~   r   r|   rC   r   rM   r_   r`   ra   rb   rN   rc   rd   r   ry   rz   emptyr   Znormal_r3   r   r   r   r	   r   rF   re   rf   rg   remove)r   r   r   r   r   r   rh   r   ri   Z	X_batchesrj   rk   r)   rl   rm   ro   rp   rq   rP   rr   r   rs   rt   ru   rv   r   )r   r   r[   rn   r   rT   r   r   r     s    
 
&*
26.
"" *&

z%_PyTorchGradientExplainer.shap_values)r   r   )r   Nr   N)	r    r!   r"   r   rF   staticmethodr   r   r   r   r   r   r   r   5  s   
;
r   )r   rM   r-   r   r   Zdistutils.versionr   r/   r+   r{   r   r
   r   r   r   r   r   <module>   s   i C