| import torch.nn as nn |
| from transformers import BertModel |
| from .config import * |
| import torch |
| import torch.nn.functional as F |
|
|
| |
| from transformers import logging |
| logging.set_verbosity_error() |
|
|
|
|
| class CasRel(nn.Module): |
|
|
| |
| def __init__(self): |
| super().__init__() |
| self.bert = BertModel.from_pretrained(BERT_MODEL_NAME) |
| |
| for name, param in self.bert.named_parameters(): |
| param.requires_grad = False |
|
|
| |
| self.sub_head_linear = nn.Linear(BERT_DIM, 1) |
| self.sub_tail_linear = nn.Linear(BERT_DIM, 1) |
|
|
| self.obj_head_linear = nn.Linear(BERT_DIM, REL_SIZE) |
| self.obj_tail_linear = nn.Linear(BERT_DIM, REL_SIZE) |
|
|
|
|
| |
| def get_encoded_text(self, input_ids, mask): |
| return self.bert(input_ids, attention_mask=mask)[0] |
|
|
| def get_subs(self, encoded_text): |
| |
| |
| pred_sub_head = torch.sigmoid(self.sub_head_linear(encoded_text)) |
| pred_sub_tail = torch.sigmoid(self.sub_tail_linear(encoded_text)) |
|
|
| return pred_sub_head, pred_sub_tail |
|
|
| def get_objs_for_specific_sub(self, encoded_text, sub_head_seq, sub_tail_seq): |
| |
| sub_head_seq = sub_head_seq.unsqueeze(1).float() |
| sub_tail_seq = sub_tail_seq.unsqueeze(1).float() |
|
|
| |
| sub_head = torch.matmul(sub_head_seq, encoded_text) |
| sub_tail = torch.matmul(sub_tail_seq, encoded_text) |
|
|
| encoded_text = encoded_text + (sub_head + sub_tail) / 2 |
|
|
| |
| pred_obj_head = torch.sigmoid(self.obj_head_linear(encoded_text)) |
| pred_obj_tail = torch.sigmoid(self.obj_tail_linear(encoded_text)) |
|
|
| |
| return pred_obj_head, pred_obj_tail |
|
|
| def forward(self, input, mask): |
|
|
| input_ids, sub_head_seq, sub_tail_seq = input |
| encoded_text = self.get_encoded_text(input_ids, mask) |
| pred_sub_head, pred_sub_tail = self.get_subs(encoded_text) |
|
|
|
|
| input_ids, sub_head_seq, sub_tail_seq = input |
| encoded_text = self.get_encoded_text(input_ids, mask) |
|
|
| |
| pred_sub_head, pred_sub_tail = self.get_subs(encoded_text) |
|
|
| |
| pred_obj_head, pred_obj_tail = self.get_objs_for_specific_sub(encoded_text, sub_head_seq, sub_tail_seq) |
|
|
| return encoded_text, (pred_sub_head, pred_sub_tail, pred_obj_head, pred_obj_tail) |
|
|
| def loss_fn(self, true_y, pred_y, mask): |
|
|
| def calc_loss(pred, true, mask): |
| true = true.float() |
|
|
| |
| pred = pred.squeeze(-1) |
| weight = torch.where(true > 0, CLS_WEIGHT_COEF[1], CLS_WEIGHT_COEF[0]) |
|
|
|
|
| loss = F.binary_cross_entropy(pred, true, weight=weight, reduction='none') |
|
|
|
|
| if loss.shape != mask.shape: |
| mask = mask.unsqueeze(-1) |
|
|
| return torch.sum(loss * mask) / torch.sum(mask) |
|
|
| pred_sub_head, pred_sub_tail, pred_obj_head, pred_obj_tail = pred_y |
| true_sub_head, true_sub_tail, true_obj_head, true_obj_tail = true_y |
|
|
|
|
| return calc_loss(pred_sub_head, true_sub_head, mask) * SUB_WEIGHT_COEF + \ |
| calc_loss(pred_sub_tail, true_sub_tail, mask) * SUB_WEIGHT_COEF + \ |
| calc_loss(pred_obj_head, true_obj_head, mask) + \ |
| calc_loss(pred_obj_tail, true_obj_tail, mask) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|