@@ -211,74 +211,83 @@ def predict_batch(
211211 ) -> list [SpanPrediction ]:
212212 torch = get_torch ()
213213
214- tokenizer , model = self ._require_loaded ()
215-
216- if not texts :
217- return []
218-
219- out : list [SpanPrediction ] = []
220- bs = max (1 , batch_size )
221- for start in range (0 , len (texts ), bs ):
222- chunk = texts [start : start + bs ]
223- encoding = tokenizer (
224- chunk ,
225- return_offsets_mapping = True ,
226- truncation = True ,
227- max_length = self ._max_length ,
228- stride = self ._stride ,
229- padding = True ,
230- return_overflowing_tokens = bool (self ._stride and self ._stride < self ._max_length ),
231- return_tensors = "pt" ,
232- )
233- if encoding .get ("overflow_to_sample_mapping" ) is not None :
234- out .extend (self ._predict_overflowing (encoding , chunk , model , tokenizer ))
235- continue
236-
237- offset_mappings = encoding .pop ("offset_mapping" )
238- skip_keys = frozenset (
239- {"offset_mapping" , "overflow_to_sample_mapping" , "num_overflowing_tokens" }
240- )
241- inputs = {
242- key : value .to (self ._device )
243- for key , value in encoding .items ()
244- if key not in skip_keys
245- }
246- with torch .no_grad ():
247- outputs = model (** inputs )
248- logits = outputs .logits
249- probs = torch .softmax (logits , dim = - 1 )
250- doc_logits = getattr (outputs , "doc_logits" , None )
251- disposition_logits = getattr (outputs , "disposition_logits" , None )
252-
253- for i , body in enumerate (chunk ):
254- offset_mapping = offset_mappings [i ].tolist ()
255- row_probs = probs [i ]
256- spans = decode_bioes_spans (
257- offset_mapping ,
258- probs = row_probs ,
259- id2label = self ._id2label ,
260- label2id = self ._label2id ,
261- inj_threshold = self ._inj_threshold ,
262- )
263- doc_prob , doc_source = self ._doc_score (
264- offset_mapping ,
265- row_probs = row_probs ,
266- doc_logits = doc_logits [i ] if doc_logits is not None else None ,
214+ with self ._load_lock :
215+ if self ._model is None :
216+ self ._load_unlocked ()
217+ if self ._tokenizer is None or self ._model is None :
218+ msg = "Model was unloaded during inference"
219+ raise ModelError (msg )
220+ tokenizer = self ._tokenizer
221+ model = self ._model
222+
223+ if not texts :
224+ return []
225+
226+ out : list [SpanPrediction ] = []
227+ bs = max (1 , batch_size )
228+ for start in range (0 , len (texts ), bs ):
229+ chunk = texts [start : start + bs ]
230+ encoding = tokenizer (
231+ chunk ,
232+ return_offsets_mapping = True ,
233+ truncation = True ,
234+ max_length = self ._max_length ,
235+ stride = self ._stride ,
236+ padding = True ,
237+ return_overflowing_tokens = bool (
238+ self ._stride and self ._stride < self ._max_length
239+ ),
240+ return_tensors = "pt" ,
267241 )
268- disposition_label , disposition_probs = self ._disposition (
269- disposition_logits [i ] if disposition_logits is not None else None
242+ if encoding .get ("overflow_to_sample_mapping" ) is not None :
243+ out .extend (self ._predict_overflowing (encoding , chunk , model , tokenizer ))
244+ continue
245+
246+ offset_mappings = encoding .pop ("offset_mapping" )
247+ skip_keys = frozenset (
248+ {"offset_mapping" , "overflow_to_sample_mapping" , "num_overflowing_tokens" }
270249 )
271- out .append (
272- SpanPrediction (
273- text_normalized = body ,
274- spans = merge_char_spans (spans ),
275- doc_score = doc_prob ,
276- doc_score_source = doc_source ,
277- disposition_label = disposition_label ,
278- disposition_probs = disposition_probs ,
250+ inputs = {
251+ key : value .to (self ._device )
252+ for key , value in encoding .items ()
253+ if key not in skip_keys
254+ }
255+ with torch .no_grad ():
256+ outputs = model (** inputs )
257+ logits = outputs .logits
258+ probs = torch .softmax (logits , dim = - 1 )
259+ doc_logits = getattr (outputs , "doc_logits" , None )
260+ disposition_logits = getattr (outputs , "disposition_logits" , None )
261+
262+ for i , body in enumerate (chunk ):
263+ offset_mapping = offset_mappings [i ].tolist ()
264+ row_probs = probs [i ]
265+ spans = decode_bioes_spans (
266+ offset_mapping ,
267+ probs = row_probs ,
268+ id2label = self ._id2label ,
269+ label2id = self ._label2id ,
270+ inj_threshold = self ._inj_threshold ,
279271 )
280- )
281- return out
272+ doc_prob , doc_source = self ._doc_score (
273+ offset_mapping ,
274+ row_probs = row_probs ,
275+ doc_logits = doc_logits [i ] if doc_logits is not None else None ,
276+ )
277+ disposition_label , disposition_probs = self ._disposition (
278+ disposition_logits [i ] if disposition_logits is not None else None
279+ )
280+ out .append (
281+ SpanPrediction (
282+ text_normalized = body ,
283+ spans = merge_char_spans (spans ),
284+ doc_score = doc_prob ,
285+ doc_score_source = doc_source ,
286+ disposition_label = disposition_label ,
287+ disposition_probs = disposition_probs ,
288+ )
289+ )
290+ return out
282291
283292 def _predict_overflowing (
284293 self ,
0 commit comments