1919import numpy as np
2020from tunix .experimental .common import datatypes
2121from tunix .experimental .orchestrator import batch_assembly
22- from tunix .rl import common as rl_common
2322
2423
2524class HelperFunctionsTest (absltest .TestCase ):
@@ -104,8 +103,8 @@ def test_completion_aligned_slices_full_sequence(self):
104103
105104class WithRefPerTokenLogpsTest (absltest .TestCase ):
106105
107- def _make_train_example (self , b = 2 , p = 3 , c = 4 ):
108- return rl_common . TrainExample (
106+ def _make_payload (self , b = 2 , p = 3 , c = 4 ):
107+ return datatypes . RLTrainerPayload (
109108 prompt_ids = np .ones ((b , p ), dtype = np .int32 ),
110109 prompt_mask = np .ones ((b , p ), dtype = np .float32 ),
111110 completion_ids = np .ones ((b , c ), dtype = np .int32 ),
@@ -116,31 +115,33 @@ def _make_train_example(self, b=2, p=3, c=4):
116115 )
117116
118117 def test_success_with_ndarray (self ):
119- batch = self ._make_train_example (b = 2 , p = 3 , c = 4 )
118+ batch = self ._make_payload (b = 2 , p = 3 , c = 4 )
120119 ref_logps = np .full ((2 , 4 ), - 0.5 , dtype = np .float32 )
121120 updated = batch_assembly .with_ref_per_token_logps (batch , ref_logps )
122121
122+ self .assertIsInstance (updated , datatypes .RLTrainerPayload )
123123 self .assertIsNotNone (updated .ref_per_token_logps )
124124 self .assertEqual (updated .ref_per_token_logps .shape , (2 , 4 ))
125125 np .testing .assert_allclose (updated .ref_per_token_logps , ref_logps )
126126 np .testing .assert_array_equal (updated .prompt_ids , batch .prompt_ids )
127127 np .testing .assert_array_equal (updated .completion_ids , batch .completion_ids )
128128
129129 def test_success_with_logprobs_response (self ):
130- batch = self ._make_train_example (b = 2 , p = 3 , c = 4 )
130+ batch = self ._make_payload (b = 2 , p = 3 , c = 4 )
131131 resp = datatypes .LogprobsResponse (
132132 per_token_logps = np .full ((2 , 4 ), - 0.8 , dtype = np .float32 )
133133 )
134134 updated = batch_assembly .with_ref_per_token_logps (batch , resp )
135135
136+ self .assertIsInstance (updated , datatypes .RLTrainerPayload )
136137 self .assertIsNotNone (updated .ref_per_token_logps )
137138 self .assertEqual (updated .ref_per_token_logps .shape , (2 , 4 ))
138139 np .testing .assert_allclose (
139140 updated .ref_per_token_logps , resp .per_token_logps
140141 )
141142
142143 def test_error_in_logprobs_response_raises_runtime_error (self ):
143- batch = self ._make_train_example (b = 2 , p = 3 , c = 4 )
144+ batch = self ._make_payload (b = 2 , p = 3 , c = 4 )
144145 resp = datatypes .LogprobsResponse (
145146 per_token_logps = None ,
146147 error = datatypes .ErrorInfo (
@@ -150,18 +151,14 @@ def test_error_in_logprobs_response_raises_runtime_error(self):
150151 with self .assertRaisesRegex (RuntimeError , "inference worker failed" ):
151152 batch_assembly .with_ref_per_token_logps (batch , resp )
152153
153- def test_rejects_non_train_example (self ):
154- payload = datatypes .RLTrainerPayload (
155- token_ids = np .array ([1 , 2 ], dtype = np .int32 ),
156- token_mask = np .array ([1 , 1 ], dtype = np .float32 ),
157- loss_mask = np .array ([0 , 1 ], dtype = np .float32 ),
158- advantages = np .array ([1.0 , 1.0 ], dtype = np .float32 ),
159- )
160- with self .assertRaisesRegex (TypeError , "expects a padded TrainExample" ):
161- batch_assembly .with_ref_per_token_logps (payload , np .zeros ((2 , 2 )))
154+ def test_rejects_unsupported_type (self ):
155+ with self .assertRaisesRegex (TypeError , "expects a padded RLTrainerPayload" ):
156+ batch_assembly .with_ref_per_token_logps (
157+ {"raw" : "batch" }, np .zeros ((2 , 2 ))
158+ )
162159
163160 def test_mismatched_shape_raises_value_error (self ):
164- batch = self ._make_train_example (b = 2 , p = 3 , c = 4 )
161+ batch = self ._make_payload (b = 2 , p = 3 , c = 4 )
165162 bad_shape_logps = np .zeros ((2 , 3 ), dtype = np .float32 )
166163 with self .assertRaisesRegex (
167164 ValueError ,
@@ -277,121 +274,6 @@ def test_sequence_packed_assembler_multiple_bins(self):
277274 self .assertEqual (payloads [1 ].token_ids .shape , (1 , 12 ))
278275
279276
280- class GRPOTrainExampleAssemblerTest (absltest .TestCase ):
281-
282- def test_rejects_non_positive_batch_size (self ):
283- with self .assertRaisesRegex (ValueError , "batch size must be positive" ):
284- batch_assembly .GRPOTrainExampleAssembler (
285- batch_size = 0 ,
286- max_prompt_length = 4 ,
287- max_response_length = 5 ,
288- pad_id = 0 ,
289- )
290-
291- def test_empty_input_returns_empty_list (self ):
292- assembler = batch_assembly .GRPOTrainExampleAssembler (
293- batch_size = 2 ,
294- max_prompt_length = 4 ,
295- max_response_length = 5 ,
296- pad_id = 0 ,
297- )
298- self .assertEmpty (assembler .pack ([]))
299-
300- def test_grpo_train_example_assembler_basic (self ):
301- payload = datatypes .RLTrainerPayload (
302- token_ids = np .array ([10 , 11 , 20 , 21 , 22 ], dtype = np .int32 ),
303- token_mask = np .ones (5 , dtype = np .float32 ),
304- loss_mask = np .array ([0 , 0 , 1 , 1 , 0 ], dtype = np .float32 ),
305- action_mask = np .array ([0 , 0 , 1 , 1 , 0 ], dtype = np .float32 ),
306- advantages = np .array ([0 , 0 , 2 , 2 , 2 ], dtype = np .float32 ),
307- prompt_ids = np .array ([10 , 11 ], dtype = np .int32 ),
308- prompt_mask = np .ones (2 , dtype = np .float32 ),
309- completion_ids = np .array ([20 , 21 , 22 ], dtype = np .int32 ),
310- completion_mask = np .array ([1 , 1 , 0 ], dtype = np .float32 ),
311- )
312-
313- assembler = batch_assembly .GRPOTrainExampleAssembler (
314- batch_size = 2 ,
315- max_prompt_length = 4 ,
316- max_response_length = 5 ,
317- pad_id = 0 ,
318- )
319- train_example = assembler .pack ([payload ])[0 ]
320-
321- self .assertEqual (train_example .prompt_ids .shape , (2 , 4 ))
322- self .assertEqual (train_example .completion_ids .shape , (2 , 5 ))
323- np .testing .assert_array_equal (
324- train_example .prompt_ids [0 ], np .array ([0 , 0 , 10 , 11 ])
325- )
326- np .testing .assert_array_equal (
327- train_example .completion_ids [0 ], np .array ([20 , 21 , 22 , 0 , 0 ])
328- )
329- np .testing .assert_array_equal (
330- train_example .completion_mask [0 ], np .array ([1 , 1 , 0 , 0 , 0 ])
331- )
332- np .testing .assert_array_equal (
333- train_example .advantages [0 ], np .array ([2 , 2 , 2 , 0 , 0 ])
334- )
335-
336- def test_grpo_assembler_optional_fields_propagation (self ):
337- payload = datatypes .RLTrainerPayload (
338- token_ids = np .array ([10 , 11 , 20 , 21 , 22 ], dtype = np .int32 ),
339- token_mask = np .ones (5 , dtype = np .float32 ),
340- loss_mask = np .array ([0 , 0 , 1 , 1 , 1 ], dtype = np .float32 ),
341- action_mask = np .array ([0 , 0 , 1 , 1 , 1 ], dtype = np .float32 ),
342- advantages = np .array ([2 , 2 , 2 ], dtype = np .float32 ),
343- prompt_ids = np .array ([10 , 11 ], dtype = np .int32 ),
344- prompt_mask = np .ones (2 , dtype = np .float32 ),
345- completion_ids = np .array ([20 , 21 , 22 ], dtype = np .int32 ),
346- completion_mask = np .ones (3 , dtype = np .float32 ),
347- ref_per_token_logps = np .array ([- 0.3 , - 0.4 , - 0.5 ], dtype = np .float32 ),
348- old_per_token_logps = np .array ([- 0.1 , - 0.2 , - 0.3 ], dtype = np .float32 ),
349- )
350-
351- assembler = batch_assembly .GRPOTrainExampleAssembler (
352- batch_size = 2 ,
353- max_prompt_length = 4 ,
354- max_response_length = 5 ,
355- pad_id = 0 ,
356- )
357- train_example = assembler .pack ([payload ])[0 ]
358-
359- self .assertIsNotNone (train_example .ref_per_token_logps )
360- self .assertIsNotNone (train_example .old_per_token_logps )
361-
362- self .assertEqual (train_example .ref_per_token_logps .shape , (2 , 5 ))
363- self .assertEqual (train_example .old_per_token_logps .shape , (2 , 5 ))
364-
365- np .testing .assert_allclose (
366- train_example .ref_per_token_logps [0 ], [- 0.3 , - 0.4 , - 0.5 , 0.0 , 0.0 ]
367- )
368- np .testing .assert_allclose (
369- train_example .old_per_token_logps [0 ], [- 0.1 , - 0.2 , - 0.3 , 0.0 , 0.0 ]
370- )
371-
372- def test_grpo_assembler_chunks_multiple_microbatches (self ):
373- payload = datatypes .RLTrainerPayload (
374- token_ids = np .array ([1 , 2 , 3 ], dtype = np .int32 ),
375- token_mask = np .ones (3 , dtype = np .float32 ),
376- loss_mask = np .array ([0 , 1 , 1 ], dtype = np .float32 ),
377- advantages = np .array ([1.0 , 1.0 ], dtype = np .float32 ),
378- prompt_ids = np .array ([1 ], dtype = np .int32 ),
379- completion_ids = np .array ([2 , 3 ], dtype = np .int32 ),
380- )
381-
382- assembler = batch_assembly .GRPOTrainExampleAssembler (
383- batch_size = 2 ,
384- max_prompt_length = 3 ,
385- max_response_length = 4 ,
386- pad_id = 0 ,
387- )
388- train_examples = assembler .pack ([payload , payload , payload ])
389-
390- self .assertLen (train_examples , 2 )
391- self .assertEqual (train_examples [0 ].prompt_ids .shape , (2 , 3 ))
392- self .assertEqual (train_examples [1 ].prompt_ids .shape , (2 , 3 ))
393-
394-
395277def _make_payload (
396278 prompt_len : int ,
397279 completion_len : int ,
@@ -585,8 +467,9 @@ def test_scalar_advantage_broadcasts_over_completion(self):
585467 np .testing .assert_allclose (payload .advantages [0 ], [2.5 , 2.5 , 2.5 , 0 , 0 ])
586468
587469 def test_sequence_aligned_advantage_is_sliced_to_completion (self ):
588- item = _make_payload (2 , 3 )
589- item .advantages = np .array ([0 , 0 , 2 , 2 , 2 ], dtype = np .float32 )
470+ item = _make_payload (
471+ 2 , 3 , advantage = np .array ([0 , 0 , 2 , 2 , 2 ], dtype = np .float32 )
472+ )
590473 payload = self ._assembler ().pack ([item ])[0 ]
591474
592475 np .testing .assert_allclose (payload .advantages [0 ], [2 , 2 , 2 , 0 , 0 ])
0 commit comments