Skip to content

Commit f967068

Browse files
llama fixes
1 parent a6013ce commit f967068

2 files changed

Lines changed: 91 additions & 14 deletions

File tree

src/fairseq2/recipes/lm/_online_finetune/_generative_judge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ def remove_think_tags(self, rollout_text):
377377
text_without_thought = text_without_thought.replace("<|endoftext|>", "")
378378
return text_without_thought
379379
else:
380-
return "" # set rollout to empty string if it doesn't contain thought or has multiple
380+
return "DUMMY" # set rollout to dummy string if it doesn't contain thought or has multiple
381381

382382
@override
383383
def format_prompt(

src/fairseq2/recipes/lm/_online_finetune/_grpo.py

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,80 @@ class GRPOBatch:
7474
rewards: torch.Tensor
7575

7676

77-
def clip_outputs_after_think_token(rollouts, tokenizer, think_tokens, num_tokens):
77+
# def clip_outputs_after_think_token(rollouts, tokenizer, num_tokens):
78+
# """
79+
# Clip token_ids and logprobs to keep only num_tokens after the </think> token sequence ends.
80+
# If </think> is not found, clip to just the first num_tokens.
81+
# Recompute the text from clipped tokens.
82+
83+
# Args:
84+
# rollouts: List of rollout objects
85+
# tokenizer: Tokenizer instance
86+
# think_tokens: List of token IDs for </think>
87+
# num_tokens: Number of tokens to keep after </think> token sequence ends (or from start if no </think>)
88+
89+
# Returns:
90+
# List of modified rollout objects
91+
# """
92+
# think_tokens = tokenizer.encode("</think>", add_special_tokens=False)
93+
# ret = []
94+
# for rollout in rollouts:
95+
# clipped_outputs = []
96+
97+
# for output in rollout.outputs:
98+
# # Find the position where </think> tokens start
99+
# think_token_len = len(think_tokens)
100+
# clip_index = None
101+
102+
# # Search for the think tokens sequence in token_ids
103+
# for i in range(len(output.token_ids) - think_token_len + 1):
104+
# if output.token_ids[i : i + think_token_len] == think_tokens:
105+
# # Clip to include everything up to and including </think> plus num_tokens after
106+
# clip_index = i + think_token_len + num_tokens
107+
# break
108+
109+
# # If </think> not found, clip to just the first num_tokens
110+
# if clip_index is None:
111+
# clip_index = num_tokens
112+
113+
# # Clip token_ids and logprobs
114+
# clipped_token_ids = output.token_ids[:clip_index]
115+
# clipped_logprobs = output.logprobs[:clip_index]
116+
117+
# # Recompute text from clipped tokens
118+
# clipped_text = tokenizer.decode(clipped_token_ids)
119+
120+
# # Recalculate cumulative_logprob from clipped logprobs
121+
# cumulative_logprob = 0.0
122+
# for logprob_dict in clipped_logprobs:
123+
# # Get the first token's logprob (the selected token)
124+
# first_token_id = list(logprob_dict.keys())[0]
125+
# cumulative_logprob += logprob_dict[first_token_id].logprob
126+
127+
# # Create new CompletionOutput with clipped data
128+
# clipped_output = type(output)(
129+
# index=output.index,
130+
# text=clipped_text,
131+
# token_ids=clipped_token_ids,
132+
# cumulative_logprob=cumulative_logprob,
133+
# logprobs=clipped_logprobs,
134+
# finish_reason=output.finish_reason,
135+
# stop_reason=output.stop_reason,
136+
# )
137+
# clipped_outputs.append(clipped_output)
138+
139+
# # Create new rollout object with clipped outputs
140+
# clipped_rollout = type(rollout)(
141+
# outputs=clipped_outputs,
142+
# # Copy other attributes from original rollout
143+
# **{k: v for k, v in vars(rollout).items() if k != "outputs"},
144+
# )
145+
# ret.append(clipped_rollout)
146+
147+
# return ret
148+
149+
150+
def clip_outputs_after_think_token(rollouts, tokenizer, num_tokens):
78151
"""
79152
Clip token_ids and logprobs to keep only num_tokens after the </think> token sequence ends.
80153
If </think> is not found, clip to just the first num_tokens.
@@ -94,16 +167,24 @@ def clip_outputs_after_think_token(rollouts, tokenizer, think_tokens, num_tokens
94167
clipped_outputs = []
95168

96169
for output in rollout.outputs:
97-
# Find the position where </think> tokens start
98-
think_token_len = len(think_tokens)
99170
clip_index = None
100171

101-
# Search for the think tokens sequence in token_ids
102-
for i in range(len(output.token_ids) - think_token_len + 1):
103-
if output.token_ids[i : i + think_token_len] == think_tokens:
104-
# Clip to include everything up to and including </think> plus num_tokens after
105-
clip_index = i + think_token_len + num_tokens
106-
break
172+
# Search for "</think>" in the decoded text to avoid tokenizer context issues
173+
text = output.text
174+
think_end_pos = text.find("</think>")
175+
176+
if think_end_pos != -1:
177+
# Found "</think>" in text - now find the corresponding token position
178+
# The end of "</think>" in the text
179+
think_end_pos += len("</think>")
180+
181+
# Decode tokens incrementally to find where we pass the think_end_pos
182+
for i in range(1, len(output.token_ids) + 1):
183+
decoded_text = tokenizer.decode(output.token_ids[:i])
184+
if len(decoded_text) >= think_end_pos:
185+
# We've passed the end of "</think>", now add num_tokens more
186+
clip_index = min(i + num_tokens, len(output.token_ids))
187+
break
107188

108189
# If </think> not found, clip to just the first num_tokens
109190
if clip_index is None:
@@ -370,13 +451,9 @@ def __call__(
370451
]
371452
for text in prompt_batch.meta_info.get("suffix")
372453
]
373-
think_tokens = self._rollout_tokenizer.encode(
374-
"</think>", add_special_tokens=False
375-
)
376454
rollouts = clip_outputs_after_think_token(
377455
rollouts,
378456
self._rollout_tokenizer,
379-
think_tokens,
380457
self._config.clip_rollout_after_think,
381458
)
382459
if self._config.loss_config.log_rollouts:

0 commit comments

Comments
 (0)