Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generation: fix test #34369

Merged
merged 4 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
44 changes: 12 additions & 32 deletions tests/generation/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,29 +669,6 @@ def test_beam_sample_generate(self):
else:
self.assertTrue(output_generate.shape[-1] == self.max_new_tokens + inputs_dict["input_ids"].shape[-1])

# for VLMs inputs embeds won't match input ids unless images are encoded and merged with ids properly
# no quick fix available, since obtaining image embeddings step is very model-specific
if any(name in model.__class__.__name__.lower() for name in ("blip", "llava", "paligemma")):
prepare_inputs_for_generation_args = set(
inspect.signature(model.prepare_inputs_for_generation).parameters
)
# `inputs_embeds` input is well supported when `cache_positions` is used, because it means the modeling
# code is up to date with our most recent standards
if (
"inputs_embeds" in prepare_inputs_for_generation_args
and "cache_positions" in prepare_inputs_for_generation_args
Copy link
Member

Choose a reason for hiding this comment

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

so this part was never executed, because of the typo in cache_positions -- correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

yep :)

):
input_embeds = model.get_input_embeddings()(inputs_dict["input_ids"])
beam_kwargs.update({"inputs_embeds": input_embeds})
output_generate2 = self._beam_sample_generate(
model=model,
input_ids=None,
inputs_dict={},
beam_kwargs=beam_kwargs,
)

torch.testing.assert_close(output_generate[:, input_embeds.shape[1] :], output_generate2)

@pytest.mark.generate
def test_beam_sample_generate_dict_output(self):
for model_class in self.all_generative_model_classes:
Expand Down Expand Up @@ -1568,7 +1545,8 @@ def test_past_key_values_format(self):
)

@pytest.mark.generate
def test_generate_from_inputs_embeds_decoder_only(self):
@parameterized.expand([(1,), (2,)])
def test_generate_from_inputs_embeds_decoder_only(self, num_beams):
# When supported, tests that the decoder model can generate from `inputs_embeds` instead of `input_ids`
# if fails, you should probably update the `prepare_inputs_for_generation` function
for model_class in self.all_generative_model_classes:
Expand All @@ -1595,11 +1573,15 @@ def test_generate_from_inputs_embeds_decoder_only(self):
continue

input_ids = inputs_dict.pop("input_ids")
generation_kwargs = {
"return_dict_in_generate": True,
"output_scores": True,
"num_beams": num_beams,
"do_sample": False,
}

# Traditional way of generating text
outputs_from_ids = model.generate(
input_ids, max_new_tokens=5, return_dict_in_generate=True, output_scores=True
)
outputs_from_ids = model.generate(input_ids, max_new_tokens=5, **generation_kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

nit: max_new_tokens can be moved to generation_kwargs

self.assertEqual(outputs_from_ids.sequences.shape, (input_ids.shape[0], input_ids.shape[1] + 5))

# Same thing, but from input embeddings (`input_ids` is passed so the prompt is present in the output)
Expand All @@ -1608,8 +1590,7 @@ def test_generate_from_inputs_embeds_decoder_only(self):
input_ids,
inputs_embeds=inputs_embeds,
max_new_tokens=5,
return_dict_in_generate=True,
output_scores=True,
**generation_kwargs,
)
self.assertListEqual(outputs_from_ids.sequences.tolist(), outputs_from_embeds.sequences.tolist())

Expand All @@ -1620,15 +1601,14 @@ def test_generate_from_inputs_embeds_decoder_only(self):
input_ids,
inputs_embeds=random_embeds,
max_new_tokens=5,
return_dict_in_generate=True,
output_scores=True,
**generation_kwargs,
)
for i in range(len(outputs_from_rand_embeds.scores)):
self.assertFalse(torch.allclose(outputs_from_embeds.scores[i], outputs_from_rand_embeds.scores[i]))

# input_ids is not a required input -- if we don't pass it, the newly generated tokens will be the same
outputs_from_embeds_wo_ids = model.generate(
inputs_embeds=inputs_embeds, max_new_tokens=5, return_dict_in_generate=True, output_scores=True
inputs_embeds=inputs_embeds, max_new_tokens=5, **generation_kwargs
)
self.assertListEqual(
outputs_from_embeds.sequences[:, inputs_embeds.shape[1] :].tolist(),
Expand Down
3 changes: 2 additions & 1 deletion tests/models/idefics/test_modeling_idefics.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,8 @@ def test_custom_4d_attention_mask(self):
@unittest.skip(
reason="IDEFICS has specific requirements for working with inputs embeds like passing also the ids and pixels"
)
def test_generate_from_inputs_embeds_decoder_only(self):
@parameterized.expand([(1,), (2,)])
def test_generate_from_inputs_embeds_decoder_only(self, num_beams):
pass

@unittest.skip(reason="IDEFICS cannot compile due to dynamic control flow when checking inputs")
Expand Down
3 changes: 2 additions & 1 deletion tests/models/mamba2/test_modeling_mamba2.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ def test_generate_without_input_ids(self):
pass

@unittest.skip(reason="To fix, Mamba 2 cache slicing test case is an edge case")
def test_generate_from_inputs_embeds_decoder_only(self):
@parameterized.expand([(1,), (2,)])
def test_generate_from_inputs_embeds_decoder_only(self, num_beams):
pass

@unittest.skip(reason="To fix, Mamba 2 cache slicing test case is an edge case")
Expand Down
22 changes: 12 additions & 10 deletions tests/models/moshi/test_modeling_moshi.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,16 +656,21 @@ def test_initialization(self):
)

@pytest.mark.generate
def test_generate_from_inputs_embeds_decoder_only(self):
@parameterized.expand([(1,), (2,)])
def test_generate_from_inputs_embeds_decoder_only(self, num_beams):
for model_class in self.all_generative_model_classes:
config, input_ids, _, inputs_dict = self._get_input_ids_and_config()

model = model_class(config).to(torch_device).eval()
generation_kwargs = {
"return_dict_in_generate": True,
"output_scores": True,
"num_beams": num_beams,
"do_sample": False,
}

# Traditional way of generating text
outputs_from_ids = model.generate(
input_ids, max_new_tokens=5, return_dict_in_generate=True, output_scores=True, **inputs_dict
)
outputs_from_ids = model.generate(input_ids, max_new_tokens=5, **generation_kwargs, **inputs_dict)
self.assertEqual(outputs_from_ids.sequences.shape, (input_ids.shape[0], input_ids.shape[1] + 5))

# Same thing, but from input embeddings (`input_ids` is passed so the prompt is present in the output)
Expand All @@ -674,8 +679,7 @@ def test_generate_from_inputs_embeds_decoder_only(self):
input_ids,
inputs_embeds=inputs_embeds,
max_new_tokens=5,
return_dict_in_generate=True,
output_scores=True,
**generation_kwargs,
**inputs_dict,
)

Expand All @@ -686,8 +690,7 @@ def test_generate_from_inputs_embeds_decoder_only(self):
input_ids,
inputs_embeds=random_embeds,
max_new_tokens=5,
return_dict_in_generate=True,
output_scores=True,
**generation_kwargs,
**inputs_dict,
)
for i in range(len(outputs_from_rand_embeds.scores)):
Expand All @@ -697,8 +700,7 @@ def test_generate_from_inputs_embeds_decoder_only(self):
outputs_from_embeds_wo_ids = model.generate(
inputs_embeds=inputs_embeds,
max_new_tokens=5,
return_dict_in_generate=True,
output_scores=True,
**generation_kwargs,
**inputs_dict,
)
self.assertListEqual(
Expand Down
Loading