Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / infer / sampler.py: 0%
56 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Sampling helpers for autoregressive generation."""
16import torch
17from torch.nn import functional as F
19from hyper_parallel.infer.utils import GenerationConfig
22def _filter_top_k(logits: torch.Tensor, top_k: int) -> torch.Tensor:
23 if top_k <= 0 or top_k >= logits.size(-1):
24 return logits
25 values, _ = torch.topk(logits, k=top_k, dim=-1)
26 threshold = values[:, -1:].contiguous()
27 return logits.masked_fill(logits < threshold, float("-inf"))
30def greedy_sample(logits: torch.Tensor) -> torch.Tensor:
31 """Select the highest-logit token for each batch item."""
32 if logits.ndim != 2:
33 raise ValueError("logits must have shape (batch, vocab)")
34 return logits.argmax(dim=-1, keepdim=True)
37def top_k_sample(
38 logits: torch.Tensor,
39 top_k: int,
40 temperature: float = 1.0,
41) -> torch.Tensor:
42 """Sample from the top-k logits."""
43 if logits.ndim != 2:
44 raise ValueError("logits must have shape (batch, vocab)")
45 filtered = _filter_top_k(logits, top_k)
46 probs = F.softmax(filtered / temperature, dim=-1)
47 sampled = torch.multinomial(probs, num_samples=1)
48 return sampled
51def top_p_sample(
52 logits: torch.Tensor,
53 top_p: float,
54 temperature: float = 1.0,
55) -> torch.Tensor:
56 """Sample from the nucleus token set."""
57 if logits.ndim != 2:
58 raise ValueError("logits must have shape (batch, vocab)")
59 if top_p >= 1.0:
60 probs = F.softmax(logits / temperature, dim=-1)
61 return torch.multinomial(probs, num_samples=1)
62 sorted_logits, sorted_indices = torch.sort(logits, descending=True, dim=-1)
63 sorted_probs = F.softmax(sorted_logits / temperature, dim=-1)
64 cumulative = sorted_probs.cumsum(dim=-1)
65 remove = cumulative - sorted_probs > top_p
66 filtered = sorted_logits.masked_fill(remove, float("-inf"))
67 probs = F.softmax(filtered / temperature, dim=-1)
68 sampled = torch.multinomial(probs, num_samples=1)
69 return sorted_indices.gather(dim=-1, index=sampled)
72def apply_repetition_penalty(
73 logits: torch.Tensor,
74 input_ids: torch.Tensor,
75 penalty: float,
76) -> torch.Tensor:
77 """Apply per-item repetition penalty to seen token ids."""
78 if penalty == 1.0:
79 return logits
80 if logits.ndim != 2 or input_ids.ndim != 2:
81 raise ValueError("logits and input_ids must be 2-D tensors")
82 adjusted = logits.clone()
83 vocab_size = logits.size(-1)
84 valid = (input_ids >= 0) & (input_ids < vocab_size)
85 seen_mask = torch.zeros_like(adjusted, dtype=torch.bool)
86 token_ids = input_ids.to(dtype=torch.long).clamp(min=0, max=max(vocab_size - 1, 0))
87 seen_mask.scatter_(dim=1, index=token_ids, src=valid)
88 penalized = torch.where(adjusted < 0, adjusted * penalty, adjusted / penalty)
89 return torch.where(seen_mask, penalized, adjusted)
92def sample_next_token(
93 logits: torch.Tensor,
94 input_ids: torch.Tensor,
95 config: GenerationConfig,
96) -> torch.Tensor:
97 """Apply repetition penalty and select the next token."""
98 logits = apply_repetition_penalty(
99 logits,
100 input_ids=input_ids,
101 penalty=config.repetition_penalty,
102 )
103 if not config.do_sample:
104 return greedy_sample(logits)
105 logits = _filter_top_k(logits, config.top_k)
106 if config.top_p < 1.0:
107 return top_p_sample(logits, top_p=config.top_p, temperature=config.temperature)
108 probs = F.softmax(logits / config.temperature, dim=-1)
109 return torch.multinomial(probs, num_samples=1)