    def _joint_likelihood(
        self,
        logits: torch.Tensor,
        transitions: torch.Tensor,
        tags: torch.Tensor,
        mask: torch.BoolTensor,
    ) -> torch.Tensor:
        """Computes the numerator term for the log-likelihood, which is just score(inputs, tags)

        Args:
            logits (torch.Tensor): a (batch_size, sequence_length num_tags) tensor of unnormalized
                log-probabilities
            transitions (torch.Tensor): a (batch_size, num_tags, num_tags) tensor of transition scores
            tags (torch.Tensor): output tag sequences (batch_size, sequence_length) $y$ for each input sequence
            mask (torch.BoolTensor): a (batch_size, sequence_length) tensor of masking flags

        Returns:
            torch.Tensor: numerator term for the log-likelihood, which is just score(inputs, tags)
        """
        batch_size, sequence_length, _ = logits.data.shape

        # Transpose batch size and sequence dimensions:
        logits = logits.transpose(0, 1).contiguous()
        mask = mask.transpose(0, 1).contiguous()
        tags = tags.transpose(0, 1).contiguous()

        # Start with the transition scores from start_tag to the first tag in each input
        if self.include_start_end_transitions:
            score = self.start_transitions.index_select(0, tags[0])
        else:
            score = 0.0

        # Add up the scores for the observed transitions and all the inputs but the last
        for i in range(sequence_length - 1):
            # Each is shape (batch_size,)
            current_tag, next_tag = tags[i], tags[i + 1]

            # The scores for transitioning from current_tag to next_tag
            transition_score = transitions[current_tag.view(-1), next_tag.view(-1)]

            # The score for using current_tag
            emit_score = logits[i].gather(1, current_tag.view(batch_size, 1)).squeeze(1)

            # Include transition score if next element is unmasked,
            # input_score if this element is unmasked.
            score = score + transition_score * mask[i + 1] + emit_score * mask[i]

        # Transition from last state to "stop" state. To start with, we need to find the last tag
        # for each instance.
        last_tag_index = mask.sum(0).long() - 1
        last_tags = tags.gather(0, last_tag_index.view(1, batch_size)).squeeze(0)

        # Compute score of transitioning to `stop_tag` from each "last tag".
        if self.include_start_end_transitions:
            last_transition_score = self.end_transitions.index_select(0, last_tags)
        else:
            last_transition_score = 0.0

        # Add the last input if it's not masked.
        last_inputs = logits[-1]  # (batch_size, num_tags)
        last_input_score = last_inputs.gather(1, last_tags.view(-1, 1))  # (batch_size, 1)
        last_input_score = last_input_score.squeeze()  # (batch_size,)

        score = score + last_transition_score + last_input_score * mask[-1]

        return score
Computes the numerator term for the log-likelihood, which is just score(inputs, tags)

Args:
logits (torch.Tensor): a (batch_size, sequence_length num_tags) tensor of unnormalized
log-probabilities
transitions (torch.Tensor): a (batch_size, num_tags, num_tags) tensor of transition scores
tags (torch.Tensor): output tag sequences (batch_size, sequence_length) $y$ for each input sequence
mask (torch.BoolTensor): a (batch_size, sequence_length) tensor of masking flags

Returns:
torch.Tensor: numerator term for the log-likelihood, which is just score(inputs, tags)
allennlp/modules/conditional_random_field/conditional_random_field.py