Purrence-3M / modeling_purrence.py
Jonnester's picture
Purrence-3M
921bf58
Raw History Blame Contribute Delete
3.24 kB
"""Transformers inference adapter using the unchanged native model equations."""
from dataclasses import fields
import torch
from transformers import PreTrainedModel, GenerationMixin
from transformers.modeling_outputs import CausalLMOutput
from .configuration_purrence import PurrenceConfig
from .purrence_core import ModelConfig, RecurrentLM
class PurrenceForCausalLM(PreTrainedModel, GenerationMixin):
config_class = PurrenceConfig
base_model_prefix = ""
main_input_name = "input_ids"
_supports_cache_class = False
def __init__(self, config, dtype=None):
super().__init__(config)
native = RecurrentLM(ModelConfig(**{
f.name: getattr(config, f.name) for f in fields(ModelConfig)
}))
self.embedding = native.embedding
self.block = native.block
self.queries = native.queries
def get_input_embeddings(self):
return self.embedding
def set_input_embeddings(self, value):
self.embedding = value
def get_output_embeddings(self):
return None # The native forward uses the embedding weight directly.
def read(self, sources, query):
return RecurrentLM.read(self, sources, query)
def prepare_inputs_for_generation(self, input_ids, attention_mask=None, **kwargs):
return dict(input_ids=input_ids, attention_mask=attention_mask, use_cache=False)
def forward(self, input_ids=None, attention_mask=None, return_dict=None,
use_cache=False, past_key_values=None, labels=None, **kwargs):
if labels is not None or past_key_values is not None:
raise ValueError("This inference adapter does not implement training or a KV cache")
if input_ids is None or input_ids.ndim != 2 or input_ids.numel() == 0:
raise ValueError("Expected a nonempty batch of token IDs")
if attention_mask is None:
mask = torch.ones_like(input_ids, dtype=torch.bool)
else:
if attention_mask.shape != input_ids.shape:
raise ValueError("Attention mask shape differs from input IDs")
mask = attention_mask.bool()
lengths = mask.sum(-1)
if (lengths == 0).any() or (lengths > self.config.max_seq_len).any():
raise ValueError("Each sequence must contain 1 to 8192 unmasked tokens")
packed = input_ids[mask]
starts = torch.cat((lengths.new_zeros(1), lengths.cumsum(0)[:-1]))
document_starts = packed.eq(self.config.eos_token_id)
document_starts[starts] = True
offsets = document_starts.nonzero().flatten()
cu = torch.cat((offsets, offsets.new_tensor([packed.numel()]))).to(torch.int32)
positions = torch.arange(packed.numel(), device=packed.device) - torch.repeat_interleave(offsets, cu.diff().long())
with torch.nn.attention.sdpa_kernel(torch.nn.attention.SDPBackend.MATH):
values = RecurrentLM.forward(self, packed, cu, positions)
logits = values.new_zeros((*input_ids.shape, self.config.vocab_size))
logits[mask] = values
if return_dict is False or (return_dict is None and not self.config.use_return_dict):
return (logits,)
return CausalLMOutput(logits=logits)