| import torch |
| import torch.nn as nn |
|
|
| class GatedAlteredResidualBlock(nn.Module): |
| def __init__(self, dim, dropout=0.1): |
| super(GatedAlteredResidualBlock, self).__init__() |
| self.norm = nn.LayerNorm(dim) |
| self.attn = nn.MultiheadAttention(embed_dim=dim, num_heads=8, batch_first=False) |
| self.dropout = nn.Dropout(dropout) |
| self.gate_linear = nn.Linear(dim, dim) |
|
|
| def forward(self, q, k, v): |
| attn_output, _ = self.attn(q, k, v) |
| attn_output = self.dropout(attn_output) |
| gate = torch.sigmoid(self.gate_linear(q)) |
| out = gate * attn_output + (1 - gate) * q |
| return self.norm(out) |
|
|
|
|
| class StackedGatedResidualBlock(nn.Module): |
| def __init__(self, dim, depth=4, dropout=0.1): |
| super(StackedGatedResidualBlock, self).__init__() |
| self.blocks = nn.ModuleList([ |
| GatedAlteredResidualBlock(dim=dim, dropout=dropout) |
| for _ in range(depth) |
| ]) |
|
|
| def forward(self, q, k=None, v=None): |
| """ |
| Permite q = k = v, mas também aceita entrada personalizada. |
| |
| Args: |
| q (Tensor): Query, formato (seq_len, batch, dim) |
| k (Tensor): Key (opcional, default=q) |
| v (Tensor): Value (opcional, default=q) |
| """ |
| if k is None: k = q |
| if v is None: v = q |
|
|
| for block in self.blocks: |
| q = block(q, k, v) |
| return q |
|
|