diff --git a/tests/utils/reward_score/test_gsm8k_on_cpu.py b/tests/utils/reward_score/test_gsm8k_on_cpu.py new file mode 100644 index 00000000000..a60530d9fe2 --- /dev/null +++ b/tests/utils/reward_score/test_gsm8k_on_cpu.py @@ -0,0 +1,40 @@ +# Copyright 2024 Bytedance Ltd. and/or its affiliates +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from verl.utils.reward_score import gsm8k + + +@pytest.mark.parametrize( + "solution_str, expected", + [ + ("The answer is 42", "42"), + ("first 7 then 13", "13"), + ("negative -5 here", "-5"), + # Only invalid tokens (a stray period): there is no real number, so the + # extraction must return None rather than the invalid "." token. + ("The result is just a period .", None), + ("no digits at all", None), + ], +) +def test_extract_solution_flexible(solution_str, expected): + assert gsm8k.extract_solution(solution_str, method="flexible") == expected + + +def test_flexible_no_valid_number_scores_zero(): + # A stray "." used to be extracted as the answer, so a non-zero format_score + # leaked to outputs that contain no real number. With no valid number the + # answer is None and the score is 0. + assert gsm8k.compute_score("just a period .", "42", method="flexible", format_score=0.1) == 0 diff --git a/verl/utils/reward_score/gsm8k.py b/verl/utils/reward_score/gsm8k.py index 98a8c24dc8c..f86165560a6 100644 --- a/verl/utils/reward_score/gsm8k.py +++ b/verl/utils/reward_score/gsm8k.py @@ -43,8 +43,9 @@ def extract_solution(solution_str, method="strict"): else: invalid_str = ["", "."] # find the last number that is not '.' - for final_answer in reversed(answer): - if final_answer not in invalid_str: + for candidate in reversed(answer): + if candidate not in invalid_str: + final_answer = candidate break return final_answer