The full details of the MMNLI model, including architecture, training, and evaluation, are described in the paper
Beyond Similarity Scoring: Detecting Entailment and Contradiction in Multilingual and Multimodal Contexts by Istaiteh, O., Mdhaffar, S., & Estève, Y. (Interspeech 2025). Please cite this paper if you use the MMNLI model in your research.
The model is trained on the
oist/multimodal_nli_dataset.
Please refer to that dataset card for details.
The model depends on
SONAR embeddings. You can use the official SONAR encoders (for text and speech)
from GitHub or the
ported SONAR text encoder cointegrated/SONAR_200_text_encoder.
1import torch
2from sonar.inference_pipelines.speech import SpeechToEmbeddingModelPipeline
3from sonar.inference_pipelines.text import TextToEmbeddingModelPipeline
4from transformers import AutoModel
5
6# 1. Load SONAR encoders
7speech_encoder = SpeechToEmbeddingModelPipeline(encoder="sonar_speech_encoder_eng")
8text_encoder = TextToEmbeddingModelPipeline(encoder="text_sonar_basic_encoder", tokenizer="text_sonar_basic_encoder")
9
10# 2. Encode premise (speech) and hypothesis (text)
11premise_embs = speech_encoder.predict(["audio.wav"])
12hypothesis_embs = text_encoder.predict(["The cat sat on the mat."], source_lang="eng_Latn")
13
14# 3. Load MMNLI model
15mmnli_model_name = "oist/multimodal_nli_model"
16mmnli_model = AutoModel.from_pretrained(mmnli_model_name, trust_remote_code=True)
17mmnli_model.eval()
18
19# 4. Run inference
20with torch.inference_mode():
21 logits = mmnli_model(premise_embs, hypothesis_embs) # returns [batch_size, 3]
22 pred_class = torch.argmax(logits, dim=-1).item()
23
24print("Prediction:", pred_class)
25# 0 = Entailment, 1 = Neutral, 2 = Contradiction
1import torch
2from sonar.inference_pipelines.text import TextToEmbeddingModelPipeline
3from transformers import AutoModel
4
5# 1. Load official SONAR text encoder
6text_encoder = TextToEmbeddingModelPipeline(
7 encoder="text_sonar_basic_encoder",
8 tokenizer="text_sonar_basic_encoder"
9)
10
11# 2. Encode premise and hypothesis
12premise_texts = ["Le chat s'assit sur le tapis."]
13hypothesis_texts = ["The cat sat on the mat."]
14
15premise_embs = text_encoder.predict(premise_texts, source_lang="fra_Latn")
16hypothesis_embs = text_encoder.predict(hypothesis_texts, source_lang="eng_Latn")
17
18# 3. Load MMNLI model
19mmnli_model = AutoModel.from_pretrained("oist/multimodal_nli_model", trust_remote_code=True)
20mmnli_model.eval()
21
22# 4. Run inference
23with torch.inference_mode():
24 logits = mmnli_model(premise_embs, hypothesis_embs)
25 pred_class = torch.argmax(logits, dim=-1).item()
26
27print("Prediction:", pred_class)
28# 0 = Entailment, 1 = Neutral, 2 = Contradiction
1# !pip install transformers sentencepiece torch -q
2import torch
3from transformers import AutoTokenizer, AutoModel
4from transformers.models.m2m_100.modeling_m2m_100 import M2M100Encoder
5
6# 1. Load ported SONAR text encoder
7sonar_model_name = "cointegrated/SONAR_200_text_encoder"
8encoder = M2M100Encoder.from_pretrained(sonar_model_name)
9tokenizer = AutoTokenizer.from_pretrained(sonar_model_name)
10
11def encode_mean_pool(texts, tokenizer, encoder, lang='eng_Latn', norm=False):
12 tokenizer.src_lang = lang
13 with torch.inference_mode():
14 batch = tokenizer(texts, return_tensors='pt', padding=True)
15 seq_embs = encoder(**batch).last_hidden_state
16 mask = batch.attention_mask
17 mean_emb = (seq_embs * mask.unsqueeze(-1)).sum(1) / mask.unsqueeze(-1).sum(1)
18 if norm:
19 mean_emb = torch.nn.functional.normalize(mean_emb)
20 return mean_emb
21
22# Example sentences
23premise_sentences = ["Le chat s'assit sur le tapis."]
24hypothesis_sentences = ["The cat sat on the mat."]
25
26# 2. Encode premise and hypothesis
27premise_embs = encode_mean_pool(premise_sentences, tokenizer, encoder, lang="fra_Latn")
28hypothesis_embs = encode_mean_pool(hypothesis_sentences, tokenizer, encoder, lang="eng_Latn")
29
30
31mmnli_model_name = "oist/multimodal_nli_model"
32mmnli_model = AutoModel.from_pretrained(mmnli_model_name, trust_remote_code=True)
33mmnli_model.eval()
34
35# 4. Run inference
36with torch.inference_mode():
37 logits = mmnli_model(premise_embs, hypothesis_embs) # returns [batch_size, 3]
38 pred_class = torch.argmax(logits, dim=-1).item()
39
40print("Prediction:", pred_class)
41# 0 = Entailment, 1 = Neutral, 2 = Contradiction
You can use the BLASER semantic score in combination with the MMNLI NLI class to get a better understanding of the relationship between source and candidate translations. The NLI class gives the entailment/contradiction/neutral label, while the BLASER score provides a fine-grained semantic similarity.
1# !pip install transformers sentencepiece torch -q
2import torch
3from transformers import AutoTokenizer, AutoModel
4from transformers.models.m2m_100.modeling_m2m_100 import M2M100Encoder
5
6# -------------------------
7# 1️⃣ Load ported SONAR text encoder
8# -------------------------
9sonar_model_name = "cointegrated/SONAR_200_text_encoder"
10encoder = M2M100Encoder.from_pretrained(sonar_model_name)
11tokenizer = AutoTokenizer.from_pretrained(sonar_model_name)
12
13def encode_mean_pool(texts, tokenizer, encoder, lang='eng_Latn', norm=False):
14 tokenizer.src_lang = lang
15 with torch.inference_mode():
16 batch = tokenizer(texts, return_tensors='pt', padding=True)
17 seq_embs = encoder(**batch).last_hidden_state
18 mask = batch.attention_mask
19 mean_emb = (seq_embs * mask.unsqueeze(-1)).sum(1) / mask.unsqueeze(-1).sum(1)
20 if norm:
21 mean_emb = torch.nn.functional.normalize(mean_emb)
22 return mean_emb
23
24# -------------------------
25# 2️⃣ Example sentences
26# -------------------------
27src_sentence = ["He is happy."]
28mt_sentences = [
29 "Il est content.", # entailment blaser:4.515
30 "Il est malheureux." # contradiction blaser: 4.41
31]
32
33# Encode source and MT sentences
34src_embs = encode_mean_pool(src_sentence, tokenizer, encoder, lang="eng_Latn")
35mt_embs = encode_mean_pool(mt_sentences, tokenizer, encoder, lang="fra_Latn")
36
37# -------------------------
38# 3️⃣ Load MMNLI model
39# -------------------------
40mmnli_model_name = "oist/multimodal_nli_model"
41mmnli_model = AutoModel.from_pretrained(mmnli_model_name, trust_remote_code=True)
42mmnli_model.eval()
43
44# -------------------------
45# 4️⃣ Load BLASER QE model
46# -------------------------
47qe_model_name = "oist/blaser_2_0_qe_ported"
48qe_model = AutoModel.from_pretrained(qe_model_name, trust_remote_code=True)
49qe_model.eval()
50
51# -------------------------
52# 5️⃣ Run inference
53# -------------------------
54for i, mt_sentence in enumerate(mt_sentences):
55 mt_emb = mt_embs[i].unsqueeze(0) # keep batch dimension
56
57 # NLI prediction
58 with torch.inference_mode():
59 logits = mmnli_model(src_embs, mt_emb)
60 pred_class = torch.argmax(logits, dim=-1).item()
61
62 # BLASER semantic score
63 with torch.inference_mode():
64 qe_score = qe_model(src_embs, mt_emb) # shape [1, 1]
65
66 print(f"\nMT sentence: '{mt_sentence}'")
67 print("NLI prediction:", ["Entailment", "Neutral", "Contradiction"][pred_class])
68 print("BLASER semantic score:", qe_score.item())
69
1@inproceedings{istaiteh2025beyond,
2 title={Beyond Similarity Scoring: Detecting Entailment and Contradiction in Multilingual and Multimodal Contexts},
3 author={Istaiteh, Othman and Mdhaffar, Salima and Est{\`e}ve, Yannick},
4 booktitle={Proc. Interspeech 2025},
5 pages={286--290},
6 year={2025}
7}