Thanks for the notice. Yeah, I mean the code is readable and very useful to understand what’s going on.
I tried to change forward algorithm like this:
def _forward_score(self, feats):
    def log_sum_exp_2(vecs):
        max_scores, max_ids = torch.max(vecs, 1)
        max_scores_exp = max_scores.expand(vecs.size(0), vecs.size(0))
        return max_scores +  torch.log(torch.sum(torch.exp(vecs - max_scores_exp), 1))

    init_alphas = torch.Tensor(1, self.tag_size).fill_(-10000.)
    init_alphas[0][START_TAG] = 0.
    init_variables = Variable(init_alphas)

    def iter_forward(variables, feature_list):
        if feature_list is None:
            end_variables = variables + self.transitions[STOP_TAG].view(1, -1)
            return log_sum_exp(end_variables)

        head_feat = feature_list[0]
        try:
            tail_feats = feature_list[1:]
        except ValueError:
            tail_feats = None

        head_feat_exp = head_feat.view(self.tag_size, 1).expand(self.tag_size, self.tag_size)
        variables_exp = variables.expand(self.tag_size, self.tag_size)
        next_tag_variables_exp = variables_exp + self.transitions + head_feat_exp
        new_forward_variables = log_sum_exp(next_tag_variables_exp).view(1, self.tag_size)

        return iter_forward(new_forward_variables, tail_feats)

    return iter_forward_score(variables=init_variables, feature_list=feats)

But still found this is not a good idea for batch training.  Any good suggestion ?