Text Ranking
sentence-transformers
Safetensors
Transformers
multilingual
t5gemma2
text2text-generation
reranker
encoder-decoder
FBNL
Retrieval
RAG

fix(reranker): avoid re-computing the first batch in predict()'s batch-size probe to reduce additional computational effort

#1
by cosyy - opened
Files changed (1) hide show
  1. kalm_reranker.py +22 -6
kalm_reranker.py CHANGED
@@ -62,7 +62,7 @@ class KaLMReranker:
62
  if self.tokenizer.eos_token_id is None:
63
  raise ValueError("The tokenizer must define a pad token or an EOS token.")
64
  self.tokenizer.pad_token = self.tokenizer.eos_token
65
-
66
  self.tokenizer.padding_side = "right"
67
 
68
  self.model = AutoModelForSeq2SeqLM.from_pretrained(
@@ -70,7 +70,11 @@ class KaLMReranker:
70
  dtype=self.dtype,
71
  **model_kwargs,
72
  )
73
-
 
 
 
 
74
  for parameter in self.model.parameters():
75
  if parameter.is_floating_point() and parameter.dtype != self.dtype:
76
  parameter.data = parameter.data.to(dtype=self.dtype)
@@ -276,16 +280,18 @@ class KaLMReranker:
276
  if not isinstance(effective_batch_size, int) or effective_batch_size <= 0:
277
  raise ValueError("batch_size must be a positive integer.")
278
 
279
-
 
280
  length_sorted_indices = np.argsort(
281
  [-(len(query) + len(document)) for query, document in validated_pairs]
282
  )
283
  sorted_pairs = [validated_pairs[index] for index in length_sorted_indices]
284
 
285
  tested_batch_size = effective_batch_size
 
286
  while tested_batch_size > 1:
287
  try:
288
- self._predict_batch(
289
  sorted_pairs[: min(len(sorted_pairs), tested_batch_size)],
290
  effective_instruction,
291
  )
@@ -295,9 +301,19 @@ class KaLMReranker:
295
  torch.cuda.empty_cache()
296
  tested_batch_size = max(1, tested_batch_size * 3 // 4)
297
 
298
- sorted_scores: List[float] = []
 
 
 
 
 
 
 
 
 
 
299
  try:
300
- for start in range(0, len(sorted_pairs), tested_batch_size):
301
  sorted_scores.extend(
302
  self._predict_batch(
303
  sorted_pairs[start : start + tested_batch_size],
 
62
  if self.tokenizer.eos_token_id is None:
63
  raise ValueError("The tokenizer must define a pad token or an EOS token.")
64
  self.tokenizer.pad_token = self.tokenizer.eos_token
65
+ # Last-token indexing below assumes right padding, matching training.
66
  self.tokenizer.padding_side = "right"
67
 
68
  self.model = AutoModelForSeq2SeqLM.from_pretrained(
 
70
  dtype=self.dtype,
71
  **model_kwargs,
72
  )
73
+ # Preserve model buffers in their checkpoint dtypes. In particular,
74
+ # T5Gemma2 keeps RoPE inverse-frequency buffers in FP32 even for BF16
75
+ # inference. Casting the whole module would silently change its scores.
76
+ # A few tied parameters can retain a nested config dtype on CPU, so only
77
+ # parameters that need correction are converted explicitly.
78
  for parameter in self.model.parameters():
79
  if parameter.is_floating_point() and parameter.dtype != self.dtype:
80
  parameter.data = parameter.data.to(dtype=self.dtype)
 
280
  if not isinstance(effective_batch_size, int) or effective_batch_size <= 0:
281
  raise ValueError("batch_size must be a positive integer.")
282
 
283
+ # Match FlagEmbedding: sort by approximate text length to reduce padding,
284
+ # score contiguous batches, then restore the caller's original order.
285
  length_sorted_indices = np.argsort(
286
  [-(len(query) + len(document)) for query, document in validated_pairs]
287
  )
288
  sorted_pairs = [validated_pairs[index] for index in length_sorted_indices]
289
 
290
  tested_batch_size = effective_batch_size
291
+ first_batch_scores: Optional[List[float]] = None
292
  while tested_batch_size > 1:
293
  try:
294
+ first_batch_scores = self._predict_batch(
295
  sorted_pairs[: min(len(sorted_pairs), tested_batch_size)],
296
  effective_instruction,
297
  )
 
301
  torch.cuda.empty_cache()
302
  tested_batch_size = max(1, tested_batch_size * 3 // 4)
303
 
304
+ # The while loop's condition (`> 1`) means batch size 1 is never
305
+ # actually probed. If every size down to 2 OOMs, it exits without a
306
+ # successful probe. Only skip ahead to `tested_batch_size` when the
307
+ # probe actually ran; otherwise fall back to starting at 0 like the
308
+ # loop below always did originally, or the first item(s) get dropped.
309
+ if first_batch_scores is None:
310
+ sorted_scores: List[float] = []
311
+ loop_start = 0
312
+ else:
313
+ sorted_scores = list(first_batch_scores)
314
+ loop_start = tested_batch_size
315
  try:
316
+ for start in range(loop_start, len(sorted_pairs), tested_batch_size):
317
  sorted_scores.extend(
318
  self._predict_batch(
319
  sorted_pairs[start : start + tested_batch_size],