Migrate to transformers 5 - #363
pmachapman wants to merge 11 commits into
Conversation
cf019f7 to
2d7748c
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #363 +/- ##
==========================================
- Coverage 92.13% 92.05% -0.08%
==========================================
Files 390 394 +4
Lines 24644 24844 +200
==========================================
+ Hits 22705 22871 +166
- Misses 1939 1973 +34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Adding @mshannon-sil as a reviewer here as well. Thank you for doing this, Peter! |
Enkidu93
left a comment
There was a problem hiding this comment.
I know this was a lot of work. Thank you, Peter! These kinds of changes always make me nervous. Unfortunately, Mike is no longer doing his BLEU tests (he mentioned SF is picking those up somehow? Not sure what he meant exactly?). Maybe we should begin doing that sort of test ourselves.
@Enkidu93 reviewed 17 files and all commit messages, and made 1 comment.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on ddaspit and mshannon-sil).
ddaspit
left a comment
There was a problem hiding this comment.
Thanks for taking this on. A few things I found while going through it; the batch_prepare_for_model one is the only one I think has to be fixed before merging.
One more that isn't in the diff: samples/machine_translation.ipynb still passes overwrite_output_dir=True, which is gone in v5, so that cell will raise.
mshannon-sil
left a comment
There was a problem hiding this comment.
@mshannon-sil reviewed 8 files and all commit messages, and made 2 comments.
Reviewable status: all files reviewed, 17 unresolved discussions (waiting on pmachapman).
.gitignore line 147 at r2 (raw file):
# Ignore custom pyright configuration pyrightconfig.json
Do we not want a standard pyrightconfig.json for the repository?
machine/translation/huggingface/transformers_compatibility.py line 1 at r2 (raw file):
import enum
What are the benefits of recreating the TranslationPipeline class ourselves, now that it's been removed from transformers? Is it just that it's more similar to what was here before? SILNLP no longer imports Pipeline at all from transformers, choosing to create a standaloneSilTranslator class instead. I had Devin review the two approaches, and it seems that using something similar to SILNLP's approach here could cut down on overhead and reduce opportunities for bugs. It also seems to make intuitive sense to me that we shouldn't need to create a whole file for transformers compatibility to replicate transformers 4.x code, if instead we can rearchitect it to feel like more natural transformers 5.x code. But I admit, I don't have a 100% understanding of the pros and cons of both approaches, so feel free to share if there's a production, repo, or other reason why keeping the pipeline makes more sense.
870183e to
355ffd8
Compare
pmachapman
left a comment
There was a problem hiding this comment.
One more that isn't in the diff:
samples/machine_translation.ipynbstill passesoverwrite_output_dir=True, which is gone in v5, so that cell will raise.
Done. Thanks!
@pmachapman made 18 comments and resolved 2 discussions.
Reviewable status: 8 of 18 files reviewed, 15 unresolved discussions (waiting on ddaspit, Enkidu93, and mshannon-sil).
machine/translation/huggingface/transformers_compatibility.py line 1 at r2 (raw file):
Previously, mshannon-sil wrote…
What are the benefits of recreating the
TranslationPipelineclass ourselves, now that it's been removed fromtransformers? Is it just that it's more similar to what was here before? SILNLP no longer importsPipelineat all fromtransformers, choosing to create a standaloneSilTranslatorclass instead. I had Devin review the two approaches, and it seems that using something similar to SILNLP's approach here could cut down on overhead and reduce opportunities for bugs. It also seems to make intuitive sense to me that we shouldn't need to create a whole file for transformers compatibility to replicate transformers 4.x code, if instead we can rearchitect it to feel like more natural transformers 5.x code. But I admit, I don't have a 100% understanding of the pros and cons of both approaches, so feel free to share if there's a production, repo, or other reason why keeping the pipeline makes more sense.
I needed to implement Pipeline for batch support. My initial implementation was with a copy of SilTranslator, but due to its lack of batch support, I could make the tests pass, but it failed when used on Serval.
My understanding of the changes in transformers 5 is just that they removed the Text2TextGenerationPipeline, with their suggestion being to use an LLM instead - see https://github.com/huggingface/transformers/blob/main/MIGRATION_GUIDE_V5.md#text-pipelines-that-should-just-be-llms. I don't think the LLM approach will work for us just yet?
My actual porting of TranslationPipeline wasn't too involved - most of the differences are me stripping out code that is unnecessary or unused, and combining TranslationPipeline and Text2TextGenerationPipeline.
.gitignore line 147 at r2 (raw file):
Previously, mshannon-sil wrote…
Do we not want a standard pyrightconfig.json for the repository?
I've removed this line - I can't find the file.
ddaspit
left a comment
There was a problem hiding this comment.
@ddaspit reviewed 18 files and all commit messages, made 4 comments, and resolved 13 discussions.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on Enkidu93, mshannon-sil, and pmachapman).
|
Previously, pmachapman (Peter Chapman) wrote…
Is there a way that Serval is calling the pipeline that is unique to Serval and not how machine.py works? I've looked through the machine.py master branch, and it seems _TranslationPipeline was only ever called on a single batch at a time, since it was called inside of |
|
Previously, mshannon-sil wrote…
And yes, your understanding of the changes are correct. We're also not at a spot to replace it with an LLM call. |
pmachapman
left a comment
There was a problem hiding this comment.
@pmachapman made 5 comments, resolved 6 discussions, and dismissed @mshannon-sil from a discussion.
Reviewable status: 17 of 18 files reviewed, 1 unresolved discussion (waiting on ddaspit, Enkidu93, and mshannon-sil).
eaac574 to
116c846
Compare
ddaspit
left a comment
There was a problem hiding this comment.
@ddaspit reviewed 4 files and all commit messages, and made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on Enkidu93 and mshannon-sil).
machine/translation/huggingface/transformers_compatibility.py line 1 at r2 (raw file):
Previously, mshannon-sil wrote…
And yes, your understanding of the changes are correct. We're also not at a spot to replace it with an LLM call.
One of the key benefits of reimplementing TranslationPipeline is that it helps us to maintain backwards compatibility. Batching is an example of this. There are two levels of batching at play here. The first is at the Machine API level. This is used to support the streaming APIs in Machine. The second is at the Huggingface level. A model will often have a batch size for training/inferencing that needs to be configured to maximize speed and memory usage for a model. This is a separate batch size that can be configured for a particular translation engine. To keep Machine flexible, we want to support both types of batches. There are other configuration options that can be passed to the pipeline that we want to continue to support for compatibility reasons (see pipeline_kwargs argument in the HuggingFaceNmtEngine constructor).
mshannon-sil
left a comment
There was a problem hiding this comment.
@mshannon-sil made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on Enkidu93 and pmachapman).
machine/translation/huggingface/transformers_compatibility.py line 1 at r2 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
One of the key benefits of reimplementing
TranslationPipelineis that it helps us to maintain backwards compatibility. Batching is an example of this. There are two levels of batching at play here. The first is at the Machine API level. This is used to support the streaming APIs in Machine. The second is at the Huggingface level. A model will often have a batch size for training/inferencing that needs to be configured to maximize speed and memory usage for a model. This is a separate batch size that can be configured for a particular translation engine. To keep Machine flexible, we want to support both types of batches. There are other configuration options that can be passed to the pipeline that we want to continue to support for compatibility reasons (seepipeline_kwargsargument in theHuggingFaceNmtEngineconstructor).
Okay that makes sense, thanks. Do we want to rename this file to something like hugging_face_nmt_pipeline.py to be more descriptive and match the neighboring files in machine/translation/huggingface?
|
Previously, mshannon-sil wrote…
The renaming I think is optional, so I'll go ahead and approve the PR. |
API / wheel surface changed:
I did not check parity with Out of scope: the OOM-retry pipeline rebuild at Findings: F1 unverified-fix pending (confirmed defect), F2 confirmed, F3 unverified, F4 accepted, F5 accepted, F6 accepted, F7 unverified, F8 unverified, F9 accepted. Each awaits the author's answer; I will mark them changed once addressed. |
|
Review summary
Public API / wheel surface changed:
Dropped after verification:
Status: F1 changed-requested, F2 answer-needed, F3 unverified, F4 answer-needed, F5 accepted, F6 accepted, F7 accepted (predates this PR). 🤖 Generated with Claude Code |
pmachapman
left a comment
There was a problem hiding this comment.
@pmachapman resolved 16 discussions.
Reviewable status: 14 of 18 files reviewed, all discussions resolved (waiting on ddaspit, Enkidu93, and mshannon-sil).
|
Review summary (round 6, follow-up)
Surface changed: the Withdrawn this round: the beam-alignment offset (round-3 F1, round-4 F3, round-5 F1). It predates this PR, because v4.47.1 Noted, not posted (Low, on code the last round already saw): a call-time Status. Earlier rounds each restarted at F1, so they are labelled here by round: R1 09-28 20:23, R2 09-29 20:37, R3 21:43, R4 22:05, R5 22:13.
Reviewed at 8ac226f 🤖 Generated with Claude Code |
ddaspit
left a comment
There was a problem hiding this comment.
@ddaspit reviewed 4 files and all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on Enkidu93 and mshannon-sil).
mshannon-sil
left a comment
There was a problem hiding this comment.
@mshannon-sil made 1 comment.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on Enkidu93).
Let transformers choose the attention implementation when attentions are not needed, since forcing "sdpa" fails to load T5/mT5. Decide whether to build alignments from the attentions generate returns, so SilTranslationPipeline no longer crashes when output_attentions is unset or overridden per call. Ignore a null group_by_length, let an explicit train_sampling_strategy take precedence, and log the deprecation so it appears in job logs. Switch a caller-owned model to eager attention only at the end of the engine constructor, so a constructor that raises leaves the model unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ddaspit
left a comment
There was a problem hiding this comment.
In the interest of trying to wrap up this PR, I added a commit that addresses some of the remaining Claude comments. I resolved the duplicates and created separate issues for the pre-existing issues that were identified in the review.
@ddaspit reviewed 4 files and all commit messages, and made 1 comment.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on Enkidu93).
| if generate_kwargs["output_attentions"] is True: | ||
| assert attentions is not None | ||
| # output_attentions can be unset or overridden per call, so rely on what generate actually returned. | ||
| if attentions is not None: |
There was a problem hiding this comment.
Minor: F11. This guard misses the SDPA case: generate returns cross_attentions as a tuple of empty tuples, not None, so attentions[0][0] on the next line raises IndexError. Repro on stas/tiny-m2m_100: load with attn_implementation="sdpa", then call SilTranslationPipeline(..., output_attentions=True), and the call raises IndexError: tuple index out of range. Checking attentions and attentions[0] would fall back to empty alignments.
| del self._pipeline | ||
| if self._is_model_owned: | ||
| del self._model | ||
| elif self._model_attn_implementation is not None: |
There was a problem hiding this comment.
FYI: F12. close() restores the saved implementation even when this engine did not change it, so two engines on one caller model break each other. Repro: engines A and B on an SDPA stas/tiny-m2m_100, both with output_attentions=True. B saves eager, A.close() sets sdpa, then B.translate(...) raises IndexError (via F11). Restoring only when this engine made the switch would avoid it.
|
Review summary (round 7, follow-up on fcf9486)
Surface changed: unchanged from round 6. The Status. Earlier rounds restarted at F1, so they are labelled by round (R1 09-28 20:23; R2–R5 09-29 20:37, 21:43, 22:05, 22:13). This round continues from the highest number.
Reviewed at fcf9486 🤖 Generated with Claude Code |
This change is