Text Generation
Transformers
Safetensors
domynedge
domyn
domyn-edge
long-context
agentic
fully-open
custom_code
Instructions to use domyn/Domyn-Edge-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use domyn/Domyn-Edge-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="domyn/Domyn-Edge-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("domyn/Domyn-Edge-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use domyn/Domyn-Edge-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "domyn/Domyn-Edge-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "domyn/Domyn-Edge-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/domyn/Domyn-Edge-Base
- SGLang
How to use domyn/Domyn-Edge-Base with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "domyn/Domyn-Edge-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "domyn/Domyn-Edge-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "domyn/Domyn-Edge-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "domyn/Domyn-Edge-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use domyn/Domyn-Edge-Base with Docker Model Runner:
docker model run hf.co/domyn/Domyn-Edge-Base
Sync modeling_domynedge.py, configuration_domynedge.py from domyn-forge@9b691e2
Browse files- configuration_domynedge.py +49 -18
- modeling_domynedge.py +158 -67
configuration_domynedge.py
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import transformers
|
| 2 |
|
| 3 |
-
|
|
|
|
| 4 |
def __init__(
|
| 5 |
self,
|
| 6 |
rope_type: str = "default",
|
|
@@ -9,10 +13,18 @@ class RopeParameters():
|
|
| 9 |
self.rope_type = rope_type
|
| 10 |
self.rope_theta = rope_theta
|
| 11 |
|
|
|
|
| 12 |
# to support both transformers > 5 and older
|
| 13 |
-
PretrainedConfig =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
class DomynEdgeConfig(PretrainedConfig):
|
|
|
|
|
|
|
| 16 |
model_type: str = "domynedge"
|
| 17 |
|
| 18 |
def __init__(
|
|
@@ -26,6 +38,7 @@ class DomynEdgeConfig(PretrainedConfig):
|
|
| 26 |
max_position_embeddings: int = 8192,
|
| 27 |
initializer_range: float = 0.02,
|
| 28 |
rms_norm_eps: float = 1e-6,
|
|
|
|
| 29 |
use_cache: bool = True,
|
| 30 |
tie_word_embeddings: bool = True,
|
| 31 |
rope_parameters: RopeParameters | None = None,
|
|
@@ -33,13 +46,16 @@ class DomynEdgeConfig(PretrainedConfig):
|
|
| 33 |
attention_bias: bool = False,
|
| 34 |
attention_dropout: float = 0.0,
|
| 35 |
position_layers: list[str] = ["nope", "nope"] + ["rope", "rope", "rope", "nope"] * 8 + ["nope", "nope"],
|
| 36 |
-
window_sizes: list[tuple[int,int]] = [(-1,
|
| 37 |
-
|
|
|
|
|
|
|
| 38 |
pad_token_id: int | None = None,
|
| 39 |
bos_token_id: int | None = None,
|
| 40 |
eos_token_id: int | None = None,
|
| 41 |
**kwargs,
|
| 42 |
):
|
|
|
|
| 43 |
self.vocab_size = vocab_size
|
| 44 |
self.max_position_embeddings = max_position_embeddings
|
| 45 |
self.hidden_size = hidden_size
|
|
@@ -58,35 +74,50 @@ class DomynEdgeConfig(PretrainedConfig):
|
|
| 58 |
self.use_cache = use_cache
|
| 59 |
self.attention_bias = attention_bias
|
| 60 |
self.attention_dropout = attention_dropout
|
| 61 |
-
|
| 62 |
self.position_layers = position_layers
|
| 63 |
self.window_sizes = window_sizes
|
| 64 |
self.head_sizes = head_sizes
|
| 65 |
|
| 66 |
-
#
|
| 67 |
if len(self.position_layers) != self.num_hidden_layers:
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
if any(pl not in ["rope", "nope"] for pl in self.position_layers):
|
| 70 |
-
|
| 71 |
-
|
|
|
|
| 72 |
if len(self.window_sizes) != self.num_hidden_layers:
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
if len(head_sizes) != self.num_hidden_layers:
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
if any(not isinstance(hs, int) for hs in head_sizes):
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
| 81 |
if len(set(rope_dims)) > 1:
|
| 82 |
-
|
|
|
|
| 83 |
self.rope_dim = rope_dims[0]
|
| 84 |
|
| 85 |
# Set default rope_parameters if not provided
|
| 86 |
if rope_parameters is None:
|
| 87 |
self.rope_parameters = RopeParameters(
|
| 88 |
-
rope_type
|
| 89 |
-
rope_theta
|
| 90 |
)
|
| 91 |
|
| 92 |
self.pad_token_id = pad_token_id
|
|
|
|
| 1 |
+
# SPDX-FileCopyrightText: 2026 Domyn
|
| 2 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
+
|
| 4 |
import transformers
|
| 5 |
|
| 6 |
+
|
| 7 |
+
class RopeParameters:
|
| 8 |
def __init__(
|
| 9 |
self,
|
| 10 |
rope_type: str = "default",
|
|
|
|
| 13 |
self.rope_type = rope_type
|
| 14 |
self.rope_theta = rope_theta
|
| 15 |
|
| 16 |
+
|
| 17 |
# to support both transformers > 5 and older
|
| 18 |
+
PretrainedConfig = (
|
| 19 |
+
transformers.modeling_utils.PreTrainedConfig
|
| 20 |
+
if hasattr(transformers.modeling_utils, "PreTrainedConfig")
|
| 21 |
+
else transformers.configuration_utils.PretrainedConfig
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
|
| 25 |
class DomynEdgeConfig(PretrainedConfig):
|
| 26 |
+
"""Configuration of a DomynEdge model, with per-layer position encoding, sliding window and head size."""
|
| 27 |
+
|
| 28 |
model_type: str = "domynedge"
|
| 29 |
|
| 30 |
def __init__(
|
|
|
|
| 38 |
max_position_embeddings: int = 8192,
|
| 39 |
initializer_range: float = 0.02,
|
| 40 |
rms_norm_eps: float = 1e-6,
|
| 41 |
+
*,
|
| 42 |
use_cache: bool = True,
|
| 43 |
tie_word_embeddings: bool = True,
|
| 44 |
rope_parameters: RopeParameters | None = None,
|
|
|
|
| 46 |
attention_bias: bool = False,
|
| 47 |
attention_dropout: float = 0.0,
|
| 48 |
position_layers: list[str] = ["nope", "nope"] + ["rope", "rope", "rope", "nope"] * 8 + ["nope", "nope"],
|
| 49 |
+
window_sizes: list[tuple[int, int]] = [(-1, 0), (-1, 0)]
|
| 50 |
+
+ [(1024, 0), (1024, 0), (1024, 0), (-1, 0)] * 8
|
| 51 |
+
+ [(-1, 0), (-1, 0)],
|
| 52 |
+
head_sizes: list[int] = [256, 256] + [64, 64, 64, 256] * 8 + [256, 256],
|
| 53 |
pad_token_id: int | None = None,
|
| 54 |
bos_token_id: int | None = None,
|
| 55 |
eos_token_id: int | None = None,
|
| 56 |
**kwargs,
|
| 57 |
):
|
| 58 |
+
"""Initialize and validate the per-layer settings, which must all have `num_hidden_layers` entries."""
|
| 59 |
self.vocab_size = vocab_size
|
| 60 |
self.max_position_embeddings = max_position_embeddings
|
| 61 |
self.hidden_size = hidden_size
|
|
|
|
| 74 |
self.use_cache = use_cache
|
| 75 |
self.attention_bias = attention_bias
|
| 76 |
self.attention_dropout = attention_dropout
|
| 77 |
+
|
| 78 |
self.position_layers = position_layers
|
| 79 |
self.window_sizes = window_sizes
|
| 80 |
self.head_sizes = head_sizes
|
| 81 |
|
| 82 |
+
# Validate position_layers
|
| 83 |
if len(self.position_layers) != self.num_hidden_layers:
|
| 84 |
+
msg = (
|
| 85 |
+
f"Length of position_layers ({len(self.position_layers)}) "
|
| 86 |
+
f"must be equal to num_hidden_layers ({self.num_hidden_layers})"
|
| 87 |
+
)
|
| 88 |
+
raise ValueError(msg)
|
| 89 |
if any(pl not in ["rope", "nope"] for pl in self.position_layers):
|
| 90 |
+
msg = f"position_layers must be one of 'rope', 'nope'. Got {self.position_layers}"
|
| 91 |
+
raise ValueError(msg)
|
| 92 |
+
# Validate window_sizes
|
| 93 |
if len(self.window_sizes) != self.num_hidden_layers:
|
| 94 |
+
msg = (
|
| 95 |
+
f"Length of window_sizes ({len(self.window_sizes)}) "
|
| 96 |
+
f"must be equal to num_hidden_layers ({self.num_hidden_layers})"
|
| 97 |
+
)
|
| 98 |
+
raise ValueError(msg)
|
| 99 |
+
# Validate head_sizes
|
| 100 |
if len(head_sizes) != self.num_hidden_layers:
|
| 101 |
+
msg = (
|
| 102 |
+
f"Length of head_sizes ({len(head_sizes)}) "
|
| 103 |
+
f"must be equal to num_hidden_layers ({self.num_hidden_layers})"
|
| 104 |
+
)
|
| 105 |
+
raise ValueError(msg)
|
| 106 |
if any(not isinstance(hs, int) for hs in head_sizes):
|
| 107 |
+
msg = f"head_sizes must be a list of integers. Got {head_sizes}"
|
| 108 |
+
raise ValueError(msg)
|
| 109 |
+
# Only one rope dim
|
| 110 |
+
rope_dims = [head_size for rope, head_size in zip(position_layers, head_sizes, strict=True) if rope == "rope"]
|
| 111 |
if len(set(rope_dims)) > 1:
|
| 112 |
+
msg = f"All rope layers must have the same head size. Got {rope_dims}"
|
| 113 |
+
raise ValueError(msg)
|
| 114 |
self.rope_dim = rope_dims[0]
|
| 115 |
|
| 116 |
# Set default rope_parameters if not provided
|
| 117 |
if rope_parameters is None:
|
| 118 |
self.rope_parameters = RopeParameters(
|
| 119 |
+
rope_type="default",
|
| 120 |
+
rope_theta=10_000,
|
| 121 |
)
|
| 122 |
|
| 123 |
self.pad_token_id = pad_token_id
|
modeling_domynedge.py
CHANGED
|
@@ -1,13 +1,59 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
import dataclasses
|
| 8 |
-
import einops
|
| 9 |
import typing
|
|
|
|
|
|
|
| 10 |
import torch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
@dataclasses.dataclass
|
| 13 |
class VarlenMetadataMask:
|
|
@@ -16,17 +62,18 @@ class VarlenMetadataMask:
|
|
| 16 |
max_q: int
|
| 17 |
max_k: int
|
| 18 |
|
|
|
|
| 19 |
class IndexFirstAxis(torch.autograd.Function):
|
| 20 |
-
"""
|
| 21 |
|
| 22 |
@staticmethod
|
| 23 |
-
def forward(ctx,
|
| 24 |
ctx.save_for_backward(indices)
|
| 25 |
-
assert
|
| 26 |
-
ctx.first_axis_dim, other_shape =
|
| 27 |
second_dim = other_shape.numel()
|
| 28 |
return torch.gather(
|
| 29 |
-
einops.rearrange(
|
| 30 |
).reshape(-1, *other_shape)
|
| 31 |
|
| 32 |
@staticmethod
|
|
@@ -43,17 +90,16 @@ class IndexFirstAxis(torch.autograd.Function):
|
|
| 43 |
grad_input.scatter_(0, einops.repeat(indices, "z -> z d", d=grad_output.shape[1]), grad_output)
|
| 44 |
return grad_input.reshape(ctx.first_axis_dim, *other_shape), None
|
| 45 |
|
|
|
|
| 46 |
class IndexPutFirstAxis(torch.autograd.Function):
|
| 47 |
-
"""
|
| 48 |
|
| 49 |
@staticmethod
|
| 50 |
def forward(ctx, values, indices, first_axis_dim):
|
| 51 |
ctx.save_for_backward(indices)
|
| 52 |
assert indices.ndim == 1
|
| 53 |
assert values.ndim >= 2
|
| 54 |
-
output = torch.zeros(
|
| 55 |
-
first_axis_dim, *values.shape[1:], device=values.device, dtype=values.dtype
|
| 56 |
-
)
|
| 57 |
output[indices] = values
|
| 58 |
return output
|
| 59 |
|
|
@@ -64,12 +110,15 @@ class IndexPutFirstAxis(torch.autograd.Function):
|
|
| 64 |
return grad_values, None, None
|
| 65 |
|
| 66 |
|
| 67 |
-
def unpad_input(
|
| 68 |
-
|
|
|
|
|
|
|
| 69 |
|
| 70 |
Arguments:
|
| 71 |
hidden_states: (batch, seqlen, ...)
|
| 72 |
attention_mask: (batch, seqlen), bool / int, 1 means valid and 0 means not valid.
|
|
|
|
| 73 |
Return:
|
| 74 |
hidden_states: (total_nnz, ...), where total_nnz = number of tokens selected in attention_mask + unused_mask.
|
| 75 |
indices: (total_nnz), the indices of masked tokens from the flattened input sequence.
|
|
@@ -88,14 +137,16 @@ def unpad_input(hidden_states: torch.Tensor, attention_mask: torch.Tensor) -> tu
|
|
| 88 |
max_seqlen,
|
| 89 |
)
|
| 90 |
|
|
|
|
| 91 |
def pad_input(hidden_states: torch.Tensor, indices: torch.Tensor, batch_size: int, seqlen: int) -> torch.Tensor:
|
| 92 |
-
"""
|
| 93 |
|
| 94 |
Arguments:
|
| 95 |
hidden_states: (total_nnz, ...), where total_nnz = number of tokens in selected in attention_mask.
|
| 96 |
indices: (total_nnz), the indices that represent the non-masked tokens of the original padded input sequence.
|
| 97 |
-
|
| 98 |
seqlen: int, maximum sequence length for the padded sequence.
|
|
|
|
| 99 |
Return:
|
| 100 |
hidden_states: (batch, seqlen, ...)
|
| 101 |
|
|
@@ -103,6 +154,7 @@ def pad_input(hidden_states: torch.Tensor, indices: torch.Tensor, batch_size: in
|
|
| 103 |
output = IndexPutFirstAxis.apply(hidden_states, indices, batch_size * seqlen)
|
| 104 |
return einops.rearrange(output, "(b s) ... -> b s ...", b=batch_size)
|
| 105 |
|
|
|
|
| 106 |
class DomynEdgeFeedForward(torch.nn.Module):
|
| 107 |
def __init__(self, config):
|
| 108 |
super().__init__()
|
|
@@ -116,6 +168,7 @@ class DomynEdgeFeedForward(torch.nn.Module):
|
|
| 116 |
def forward(self, x):
|
| 117 |
return self.down_proj(torch.nn.functional.silu(self.gate_proj(x)) * self.up_proj(x))
|
| 118 |
|
|
|
|
| 119 |
class DomynEdgeRotaryEmbedding(torch.nn.Module):
|
| 120 |
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 121 |
|
|
@@ -137,17 +190,15 @@ class DomynEdgeRotaryEmbedding(torch.nn.Module):
|
|
| 137 |
def compute_default_rope_parameters(
|
| 138 |
config: DomynEdgeConfig | None = None,
|
| 139 |
device: typing.Optional["torch.device"] = None,
|
| 140 |
-
seq_len: int | None = None,
|
| 141 |
) -> tuple["torch.Tensor", float]:
|
| 142 |
-
"""
|
| 143 |
-
|
| 144 |
Args:
|
| 145 |
config ([`~transformers.PreTrainedConfig`]):
|
| 146 |
The model configuration.
|
| 147 |
device (`torch.device`):
|
| 148 |
The device to use for initialization of the inverse frequencies.
|
| 149 |
-
|
| 150 |
-
The current sequence length. Unused for this type of RoPE.
|
| 151 |
Returns:
|
| 152 |
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 153 |
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
|
@@ -168,6 +219,11 @@ class DomynEdgeRotaryEmbedding(torch.nn.Module):
|
|
| 168 |
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 169 |
position_ids_expanded = position_ids[:, None, :].float()
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 172 |
emb = torch.cat((freqs, freqs), dim=-1)
|
| 173 |
cos = emb.cos() * self.attention_scaling
|
|
@@ -198,6 +254,7 @@ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
|
| 198 |
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 199 |
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 200 |
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
|
|
|
| 201 |
Returns:
|
| 202 |
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 203 |
"""
|
|
@@ -208,23 +265,36 @@ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
|
| 208 |
k_embed = (kf * cos) + (rotate_half(kf) * sin)
|
| 209 |
return q_embed.to(q.dtype), k_embed.to(k.dtype)
|
| 210 |
|
|
|
|
| 211 |
class DomynEdgeAttention(torch.nn.Module):
|
| 212 |
-
"""
|
| 213 |
|
| 214 |
def __init__(self, config: DomynEdgeConfig, layer_idx: int):
|
| 215 |
super().__init__()
|
| 216 |
self.config = config
|
| 217 |
self.head_dim = config.head_sizes[layer_idx]
|
| 218 |
-
self.scaling = self.head_dim
|
| 219 |
self.window_size = config.window_sizes[layer_idx]
|
| 220 |
-
self.apply_rope =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
self.layer_idx = layer_idx
|
| 222 |
self.enable_gqa = config.num_attention_heads > config.num_key_value_heads
|
| 223 |
|
| 224 |
-
self.q_proj = torch.nn.Linear(
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
self.q_norm = torch.nn.RMSNorm(self.head_dim, eps=config.rms_norm_eps, elementwise_affine=False)
|
| 229 |
self.k_norm = torch.nn.RMSNorm(self.head_dim, eps=config.rms_norm_eps, elementwise_affine=True)
|
| 230 |
|
|
@@ -234,13 +304,17 @@ class DomynEdgeAttention(torch.nn.Module):
|
|
| 234 |
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 235 |
attention_mask: torch.Tensor,
|
| 236 |
past_key_values: transformers.Cache | None = None,
|
| 237 |
-
**
|
| 238 |
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 239 |
|
| 240 |
-
batch_size, sequence_length,
|
| 241 |
|
| 242 |
-
q = self.q_norm(
|
| 243 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
v = self.v_proj(hidden_states).view(batch_size, sequence_length, self.config.num_key_value_heads, self.head_dim)
|
| 245 |
|
| 246 |
cos, sin = position_embeddings
|
|
@@ -252,33 +326,33 @@ class DomynEdgeAttention(torch.nn.Module):
|
|
| 252 |
k, v = k.transpose(1, 2), v.transpose(1, 2)
|
| 253 |
|
| 254 |
if q.size(1) > 1:
|
| 255 |
-
q, q_indices, q_cu_seqlen, q_maxseq = unpad_input(q, attention_mask)
|
| 256 |
else:
|
| 257 |
q_maxseq = 1
|
| 258 |
q_cu_seqlen = torch.arange(batch_size + 1, dtype=torch.int32, device=q.device)
|
| 259 |
q_indices = q_cu_seqlen[:-1]
|
| 260 |
-
q = q.squeeze(1)
|
| 261 |
|
| 262 |
-
k,
|
| 263 |
-
v,
|
| 264 |
|
| 265 |
attn_output = torch.nn.attention.varlen.varlen_attn(
|
| 266 |
q if q.dtype in [torch.float16, torch.bfloat16] else q.to(torch.bfloat16),
|
| 267 |
k if k.dtype in [torch.float16, torch.bfloat16] else k.to(torch.bfloat16),
|
| 268 |
v if v.dtype in [torch.float16, torch.bfloat16] else v.to(torch.bfloat16),
|
| 269 |
-
cu_seq_q
|
| 270 |
-
cu_seq_k
|
| 271 |
-
max_q
|
| 272 |
-
max_k
|
| 273 |
-
scale
|
| 274 |
-
window_size
|
| 275 |
-
enable_gqa
|
| 276 |
).to(q.dtype)
|
| 277 |
|
| 278 |
attn_output = pad_input(attn_output, q_indices, batch_size, sequence_length)
|
| 279 |
attn_output = attn_output.view(batch_size, sequence_length, self.config.num_attention_heads * self.head_dim)
|
| 280 |
-
|
| 281 |
-
|
| 282 |
|
| 283 |
class DomynEdgeDecoderLayer(torch.nn.Module):
|
| 284 |
def __init__(self, config: DomynEdgeConfig, layer_idx: int):
|
|
@@ -305,24 +379,21 @@ class DomynEdgeDecoderLayer(torch.nn.Module):
|
|
| 305 |
# Self Attention
|
| 306 |
hidden_states = hidden_states + self.post_attention_norm(
|
| 307 |
self.attention(
|
| 308 |
-
hidden_states
|
| 309 |
-
attention_mask
|
| 310 |
-
past_key_values
|
| 311 |
-
position_embeddings
|
| 312 |
**kwargs,
|
| 313 |
)
|
| 314 |
)
|
| 315 |
|
| 316 |
## Fully Connected
|
| 317 |
-
|
| 318 |
-
self.feedforward(
|
| 319 |
-
self.pre_feedforward_norm(hidden_states)
|
| 320 |
-
)
|
| 321 |
-
)
|
| 322 |
|
| 323 |
-
return hidden_states
|
| 324 |
|
| 325 |
class DomynEdgePreTrainedModel(transformers.PreTrainedModel):
|
|
|
|
|
|
|
| 326 |
config: DomynEdgeConfig
|
| 327 |
base_model_prefix = "model"
|
| 328 |
supports_gradient_checkpointing = False
|
|
@@ -338,13 +409,18 @@ class DomynEdgePreTrainedModel(transformers.PreTrainedModel):
|
|
| 338 |
|
| 339 |
|
| 340 |
class DomynEdgeModel(DomynEdgePreTrainedModel):
|
|
|
|
|
|
|
| 341 |
def __init__(self, config: DomynEdgeConfig):
|
|
|
|
| 342 |
super().__init__(config)
|
| 343 |
self.padding_idx = config.pad_token_id
|
| 344 |
self.vocab_size = config.vocab_size
|
| 345 |
|
| 346 |
self.embed_tokens = torch.nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 347 |
-
self.layers = torch.nn.ModuleList(
|
|
|
|
|
|
|
| 348 |
self.norm = torch.nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 349 |
self.rotary_emb = DomynEdgeRotaryEmbedding(config=config)
|
| 350 |
|
|
@@ -361,9 +437,10 @@ class DomynEdgeModel(DomynEdgePreTrainedModel):
|
|
| 361 |
use_cache: bool | None = None,
|
| 362 |
**kwargs,
|
| 363 |
) -> transformers.modeling_outputs.BaseModelOutputWithPast:
|
| 364 |
-
|
| 365 |
if input_ids is not None and inputs_embeds is not None:
|
| 366 |
-
|
|
|
|
| 367 |
|
| 368 |
if inputs_embeds is None:
|
| 369 |
inputs_embeds = self.embed_tokens(input_ids)
|
|
@@ -371,8 +448,9 @@ class DomynEdgeModel(DomynEdgePreTrainedModel):
|
|
| 371 |
if use_cache and past_key_values is None:
|
| 372 |
past_key_values = transformers.DynamicCache(config=self.config)
|
| 373 |
|
|
|
|
|
|
|
| 374 |
if position_ids is None:
|
| 375 |
-
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 376 |
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 377 |
position_ids = position_ids.unsqueeze(0)
|
| 378 |
|
|
@@ -380,7 +458,11 @@ class DomynEdgeModel(DomynEdgePreTrainedModel):
|
|
| 380 |
position_embeddings = self.rotary_emb(hidden_states, position_ids)
|
| 381 |
|
| 382 |
if attention_mask is None:
|
| 383 |
-
attention_mask = torch.ones(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 384 |
|
| 385 |
for decoder_layer in self.layers:
|
| 386 |
hidden_states = decoder_layer(
|
|
@@ -397,10 +479,14 @@ class DomynEdgeModel(DomynEdgePreTrainedModel):
|
|
| 397 |
past_key_values=past_key_values if use_cache else None,
|
| 398 |
)
|
| 399 |
|
|
|
|
| 400 |
class DomynEdgeForCausalLM(DomynEdgePreTrainedModel, transformers.GenerationMixin):
|
|
|
|
|
|
|
| 401 |
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 402 |
|
| 403 |
def __init__(self, config):
|
|
|
|
| 404 |
super().__init__(config)
|
| 405 |
self.model = DomynEdgeModel(config)
|
| 406 |
self.vocab_size = config.vocab_size
|
|
@@ -419,9 +505,9 @@ class DomynEdgeForCausalLM(DomynEdgePreTrainedModel, transformers.GenerationMixi
|
|
| 419 |
labels: torch.LongTensor | None = None,
|
| 420 |
use_cache: bool | None = None,
|
| 421 |
logits_to_keep: int | torch.Tensor = 0,
|
| 422 |
-
**kwargs
|
| 423 |
) -> transformers.modeling_outputs.CausalLMOutputWithPast:
|
| 424 |
-
|
| 425 |
outputs = self.model(
|
| 426 |
input_ids=input_ids,
|
| 427 |
attention_mask=attention_mask,
|
|
@@ -436,7 +522,11 @@ class DomynEdgeForCausalLM(DomynEdgePreTrainedModel, transformers.GenerationMixi
|
|
| 436 |
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 437 |
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 438 |
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 439 |
-
loss =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
|
| 441 |
return transformers.modeling_outputs.CausalLMOutputWithPast(
|
| 442 |
loss=loss,
|
|
@@ -446,6 +536,7 @@ class DomynEdgeForCausalLM(DomynEdgePreTrainedModel, transformers.GenerationMixi
|
|
| 446 |
attentions=outputs.attentions,
|
| 447 |
)
|
| 448 |
|
|
|
|
| 449 |
__all__ = [
|
| 450 |
"DomynEdgeForCausalLM",
|
| 451 |
"DomynEdgeModel",
|
|
|
|
| 1 |
+
# SPDX-FileCopyrightText: 2026 Domyn
|
| 2 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
+
#
|
| 4 |
+
# This file includes third-party code:
|
| 5 |
+
#
|
| 6 |
+
# - `IndexFirstAxis`, `IndexPutFirstAxis`, `unpad_input` and `pad_input` are adapted from
|
| 7 |
+
# https://github.com/Dao-AILab/flash-attention/blob/main/flash_attn/bert_padding.py
|
| 8 |
+
# and are distributed under the following license:
|
| 9 |
+
#
|
| 10 |
+
# BSD 3-Clause License
|
| 11 |
+
#
|
| 12 |
+
# Copyright (c) 2022, the respective contributors, as shown by the AUTHORS file.
|
| 13 |
+
# All rights reserved.
|
| 14 |
+
#
|
| 15 |
+
# Redistribution and use in source and binary forms, with or without
|
| 16 |
+
# modification, are permitted provided that the following conditions are met:
|
| 17 |
+
#
|
| 18 |
+
# * Redistributions of source code must retain the above copyright notice, this
|
| 19 |
+
# list of conditions and the following disclaimer.
|
| 20 |
+
#
|
| 21 |
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
| 22 |
+
# this list of conditions and the following disclaimer in the documentation
|
| 23 |
+
# and/or other materials provided with the distribution.
|
| 24 |
+
#
|
| 25 |
+
# * Neither the name of the copyright holder nor the names of its
|
| 26 |
+
# contributors may be used to endorse or promote products derived from
|
| 27 |
+
# this software without specific prior written permission.
|
| 28 |
+
#
|
| 29 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 30 |
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 31 |
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 32 |
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
| 33 |
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 34 |
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 35 |
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 36 |
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 37 |
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 38 |
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 39 |
+
#
|
| 40 |
+
# - `DomynEdgeRotaryEmbedding.compute_default_rope_parameters`, `rotate_half` and
|
| 41 |
+
# `apply_rotary_pos_emb` are adapted from HuggingFace transformers
|
| 42 |
+
# (https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py),
|
| 43 |
+
# Copyright The HuggingFace Team, licensed under the Apache License, Version 2.0.
|
| 44 |
+
# Modified for DomynEdge.
|
| 45 |
+
|
| 46 |
import dataclasses
|
|
|
|
| 47 |
import typing
|
| 48 |
+
|
| 49 |
+
import einops
|
| 50 |
import torch
|
| 51 |
+
import torch.nn.attention.varlen
|
| 52 |
+
import transformers
|
| 53 |
+
import transformers.modeling_outputs
|
| 54 |
+
|
| 55 |
+
from .configuration_domynedge import DomynEdgeConfig
|
| 56 |
+
|
| 57 |
|
| 58 |
@dataclasses.dataclass
|
| 59 |
class VarlenMetadataMask:
|
|
|
|
| 62 |
max_q: int
|
| 63 |
max_k: int
|
| 64 |
|
| 65 |
+
|
| 66 |
class IndexFirstAxis(torch.autograd.Function):
|
| 67 |
+
"""Gather the rows of the first axis at `indices`, scattering the gradient back in backward."""
|
| 68 |
|
| 69 |
@staticmethod
|
| 70 |
+
def forward(ctx, input_, indices):
|
| 71 |
ctx.save_for_backward(indices)
|
| 72 |
+
assert input_.ndim >= 2
|
| 73 |
+
ctx.first_axis_dim, other_shape = input_.shape[0], input_.shape[1:]
|
| 74 |
second_dim = other_shape.numel()
|
| 75 |
return torch.gather(
|
| 76 |
+
einops.rearrange(input_, "b ... -> b (...)"), 0, einops.repeat(indices, "z -> z d", d=second_dim)
|
| 77 |
).reshape(-1, *other_shape)
|
| 78 |
|
| 79 |
@staticmethod
|
|
|
|
| 90 |
grad_input.scatter_(0, einops.repeat(indices, "z -> z d", d=grad_output.shape[1]), grad_output)
|
| 91 |
return grad_input.reshape(ctx.first_axis_dim, *other_shape), None
|
| 92 |
|
| 93 |
+
|
| 94 |
class IndexPutFirstAxis(torch.autograd.Function):
|
| 95 |
+
"""Scatter `values` into a zero tensor at the first-axis `indices`, gathering the gradient back in backward."""
|
| 96 |
|
| 97 |
@staticmethod
|
| 98 |
def forward(ctx, values, indices, first_axis_dim):
|
| 99 |
ctx.save_for_backward(indices)
|
| 100 |
assert indices.ndim == 1
|
| 101 |
assert values.ndim >= 2
|
| 102 |
+
output = torch.zeros(first_axis_dim, *values.shape[1:], device=values.device, dtype=values.dtype)
|
|
|
|
|
|
|
| 103 |
output[indices] = values
|
| 104 |
return output
|
| 105 |
|
|
|
|
| 110 |
return grad_values, None, None
|
| 111 |
|
| 112 |
|
| 113 |
+
def unpad_input(
|
| 114 |
+
hidden_states: torch.Tensor, attention_mask: torch.Tensor
|
| 115 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, int]:
|
| 116 |
+
"""Remove the padding tokens, packing the valid tokens of all sequences along one axis.
|
| 117 |
|
| 118 |
Arguments:
|
| 119 |
hidden_states: (batch, seqlen, ...)
|
| 120 |
attention_mask: (batch, seqlen), bool / int, 1 means valid and 0 means not valid.
|
| 121 |
+
|
| 122 |
Return:
|
| 123 |
hidden_states: (total_nnz, ...), where total_nnz = number of tokens selected in attention_mask + unused_mask.
|
| 124 |
indices: (total_nnz), the indices of masked tokens from the flattened input sequence.
|
|
|
|
| 137 |
max_seqlen,
|
| 138 |
)
|
| 139 |
|
| 140 |
+
|
| 141 |
def pad_input(hidden_states: torch.Tensor, indices: torch.Tensor, batch_size: int, seqlen: int) -> torch.Tensor:
|
| 142 |
+
"""Restore the padded (batch, seqlen, ...) layout from packed tokens, the inverse of `unpad_input`.
|
| 143 |
|
| 144 |
Arguments:
|
| 145 |
hidden_states: (total_nnz, ...), where total_nnz = number of tokens in selected in attention_mask.
|
| 146 |
indices: (total_nnz), the indices that represent the non-masked tokens of the original padded input sequence.
|
| 147 |
+
batch_size: int, batch size for the padded sequence.
|
| 148 |
seqlen: int, maximum sequence length for the padded sequence.
|
| 149 |
+
|
| 150 |
Return:
|
| 151 |
hidden_states: (batch, seqlen, ...)
|
| 152 |
|
|
|
|
| 154 |
output = IndexPutFirstAxis.apply(hidden_states, indices, batch_size * seqlen)
|
| 155 |
return einops.rearrange(output, "(b s) ... -> b s ...", b=batch_size)
|
| 156 |
|
| 157 |
+
|
| 158 |
class DomynEdgeFeedForward(torch.nn.Module):
|
| 159 |
def __init__(self, config):
|
| 160 |
super().__init__()
|
|
|
|
| 168 |
def forward(self, x):
|
| 169 |
return self.down_proj(torch.nn.functional.silu(self.gate_proj(x)) * self.up_proj(x))
|
| 170 |
|
| 171 |
+
|
| 172 |
class DomynEdgeRotaryEmbedding(torch.nn.Module):
|
| 173 |
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 174 |
|
|
|
|
| 190 |
def compute_default_rope_parameters(
|
| 191 |
config: DomynEdgeConfig | None = None,
|
| 192 |
device: typing.Optional["torch.device"] = None,
|
|
|
|
| 193 |
) -> tuple["torch.Tensor", float]:
|
| 194 |
+
"""Computes the inverse frequencies according to the original RoPE implementation.
|
| 195 |
+
|
| 196 |
Args:
|
| 197 |
config ([`~transformers.PreTrainedConfig`]):
|
| 198 |
The model configuration.
|
| 199 |
device (`torch.device`):
|
| 200 |
The device to use for initialization of the inverse frequencies.
|
| 201 |
+
|
|
|
|
| 202 |
Returns:
|
| 203 |
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 204 |
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
|
|
|
| 219 |
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 220 |
position_ids_expanded = position_ids[:, None, :].float()
|
| 221 |
|
| 222 |
+
# TODO: the angles lose precision in two cases, both wrong at large positions:
|
| 223 |
+
# - under torch.autocast(bfloat16) the matmul below runs in bf16 despite the `.float()` casts;
|
| 224 |
+
# - after model.to(torch.bfloat16) / model.bfloat16() the `inv_freq` buffer itself is cast to bf16.
|
| 225 |
+
# Loading with `from_pretrained(dtype=torch.bfloat16)` and no autocast is not affected. Candidate fix:
|
| 226 |
+
# recompute `inv_freq` in fp32 here, with autocast disabled, instead of reading the buffer.
|
| 227 |
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 228 |
emb = torch.cat((freqs, freqs), dim=-1)
|
| 229 |
cos = emb.cos() * self.attention_scaling
|
|
|
|
| 254 |
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 255 |
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 256 |
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 257 |
+
|
| 258 |
Returns:
|
| 259 |
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 260 |
"""
|
|
|
|
| 265 |
k_embed = (kf * cos) + (rotate_half(kf) * sin)
|
| 266 |
return q_embed.to(q.dtype), k_embed.to(k.dtype)
|
| 267 |
|
| 268 |
+
|
| 269 |
class DomynEdgeAttention(torch.nn.Module):
|
| 270 |
+
"""Grouped Query Attention with support for sliding window."""
|
| 271 |
|
| 272 |
def __init__(self, config: DomynEdgeConfig, layer_idx: int):
|
| 273 |
super().__init__()
|
| 274 |
self.config = config
|
| 275 |
self.head_dim = config.head_sizes[layer_idx]
|
| 276 |
+
self.scaling = self.head_dim**-0.5
|
| 277 |
self.window_size = config.window_sizes[layer_idx]
|
| 278 |
+
self.apply_rope = (
|
| 279 |
+
apply_rotary_pos_emb
|
| 280 |
+
if config.position_layers[layer_idx] == "rope"
|
| 281 |
+
else lambda q, k, cos, sin, unsqueeze_dim: (q, k) # noqa: ARG005
|
| 282 |
+
)
|
| 283 |
self.layer_idx = layer_idx
|
| 284 |
self.enable_gqa = config.num_attention_heads > config.num_key_value_heads
|
| 285 |
|
| 286 |
+
self.q_proj = torch.nn.Linear(
|
| 287 |
+
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
| 288 |
+
)
|
| 289 |
+
self.k_proj = torch.nn.Linear(
|
| 290 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 291 |
+
)
|
| 292 |
+
self.v_proj = torch.nn.Linear(
|
| 293 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 294 |
+
)
|
| 295 |
+
self.o_proj = torch.nn.Linear(
|
| 296 |
+
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
| 297 |
+
)
|
| 298 |
self.q_norm = torch.nn.RMSNorm(self.head_dim, eps=config.rms_norm_eps, elementwise_affine=False)
|
| 299 |
self.k_norm = torch.nn.RMSNorm(self.head_dim, eps=config.rms_norm_eps, elementwise_affine=True)
|
| 300 |
|
|
|
|
| 304 |
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 305 |
attention_mask: torch.Tensor,
|
| 306 |
past_key_values: transformers.Cache | None = None,
|
| 307 |
+
**_kwargs,
|
| 308 |
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 309 |
|
| 310 |
+
batch_size, sequence_length, _ = hidden_states.shape
|
| 311 |
|
| 312 |
+
q = self.q_norm(
|
| 313 |
+
self.q_proj(hidden_states).view(batch_size, sequence_length, self.config.num_attention_heads, self.head_dim)
|
| 314 |
+
)
|
| 315 |
+
k = self.k_norm(
|
| 316 |
+
self.k_proj(hidden_states).view(batch_size, sequence_length, self.config.num_key_value_heads, self.head_dim)
|
| 317 |
+
)
|
| 318 |
v = self.v_proj(hidden_states).view(batch_size, sequence_length, self.config.num_key_value_heads, self.head_dim)
|
| 319 |
|
| 320 |
cos, sin = position_embeddings
|
|
|
|
| 326 |
k, v = k.transpose(1, 2), v.transpose(1, 2)
|
| 327 |
|
| 328 |
if q.size(1) > 1:
|
| 329 |
+
q, q_indices, q_cu_seqlen, q_maxseq = unpad_input(q, attention_mask[:, -sequence_length:])
|
| 330 |
else:
|
| 331 |
q_maxseq = 1
|
| 332 |
q_cu_seqlen = torch.arange(batch_size + 1, dtype=torch.int32, device=q.device)
|
| 333 |
q_indices = q_cu_seqlen[:-1]
|
| 334 |
+
q = q.squeeze(1)
|
| 335 |
|
| 336 |
+
k, _, k_cu_seqlen, k_maxseq = unpad_input(k, attention_mask)
|
| 337 |
+
v, *_ = unpad_input(v, attention_mask)
|
| 338 |
|
| 339 |
attn_output = torch.nn.attention.varlen.varlen_attn(
|
| 340 |
q if q.dtype in [torch.float16, torch.bfloat16] else q.to(torch.bfloat16),
|
| 341 |
k if k.dtype in [torch.float16, torch.bfloat16] else k.to(torch.bfloat16),
|
| 342 |
v if v.dtype in [torch.float16, torch.bfloat16] else v.to(torch.bfloat16),
|
| 343 |
+
cu_seq_q=q_cu_seqlen,
|
| 344 |
+
cu_seq_k=k_cu_seqlen,
|
| 345 |
+
max_q=q_maxseq,
|
| 346 |
+
max_k=k_maxseq,
|
| 347 |
+
scale=self.scaling,
|
| 348 |
+
window_size=self.window_size,
|
| 349 |
+
enable_gqa=self.enable_gqa,
|
| 350 |
).to(q.dtype)
|
| 351 |
|
| 352 |
attn_output = pad_input(attn_output, q_indices, batch_size, sequence_length)
|
| 353 |
attn_output = attn_output.view(batch_size, sequence_length, self.config.num_attention_heads * self.head_dim)
|
| 354 |
+
return self.o_proj(attn_output)
|
| 355 |
+
|
| 356 |
|
| 357 |
class DomynEdgeDecoderLayer(torch.nn.Module):
|
| 358 |
def __init__(self, config: DomynEdgeConfig, layer_idx: int):
|
|
|
|
| 379 |
# Self Attention
|
| 380 |
hidden_states = hidden_states + self.post_attention_norm(
|
| 381 |
self.attention(
|
| 382 |
+
hidden_states=self.pre_attention_norm(hidden_states),
|
| 383 |
+
attention_mask=attention_mask,
|
| 384 |
+
past_key_values=past_key_values,
|
| 385 |
+
position_embeddings=position_embeddings,
|
| 386 |
**kwargs,
|
| 387 |
)
|
| 388 |
)
|
| 389 |
|
| 390 |
## Fully Connected
|
| 391 |
+
return hidden_states + self.post_feedforward_norm(self.feedforward(self.pre_feedforward_norm(hidden_states)))
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
|
|
|
|
| 393 |
|
| 394 |
class DomynEdgePreTrainedModel(transformers.PreTrainedModel):
|
| 395 |
+
"""Base class wiring DomynEdge into the HuggingFace `PreTrainedModel` machinery."""
|
| 396 |
+
|
| 397 |
config: DomynEdgeConfig
|
| 398 |
base_model_prefix = "model"
|
| 399 |
supports_gradient_checkpointing = False
|
|
|
|
| 409 |
|
| 410 |
|
| 411 |
class DomynEdgeModel(DomynEdgePreTrainedModel):
|
| 412 |
+
"""DomynEdge decoder stack without the language modeling head."""
|
| 413 |
+
|
| 414 |
def __init__(self, config: DomynEdgeConfig):
|
| 415 |
+
"""Build the embeddings, decoder layers, final norm and rotary embedding from `config`."""
|
| 416 |
super().__init__(config)
|
| 417 |
self.padding_idx = config.pad_token_id
|
| 418 |
self.vocab_size = config.vocab_size
|
| 419 |
|
| 420 |
self.embed_tokens = torch.nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 421 |
+
self.layers = torch.nn.ModuleList(
|
| 422 |
+
[DomynEdgeDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 423 |
+
)
|
| 424 |
self.norm = torch.nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 425 |
self.rotary_emb = DomynEdgeRotaryEmbedding(config=config)
|
| 426 |
|
|
|
|
| 437 |
use_cache: bool | None = None,
|
| 438 |
**kwargs,
|
| 439 |
) -> transformers.modeling_outputs.BaseModelOutputWithPast:
|
| 440 |
+
"""Run the decoder stack and return the final hidden states (and the cache when `use_cache` is set)."""
|
| 441 |
if input_ids is not None and inputs_embeds is not None:
|
| 442 |
+
msg = "You must specify exactly one of input_ids or inputs_embeds"
|
| 443 |
+
raise ValueError(msg)
|
| 444 |
|
| 445 |
if inputs_embeds is None:
|
| 446 |
inputs_embeds = self.embed_tokens(input_ids)
|
|
|
|
| 448 |
if use_cache and past_key_values is None:
|
| 449 |
past_key_values = transformers.DynamicCache(config=self.config)
|
| 450 |
|
| 451 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 452 |
+
|
| 453 |
if position_ids is None:
|
|
|
|
| 454 |
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 455 |
position_ids = position_ids.unsqueeze(0)
|
| 456 |
|
|
|
|
| 458 |
position_embeddings = self.rotary_emb(hidden_states, position_ids)
|
| 459 |
|
| 460 |
if attention_mask is None:
|
| 461 |
+
attention_mask = torch.ones(
|
| 462 |
+
(hidden_states.shape[0], past_seen_tokens + hidden_states.shape[1]),
|
| 463 |
+
device=hidden_states.device,
|
| 464 |
+
dtype=torch.bool,
|
| 465 |
+
)
|
| 466 |
|
| 467 |
for decoder_layer in self.layers:
|
| 468 |
hidden_states = decoder_layer(
|
|
|
|
| 479 |
past_key_values=past_key_values if use_cache else None,
|
| 480 |
)
|
| 481 |
|
| 482 |
+
|
| 483 |
class DomynEdgeForCausalLM(DomynEdgePreTrainedModel, transformers.GenerationMixin):
|
| 484 |
+
"""DomynEdge model with a language modeling head tied to the input embeddings."""
|
| 485 |
+
|
| 486 |
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 487 |
|
| 488 |
def __init__(self, config):
|
| 489 |
+
"""Build the decoder stack and the language modeling head from `config`."""
|
| 490 |
super().__init__(config)
|
| 491 |
self.model = DomynEdgeModel(config)
|
| 492 |
self.vocab_size = config.vocab_size
|
|
|
|
| 505 |
labels: torch.LongTensor | None = None,
|
| 506 |
use_cache: bool | None = None,
|
| 507 |
logits_to_keep: int | torch.Tensor = 0,
|
| 508 |
+
**kwargs,
|
| 509 |
) -> transformers.modeling_outputs.CausalLMOutputWithPast:
|
| 510 |
+
"""Compute logits for the last `logits_to_keep` positions, plus the loss when `labels` are given."""
|
| 511 |
outputs = self.model(
|
| 512 |
input_ids=input_ids,
|
| 513 |
attention_mask=attention_mask,
|
|
|
|
| 522 |
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 523 |
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 524 |
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 525 |
+
loss = (
|
| 526 |
+
self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
|
| 527 |
+
if labels is not None
|
| 528 |
+
else None
|
| 529 |
+
)
|
| 530 |
|
| 531 |
return transformers.modeling_outputs.CausalLMOutputWithPast(
|
| 532 |
loss=loss,
|
|
|
|
| 536 |
attentions=outputs.attentions,
|
| 537 |
)
|
| 538 |
|
| 539 |
+
|
| 540 |
__all__ = [
|
| 541 |
"DomynEdgeForCausalLM",
|
| 542 |
"DomynEdgeModel",
|