Download runtime/joint_group_model.py from snchimata/tokenfold-select-v2: direct link, hf CLI and curl.
- Browser
- Download file 2.74 kB
-
https://huggingface.co/snchimata/tokenfold-select-v2/resolve/main/runtime/joint_group_model.py
- Command line
-
hf download hf://snchimata/tokenfold-select-v2/runtime/joint_group_model.py
-
curl -L -o joint_group_model.py https://huggingface.co/snchimata/tokenfold-select-v2/resolve/main/runtime/joint_group_model.py
2.74 kB
| """Development-only joint group encoder. Random head: NOT a usable Select scorer. | |
| No downloads, truncation, windowing, generated text or production integration. | |
| The caller owns request validation and supplies the provisioned encoder/tokenizer. | |
| """ | |
| import torch | |
| from torch import nn | |
| def pack_groups(tokenizer, query, groups, cap=8192): | |
| """Return one sequence and explicit content ranges in caller order.""" | |
| if not 1 <= cap <= 8192 or not query or not 1 <= len(groups) <= 512: | |
| raise ValueError("invalid_admission") | |
| ids_seen = set() | |
| cls, sep = tokenizer.cls_token_id, tokenizer.sep_token_id | |
| if cls is None or sep is None: | |
| raise ValueError("missing_special_tokens") | |
| ids = [cls] + tokenizer.encode(query, add_special_tokens=False, truncation=False) + [sep] | |
| ranges = [] | |
| for group in groups: | |
| gid, text = group['id'], group['text'] | |
| if not isinstance(gid, str) or not gid or gid in ids_seen or not isinstance(text, str) or not text: | |
| raise ValueError("invalid_group") | |
| ids_seen.add(gid) | |
| content = tokenizer.encode(text, add_special_tokens=False, truncation=False) | |
| if not content: | |
| raise ValueError("empty_group_range") | |
| start = len(ids) | |
| ids.extend(content) | |
| ranges.append((start, len(ids))) | |
| ids.append(sep) | |
| if len(ids) > cap: | |
| raise ValueError("token_cap") | |
| return ids, ranges | |
| class JointGroupModel(nn.Module): | |
| """One encoder invocation, masked content mean and a shared linear head.""" | |
| def __init__(self, encoder): | |
| super().__init__() | |
| self.encoder = encoder | |
| self.head = nn.Linear(encoder.config.hidden_size, 1) | |
| def forward(self, input_ids, attention_mask, ranges): | |
| if input_ids.ndim != 2 or input_ids.shape[0] != 1 or attention_mask.shape != input_ids.shape: | |
| raise ValueError("single_sequence_required") | |
| previous = 0 | |
| if not 1 <= len(ranges) <= 512: | |
| raise ValueError("invalid_ranges") | |
| for start, end in ranges: | |
| if not previous <= start < end <= input_ids.shape[1] or not attention_mask[0, start:end].all(): | |
| raise ValueError("invalid_ranges") | |
| previous = end | |
| positions = torch.arange(input_ids.shape[1], device=input_ids.device).unsqueeze(0) | |
| states = self.encoder(input_ids=input_ids, attention_mask=attention_mask, | |
| position_ids=positions).last_hidden_state[0] | |
| pooled = torch.stack([states[start:end].mean(0) for start, end in ranges]) | |
| scores = self.head(pooled).squeeze(-1) | |
| if not torch.isfinite(scores).all(): | |
| raise ValueError("nonfinite_scores") | |
| return scores | |