Improve performance of encoding Moss prompts with a batch size > 1
This commit is contained in:
1 parent
2d4c89d392
commit
04733873cf
1 file changed
+41
-14
@@ -117,6 +117,30 @@ def _hub_file_folder(repo_id: str, filename: str) -> str:
|
|||||||
return os.path.dirname(path)
|
return os.path.dirname(path)
|
||||||
|
|
||||||
|
|
||||||
|
@torch.no_grad()
|
||||||
|
def encode_text_batch(text_encoder, tokenizer, texts, max_length, device) -> List[torch.Tensor]:
|
||||||
|
"""Chat-templated prompts -> per-item (L_i, D) final states from ONE forward.
|
||||||
|
Right-padded, no attention mask: for the causal model the pads sit after
|
||||||
|
each prompt's real tokens, so neither causal attention nor the gated-delta
|
||||||
|
recurrence can reach them -- each item's first L_i states equal its
|
||||||
|
unpadded forward (the HF mask path only zeroes padded states, which is
|
||||||
|
left-padding hygiene, and would also drop attention off its fast path).
|
||||||
|
Default arange positions are right for right padding."""
|
||||||
|
enc = tokenizer(
|
||||||
|
texts,
|
||||||
|
return_tensors="pt",
|
||||||
|
padding=True,
|
||||||
|
padding_side="right",
|
||||||
|
truncation=True,
|
||||||
|
max_length=max_length,
|
||||||
|
)
|
||||||
|
lengths = enc["attention_mask"].sum(1).tolist()
|
||||||
|
states = text_encoder(
|
||||||
|
input_ids=enc["input_ids"].to(device), use_cache=False
|
||||||
|
).last_hidden_state
|
||||||
|
return [states[i, :n] for i, n in enumerate(lengths)]
|
||||||
|
|
||||||
|
|
||||||
def _drop_repeats(images):
|
def _drop_repeats(images):
|
||||||
"""ctrl_img_1 defaults to ctrl_img, so a single reference can arrive twice."""
|
"""ctrl_img_1 defaults to ctrl_img, so a single reference can arrive twice."""
|
||||||
kept = []
|
kept = []
|
||||||
@@ -559,21 +583,24 @@ class MossImageModel(BaseModel):
|
|||||||
else:
|
else:
|
||||||
control_images = [None] * len(prompt)
|
control_images = [None] * len(prompt)
|
||||||
|
|
||||||
embeds = []
|
# text-only prompts go through ONE right-padded forward (exact, see
|
||||||
# one unpadded forward per prompt, like the vendor (padding would leak
|
# encode_text_batch); prompts with references stay one forward each
|
||||||
# into the gated-delta recurrence)
|
# (their image-pad runs differ per prompt)
|
||||||
for text, images in zip(prompt, control_images):
|
embeds: List[Optional[torch.Tensor]] = [None] * len(prompt)
|
||||||
|
text_only = [i for i, images in enumerate(control_images) if not images]
|
||||||
|
if text_only:
|
||||||
|
states = encode_text_batch(
|
||||||
|
self.text_encoder,
|
||||||
|
self.tokenizer,
|
||||||
|
[self._chat(prompt[i]) for i in text_only],
|
||||||
|
self.max_text_length,
|
||||||
|
self.device_torch,
|
||||||
|
)
|
||||||
|
for i, st in zip(text_only, states):
|
||||||
|
embeds[i] = st.to(self.torch_dtype)
|
||||||
|
for i, (text, images) in enumerate(zip(prompt, control_images)):
|
||||||
if images:
|
if images:
|
||||||
states = self._encode_with_images(text, images)
|
embeds[i] = self._encode_with_images(text, images).to(self.torch_dtype)
|
||||||
else:
|
|
||||||
input_ids = self.tokenizer(
|
|
||||||
self._chat(text),
|
|
||||||
return_tensors="pt",
|
|
||||||
truncation=True,
|
|
||||||
max_length=self.max_text_length,
|
|
||||||
)["input_ids"].to(self.device_torch)
|
|
||||||
states = self.text_encoder(input_ids=input_ids, use_cache=False).last_hidden_state[0]
|
|
||||||
embeds.append(states.to(self.torch_dtype))
|
|
||||||
return AdvancedPromptEmbeds(text_embeds=embeds)
|
return AdvancedPromptEmbeds(text_embeds=embeds)
|
||||||
|
|
||||||
def get_loss_target(self, *args, **kwargs):
|
def get_loss_target(self, *args, **kwargs):
|
||||||
|
|||||||
Reference in new issue
Block a user