Download source/src/vimeml/deployment/v4.py from Voltline/vimeml-tiny-ja-v4.2: direct link, hf CLI and curl.
- Browser
- Download file 2.86 kB
-
https://huggingface.co/Voltline/vimeml-tiny-ja-v4.2/resolve/main/source/src/vimeml/deployment/v4.py
- Command line
-
hf download hf://Voltline/vimeml-tiny-ja-v4.2/source/src/vimeml/deployment/v4.py
-
curl -L -o v4.py https://huggingface.co/Voltline/vimeml-tiny-ja-v4.2/resolve/main/source/src/vimeml/deployment/v4.py
2.86 kB
| """V4 functional single-token KV graph and local TorchScript validation.""" | |
| import math | |
| import torch | |
| from torch import nn | |
| from vimeml.deployment.graph import trace_graph | |
| CACHE_SHAPE = (7, 1, 6, 128, 64) | |
| class KVStepGraphV4(nn.Module): | |
| """Explicit functional FP32 buffers; caller owns snapshots and rollback.""" | |
| def __init__(self, model): | |
| super().__init__() | |
| self.model = model.eval() | |
| self.register_buffer("slots", torch.arange(128)) | |
| def forward(self, input_ids, position, key_cache, value_cache): | |
| position = position.to(torch.int64) | |
| hidden = self.model.token_embedding(input_ids) + self.model.position_embedding(position).unsqueeze(0) | |
| insert = (self.slots == position[0]).reshape(1, 1, 128, 1) | |
| valid = (self.slots <= position[0]).reshape(1, 1, 1, 128) | |
| keys, values = [], [] | |
| for layer, block in enumerate(self.model.blocks): | |
| qkv = block.attention.qkv(block.attention_norm(hidden)).reshape(1, 1, 3, 6, 64) | |
| query, key, value = qkv.permute(2, 0, 3, 1, 4).unbind(0) | |
| updated_key = torch.where(insert, key, key_cache[layer]) | |
| updated_value = torch.where(insert, value, value_cache[layer]) | |
| scores = torch.matmul(query, updated_key.transpose(-2, -1)) / math.sqrt(64) | |
| probabilities = torch.softmax(scores.masked_fill(~valid, -torch.inf), dim=-1) | |
| attended = torch.matmul(probabilities, updated_value).transpose(1, 2).reshape(1, 1, 384) | |
| hidden = hidden + block.attention.projection(attended) | |
| hidden = hidden + block.ffn(block.ffn_norm(hidden)) | |
| keys.append(updated_key) | |
| values.append(updated_value) | |
| return self.model.lm_head(self.model.final_norm(hidden)), torch.stack(keys), torch.stack(values) | |
| def trace_kv_graph(model): | |
| graph = KVStepGraphV4(model).eval() | |
| args = (torch.tensor([[2]], dtype=torch.int32), torch.tensor([0], dtype=torch.int32), | |
| torch.zeros(CACHE_SHAPE), torch.zeros(CACHE_SHAPE)) | |
| traced = torch.jit.trace(graph, args) | |
| # Different positions from the tracing example, including last cache slot. | |
| ids = torch.randint(7, 8192, (1, 128), generator=torch.Generator().manual_seed(940)) | |
| cache = model.new_cache() | |
| for position in (0, 7, 127): | |
| if position > cache.length: | |
| model.forward_cached(ids[:, cache.length:position], cache) | |
| key, value = cache.key.clone(), cache.value.clone() | |
| token = ids[:, position:position + 1].int() | |
| reference = model.forward_cached(token, cache) | |
| actual = traced(token, torch.tensor([position], dtype=torch.int32), key, value) | |
| for a, b in zip(actual, (reference, cache.key, cache.value), strict=True): | |
| torch.testing.assert_close(a, b, atol=3e-4, rtol=3e-4) | |
| return traced | |