File size: 2,610 Bytes
58627fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import torch
import torch.nn as nn

from transformers import ElectraPreTrainedModel, ElectraModel


class ElectraReader(ElectraPreTrainedModel):
    def __init__(self, config, learn_labels=False):
        super(ElectraReader, self).__init__(config)

        self.electra = ElectraModel(config)

        self.relevance = nn.Linear(config.hidden_size, 1)

        if learn_labels:
            self.linear = nn.Linear(config.hidden_size, 2)
        else:
            self.linear = nn.Linear(config.hidden_size, 1)

        self.init_weights()

        self.learn_labels = learn_labels

    def forward(self, encoding):
        outputs = self.electra(encoding.input_ids,
                               attention_mask=encoding.attention_mask,
                               token_type_ids=encoding.token_type_ids)[0]

        scores = self.linear(outputs)

        if self.learn_labels:
            scores = scores[:, 0].squeeze(1)
        else:
            scores = scores.squeeze(-1)
            candidates = (encoding.input_ids == 103)
            scores = self._mask_2d_index(scores, candidates)

        return scores

    def _mask_2d_index(self, scores, mask):
        bsize, maxlen = scores.size()
        bsize_, maxlen_ = mask.size()

        assert bsize == bsize_, (scores.size(), mask.size())
        assert maxlen == maxlen_, (scores.size(), mask.size())

        # Get flat scores corresponding to the True mask positions, with -inf at the end
        flat_scores = scores[mask]
        flat_scores = torch.cat((flat_scores, torch.ones(1, device=self.device) * float('-inf')))

        # Get 2D indexes
        rowidxs, nnzs = torch.unique(torch.nonzero(mask, as_tuple=False)[:, 0], return_counts=True)
        max_nnzs = nnzs.max().item()

        rows = [[-1] * max_nnzs for _ in range(bsize)]
        offset = 0
        for rowidx, nnz in zip(rowidxs.tolist(), nnzs.tolist()):
            rows[rowidx] = [offset + i for i in range(nnz)]
            rows[rowidx] += [-1] * (max_nnzs - len(rows[rowidx]))
            offset += nnz

        indexes = torch.tensor(rows).to(self.device)

        # Index with the 2D indexes
        scores_2d = flat_scores[indexes]

        return scores_2d

    def _2d_index(self, embeddings, positions):
        bsize, maxlen, hdim = embeddings.size()
        bsize_, max_out = positions.size()

        assert bsize == bsize_
        assert positions.max() < maxlen

        embeddings = embeddings.view(bsize * maxlen, hdim)
        positions = positions + torch.arange(bsize, device=positions.device).unsqueeze(-1) * maxlen

        return embeddings[positions]