vit-oct-wamd / embedder.py
Kavin
Upload embedder.py with huggingface_hub
4d2099e verified
Raw
History Blame Contribute Delete
2.79 kB
from typing import List
from typing import Tuple
import numpy as np
import torch
from torch import nn
from transformers import AutoTokenizer, T5EncoderModel
class TextEmbedder(nn.Module):
"""
Minimal wrapper around a *frozen* T5-base (or any seq-to-seq encoder).
──────────── Usage ─────────────
>>> txt = TextEmbedder("google-t5/t5-base", max_len=128)
>>> ids, mask = txt.tokenize("some text")
>>> z_txt = txt.encode(torch.tensor(ids)[None, :],
torch.tensor(mask)[None, :])
"""
def __init__(
self,
model_name: str = "google-t5/t5-base",
max_len: int = 128,
dtype: torch.dtype = torch.float16, # keeps weights β‰ˆ2Γ— smaller
):
super(TextEmbedder, self).__init__()
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.encoder = T5EncoderModel.from_pretrained(model_name).to(dtype=dtype)
self.encoder.eval()
for p in self.encoder.parameters(): # freeze
p.requires_grad = False
self.max_len = max_len
# ------------------------------------------------------------ tokenize
@torch.no_grad()
def tokenize(self, text: str | List[str]) -> Tuple[np.ndarray, np.ndarray]:
"""
padded position are set to 0, and attention mask to 1.
For example, if max_len=5 and text="hellow world",
the tokenizer will return:
input_ids = [21820, 296, 0, 0, 0]
attention_mask = [1, 1, 0, 0, 0]
Returns (input_ids[int32], attn_mask[int8]) shaped (max_len,)
(If *text* is a list, shapes are (B,max_len).)
"""
batch = self.tokenizer(
text,
padding="max_length",
truncation=True,
max_length=self.max_len,
return_attention_mask=True,
)
ids = np.asarray(batch["input_ids"], dtype=np.int32)
mask = np.asarray(batch["attention_mask"], dtype=np.int8)
return ids, mask
# ------------------------------------------------------------ encode
@torch.no_grad()
def encode(
self,
input_ids: torch.LongTensor, # (B,L)
attention_mask: torch.BoolTensor, # (B,L)
) -> torch.Tensor: # (B,L,H)
"""
Run the frozen encoder and return the sequence embeddings
(no pooling – do that in your SigLIP loss if you wish).
"""
input_ids = input_ids
attention_mask = attention_mask
out = self.encoder(input_ids=input_ids,
attention_mask=attention_mask,
return_dict=True)
return out.last_hidden_state # (B,L,hidden)