o
    –h  ã                   @   sn   d Z ddlZddlmZ ddlZddlZddlmZ ddlm  m	Z	 G dd„ dej
ƒZdd„ Zdd
d„ZdS )z 
CRF loss and viterbi decoding.
é    N)ÚNumber)Únnc                       sB   e Zd ZdZd‡ fdd„	Zdd„ Zdd„ Zd	d
„ Zdd„ Z‡  Z	S )ÚCRFLosszo
    Calculate log-space crf loss, given unary potentials, a transition matrix
    and gold tag sequences.
    Tc                    s(   t ƒ  ¡  t t ||¡¡| _|| _d S )N)ÚsuperÚ__init__r   Ú	ParameterÚtorchÚzerosÚ_transitionsÚ_batch_average)ÚselfÚnum_tagÚbatch_average©Ú	__class__© úS/var/www/html/env_mimamsha/lib/python3.10/site-packages/stanza/models/common/crf.pyr      s   

zCRFLoss.__init__c                 C   s   |  ¡ \}}}|  ||||||¡}|  ||||||¡}|  |||¡}	|| |	 }
t |
 ¡}| jr6|| }n| d¡ ¡ }||d  }|| jfS )a  
        inputs: batch_size x seq_len x num_tags
        masks: batch_size x seq_len
        tag_indices: batch_size x seq_len
        
        @return:
            loss: CRF negative log likelihood on all instances.
            transitions: the transition matrix
        r   g:Œ0âŽyE>)	ÚsizeÚcrf_unary_scoreÚcrf_binary_scoreÚcrf_log_normr   Úsumr   Úeqr
   )r   ÚinputsÚmasksÚtag_indicesÚinput_bsÚinput_slÚinput_ncÚunary_scoresÚbinary_scoresÚlog_normÚlog_likelihoodÚlossÚtotalr   r   r   Úforward   s   

zCRFLoss.forwardc           
      C   s\   |  |d¡}|tj||jd ¡  d¡|  }t |d|¡  |d¡}	|	 |d¡ |	jddS )z?
        @return:
            unary_scores: batch_size
        éÿÿÿÿ)Údevicer   é   ©Údim)	Úviewr   Úaranger'   ÚlongÚ	unsqueezeÚgatherÚmasked_fill_r   )
r   r   r   r   r   r   r   Úflat_inputsÚflat_tag_indicesr   r   r   r   r   .   s
   "zCRFLoss.crf_unary_scorec                 C   sš   |  d¡d }|dd…d|…f }|dd…dd…f }	|| |	 }
|
 d¡}
| j d¡}t |d|
¡ |d¡}|dd…dd…f }| |d¡ |jddS )z@
        @return:
            binary_scores: batch_size
        r&   r(   Nr   r)   )r   r+   r
   r   r/   r0   r   )r   r   r   r   r   r   r   ÚntÚstart_indicesÚend_indicesÚflat_transition_indicesÚflat_transition_matrixr    Úscore_masksr   r   r   r   9   s   
ÿzCRFLoss.crf_binary_scorec                 C   sö   |dd…ddd…f }|dd…dd…dd…f }|dd…dd…f }|}| j  d¡}t| d¡ƒD ]3}	| d¡| }
|dd…|	dd…f t|
dd }|dd…|	f  d¡ |¡}| || |¡¡ |}q1t|dd}tj	|dd}|t 
|¡ }|S )zÂ
        Calculate the CRF partition in log space for each instance, following:
            http://www.cs.columbia.edu/~mcollins/fb.pdf
        @return:
            log_norm: batch_size
        Nr   r(   é   r)   )r
   r.   Úranger   Úlog_sum_expÚ	expand_asÚmasked_scatter_Úmasked_selectr   ÚallÚlogical_not)r   r   r   r   Ústart_inputsÚrest_inputsÚ
rest_masksÚalphasÚtransÚiÚtransition_scoresÚ
new_alphasÚmr!   Ú
all_maskedr   r   r   r   L   s   "zCRFLoss.crf_log_norm)T)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r%   r   r   r   Ú__classcell__r   r   r   r   r      s    r   c           	      C   sÒ   t  | ¡}t j| t jd}| d |d< td| jd ƒD ]"}t  ||d  d¡| }| | t  |d¡ ||< t  |d¡||< qt  |d ¡g}t|dd… ƒD ]}| 	||d  ¡ qN| 
¡  t  |d ¡}||fS )a	  
    Decode a tag sequence with viterbi algorithm.
    scores: seq_len x num_tags (numpy array)
    transition_params: num_tags x num_tags (numpy array)
    @return:
        viterbi: a list of tag ids with highest score
        viterbi_score: the highest score
    )Údtyper   r(   r&   N)ÚnpÚ
zeros_likeÚint32r:   ÚshapeÚexpand_dimsÚmaxÚargmaxÚreversedÚappendÚreverse)	ÚscoresÚtransition_paramsÚtrellisÚbackpointersÚtÚvÚviterbiÚbpÚviterbi_scorer   r   r   Úviterbi_decodek   s   
	rd   Fc                 C   sš   |dur+t j| |dd\}}| | }|du r| |¡}|t  t jt  |¡||d¡ S t  | ¡}t  t  | | ¡¡}t|tƒrF|t |¡ S |t  |¡ S )z_Numerically stable implementation of the operation
    value.exp().sum(dim, keepdim).log()
    NT)r*   ÚkeepdimF)	r   rV   ÚsqueezeÚlogr   ÚexpÚ
isinstancer   Úmath)Úvaluer*   re   rI   Ú_Úvalue0Úsum_expr   r   r   r;   „   s   

ÿ

r;   )NF)rN   rj   Únumbersr   ÚnumpyrQ   r   r   Útorch.nn.initÚinitÚModuler   rd   r;   r   r   r   r   Ú<module>   s    _