Pytorch - Как добавить внимания к другой архитектуре - PullRequest
0 голосов
/ 05 мая 2020

Я новичок во фреймворке pytorch и пытаюсь добавить многоголовое внимание к себе поверх другой архитектуры (BERT) (это простой вопрос, но я не знаком с PyTorch):

ОБНОВЛЕНИЕ 1

import math
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)
        self.d_model = d_model

        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)

    def forward(self, x, seq_len = 768, mask = None):
        pos_emb = self.pe[:, :seq_len]
        x = x * mask[:, :, None].float()
        x = x + pos_emb
        return x

Проблема в том, как добавить трансформатор, находится в следующем классе:

class CamemBERTQA(nn.Module):
   def __init__(self,bert_type, hidden_size, num_labels, num_inter_layers=1, heads = 12, do_lower_case = True):
       super(CamemBERTQA, self).__init__()
       self.do_lower_case = do_lower_case
       self.bert_type = bert_type
       self.hidden_size = hidden_size
       self.num_labels = num_labels       
       self.num_inter_layers = num_inter_layers
       self.camembert = CamembertModel.from_pretrained(self.bert_type)

       # ---------------- Transformer ------------------------------------------
       self.d_model = self.hidden_size # 768
       dropout = 0.1
       self.pos_emb = PositionalEncoding(d_model = self.d_model, dropout = dropout)
       self.transformer_inter = nn.ModuleList(
           [nn.TransformerEncoderLayer(d_model = self.d_model, nhead = heads, dim_feedforward = 2048, dropout = dropout)
            for _ in range(num_inter_layers)])
       # ---------------- Transformer ------------------------------------------

       self.qa_outputs = nn.Linear(self.hidden_size, self.num_labels)



   def forward(self, input_ids, mask=None):
       bert_output = self.camembert(input_ids = input_ids) # input_ids is a tensor

       # ---------------- Transformer ------------------------------------------
       seq_len = self.hidden_size
       x = self.pos_emb(x = bert_output, seq_len = seq_len, mask = None)

       for i in range(self.num_inter_layers):
           x = self.transformer_inter[i](i, x, x, 1 - mask)  # all_tokens * max_tokens * dim
       output = self.layer_norm(x)
       # ---------------- Transformer ------------------------------------------

       sequence_output = output[0]
       logits = self.qa_outputs(sequence_output)
       start_logits, end_logits = logits.split(1, dim=-1)
       start_logits = start_logits.squeeze(-1)
       end_logits = end_logits.squeeze(-1)
       outputs = (start_logits, end_logits,)
       return x

Большое спасибо.

1 Ответ

0 голосов
/ 07 мая 2020

Похоже, вы пытаетесь добавить сеть Transformer поверх компонента BERT. Следует отметить, что сеть самовнимания - это только a часть сети трансформатора, а это означает, что у трансформаторов есть и другие компоненты, помимо самовнимания. Я бы рекомендовал использовать Transformer (в который включен компонент самовнимания) в качестве кодировщика, который получает векторы BERT и преобразует их в другое представление (в другом пространстве).

Попробуйте это вместо self.attention = MultiHeadAttention():

self.transformer_inter = nn.ModuleList(
            [TransformerEncoderLayer(d_model, heads, d_ff, dropout)
             for _ in range(num_inter_layers)])

, а затем в forward() вызовите self.transformer_inter через al oop, который предоставит вам представления, созданные архитектурой Transformer. Примерно так:

def forward(self, bert_output, mask):

    batch_size, seq_len = bert_output.size(0), bert_output.size(1)

    # Transformer Encoder
    pos_emb = self.pos_emb.pe[:, :seq_len]
    x = bert_output * mask[:, :, None].float()
    x = x + pos_emb

    for i in range(self.num_inter_layers):
        x = self.transformer_inter[i](i, x, x, 1 - mask)  # all_tokens * max_tokens * dim
    x = self.layer_norm(x) # Transformer also normalizes the outputs from each layer.

    # x is the encoded vectors by Transformer encoder

    return x

Затем, используя слой nn.Linear(.), выполните другое преобразование, чтобы сопоставить hidden_size количеству меток для вашей задачи, что даст вам логиты для каждой метки. Все это должно быть выполнено в классе BERT, который вы опубликовали.

Обратите внимание на , что TransformerEncoderLayer - это класс-заполнитель, который я использовал выше. Поэтому вам нужно либо реализовать его, либо использовать пакеты с открытым исходным кодом. Поскольку «Трансформеры» довольно хорошо известны, я думаю, у вас не возникнет проблем с их реализацией.

...