Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions src/llamafactory/data/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,19 @@ def __call__(self, example: dict[str, Any]) -> dict[str, Any]:
or rejected[self.dataset_attr.role_tag] not in accept_tags[-1]
):
logger.warning_rank0(f"Invalid role tag in {[chosen, rejected]}.")
broken_data = True

prompt = aligned_messages
response = [
{
"role": tag_mapping[chosen[self.dataset_attr.role_tag]],
"content": chosen[self.dataset_attr.content_tag],
},
{
"role": tag_mapping[rejected[self.dataset_attr.role_tag]],
"content": rejected[self.dataset_attr.content_tag],
},
]
prompt, response = [], []
else:
prompt = aligned_messages
response = [
{
"role": tag_mapping[chosen[self.dataset_attr.role_tag]],
"content": chosen[self.dataset_attr.content_tag],
},
{
"role": tag_mapping[rejected[self.dataset_attr.role_tag]],
"content": rejected[self.dataset_attr.content_tag],
},
]
else: # normal example
prompt = aligned_messages[:-1]
response = aligned_messages[-1:]
Expand Down Expand Up @@ -319,19 +319,19 @@ def __call__(self, example: dict[str, Any]) -> dict[str, Any]:
or rejected[self.dataset_attr.role_tag] not in accept_tags[-1]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In OpenAIDatasetConverter, accept_tags contains standardized roles (Role.ASSISTANT.value, Role.FUNCTION.value), whereas chosen and rejected contain raw role tags from the dataset (e.g., "gpt"). Comparing the raw role tags directly against accept_tags[-1] will always fail if custom role tags are used, causing valid examples to be incorrectly skipped as having an invalid role tag.

To fix this, we should look up the raw role tags in tag_mapping using .get() before comparing them to accept_tags[-1].

            if (
                tag_mapping.get(chosen[self.dataset_attr.role_tag]) not in accept_tags[-1]
                or tag_mapping.get(rejected[self.dataset_attr.role_tag]) not in accept_tags[-1]
            ):

):
logger.warning_rank0(f"Invalid role tag in {[chosen, rejected]}.")
broken_data = True

prompt = aligned_messages
response = [
{
"role": tag_mapping[chosen[self.dataset_attr.role_tag]],
"content": chosen[self.dataset_attr.content_tag],
},
{
"role": tag_mapping[rejected[self.dataset_attr.role_tag]],
"content": rejected[self.dataset_attr.content_tag],
},
]
prompt, response = [], []
else:
prompt = aligned_messages
response = [
{
"role": tag_mapping[chosen[self.dataset_attr.role_tag]],
"content": chosen[self.dataset_attr.content_tag],
},
{
"role": tag_mapping[rejected[self.dataset_attr.role_tag]],
"content": rejected[self.dataset_attr.content_tag],
},
]
else: # normal example
prompt = aligned_messages[:-1]
response = aligned_messages[-1:]
Expand Down
20 changes: 20 additions & 0 deletions tests/data/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,23 @@ def test_sharegpt_converter():
"_videos": None,
"_audios": None,
}


@pytest.mark.runs_on(["cpu", "mps"])
def test_sharegpt_converter_ranking_skips_invalid_role():
# A pairwise (ranking) example whose chosen/rejected carries a role tag not
# in the accepted set must be skipped, not crash with KeyError on tag_mapping.
dataset_attr = DatasetAttr("hf_hub", "llamafactory/tiny-supervised-dataset")
dataset_attr.ranking = True
dataset_attr.chosen = "chosen"
dataset_attr.rejected = "rejected"
data_args = DataArguments()
example = {
"conversations": [{"from": "human", "value": "Solve the math problem.\n3 + 4"}],
"chosen": {"from": "not_a_role", "value": "The answer is 7."},
"rejected": {"from": "gpt", "value": "The answer is 8."},
}
dataset_converter = get_dataset_converter("sharegpt", dataset_attr, data_args)
result = dataset_converter(example)
assert result["_prompt"] == []
assert result["_response"] == []