1use crate::albert::AlbertForQuestionAnswering;
47use crate::bert::BertForQuestionAnswering;
48use crate::common::error::RustBertError;
49use crate::deberta::DebertaForQuestionAnswering;
50use crate::distilbert::DistilBertForQuestionAnswering;
51use crate::fnet::FNetForQuestionAnswering;
52use crate::longformer::LongformerForQuestionAnswering;
53use crate::mobilebert::MobileBertForQuestionAnswering;
54use crate::pipelines::common::{
55 cast_var_store, get_device, ConfigOption, ModelResource, ModelType, TokenizerOption,
56};
57use crate::reformer::ReformerForQuestionAnswering;
58use crate::resources::ResourceProvider;
59use crate::roberta::RobertaForQuestionAnswering;
60use crate::xlnet::XLNetForQuestionAnswering;
61use rust_tokenizers::{Offset, TokenIdsWithOffsets, TokenizedInput};
62use serde::{Deserialize, Serialize};
63use std::cmp::min;
64use std::collections::HashMap;
65use std::fs;
66use std::path::PathBuf;
67use tch::nn::VarStore;
68use tch::{no_grad, Device, Kind, Tensor};
69
70use crate::deberta_v2::DebertaV2ForQuestionAnswering;
71#[cfg(feature = "onnx")]
72use crate::pipelines::onnx::{config::ONNXEnvironmentConfig, ONNXEncoder};
73
74use crate::common::kind::get_min;
75#[cfg(feature = "remote")]
76use crate::{
77 distilbert::{DistilBertConfigResources, DistilBertModelResources, DistilBertVocabResources},
78 resources::RemoteResource,
79};
80
81#[derive(Serialize, Deserialize)]
82pub struct QaInput {
85 pub question: String,
87 pub context: String,
89}
90
91#[derive(Debug)]
92struct QaFeature {
93 pub input_ids: Vec<i64>,
94 pub offsets: Vec<Option<Offset>>,
95 pub token_type_ids: Vec<i8>,
96 pub p_mask: Vec<i8>,
97 pub example_index: i64,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Answer {
103 pub score: f64,
105 pub start: usize,
107 pub end: usize,
109 pub answer: String,
111}
112
113impl PartialEq for Answer {
114 fn eq(&self, other: &Self) -> bool {
115 (self.start == other.start) && (self.end == other.end) && (self.answer == other.answer)
116 }
117}
118
119fn remove_duplicates<T: PartialEq + Clone>(vector: &mut Vec<T>) -> &mut Vec<T> {
120 let mut potential_duplicates = vec![];
121 vector.retain(|item| {
122 if potential_duplicates.contains(item) {
123 false
124 } else {
125 potential_duplicates.push(item.clone());
126 true
127 }
128 });
129 vector
130}
131
132pub struct QuestionAnsweringConfig {
135 pub model_resource: ModelResource,
137 pub config_resource: Box<dyn ResourceProvider + Send>,
139 pub vocab_resource: Box<dyn ResourceProvider + Send>,
141 pub merges_resource: Option<Box<dyn ResourceProvider + Send>>,
143 pub device: Device,
145 pub model_type: ModelType,
147 pub lower_case: bool,
149 pub strip_accents: Option<bool>,
151 pub add_prefix_space: Option<bool>,
153 pub max_seq_length: usize,
155 pub doc_stride: usize,
157 pub max_query_length: usize,
159 pub max_answer_length: usize,
161 pub kind: Option<Kind>,
163}
164
165impl QuestionAnsweringConfig {
166 pub fn new<RC, RV>(
177 model_type: ModelType,
178 model_resource: ModelResource,
179 config_resource: RC,
180 vocab_resource: RV,
181 merges_resource: Option<RV>,
182 lower_case: bool,
183 strip_accents: impl Into<Option<bool>>,
184 add_prefix_space: impl Into<Option<bool>>,
185 ) -> QuestionAnsweringConfig
186 where
187 RC: ResourceProvider + Send + 'static,
188 RV: ResourceProvider + Send + 'static,
189 {
190 QuestionAnsweringConfig {
191 model_type,
192 model_resource,
193 config_resource: Box::new(config_resource),
194 vocab_resource: Box::new(vocab_resource),
195 merges_resource: merges_resource.map(|r| Box::new(r) as Box<_>),
196 lower_case,
197 strip_accents: strip_accents.into(),
198 add_prefix_space: add_prefix_space.into(),
199 device: Device::cuda_if_available(),
200 max_seq_length: 384,
201 doc_stride: 128,
202 max_query_length: 64,
203 max_answer_length: 15,
204 kind: None,
205 }
206 }
207
208 pub fn custom_new<RC, RV>(
223 model_type: ModelType,
224 model_resource: ModelResource,
225 config_resource: RC,
226 vocab_resource: RV,
227 merges_resource: Option<RV>,
228 lower_case: bool,
229 strip_accents: impl Into<Option<bool>>,
230 add_prefix_space: impl Into<Option<bool>>,
231 max_seq_length: impl Into<Option<usize>>,
232 doc_stride: impl Into<Option<usize>>,
233 max_query_length: impl Into<Option<usize>>,
234 max_answer_length: impl Into<Option<usize>>,
235 ) -> QuestionAnsweringConfig
236 where
237 RC: ResourceProvider + Send + 'static,
238 RV: ResourceProvider + Send + 'static,
239 {
240 QuestionAnsweringConfig {
241 model_type,
242 model_resource,
243 config_resource: Box::new(config_resource),
244 vocab_resource: Box::new(vocab_resource),
245 merges_resource: merges_resource.map(|r| Box::new(r) as Box<_>),
246 lower_case,
247 strip_accents: strip_accents.into(),
248 add_prefix_space: add_prefix_space.into(),
249 device: Device::cuda_if_available(),
250 max_seq_length: max_seq_length.into().unwrap_or(384),
251 doc_stride: doc_stride.into().unwrap_or(128),
252 max_query_length: max_query_length.into().unwrap_or(64),
253 max_answer_length: max_answer_length.into().unwrap_or(15),
254 kind: None,
255 }
256 }
257}
258
259#[cfg(feature = "remote")]
260impl Default for QuestionAnsweringConfig {
261 fn default() -> QuestionAnsweringConfig {
262 QuestionAnsweringConfig {
263 model_resource: ModelResource::Torch(Box::new(RemoteResource::from_pretrained(
264 DistilBertModelResources::DISTIL_BERT_SQUAD,
265 ))),
266 config_resource: Box::new(RemoteResource::from_pretrained(
267 DistilBertConfigResources::DISTIL_BERT_SQUAD,
268 )),
269 vocab_resource: Box::new(RemoteResource::from_pretrained(
270 DistilBertVocabResources::DISTIL_BERT_SQUAD,
271 )),
272 merges_resource: None,
273 device: Device::cuda_if_available(),
274 kind: None,
275 model_type: ModelType::DistilBert,
276 lower_case: false,
277 add_prefix_space: None,
278 strip_accents: None,
279 max_seq_length: 384,
280 doc_stride: 128,
281 max_query_length: 64,
282 max_answer_length: 15,
283 }
284 }
285}
286
287#[allow(clippy::large_enum_variant)]
288pub enum QuestionAnsweringOption {
290 Bert(BertForQuestionAnswering),
292 Deberta(DebertaForQuestionAnswering),
294 DebertaV2(DebertaV2ForQuestionAnswering),
296 DistilBert(DistilBertForQuestionAnswering),
298 MobileBert(MobileBertForQuestionAnswering),
300 Roberta(RobertaForQuestionAnswering),
302 XLMRoberta(RobertaForQuestionAnswering),
304 Albert(AlbertForQuestionAnswering),
306 XLNet(XLNetForQuestionAnswering),
308 Reformer(ReformerForQuestionAnswering),
310 Longformer(LongformerForQuestionAnswering),
312 FNet(FNetForQuestionAnswering),
314 #[cfg(feature = "onnx")]
316 ONNX(ONNXEncoder),
317}
318
319impl QuestionAnsweringOption {
320 pub fn new(config: &QuestionAnsweringConfig) -> Result<Self, RustBertError> {
327 match config.model_resource {
328 ModelResource::Torch(_) => Self::new_torch(config),
329 #[cfg(feature = "onnx")]
330 ModelResource::ONNX(_) => Self::new_onnx(config),
331 }
332 }
333
334 fn new_torch(config: &QuestionAnsweringConfig) -> Result<Self, RustBertError> {
335 let device = config.device;
336 let weights_path = config.model_resource.get_torch_local_path()?;
337 let mut var_store = VarStore::new(device);
338 let model_config = &mut ConfigOption::from_file(
339 config.model_type,
340 config.config_resource.get_local_path()?,
341 );
342 let model_type = config.model_type;
343 let model = match model_type {
344 ModelType::Bert => {
345 if let ConfigOption::Bert(config) = model_config {
346 Ok(QuestionAnsweringOption::Bert(
347 BertForQuestionAnswering::new(var_store.root(), config),
348 ))
349 } else {
350 Err(RustBertError::InvalidConfigurationError(
351 "You can only supply a BertConfig for Bert!".to_string(),
352 ))
353 }
354 }
355 ModelType::Deberta => {
356 if let ConfigOption::Deberta(config) = model_config {
357 Ok(QuestionAnsweringOption::Deberta(
358 DebertaForQuestionAnswering::new(var_store.root(), config),
359 ))
360 } else {
361 Err(RustBertError::InvalidConfigurationError(
362 "You can only supply a DebertaConfig for DeBERTa!".to_string(),
363 ))
364 }
365 }
366 ModelType::DebertaV2 => {
367 if let ConfigOption::DebertaV2(config) = model_config {
368 Ok(QuestionAnsweringOption::DebertaV2(
369 DebertaV2ForQuestionAnswering::new(var_store.root(), config),
370 ))
371 } else {
372 Err(RustBertError::InvalidConfigurationError(
373 "You can only supply a DebertaV2Config for DeBERTa V2!".to_string(),
374 ))
375 }
376 }
377 ModelType::DistilBert => {
378 if let ConfigOption::DistilBert(ref mut config) = model_config {
379 config.sinusoidal_pos_embds = false;
380 Ok(QuestionAnsweringOption::DistilBert(
381 DistilBertForQuestionAnswering::new(var_store.root(), config),
382 ))
383 } else {
384 Err(RustBertError::InvalidConfigurationError(
385 "You can only supply a DistilBertConfig for DistilBert!".to_string(),
386 ))
387 }
388 }
389 ModelType::MobileBert => {
390 if let ConfigOption::MobileBert(config) = model_config {
391 Ok(QuestionAnsweringOption::MobileBert(
392 MobileBertForQuestionAnswering::new(var_store.root(), config),
393 ))
394 } else {
395 Err(RustBertError::InvalidConfigurationError(
396 "You can only supply a MobileBertConfig for MobileBert!".to_string(),
397 ))
398 }
399 }
400 ModelType::Roberta => {
401 if let ConfigOption::Roberta(config) = model_config {
402 Ok(QuestionAnsweringOption::Roberta(
403 RobertaForQuestionAnswering::new(var_store.root(), config),
404 ))
405 } else {
406 Err(RustBertError::InvalidConfigurationError(
407 "You can only supply a RobertaConfig for Roberta!".to_string(),
408 ))
409 }
410 }
411 ModelType::XLMRoberta => {
412 if let ConfigOption::Bert(config) = model_config {
413 Ok(QuestionAnsweringOption::XLMRoberta(
414 RobertaForQuestionAnswering::new(var_store.root(), config),
415 ))
416 } else {
417 Err(RustBertError::InvalidConfigurationError(
418 "You can only supply a BertConfig for Roberta!".to_string(),
419 ))
420 }
421 }
422 ModelType::Albert => {
423 if let ConfigOption::Albert(config) = model_config {
424 Ok(QuestionAnsweringOption::Albert(
425 AlbertForQuestionAnswering::new(var_store.root(), config),
426 ))
427 } else {
428 Err(RustBertError::InvalidConfigurationError(
429 "You can only supply an AlbertConfig for Albert!".to_string(),
430 ))
431 }
432 }
433 ModelType::XLNet => {
434 if let ConfigOption::XLNet(config) = model_config {
435 Ok(QuestionAnsweringOption::XLNet(
436 XLNetForQuestionAnswering::new(var_store.root(), config)?,
437 ))
438 } else {
439 Err(RustBertError::InvalidConfigurationError(
440 "You can only supply a XLNetConfig for XLNet!".to_string(),
441 ))
442 }
443 }
444 ModelType::Reformer => {
445 if let ConfigOption::Reformer(config) = model_config {
446 Ok(QuestionAnsweringOption::Reformer(
447 ReformerForQuestionAnswering::new(var_store.root(), config)?,
448 ))
449 } else {
450 Err(RustBertError::InvalidConfigurationError(
451 "You can only supply a ReformerConfig for Reformer!".to_string(),
452 ))
453 }
454 }
455 ModelType::Longformer => {
456 if let ConfigOption::Longformer(config) = model_config {
457 Ok(QuestionAnsweringOption::Longformer(
458 LongformerForQuestionAnswering::new(var_store.root(), config),
459 ))
460 } else {
461 Err(RustBertError::InvalidConfigurationError(
462 "You can only supply a LongformerConfig for Longformer!".to_string(),
463 ))
464 }
465 }
466 ModelType::FNet => {
467 if let ConfigOption::FNet(config) = model_config {
468 Ok(QuestionAnsweringOption::FNet(
469 FNetForQuestionAnswering::new(var_store.root(), config),
470 ))
471 } else {
472 Err(RustBertError::InvalidConfigurationError(
473 "You can only supply a FNetConfig for FNet!".to_string(),
474 ))
475 }
476 }
477 _ => Err(RustBertError::InvalidConfigurationError(format!(
478 "QuestionAnswering not implemented for {model_type:?}!",
479 ))),
480 }?;
481 var_store.load(weights_path)?;
482 cast_var_store(&mut var_store, config.kind, device);
483 Ok(model)
484 }
485
486 #[cfg(feature = "onnx")]
487 pub fn new_onnx(config: &QuestionAnsweringConfig) -> Result<Self, RustBertError> {
488 let onnx_config = ONNXEnvironmentConfig::from_device(config.device);
489 let environment = onnx_config.get_environment()?;
490 let encoder_file = config
491 .model_resource
492 .get_onnx_local_paths()?
493 .encoder_path
494 .ok_or(RustBertError::InvalidConfigurationError(
495 "An encoder file must be provided for question answering ONNX models.".to_string(),
496 ))?;
497
498 Ok(Self::ONNX(ONNXEncoder::new(
499 encoder_file,
500 &environment,
501 &onnx_config,
502 )?))
503 }
504
505 pub fn model_type(&self) -> ModelType {
507 match *self {
508 Self::Bert(_) => ModelType::Bert,
509 Self::Deberta(_) => ModelType::Deberta,
510 Self::DebertaV2(_) => ModelType::DebertaV2,
511 Self::Roberta(_) => ModelType::Roberta,
512 Self::XLMRoberta(_) => ModelType::XLMRoberta,
513 Self::DistilBert(_) => ModelType::DistilBert,
514 Self::MobileBert(_) => ModelType::MobileBert,
515 Self::Albert(_) => ModelType::Albert,
516 Self::XLNet(_) => ModelType::XLNet,
517 Self::Reformer(_) => ModelType::Reformer,
518 Self::Longformer(_) => ModelType::Longformer,
519 Self::FNet(_) => ModelType::FNet,
520 #[cfg(feature = "onnx")]
521 Self::ONNX(_) => ModelType::ONNX,
522 }
523 }
524
525 pub fn forward_t(
527 &self,
528 input_ids: Option<&Tensor>,
529 mask: Option<&Tensor>,
530 input_embeds: Option<&Tensor>,
531 _token_type_ids: Option<&Tensor>,
532 train: bool,
533 ) -> (Tensor, Tensor) {
534 match *self {
535 Self::Bert(ref model) => {
536 let outputs = model.forward_t(input_ids, mask, None, None, input_embeds, train);
537 (outputs.start_logits, outputs.end_logits)
538 }
539 Self::Deberta(ref model) => {
540 let outputs = model
541 .forward_t(input_ids, mask, None, None, input_embeds, train)
542 .expect("Error in Deberta forward_t");
543 (outputs.start_logits, outputs.end_logits)
544 }
545 Self::DebertaV2(ref model) => {
546 let outputs = model
547 .forward_t(input_ids, mask, None, None, input_embeds, train)
548 .expect("Error in Deberta V2 forward_t");
549 (outputs.start_logits, outputs.end_logits)
550 }
551 Self::DistilBert(ref model) => {
552 let outputs = model
553 .forward_t(input_ids, mask, input_embeds, train)
554 .expect("Error in distilbert forward_t");
555 (outputs.start_logits, outputs.end_logits)
556 }
557 Self::MobileBert(ref model) => {
558 let outputs = model
559 .forward_t(input_ids, None, None, input_embeds, mask, train)
560 .expect("Error in mobilebert forward_t");
561 (outputs.start_logits, outputs.end_logits)
562 }
563 Self::Roberta(ref model) | Self::XLMRoberta(ref model) => {
564 let outputs = model.forward_t(input_ids, mask, None, None, input_embeds, train);
565 (outputs.start_logits, outputs.end_logits)
566 }
567 Self::Albert(ref model) => {
568 let outputs = model.forward_t(input_ids, mask, None, None, input_embeds, train);
569 (outputs.start_logits, outputs.end_logits)
570 }
571 Self::XLNet(ref model) => {
572 let outputs =
573 model.forward_t(input_ids, mask, None, None, None, None, input_embeds, train);
574 (outputs.start_logits, outputs.end_logits)
575 }
576 Self::Reformer(ref model) => {
577 let outputs = model
578 .forward_t(input_ids, None, None, mask, None, train)
579 .expect("Error in reformer forward pass");
580 (outputs.start_logits, outputs.end_logits)
581 }
582 Self::Longformer(ref model) => {
583 let outputs = model
584 .forward_t(input_ids, mask, None, None, None, None, train)
585 .expect("Error in reformer forward pass");
586 (outputs.start_logits, outputs.end_logits)
587 }
588 Self::FNet(ref model) => {
589 let outputs = model
590 .forward_t(input_ids, None, None, None, train)
591 .expect("Error in fnet forward pass");
592 (outputs.start_logits, outputs.end_logits)
593 }
594 #[cfg(feature = "onnx")]
595 Self::ONNX(ref model) => {
596 let outputs = model
597 .forward(
598 input_ids,
599 mask.map(|tensor| tensor.to_kind(Kind::Int64)).as_ref(),
600 _token_type_ids,
601 None,
602 input_embeds,
603 )
604 .expect("Error in ONNX forward pass.");
605 (outputs.start_logits.unwrap(), outputs.end_logits.unwrap())
606 }
607 }
608 }
609}
610
611pub struct QuestionAnsweringModel {
613 tokenizer: TokenizerOption,
614 pad_idx: i64,
615 sep_idx: i64,
616 max_seq_len: usize,
617 doc_stride: usize,
618 max_query_length: usize,
619 max_answer_len: usize,
620 qa_model: QuestionAnsweringOption,
621 device: Device,
622}
623
624impl QuestionAnsweringModel {
625 pub fn new(
642 question_answering_config: QuestionAnsweringConfig,
643 ) -> Result<QuestionAnsweringModel, RustBertError> {
644 let vocab_path = question_answering_config.vocab_resource.get_local_path()?;
645 let merges_path = question_answering_config
646 .merges_resource
647 .as_ref()
648 .map(|resource| resource.get_local_path())
649 .transpose()?;
650
651 let tokenizer = TokenizerOption::from_file(
652 question_answering_config.model_type,
653 vocab_path.to_str().unwrap(),
654 merges_path.as_deref().map(|path| path.to_str().unwrap()),
655 question_answering_config.lower_case,
656 question_answering_config.strip_accents,
657 question_answering_config.add_prefix_space,
658 )?;
659 Self::new_with_tokenizer(question_answering_config, tokenizer)
660 }
661
662 pub fn new_with_tokenizer(
688 question_answering_config: QuestionAnsweringConfig,
689 tokenizer: TokenizerOption,
690 ) -> Result<QuestionAnsweringModel, RustBertError> {
691 let qa_model = QuestionAnsweringOption::new(&question_answering_config)?;
692
693 let pad_idx = tokenizer
694 .get_pad_id()
695 .expect("The Tokenizer used for Question Answering should contain a PAD id");
696 let sep_idx = tokenizer
697 .get_sep_id()
698 .expect("The Tokenizer used for Question Answering should contain a SEP id");
699
700 if question_answering_config.max_seq_length
701 < (question_answering_config.max_query_length
702 + question_answering_config.doc_stride
703 + 24)
704 {
705 return Err(RustBertError::InvalidConfigurationError(format!(
706 "This configuration could cause an excessive number of sliding windows generated.\
707 Please ensure max_seq_length > max_query_length + doc_stride + 24.\
708 Got max_seq_length: {}, max_query_length: {}, doc_stride: {}",
709 question_answering_config.max_seq_length,
710 question_answering_config.max_query_length,
711 question_answering_config.doc_stride
712 )));
713 }
714 let device = get_device(
715 question_answering_config.model_resource,
716 question_answering_config.device,
717 );
718 Ok(QuestionAnsweringModel {
719 tokenizer,
720 pad_idx,
721 sep_idx,
722 max_seq_len: question_answering_config.max_seq_length,
723 doc_stride: question_answering_config.doc_stride,
724 max_query_length: question_answering_config.max_query_length,
725 max_answer_len: question_answering_config.max_answer_length,
726 qa_model,
727 device,
728 })
729 }
730
731 pub fn get_tokenizer(&self) -> &TokenizerOption {
733 &self.tokenizer
734 }
735
736 pub fn get_tokenizer_mut(&mut self) -> &mut TokenizerOption {
738 &mut self.tokenizer
739 }
740
741 pub fn predict(
779 &self,
780 qa_inputs: &[QaInput],
781 top_k: i64,
782 batch_size: usize,
783 ) -> Vec<Vec<Answer>> {
784 let mut features: Vec<QaFeature> = qa_inputs
785 .iter()
786 .enumerate()
787 .flat_map(|(example_index, qa_example)| {
788 self.generate_features(
789 qa_example,
790 self.max_seq_len,
791 self.doc_stride,
792 self.max_query_length,
793 example_index as i64,
794 )
795 })
796 .collect();
797
798 let mut example_top_k_answers_map: HashMap<usize, Vec<Answer>> = HashMap::new();
799 let mut start = 0usize;
800 let len_features = features.len();
801
802 while start < len_features {
803 let end = start + min(len_features - start, batch_size);
804 let batch_features = &mut features[start..end];
805 no_grad(|| {
806 let (input_ids, attention_masks, token_type_ids) =
807 self.pad_features(batch_features);
808
809 let (start_logits, end_logits) = self.qa_model.forward_t(
810 Some(&input_ids),
811 Some(&attention_masks),
812 None,
813 Some(&token_type_ids),
814 false,
815 );
816
817 let start_logits = start_logits.detach();
818 let end_logits = end_logits.detach();
819 let example_index_to_feature_end_position: Vec<(usize, i64)> = batch_features
820 .iter()
821 .enumerate()
822 .map(|(feature_index, feature)| {
823 (feature.example_index as usize, feature_index as i64 + 1)
824 })
825 .collect();
826
827 let mut feature_id_start = 0;
828
829 for (example_id, max_feature_id) in example_index_to_feature_end_position {
830 let mut answers: Vec<Answer> = vec![];
831 let example = &qa_inputs[example_id];
832 for feature_idx in feature_id_start..max_feature_id {
833 let feature = &batch_features[feature_idx as usize];
834 let p_mask = (Tensor::from_slice(&feature.p_mask) - 1)
835 .abs()
836 .to_device(start_logits.device())
837 .eq(0);
838
839 let start = start_logits
840 .get(feature_idx)
841 .masked_fill(&p_mask, get_min(start_logits.kind()).unwrap());
842 let end = end_logits
843 .get(feature_idx)
844 .masked_fill(&p_mask, get_min(start_logits.kind()).unwrap());
845
846 let start = start.softmax(0, start.kind());
847 let end = end.softmax(0, end.kind());
848
849 let (starts, ends, scores) = self.decode(&start, &end, top_k);
850
851 for idx in 0..starts.len() {
852 let start_pos = feature.offsets[starts[idx] as usize]
853 .unwrap_or(Offset { begin: 0, end: 0 })
854 .begin as usize;
855 let end_pos = feature.offsets[ends[idx] as usize]
856 .unwrap_or(Offset { begin: 0, end: 0 })
857 .end as usize;
858 let answer = example
859 .context
860 .chars()
861 .take(end_pos)
862 .skip(start_pos)
863 .collect::<String>();
864
865 answers.push(Answer {
866 score: scores[idx],
867 start: start_pos,
868 end: end_pos,
869 answer,
870 });
871 }
872 }
873 feature_id_start = max_feature_id;
874 let example_answers = example_top_k_answers_map.entry(example_id).or_default();
875 example_answers.extend(answers);
876 }
877 });
878 start = end;
879 }
880 let mut all_answers = vec![];
881 for example_id in 0..qa_inputs.len() {
882 if let Some(answers) = example_top_k_answers_map.get_mut(&example_id) {
883 remove_duplicates(answers).sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap());
884 all_answers.push(answers[..min(answers.len(), top_k as usize)].to_vec());
885 } else {
886 all_answers.push(vec![]);
887 }
888 }
889 all_answers
890 }
891
892 fn decode(&self, start: &Tensor, end: &Tensor, top_k: i64) -> (Vec<i64>, Vec<i64>, Vec<f64>) {
893 let outer = start.unsqueeze(-1).matmul(&end.unsqueeze(0));
894 let start_dim = start.size()[0];
895 let end_dim = end.size()[0];
896 let candidates = outer
897 .triu(0)
898 .tril(self.max_answer_len as i64 - 1)
899 .flatten(0, -1);
900 let idx_sort = if top_k == 1 {
901 candidates.argmax(0, true)
902 } else if candidates.size()[0] < top_k {
903 candidates.argsort(0, true)
904 } else {
905 candidates.argsort(0, true).slice(0, 0, top_k, 1)
906 };
907 let mut start: Vec<i64> = vec![];
908 let mut end: Vec<i64> = vec![];
909 let mut scores: Vec<f64> = vec![];
910 for flat_index_position in 0..idx_sort.size()[0] {
911 let flat_index = idx_sort.int64_value(&[flat_index_position]);
912 scores.push(candidates.double_value(&[flat_index]));
913 start.push(flat_index / start_dim);
914 end.push(flat_index % end_dim);
915 }
916 (start, end, scores)
917 }
918
919 fn generate_features(
920 &self,
921 qa_example: &QaInput,
922 max_seq_length: usize,
923 doc_stride: usize,
924 max_query_length: usize,
925 example_index: i64,
926 ) -> Vec<QaFeature> {
927 let mut encoded_query = self.tokenizer.tokenize_with_offsets(&qa_example.question);
928 encoded_query.tokens.truncate(max_query_length);
929 encoded_query.offsets.truncate(max_query_length);
930 encoded_query.reference_offsets.truncate(max_query_length);
931 encoded_query.masks.truncate(max_query_length);
932 let encoded_query = TokenIdsWithOffsets {
933 ids: self.tokenizer.convert_tokens_to_ids(&encoded_query.tokens),
934 offsets: encoded_query.offsets,
935 reference_offsets: encoded_query.reference_offsets,
936 masks: encoded_query.masks,
937 };
938
939 let sequence_added_tokens = self
940 .tokenizer
941 .build_input_with_special_tokens(
942 TokenIdsWithOffsets {
943 ids: vec![],
944 offsets: vec![],
945 reference_offsets: vec![],
946 masks: vec![],
947 },
948 None,
949 )
950 .token_ids
951 .len();
952
953 let sequence_pair_added_tokens = self
954 .tokenizer
955 .build_input_with_special_tokens(
956 TokenIdsWithOffsets {
957 ids: vec![],
958 offsets: vec![],
959 reference_offsets: vec![],
960 masks: vec![],
961 },
962 Some(TokenIdsWithOffsets {
963 ids: vec![],
964 offsets: vec![],
965 reference_offsets: vec![],
966 masks: vec![],
967 }),
968 )
969 .token_ids
970 .len();
971
972 let mut spans: Vec<QaFeature> = vec![];
973
974 let tokenized_context = self.tokenizer.tokenize_with_offsets(&qa_example.context);
975 let encoded_context = TokenIdsWithOffsets {
976 ids: self
977 .tokenizer
978 .convert_tokens_to_ids(&tokenized_context.tokens),
979 offsets: tokenized_context.offsets,
980 reference_offsets: tokenized_context.reference_offsets,
981 masks: tokenized_context.masks,
982 };
983 let max_context_length =
984 max_seq_length - sequence_pair_added_tokens - encoded_query.ids.len();
985
986 let mut start_token = 0_usize;
987 while (spans.len() * doc_stride) < encoded_context.ids.len() {
988 let end_token = min(start_token + max_context_length, encoded_context.ids.len());
989 let sub_encoded_context = TokenIdsWithOffsets {
990 ids: encoded_context.ids[start_token..end_token].to_vec(),
991 offsets: encoded_context.offsets[start_token..end_token].to_vec(),
992 reference_offsets: encoded_context.reference_offsets[start_token..end_token]
993 .to_vec(),
994 masks: encoded_context.masks[start_token..end_token].to_vec(),
995 };
996
997 let encoded_span = self
998 .tokenizer
999 .build_input_with_special_tokens(encoded_query.clone(), Some(sub_encoded_context));
1000 let p_mask = self.get_mask(
1001 &encoded_span,
1002 encoded_query.ids.len() + sequence_added_tokens,
1003 );
1004 let qa_feature = QaFeature {
1005 input_ids: encoded_span.token_ids,
1006 offsets: encoded_span.token_offsets,
1007 token_type_ids: encoded_span.segment_ids,
1008 p_mask,
1009 example_index,
1010 };
1011 spans.push(qa_feature);
1012 if end_token == encoded_context.ids.len() {
1013 break;
1014 }
1015 start_token = end_token - doc_stride;
1016 }
1017 spans
1018 }
1019
1020 fn pad_features(&self, features: &mut [QaFeature]) -> (Tensor, Tensor, Tensor) {
1021 let max_len = features
1022 .iter()
1023 .map(|feature| feature.input_ids.len())
1024 .max()
1025 .unwrap();
1026
1027 let attention_masks = features
1028 .iter()
1029 .map(|feature| &feature.input_ids)
1030 .map(|input| {
1031 let mut attention_mask = Vec::with_capacity(max_len);
1032 attention_mask.resize(input.len(), 1);
1033 attention_mask.resize(max_len, 0);
1034 attention_mask
1035 })
1036 .map(|input| Tensor::from_slice(&(input)))
1037 .collect::<Vec<_>>();
1038
1039 for feature in features.iter_mut() {
1040 feature.offsets.resize(max_len, None);
1041 feature.p_mask.resize(max_len, 1);
1042 feature.input_ids.resize(max_len, self.pad_idx);
1043 feature
1044 .token_type_ids
1045 .resize(max_len, *feature.token_type_ids.last().unwrap_or(&0));
1046 }
1047
1048 let padded_input_ids = features
1049 .iter_mut()
1050 .map(|input| Tensor::from_slice(input.input_ids.as_slice()))
1051 .collect::<Vec<_>>();
1052
1053 let padded_token_type_ids = features
1054 .iter_mut()
1055 .map(|input| Tensor::from_slice(input.token_type_ids.as_slice()))
1056 .collect::<Vec<_>>();
1057
1058 let input_ids = Tensor::stack(&padded_input_ids, 0).to(self.device);
1059 let attention_masks = Tensor::stack(&attention_masks, 0).to(self.device);
1060 let token_type_ids = Tensor::stack(&padded_token_type_ids, 0)
1061 .to(self.device)
1062 .to_kind(Kind::Int64);
1063 (input_ids, attention_masks, token_type_ids)
1064 }
1065
1066 fn get_mask(&self, encoded_span: &TokenizedInput, question_length: usize) -> Vec<i8> {
1067 let sep_indices: Vec<usize> = encoded_span
1068 .token_ids
1069 .iter()
1070 .enumerate()
1071 .filter(|(_, &value)| value == self.sep_idx)
1072 .map(|(position, _)| position)
1073 .collect();
1074
1075 let mut p_mask: Vec<i8> = Vec::with_capacity(encoded_span.token_ids.len());
1076 p_mask.extend(vec![1; question_length]);
1077 p_mask.extend(vec![0; encoded_span.token_ids.len() - question_length]);
1078 for sep_position in sep_indices {
1079 p_mask[sep_position] = 1;
1080 }
1081 p_mask
1082 }
1083}
1084
1085pub fn squad_processor(file_path: PathBuf) -> Vec<QaInput> {
1086 let file = fs::File::open(file_path).expect("unable to open file");
1087 let json: serde_json::Value =
1088 serde_json::from_reader(file).expect("JSON not properly formatted");
1089 let data = json
1090 .get("data")
1091 .expect("SQuAD file does not contain data field")
1092 .as_array()
1093 .expect("Data array not properly formatted");
1094
1095 let mut qa_inputs: Vec<QaInput> = Vec::with_capacity(data.len());
1096 for qa_input in data.iter() {
1097 let qa_input = qa_input.as_object().unwrap();
1098 let paragraphs = qa_input.get("paragraphs").unwrap().as_array().unwrap();
1099 for paragraph in paragraphs.iter() {
1100 let paragraph = paragraph.as_object().unwrap();
1101 let context = paragraph.get("context").unwrap().as_str().unwrap();
1102 let qas = paragraph.get("qas").unwrap().as_array().unwrap();
1103 for qa in qas.iter() {
1104 let question = qa
1105 .as_object()
1106 .unwrap()
1107 .get("question")
1108 .unwrap()
1109 .as_str()
1110 .unwrap();
1111 qa_inputs.push(QaInput {
1112 question: question.to_owned(),
1113 context: context.to_owned(),
1114 });
1115 }
1116 }
1117 }
1118 qa_inputs
1119}
1120
1121#[cfg(test)]
1122mod test {
1123 use super::*;
1124
1125 #[test]
1126 #[ignore] fn test() {
1128 let config = QuestionAnsweringConfig::default();
1129 let _: Box<dyn Send> = Box::new(QuestionAnsweringModel::new(config));
1130 }
1131}