Download model.py from MannyLM/Synapse-V1: direct link, hf CLI and curl.
- Browser
- Download file 4.49 kB
-
https://huggingface.co/MannyLM/Synapse-V1/resolve/main/model.py
- Command line
-
hf download hf://MannyLM/Synapse-V1/model.py
-
curl -L -o model.py https://huggingface.co/MannyLM/Synapse-V1/resolve/main/model.py
4.49 kB
| from torch import nn | |
| import torch | |
| import math | |
| class MultiHeadAttention(nn.Module): | |
| def __init__(self, d_model, num_heads): | |
| super().__init__() | |
| assert d_model % num_heads == 0, \ | |
| "d_model must be divisible by num_heads" | |
| self.d_model = d_model | |
| self.num_heads = num_heads | |
| self.d_head = d_model // num_heads | |
| self.q_proj = nn.Linear(d_model, d_model) | |
| self.k_proj = nn.Linear(d_model, d_model) | |
| self.v_proj = nn.Linear(d_model, d_model) | |
| self.o_proj = nn.Linear(d_model, d_model) | |
| def forward(self, X): | |
| Q = self.q_proj(X) | |
| K = self.k_proj(X) | |
| V = self.v_proj(X) | |
| batch, sequence, _ = X.shape | |
| Q = Q.reshape( | |
| batch, | |
| sequence, | |
| self.num_heads, | |
| self.d_head | |
| ) | |
| K = K.reshape( | |
| batch, | |
| sequence, | |
| self.num_heads, | |
| self.d_head | |
| ) | |
| V = V.reshape( | |
| batch, | |
| sequence, | |
| self.num_heads, | |
| self.d_head | |
| ) | |
| Q = Q.transpose(1, 2) | |
| K = K.transpose(1, 2) | |
| V = V.transpose(1, 2) | |
| scores = torch.matmul( | |
| Q, | |
| K.transpose(-2, -1) | |
| ) | |
| scaled_scores = scores / math.sqrt(self.d_head) | |
| mask = torch.tril( | |
| torch.ones( | |
| sequence, | |
| sequence, | |
| device=X.device, | |
| dtype=torch.bool | |
| ) | |
| ) | |
| masked_scores = scaled_scores.masked_fill( | |
| ~mask, | |
| -math.inf | |
| ) | |
| attention_weights = torch.softmax( | |
| masked_scores, | |
| dim=-1 | |
| ) | |
| attention_output = torch.matmul( | |
| attention_weights, | |
| V | |
| ) | |
| attention_output = attention_output.transpose(1, 2) | |
| attention_output = attention_output.reshape( | |
| batch, | |
| sequence, | |
| self.d_model | |
| ) | |
| attention_output = self.o_proj(attention_output) | |
| return attention_output | |
| class FeedForwardNetwork(nn.Module): | |
| def __init__(self, d_model, d_ff): | |
| super().__init__() | |
| self.linear1 = nn.Linear(d_model, d_ff) | |
| self.linear2 = nn.Linear(d_ff, d_model) | |
| def forward(self, x): | |
| x = self.linear1(x) | |
| x = torch.relu(x) | |
| x = self.linear2(x) | |
| return x | |
| class TransformerBlock(nn.Module): | |
| def __init__(self, d_model, num_heads, d_ff): | |
| super().__init__() | |
| self.ln1 = nn.LayerNorm(d_model) | |
| self.attention = MultiHeadAttention( | |
| d_model, | |
| num_heads | |
| ) | |
| self.ln2 = nn.LayerNorm(d_model) | |
| self.ffn = FeedForwardNetwork( | |
| d_model, | |
| d_ff | |
| ) | |
| def forward(self, x): | |
| x_norm = self.ln1(x) | |
| x = x + self.attention(x_norm) | |
| x_norm = self.ln2(x) | |
| x = x + self.ffn(x_norm) | |
| return x | |
| class Transformer(nn.Module): | |
| def __init__( | |
| self, | |
| vocab_size, | |
| max_sequence_length, | |
| d_model, | |
| num_heads, | |
| d_ff, | |
| num_layers | |
| ): | |
| super().__init__() | |
| self.vocab_size = vocab_size | |
| self.max_sequence_length = max_sequence_length | |
| self.d_model = d_model | |
| self.token_embedding = nn.Embedding( | |
| vocab_size, | |
| d_model | |
| ) | |
| self.position_embedding = nn.Embedding( | |
| max_sequence_length, | |
| d_model | |
| ) | |
| self.blocks = nn.ModuleList([ | |
| TransformerBlock( | |
| d_model, | |
| num_heads, | |
| d_ff | |
| ) | |
| for _ in range(num_layers) | |
| ]) | |
| self.final_ln = nn.LayerNorm(d_model) | |
| self.lm_head = nn.Linear( | |
| d_model, | |
| vocab_size | |
| ) | |
| def forward(self, x): | |
| _, sequence = x.shape | |
| assert sequence <= self.max_sequence_length, \ | |
| "Sequence length exceeds max_sequence_length" | |
| token_embeddings = self.token_embedding(x) | |
| positions = torch.arange( | |
| sequence, | |
| device=x.device | |
| ) | |
| position_embeddings = self.position_embedding( | |
| positions | |
| ) | |
| x = token_embeddings + position_embeddings | |
| for block in self.blocks: | |
| x = block(x) | |
| x = self.final_ln(x) | |
| logits = self.lm_head(x) | |
| return logits |