Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add ViT NEPA#42978

Open
sbucaille wants to merge 21 commits into
huggingface:mainfrom
sbucaille:add_nepa
Open

Add ViT NEPA#42978
sbucaille wants to merge 21 commits into
huggingface:mainfrom
sbucaille:add_nepa

Conversation

@sbucaille

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #42977

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you read the contributor guideline,
    Pull Request section?
  • Was this discussed/approved via a Github issue or the forum? Please add a link
    to it if that's the case.
  • Did you make sure to update the documentation with your changes? Here are the
    documentation guidelines, and
    here are tips on formatting docstrings.
  • Did you write any new necessary tests?

Who can review?

@yonigozlan

@sbucaille sbucaille changed the title Add NEPA Add ViT NEPA Dec 21, 2025
@sbucaille sbucaille marked this pull request as ready for review December 22, 2025 03:04
@sbucaille

Copy link
Copy Markdown
Contributor Author

Hey @yonigozlan that was quick, the PR is ready for a review. This consists mostly in wrapping ViT with the NEPA self supervised framework, pretty straightforward. Test suite is mostly the same as ViT, with an added test for the ViTNepaForPreTraining class.
@stevhliu let me know what you think about the docs, same, mostly pasted from ViT and adapted with a small description of the framework

@ArthurZucker

Copy link
Copy Markdown
Collaborator

cc @molbap as well if you have time to review!

@molbap molbap self-requested a review January 5, 2026 15:28

@molbap molbap left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hey @sbucaille ! Thanks for the addition, left a few questions to clarify, if you can help me understand a bit!

Comment thread docs/source/en/model_doc/vit_nepa.md Outdated
Comment on lines +299 to +301
# Mask heads if we want to
if attention_mask is not None:
attn_weights = attn_weights * attention_mask

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

sorry, came back to this. I'm a bit confused at the presence of both causal_mask and attention_mask here, especially since at this stage, attention mask has to be added to the weights pre-softmax, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe the attention_mask is the head mask which would be a leftover from pre-v5 since head mask support has been dropped if I'm correct. causal_mask in this case is the for the model to attend previous patchs to predict the next (as per the goal of the paper). Since head masks are dropped, attention_mask is always None. But you are right, this is from the original code and the position of these instructions should be above, I fixed it in 835d204 let me know what you think

Comment on lines +336 to +337
query_layer = self.q_norm(query_layer)
key_layer = self.k_norm(key_layer)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this runs regardless of the config.qk_norm value, right? right now it exists and defaults to False, it should inform of the normalization rather (or not exist)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed in af6bc0f

Comment on lines +242 to +264
def forward(
self,
pixel_values: torch.Tensor,
bool_masked_pos: Optional[torch.BoolTensor] = None,
) -> torch.Tensor:
batch_size, _, height, width = pixel_values.shape
embeddings = self.patch_embeddings(pixel_values, interpolate_pos_encoding=False)
embeddings_clean = embeddings

if bool_masked_pos is not None:
seq_length = embeddings.shape[1]
mask_tokens = self.mask_token.expand(batch_size, seq_length, -1)
mask = bool_masked_pos.unsqueeze(-1).type_as(mask_tokens)
embeddings = embeddings * (1.0 - mask) + mask_tokens * mask

# add the [CLS] token
cls_tokens = self.cls_token.expand(batch_size, -1, -1)
embeddings = torch.cat((cls_tokens, embeddings), dim=1)
embeddings_clean = torch.cat((cls_tokens, embeddings_clean), dim=1)

embeddings = self.dropout(embeddings)

return embeddings, embeddings_clean

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this returns a tuple of Tensors (so need to change the hinting). Also returning tuples in module forwards is sometimes causing issues with tracing modules, if both are needed (for training) it would be worth having something like

     @dataclass
     class ViTNepaEmbeddingOutput:
         embeddings: torch.Tensor
         clean_embeddings: torch.Tensor

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Was not aware of such tracing problems thanks for the heads up, I added the dataclass in 77e4268

key: torch.Tensor,
value: torch.Tensor,
attention_mask: Optional[torch.Tensor],
scaling: float,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

if scaling is None, should fallback (like in vit eager)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 5653d13

Comment thread src/transformers/loss/loss_vit_nepa.py Outdated
Comment on lines +20 to +27
if shift:
# shift one step forward
p = hidden_states_out[:, :-1, :] # predict next
z = hidden_states_in[:, 1:, :] # target is next hidden state
else:
# same-position matching
p = hidden_states_out
z = hidden_states_in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do we need the same-position matching? I'm not 100% familiar with the NEPA training setup but we don't need MAE no? (feel free to correct me 😆 )

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You are right, the same-position branch should not exist, shift is never different from True, I removed it in c3279f6

@stevhliu stevhliu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks, just one tiny nit!

Comment thread docs/source/en/model_doc/vit_nepa.md Outdated
@sbucaille

Copy link
Copy Markdown
Contributor Author

Hey @molbap , thanks for your comments ! I addressed them, let me know if it looks good to you !

@sbucaille

Copy link
Copy Markdown
Contributor Author

Hey @molbap , just bumping this PR as someone asked if it could be merged soon in the original issue

@github-actions

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: auto, vit_nepa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ViT NEPA

4 participants