Download code/decision_lab/models/scratch_transformer.py from axondendriteplus/decipop-v7-r2-multi-entity: direct link, hf CLI and curl.
- Browser
- Download file 3.57 kB
-
https://huggingface.co/axondendriteplus/decipop-v7-r2-multi-entity/resolve/main/code/decision_lab/models/scratch_transformer.py
- Command line
-
hf download hf://axondendriteplus/decipop-v7-r2-multi-entity/code/decision_lab/models/scratch_transformer.py
-
curl -L -o scratch_transformer.py https://huggingface.co/axondendriteplus/decipop-v7-r2-multi-entity/resolve/main/code/decision_lab/models/scratch_transformer.py
3.57 kB
| import torch | |
| from torch import nn | |
| from torch.nn import functional as F | |
| from decision_lab.model_config import ScratchConfig | |
| class Attention(nn.Module): | |
| def __init__(self, config: ScratchConfig): | |
| super().__init__() | |
| self.heads = config.heads | |
| self.head_size = config.hidden_size // config.heads | |
| self.dropout = config.dropout | |
| self.qkv = nn.Linear(config.hidden_size, 3 * config.hidden_size) | |
| self.output = nn.Linear(config.hidden_size, config.hidden_size) | |
| def forward(self, hidden, attention_mask): | |
| batch, length, width = hidden.shape | |
| qkv = self.qkv(hidden).view(batch, length, 3, self.heads, self.head_size) | |
| query, key, value = qkv.permute(2, 0, 3, 1, 4).unbind(0) | |
| attended = F.scaled_dot_product_attention( | |
| query, | |
| key, | |
| value, | |
| attn_mask=attention_mask[:, None, None, :].bool(), | |
| dropout_p=self.dropout if self.training else 0.0, | |
| ) | |
| return self.output(attended.transpose(1, 2).reshape(batch, length, width)) | |
| class Block(nn.Module): | |
| def __init__(self, config: ScratchConfig): | |
| super().__init__() | |
| self.attention_norm = nn.LayerNorm(config.hidden_size) | |
| self.attention = Attention(config) | |
| self.feedforward_norm = nn.LayerNorm(config.hidden_size) | |
| self.feedforward = nn.Sequential( | |
| nn.Linear(config.hidden_size, config.intermediate_size), | |
| nn.GELU(), | |
| nn.Dropout(config.dropout), | |
| nn.Linear(config.intermediate_size, config.hidden_size), | |
| ) | |
| self.dropout = nn.Dropout(config.dropout) | |
| def forward(self, hidden, attention_mask): | |
| hidden = hidden + self.dropout(self.attention(self.attention_norm(hidden), attention_mask)) | |
| return hidden + self.dropout(self.feedforward(self.feedforward_norm(hidden))) | |
| class ScratchDecisionModel(nn.Module): | |
| def __init__(self, config: ScratchConfig): | |
| super().__init__() | |
| self.config = config | |
| self.tokens = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_id) | |
| self.positions = nn.Embedding(config.max_length, config.hidden_size) | |
| self.blocks = nn.ModuleList(Block(config) for _ in range(config.layers)) | |
| self.final_norm = nn.LayerNorm(config.hidden_size) | |
| self.head = nn.Linear(config.hidden_size, config.classes) | |
| self.apply(self.initialize) | |
| with torch.no_grad(): | |
| self.tokens.weight[config.pad_id].zero_() | |
| def initialize(self, module): | |
| if isinstance(module, (nn.Linear, nn.Embedding)): | |
| nn.init.normal_(module.weight, std=self.config.initializer_std) | |
| if isinstance(module, nn.Linear) and module.bias is not None: | |
| nn.init.zeros_(module.bias) | |
| def forward(self, input_ids, attention_mask): | |
| length = input_ids.shape[1] | |
| if length > self.config.max_length: | |
| raise ValueError("Input exceeds scratch model's position limit") | |
| if not torch.all(attention_mask[:, 0]): | |
| raise ValueError("The first decision token cannot be padding") | |
| positions = torch.arange(length, device=input_ids.device) | |
| hidden = self.tokens(input_ids) + self.positions(positions) | |
| for block in self.blocks: | |
| hidden = block(hidden, attention_mask) | |
| return self.head(self.final_norm(hidden[:, 0])) | |
| def loss(self, logits, labels): | |
| return F.cross_entropy(logits.float(), labels) | |
| def class_logits(self, logits): | |
| return logits | |