main
py 290 lines 10.3 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import pytest
4
5 from vllm.sampling_params import RepetitionDetectionParams, SamplingParams
6 from vllm.v1.core.sched.utils import check_sequence_repetition, check_stop
7 from vllm.v1.request import Request, RequestStatus
8
9 pytestmark = pytest.mark.cpu_test
10
11 # ============================================================================
12 # UNIT TESTS - check_sequence_repetition function
13 # ============================================================================
14
15
16 class TestCheckSequenceRepetition:
17 """Unit tests for the check_sequence_repetition function."""
18
19 def test_simple_repetition_detected(self):
20 """Test detection of simple repetitive patterns."""
21 token_ids = [1, 2, 3, 1, 2, 3, 1, 2, 3]
22 params = RepetitionDetectionParams(
23 max_pattern_size=3,
24 min_pattern_size=2,
25 min_count=3,
26 )
27 assert check_sequence_repetition(token_ids, params)
28
29 def test_repetition_below_min_count(self):
30 """Test that pattern below min_count is not detected."""
31 token_ids = [1, 2, 3, 1, 2, 3]
32 params = RepetitionDetectionParams(
33 max_pattern_size=3,
34 min_pattern_size=2,
35 min_count=3,
36 )
37 assert not check_sequence_repetition(token_ids, params)
38
39 def test_two_token_pattern(self):
40 """Test detection of 2-token patterns."""
41 token_ids = [1, 2, 1, 2, 1, 2, 1, 2]
42 params = RepetitionDetectionParams(
43 max_pattern_size=5,
44 min_pattern_size=2,
45 min_count=4,
46 )
47 assert check_sequence_repetition(token_ids, params)
48
49 def test_no_repetition_varied_sequence(self):
50 """Test that non-repetitive sequences are not flagged."""
51 token_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9]
52 params = RepetitionDetectionParams(
53 max_pattern_size=5,
54 min_pattern_size=2,
55 min_count=2,
56 )
57 assert not check_sequence_repetition(token_ids, params)
58
59 def test_partial_repetition_not_detected(self):
60 """Test that incomplete repetitions are not detected."""
61 token_ids = [1, 2, 3, 1, 2, 3, 1, 2, 4]
62 params = RepetitionDetectionParams(
63 max_pattern_size=3,
64 min_pattern_size=2,
65 min_count=3,
66 )
67 assert not check_sequence_repetition(token_ids, params)
68
69 def test_empty_token_list(self):
70 """Test with empty token list."""
71 params = RepetitionDetectionParams(
72 max_pattern_size=3,
73 min_pattern_size=2,
74 min_count=2,
75 )
76 assert not check_sequence_repetition([], params)
77
78 def test_detection_disabled_max_size_zero(self):
79 """Test that zero max_pattern_size disables detection."""
80 token_ids = [1, 2, 1, 2, 1, 2]
81 params = RepetitionDetectionParams()
82 assert not check_sequence_repetition(token_ids, params)
83
84 def test_invalid_min_count(self):
85 """Test that min_count < 2 returns False."""
86 token_ids = [1, 2, 1, 2]
87 params = RepetitionDetectionParams()
88 assert not check_sequence_repetition(token_ids, params)
89
90 def test_repetition_at_end_of_sequence(self):
91 """Test detection when repetition occurs at the end."""
92 token_ids = [1, 2, 3, 4, 5, 6, 5, 6, 5, 6]
93 params = RepetitionDetectionParams(
94 max_pattern_size=3,
95 min_pattern_size=2,
96 min_count=3,
97 )
98 assert check_sequence_repetition(token_ids, params)
99
100 def test_large_pattern_many_repetitions(self):
101 """Test large pattern repeated many times."""
102 token_ids = [1, 2, 3, 4, 5, 6, 7, 8] * 5
103 params = RepetitionDetectionParams(
104 max_pattern_size=10,
105 min_pattern_size=2,
106 min_count=3,
107 )
108 assert check_sequence_repetition(token_ids, params)
109
110
111 # ============================================================================
112 # INTEGRATION TESTS - check_stop with repetition detection
113 # ============================================================================
114
115
116 class TestRepetitionDetectionIntegration:
117 """Integration tests for repetition detection in check_stop."""
118
119 def test_basic_repetition_stops_generation(self):
120 """Test that repetition is detected and stops generation."""
121 params = SamplingParams(
122 max_tokens=100,
123 repetition_detection=RepetitionDetectionParams(
124 max_pattern_size=5,
125 min_pattern_size=2,
126 min_count=3,
127 ),
128 )
129 request = Request(
130 request_id="test",
131 prompt_token_ids=[1, 2, 3],
132 sampling_params=params,
133 pooling_params=None,
134 )
135 request.append_output_token_ids([10, 20, 10, 20, 10, 20])
136 assert check_stop(request, max_model_len=1024)
137 assert request.status == RequestStatus.FINISHED_REPETITION
138 assert request.stop_reason == "repetition_detected"
139
140 def test_detection_disabled_no_stop(self):
141 """Test that disabled detection doesn't stop generation."""
142 params = SamplingParams(
143 max_tokens=100,
144 )
145 request = Request(
146 request_id="test",
147 prompt_token_ids=[1, 2, 3],
148 sampling_params=params,
149 pooling_params=None,
150 )
151 request.append_output_token_ids([10, 20, 10, 20, 10, 20])
152 assert not check_stop(request, max_model_len=1024)
153
154 def test_repetition_respects_min_tokens(self):
155 """Test that repetition detection respects min_tokens."""
156 params = SamplingParams(
157 min_tokens=10,
158 max_tokens=100,
159 repetition_detection=RepetitionDetectionParams(
160 max_pattern_size=5,
161 min_pattern_size=2,
162 min_count=3,
163 ),
164 )
165 request = Request(
166 request_id="test",
167 prompt_token_ids=[1, 2, 3],
168 sampling_params=params,
169 pooling_params=None,
170 )
171 request.append_output_token_ids([10, 20, 10, 20, 10, 20])
172 assert not check_stop(request, max_model_len=1024)
173
174 def test_no_repetition_continues_generation(self):
175 """Test that non-repetitive tokens don't stop generation."""
176 params = SamplingParams(
177 max_tokens=100,
178 repetition_detection=RepetitionDetectionParams(
179 max_pattern_size=5,
180 min_pattern_size=2,
181 min_count=3,
182 ),
183 )
184 request = Request(
185 request_id="test",
186 prompt_token_ids=[1, 2, 3],
187 sampling_params=params,
188 pooling_params=None,
189 )
190 request.append_output_token_ids([10, 20, 30, 40, 50, 60])
191 assert not check_stop(request, max_model_len=1024)
192
193 def test_pattern_at_size_boundary(self):
194 """Test detection at exact pattern size boundary."""
195 params = SamplingParams(
196 max_tokens=100,
197 repetition_detection=RepetitionDetectionParams(
198 max_pattern_size=3,
199 min_pattern_size=3,
200 min_count=2,
201 ),
202 )
203 request = Request(
204 request_id="test",
205 prompt_token_ids=[1, 2],
206 sampling_params=params,
207 pooling_params=None,
208 )
209 request.append_output_token_ids([10, 20, 30, 10, 20, 30])
210 assert check_stop(request, max_model_len=1024)
211 assert request.status == RequestStatus.FINISHED_REPETITION
212
213 def test_multiple_pattern_sizes_checked(self):
214 """Test that function checks pattern sizes in range."""
215 params = SamplingParams(
216 max_tokens=100,
217 repetition_detection=RepetitionDetectionParams(
218 max_pattern_size=5,
219 min_pattern_size=2,
220 min_count=3,
221 ),
222 )
223 request = Request(
224 request_id="test",
225 prompt_token_ids=[1],
226 sampling_params=params,
227 pooling_params=None,
228 )
229 request.append_output_token_ids([7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10])
230 assert check_stop(request, max_model_len=1024)
231 assert request.status == RequestStatus.FINISHED_REPETITION
232
233 def test_eos_takes_precedence_over_repetition(self):
234 """Test that EOS token stops before repetition check."""
235 params = SamplingParams(
236 max_tokens=100,
237 stop_token_ids=[999],
238 repetition_detection=RepetitionDetectionParams(
239 max_pattern_size=5,
240 min_pattern_size=2,
241 min_count=3,
242 ),
243 )
244 request = Request(
245 request_id="test",
246 prompt_token_ids=[1, 2, 3],
247 sampling_params=params,
248 pooling_params=None,
249 )
250 request.append_output_token_ids([10, 20, 10, 20, 999])
251 assert check_stop(request, max_model_len=1024)
252 assert request.status == RequestStatus.FINISHED_STOPPED
253
254 def test_min_pattern_size_filters_small_patterns(self):
255 """Test that min_pattern_size filters out smaller patterns."""
256 params = SamplingParams(
257 max_tokens=100,
258 repetition_detection=RepetitionDetectionParams(
259 max_pattern_size=5,
260 min_pattern_size=3,
261 min_count=3,
262 ),
263 )
264 request = Request(
265 request_id="test",
266 prompt_token_ids=[1],
267 sampling_params=params,
268 pooling_params=None,
269 )
270 request.append_output_token_ids([10, 20, 10, 20, 10, 20])
271 assert not check_stop(request, max_model_len=1024)
272
273 def test_high_repetition_threshold(self):
274 """Test that high min_count requires many repetitions."""
275 params = SamplingParams(
276 max_tokens=100,
277 repetition_detection=RepetitionDetectionParams(
278 max_pattern_size=5,
279 min_pattern_size=2,
280 min_count=5,
281 ),
282 )
283 request = Request(
284 request_id="test",
285 prompt_token_ids=[1],
286 sampling_params=params,
287 pooling_params=None,
288 )
289 request.append_output_token_ids([10, 20, 10, 20, 10, 20])
290 assert not check_stop(request, max_model_len=1024)