| import torch |
| import torch.nn as nn |
| from torch import Tensor |
| from typing import Optional, Tuple, Any |
|
|
| class QAHead(nn.Module): |
| """ |
| Extractive QA head to predict start and end token positions. |
| """ |
| def __init__(self, d_model: int): |
| super().__init__() |
| |
| self.qa_outputs = nn.Linear(d_model, 2) |
|
|
| def forward( |
| self, |
| hidden_states: Tensor, |
| context_start: Optional[Any] = None, |
| ) -> Tuple[Tensor, Tensor]: |
| logits = self.qa_outputs(hidden_states) |
| start_logits, end_logits = logits.split(1, dim=-1) |
| start_logits = start_logits.squeeze(-1).clone() |
| end_logits = end_logits.squeeze(-1).clone() |
|
|
| |
| if context_start is not None: |
| mask_val = torch.finfo(start_logits.dtype).min |
| if isinstance(context_start, torch.Tensor): |
| B, T = start_logits.shape |
| |
| |
| ctx_start = context_start.to(start_logits.device) |
| rng = torch.arange(T, device=start_logits.device).unsqueeze(0) |
| mask = rng < ctx_start.unsqueeze(1) |
| start_logits = start_logits.masked_fill(mask, mask_val) |
| end_logits = end_logits.masked_fill(mask, mask_val) |
| else: |
| start_logits[:, :context_start] = mask_val |
| end_logits [:, :context_start] = mask_val |
|
|
| return start_logits, end_logits |
|
|