Atomic Proposition Embeddings (APE)
APE is a language representation model that maps sentences to variable-size sets of independent atomic-proposition embeddings. It consists of a decoder with learned query vectors built on top of an encoder backbone. The query vectors attend to the encoder's hidden states via cross-attention. Each of the resulting vectors is passed through (1) an embedding head, to project it into the teacher sentence embedding space; (2) an activity head, to check whether the resulting vector represents an actual propositon or should be discarded.
This model has been trained on sentences with a maximum number of five atomic propositions each.
Usage
This model relies on the APE package. Install it by running:
# pip
pip install "git+https://github.com/SapienzaNLP/APE.git"
# or uv (inside a uv project)
uv add "git+https://github.com/SapienzaNLP/APE.git"
Load a Pretrained APE Model
You can load the pretrained model's weights from this HF repository with APE.from_pretrained:
from ape import APE, APEScore
model = APE.from_pretrained("sapienzanlp/ape-bge-small")
sentences = [
"Rome was built in 753 BC and is now the capital of Italy.",
"Rome is the capital of Italy.",
]
prop_embds, act_scores = model.encode(
sentences,
activity_threshold=0.6,
return_scores=True
)
print([e.shape for e in prop_embds])
# [torch.Size([2, 384]), torch.Size([1, 384])]
print("activity scores:", [[round(x, 4) for x in s.tolist()] for s in act_scores])
# activity scores: [[0.9988, 0.9984], [0.9987]]
print("all slot activities:")
for s, row in zip("AB", model.activity_scores(sentences)):
print(s, [round(float(x), 3) for x in row])
# all slot activities:
# A [0.001, 0.0, 0.999, 0.0, 0.001, 0.998, 0.0, 0.0] -> one active slot
# B [0.0, 0.0, 0.999, 0.0, 0.001, 0.001, 0.0, 0.0] -> two active slots
An output vector counts as a proposition embedding if its activity score exceeds activity_threshold (we recommend ~0.6 as a starting point). Every sentence gets at least one active embedding.
Inference Scoring Rules
With APE, sentence-to-sentence comparisons produce cosine similarity matrices. We can extract a single score from them, with the aggregation technique (scoring rule) depdending on the task.
| Rule | Description | Task |
|---|---|---|
hungarian |
Optimal one-to-one matching between Sentence A and Sentence B, averaged over matched pairs. Symmetric scoring rule (sentence ordering is irrelevant). | Propositional equivalence (e.g., PAWS-style). |
maxsim |
Mean of each proposition's best match, averaged over both directions. Symmetric scoring rule (sentence ordering is irrelevant). | General semantic similarity. |
pool |
Cosine similarity of the mean-pooled proposition embedding sets. Symmetric scoring rule (sentence ordering is irrelevant). | General semantic similarity. Tends to work worse than maxsim. |
h_min_to_p |
Worst best-match of any Sentence A-proposition (hypothesis/query) to Sentence B propositions (premise/document). Asymmetric scoring rule (pass hypothesis/query first, then premise/document) | NLI entailment detection; Proposition-level retrieval.¹ |
¹Note: APE has not yet been trained on query/passage pairs, so typical asymmetric retrieval may not work as intended.
You can access these scoring rules from the APEScore class:
scorer = APEScore(prop_embds[1], prop_embds[0]) # (hypothesis, premise)
print("Hungarian Score: ", round(scorer.score("hungarian"), 3))
print("MaxSim Score: ", round(scorer.score("maxsim"), 3))
print("Pooled Score: ", round(scorer.score("pool"), 3))
print("H2P Score: ", round(scorer.score("h_min_to_p"), 3))
# Hungarian Score: 0.973
# MaxSim Score: 0.939
# Pooled Score: 0.973
# H2P Score: 0.937
# to pretty-print the full cosine similarity matrix
scorer.print_similarity_matrix()
# B0 B1
# A0 0.838 0.973
Interpretability via Proposition Seeding
APE proposition embeddings are not tied to any text, but they can be interpreted via proposition seeding. We encode a candidate atomic proposition (the seed) with APE anche check which of the sentence's proposition embeddings is the strongest match.
import torch
from ape import APE, APEScore
model = APE.from_pretrained("sapienzanlp/ape-bge-small")
sentence = "Rome was built in 753 BC and is now the capital of Italy."
prop_seeds = [
"Rome was built in 753 BC.",
"Rome is now the capital of Italy.",
]
prop_embds = model.encode(sentence) # [n_propositions, D]
seed_embds = torch.cat(model.encode(prop_seeds)) # one embedding per seed
scorer = APEScore(seed_embds, prop_embds) # rows: seeds, columns: APE propositions
scorer.print_similarity_matrix()
for seed, j in zip(prop_seeds, scorer.similarity_matrix().argmax(axis=1)):
print(f"{seed!r} -> proposition B{j}")
This will output:
B0 B1
A0 0.996 0.862
A1 0.833 0.985
'Rome was built in 753 BC.' -> proposition B0
'Rome is now the capital of Italy.' -> proposition B1
Seeds should be single atomic propositions, so that APE encodes each one into exactly one embedding. A seed that contains several propositions produces several rows in
seed_embds. If APE mistakenly produces more than one vector for a single atomic proposition, one way around it is to pool the embeddings of the seed before matching.
Performance
Zero-shot performance measured by "AUC | Average Precision" for PAWS-Wiki and SNLI (entailment vs rest), Spearman correlation coefficient for STS-B and SICK-R, and MRR for PropSearch.
Note that APE is designed to represent propositions as independent and self-contained; therefore, the slight performance decrease on STS benchmarks is likely due to the discarded inter-propositional relationships.
| Model | Size | PAWS-Wiki | SNLI | STS-B | SICK-R | PropSearch² |
|---|---|---|---|---|---|---|
| ape-bge-small | 40M | 81.1 | 77.1 | 84.1 | 72.3 | 84.9 | 78.8 | 91.4 |
| SSE-T5 (multi-vector) | 879M | 76.0 | 73.4 | 80.7 | 69.1 | 80.1 | 76.1 | 55.4 |
| bge-small-en-v1.5 | 33M | 60.5 | 56.0 | 81.1 | 65.3 | 86.8 | 79.9 | 83.4 |
| bge-large-en-v1.5 | 335M | 64.2 | 60.6 | 82.0 | 66.6 | 87.5 | 81.7 | 86.2 |
| embeddinggemma-300m | 308M | 66.1 | 62.9 | 84.2 | 68.5 | 88.8 | 82.1 | 90.9 |
| Qwen3-Embedding-0.6B | 596M | 74.0 | 67.0 | 81.2 | 65.3 | 91.2 | 84.9 | 85.1 |
²For PropSearch, we show results (MRR) for the most challenging sub-task (6 or more propositions in the correct source sentence).
We use the hungarian scoring rule for PAWS-Wiki, h_min_to_p for SNLI and PropSearch, and maxsim for STS-B and SICK-R.
Citation
If you find our work helpful, please consider citing it:
@inproceedings{ortame-navigli-2026-variable,
title = "Variable-size Discovery and Representation of Atomic Propositions",
author = "Ortame, Francesco and
Navigli, Roberto",
editor = "Lee, Hung-Yi and
Dev, Sunipa and
Li, Jessy and
Elliott, Desmond",
booktitle = "Proceedings of the 2026 Conference on Empirical Methods in Natural Language Processing",
month = oct,
year = "2026",
address = "Budapest, Hungary",
publisher = "Association for Computational Linguistics",
url = "https://aclanthology.org/2026.emnlp-main.2302/",
pages = "52330--52348",
ISBN = "979-8-89176-459-0"
}
- Downloads last month
- 36
Model tree for sapienzanlp/ape-bge-small
Base model
BAAI/bge-small-en-v1.5
