input-ambiguity-detection 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. input_ambiguity_detection-0.1.0/CITATION.cff +47 -0
  2. input_ambiguity_detection-0.1.0/LICENSE +21 -0
  3. input_ambiguity_detection-0.1.0/MANIFEST.in +7 -0
  4. input_ambiguity_detection-0.1.0/PKG-INFO +239 -0
  5. input_ambiguity_detection-0.1.0/README.md +193 -0
  6. input_ambiguity_detection-0.1.0/blackbox/__init__.py +0 -0
  7. input_ambiguity_detection-0.1.0/blackbox/analyze_uq.py +669 -0
  8. input_ambiguity_detection-0.1.0/blackbox/compute_uq.py +400 -0
  9. input_ambiguity_detection-0.1.0/blackbox/llm_utils.py +277 -0
  10. input_ambiguity_detection-0.1.0/blackbox/perturbation_rules.py +848 -0
  11. input_ambiguity_detection-0.1.0/blackbox/run_llm_perturbation.py +655 -0
  12. input_ambiguity_detection-0.1.0/blackbox/run_paraphrase.py +351 -0
  13. input_ambiguity_detection-0.1.0/blackbox/run_perturbation.py +353 -0
  14. input_ambiguity_detection-0.1.0/input_ambiguity/__init__.py +10 -0
  15. input_ambiguity_detection-0.1.0/input_ambiguity/__main__.py +3 -0
  16. input_ambiguity_detection-0.1.0/input_ambiguity/cli.py +74 -0
  17. input_ambiguity_detection-0.1.0/input_ambiguity/quickstart.py +53 -0
  18. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/PKG-INFO +239 -0
  19. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/SOURCES.txt +43 -0
  20. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/dependency_links.txt +1 -0
  21. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/entry_points.txt +2 -0
  22. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/requires.txt +33 -0
  23. input_ambiguity_detection-0.1.0/input_ambiguity_detection.egg-info/top_level.txt +1 -0
  24. input_ambiguity_detection-0.1.0/pyproject.toml +87 -0
  25. input_ambiguity_detection-0.1.0/quickstart/intermediate/pipeline_b_baseline_n10.json +16569 -0
  26. input_ambiguity_detection-0.1.0/quickstart/intermediate/pipeline_b_logit_lens.json +14224 -0
  27. input_ambiguity_detection-0.1.0/requirements.txt +28 -0
  28. input_ambiguity_detection-0.1.0/setup.cfg +4 -0
  29. input_ambiguity_detection-0.1.0/whitebox/__init__.py +0 -0
  30. input_ambiguity_detection-0.1.0/whitebox/pipeline/__init__.py +0 -0
  31. input_ambiguity_detection-0.1.0/whitebox/pipeline/compute_auroc.py +95 -0
  32. input_ambiguity_detection-0.1.0/whitebox/pipeline/compute_uq_from_checkpoint.py +268 -0
  33. input_ambiguity_detection-0.1.0/whitebox/pipeline/pipeline_b_perturb_and_uq.py +1258 -0
  34. input_ambiguity_detection-0.1.0/whitebox/pipeline/pipeline_b_perturb_and_uq_vl.py +766 -0
  35. input_ambiguity_detection-0.1.0/whitebox/text/__init__.py +0 -0
  36. input_ambiguity_detection-0.1.0/whitebox/text/attribution_utils.py +330 -0
  37. input_ambiguity_detection-0.1.0/whitebox/text/diffmask_uncertainty.py +755 -0
  38. input_ambiguity_detection-0.1.0/whitebox/text/gradient_attribution.py +440 -0
  39. input_ambiguity_detection-0.1.0/whitebox/text/logit_lens_uncertainty.py +605 -0
  40. input_ambiguity_detection-0.1.0/whitebox/text/normalize_attributions.py +106 -0
  41. input_ambiguity_detection-0.1.0/whitebox/vision/__init__.py +0 -0
  42. input_ambiguity_detection-0.1.0/whitebox/vision/diffmask_uncertainty.py +318 -0
  43. input_ambiguity_detection-0.1.0/whitebox/vision/gradient_attribution.py +252 -0
  44. input_ambiguity_detection-0.1.0/whitebox/vision/logit_lens_uncertainty.py +367 -0
  45. input_ambiguity_detection-0.1.0/whitebox/vision/vl_attribution_utils.py +342 -0
@@ -0,0 +1,47 @@
1
+ cff-version: 1.2.0
2
+ title: "Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs"
3
+ message: "If you use this code in your research, please cite the AACL 2026 paper."
4
+ type: software
5
+ authors:
6
+ - family-names: Chen
7
+ given-names: Tiejin
8
+ - family-names: Liu
9
+ given-names: Xiaoou
10
+ - family-names: Clifford
11
+ given-names: Michael
12
+ - family-names: Moradipari
13
+ given-names: Ahmadreza
14
+ - family-names: Chen
15
+ given-names: Yitao
16
+ - family-names: Han
17
+ given-names: Kyungtae
18
+ - family-names: Ammar
19
+ given-names: Nejib
20
+ - family-names: Wei
21
+ given-names: Hua
22
+ year: 2026
23
+ repository-code: "https://github.com/Xiao0o0o/input-ambiguity-detection"
24
+ license: MIT
25
+ preferred-citation:
26
+ type: conference-paper
27
+ title: "Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs"
28
+ authors:
29
+ - family-names: Chen
30
+ given-names: Tiejin
31
+ - family-names: Liu
32
+ given-names: Xiaoou
33
+ - family-names: Clifford
34
+ given-names: Michael
35
+ - family-names: Moradipari
36
+ given-names: Ahmadreza
37
+ - family-names: Chen
38
+ given-names: Yitao
39
+ - family-names: Han
40
+ given-names: Kyungtae
41
+ - family-names: Ammar
42
+ given-names: Nejib
43
+ - family-names: Wei
44
+ given-names: Hua
45
+ year: 2026
46
+ conference:
47
+ name: "The Asia-Pacific Chapter of the Association for Computational Linguistics (AACL 2026)"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tiejin Chen, Xiaoou Liu, Michael Clifford, Ahmadreza Moradipari, Yitao Chen, Kyungtae Han, Nejib Ammar, and Hua Wei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include LICENSE README.md CITATION.cff requirements.txt
2
+ prune data
3
+ prune quickstart
4
+ include quickstart/intermediate/pipeline_b_logit_lens.json quickstart/intermediate/pipeline_b_baseline_n10.json
5
+ prune tests
6
+ prune scripts
7
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,239 @@
1
+ Metadata-Version: 2.4
2
+ Name: input-ambiguity-detection
3
+ Version: 0.1.0
4
+ Summary: Perturbation-based input ambiguity detection for LLMs (white-box and black-box detectors, AACL 2026)
5
+ Author: Tiejin Chen, Xiaoou Liu, Michael Clifford, Ahmadreza Moradipari, Yitao Chen, Kyungtae Han, Nejib Ammar, Hua Wei
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/Xiao0o0o/input-ambiguity-detection
8
+ Project-URL: Issues, https://github.com/Xiao0o0o/input-ambiguity-detection/issues
9
+ Keywords: llm,ambiguity,uncertainty quantification,perturbation,question answering
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: torch
18
+ Requires-Dist: transformers
19
+ Requires-Dist: accelerate
20
+ Requires-Dist: numpy
21
+ Requires-Dist: scipy
22
+ Requires-Dist: scikit-learn
23
+ Requires-Dist: nltk
24
+ Requires-Dist: pillow
25
+ Requires-Dist: tqdm
26
+ Provides-Extra: blackbox
27
+ Requires-Dist: vllm; extra == "blackbox"
28
+ Requires-Dist: lm-polygraph; extra == "blackbox"
29
+ Requires-Dist: spacy; extra == "blackbox"
30
+ Requires-Dist: lemminflect; extra == "blackbox"
31
+ Requires-Dist: matplotlib; extra == "blackbox"
32
+ Provides-Extra: int8
33
+ Requires-Dist: bitsandbytes; extra == "int8"
34
+ Provides-Extra: data
35
+ Requires-Dist: datasets; extra == "data"
36
+ Requires-Dist: httpx; extra == "data"
37
+ Provides-Extra: all
38
+ Requires-Dist: input-ambiguity-detection[blackbox,data,int8]; extra == "all"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest; extra == "dev"
41
+ Requires-Dist: build; extra == "dev"
42
+ Requires-Dist: twine; extra == "dev"
43
+ Requires-Dist: spacy; extra == "dev"
44
+ Requires-Dist: lemminflect; extra == "dev"
45
+ Dynamic: license-file
46
+
47
+ # Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs
48
+
49
+ [![PyPI](https://img.shields.io/pypi/v/input-ambiguity-detection.svg)](https://pypi.org/project/input-ambiguity-detection/)
50
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
52
+ [![CI](https://github.com/Xiao0o0o/input-ambiguity-detection/actions/workflows/ci.yml/badge.svg)](https://github.com/Xiao0o0o/input-ambiguity-detection/actions/workflows/ci.yml)
53
+
54
+ Code and data for the AACL 2026 paper **"Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs"** by Tiejin Chen\*, Xiaoou Liu\*, Michael Clifford, Ahmadreza Moradipari, Yitao Chen, Kyungtae Han, Nejib Ammar and Hua Wei (\*equal contribution).
55
+
56
+ ## Overview
57
+
58
+ LLMs often answer an ambiguous question as if it had a single meaning. A common way to detect ambiguity is to have an LLM paraphrase or clarify the question and measure how much the answers disagree. But to rephrase a question the model must first understand it, and understanding an ambiguous question means picking one reading. The rewrite can remove the very ambiguity it is meant to measure.
59
+
60
+ We instead perturb the input with **low-capacity, label-preserving, semantics-blind** edits. These are small surface changes that never choose an interpretation. We then measure how much the model's answers spread across the original and perturbed questions. Two detectors implement this:
61
+
62
+ | detector | access | how it perturbs | code |
63
+ |---|---|---|---|
64
+ | **White-box** | model internals | Vanilla Gradient, Logit Lens or DiffMask ranks the input tokens; the top-3 question words are replaced by WordNet synonyms | [`whitebox/`](whitebox/) |
65
+ | **Black-box** | text in, text out | a fixed library of 11 rules: POS-constrained WordNet synonyms, contraction expand/contract, register prefixes, wh-word templates | [`blackbox/`](blackbox/) |
66
+
67
+ Both pool the answers to the original and perturbed questions. An NLI model (`microsoft/deberta-large-mnli`) builds an agreement matrix over them, and **EigV(Agree)**, the eigenvalue dispersion of its graph Laplacian, is the ambiguity score. A higher score means a more likely ambiguous question.
68
+
69
+ ## Repository layout
70
+
71
+ ```
72
+ .
73
+ ├── data/ # the four evaluation sets (shared by both detectors)
74
+ │ ├── abg_coqa_200_input.json # ABG-CoQA, 200 items (100 ambiguous / 100 not)
75
+ │ ├── abg_coqa_200_blackbox.json # the same 200 items in the original ABG-CoQA format (black-box input)
76
+ │ ├── ambigqa_with_ctx_500_input.json # AmbigQA + Wikipedia context, 500 items (250 / 250)
77
+ │ ├── aqua_720_input.json # AQuA, 720 items (540 / 180)
78
+ │ ├── vqfa_720_input.json # VQ-FocusAmbiguity, 720 items (422 / 298)
79
+ │ └── build/ # scripts that built these files (+ images for AQuA / VQ-FA)
80
+ ├── whitebox/ # white-box detector → see whitebox/README.md
81
+ │ ├── text/ vision/ # Vanilla Gradient, Logit Lens, DiffMask attribution
82
+ │ └── pipeline/ # top-k WordNet perturbation, generation, NLI UQ, AUROC
83
+ ├── blackbox/ # black-box detector → see blackbox/README.md
84
+ │ ├── perturbation_rules.py # the 11-rule library
85
+ │ ├── run_perturbation.py # rules → vLLM sampling
86
+ │ ├── compute_uq.py analyze_uq.py # NLI UQ (per variant / pooled) → AUROC + plots
87
+ │ └── run_llm_perturbation.py run_paraphrase.py # LLM-executed rules (ablation), LLM paraphrase baseline
88
+ ├── scripts/ # one command per (model, dataset)
89
+ │ ├── run_whitebox_text.sh run_whitebox_vision.sh
90
+ │ └── run_blackbox.sh
91
+ ├── quickstart/ # every intermediate file of one paper run + a resumable script
92
+ ├── input_ambiguity/ # package entry point: the `input-ambiguity` CLI
93
+ ├── tests/
94
+ ├── pyproject.toml # PyPI package (installs whitebox/ and blackbox/ as input_ambiguity.*)
95
+ └── requirements.txt # full environment for both detectors
96
+ ```
97
+
98
+ ## Installation
99
+
100
+ From PyPI:
101
+
102
+ ```bash
103
+ pip install input-ambiguity-detection # white-box detector, NLI scoring, AUROC
104
+ pip install "input-ambiguity-detection[blackbox]" # + black-box detector (vLLM, lm-polygraph, spaCy)
105
+ pip install "input-ambiguity-detection[all]" # + INT8 DiffMask (bitsandbytes) and data/build/* deps
106
+ ```
107
+
108
+ From source, with the data, quick start and shell scripts (recommended to reproduce the paper):
109
+
110
+ ```bash
111
+ git clone https://github.com/Xiao0o0o/input-ambiguity-detection.git
112
+ cd input-ambiguity-detection
113
+ pip install -r requirements.txt # exact versions used for the release checks
114
+ pip install -e . --no-deps # optional: also installs the `input-ambiguity` command
115
+ ```
116
+
117
+ Then:
118
+
119
+ ```bash
120
+ python -m spacy download en_core_web_sm # POS tags for the black-box rules
121
+ export HF_CACHE_DIR=/path/to/hf_cache # optional; HF default cache otherwise
122
+ export HF_TOKEN=... # for meta-llama/Llama-3.1-8B-Instruct and google/gemma-3-*
123
+ ```
124
+
125
+ NLTK downloads WordNet and the POS tagger on first use (`make nltk-data` fetches them up front).
126
+
127
+ Every script is also available through the installed command, with the same arguments:
128
+
129
+ ```bash
130
+ input-ambiguity --help # list of commands
131
+ input-ambiguity rules # black-box rule variants for a few sample questions
132
+ input-ambiguity bb-perturb --help # = python blackbox/run_perturbation.py --help
133
+ input-ambiguity wb-vision-logit-lens --help # = python whitebox/vision/logit_lens_uncertainty.py --help
134
+ ```
135
+
136
+ ## Quick start
137
+
138
+ The quick start is one paper run: the white-box detector on AQuA with Qwen2.5-VL-3B-Instruct. Its per-question scores are stored, so the paper's AUROC can be checked on a CPU in seconds, in either of two ways.
139
+
140
+ **Option A: with the PyPI package** (no clone, no GPU, no model download; the scores ship with the package)
141
+
142
+ ```bash
143
+ pip install input-ambiguity-detection
144
+ input-ambiguity quickstart
145
+ ```
146
+
147
+ **Option B: with the code in this repository**
148
+
149
+ ```bash
150
+ git clone https://github.com/Xiao0o0o/input-ambiguity-detection.git
151
+ cd input-ambiguity-detection
152
+ pip install -r requirements.txt
153
+ bash quickstart/run_quickstart.sh # or: make quick-eval
154
+ ```
155
+
156
+ | setting | |
157
+ |---|---|
158
+ | model | Qwen2.5-VL-3B-Instruct |
159
+ | dataset | AQuA, 720 visual questions (540 ambiguous / 180 unambiguous) |
160
+ | detector | white-box, Logit Lens importance, top-3 words → WordNet synonyms (up to 4 variants) |
161
+ | sampling | original: 1 greedy + 2 sampled (T=0.5, top-p 0.9); each variant: 1 greedy |
162
+ | score | EigV(Agree), `microsoft/deberta-large-mnli` |
163
+
164
+ | method | quick-start AUROC | paper (Table 1) |
165
+ |---|---|---|
166
+ | EigV(Agree) baseline (K=10 samples, no perturbation) | 0.6435 | 0.644 |
167
+ | **Ours (White-Box, Logit Lens)** | **0.7083** | **0.708** |
168
+
169
+ Both options give the numbers above, which match the paper. Option B also stores every intermediate file of the run (attribution, perturbations, answers), and the same script resumes from any earlier stage: `uq` (recompute NLI from the stored answers), `generate`, `perturb` or `attribution` (from scratch), e.g. `bash quickstart/run_quickstart.sh uq`. Expected deviations when re-running those stages are listed in [`quickstart/README.md`](quickstart/README.md).
170
+
171
+ To see what the black-box rules do to a question, without a model:
172
+
173
+ ```bash
174
+ python blackbox/perturbation_rules.py
175
+ python blackbox/run_perturbation.py --dry_run --input_path data/abg_coqa_200_blackbox.json --output_path variants.json
176
+ ```
177
+
178
+ ## Running the detectors
179
+
180
+ **White-box**: attribution → top-3 words → WordNet perturbation → sampling → NLI UQ → AUROC, for all three importance methods and the K=10 EigV(Agree) baseline:
181
+
182
+ ```bash
183
+ bash scripts/run_whitebox_text.sh Qwen/Qwen3-4B-Instruct-2507 data/abg_coqa_200_input.json results/qwen3_abg
184
+ bash scripts/run_whitebox_text.sh meta-llama/Llama-3.1-8B-Instruct data/ambigqa_with_ctx_500_input.json results/llama_ambigqa
185
+ bash scripts/run_whitebox_vision.sh Qwen/Qwen2.5-VL-3B-Instruct data/aqua_720_input.json results/qwenvl_aqua
186
+ bash scripts/run_whitebox_vision.sh OpenGVLab/InternVL3-8B-hf data/vqfa_720_input.json results/internvl_vqfa
187
+ ```
188
+
189
+ The vision inputs need the AQuA / VQ-FA images: `python data/build/build_aqua_input.py` downloads AQuA, and `VQFA_ROOT=... python data/build/build_vqfa_input.py` builds VQ-FA from its release. Settings, output files, the two EigV variants and memory notes are documented in [`whitebox/README.md`](whitebox/README.md).
190
+
191
+ **Black-box**: 11 rules → N samples per variant (vLLM) → NLI UQ per variant and pooled → AUROC per rule and pooled:
192
+
193
+ ```bash
194
+ bash scripts/run_blackbox.sh Qwen/Qwen3-4B-Instruct-2507 data/abg_coqa_200_blackbox.json results/blackbox_qwen3_abg
195
+ bash scripts/run_blackbox.sh meta-llama/Llama-3.1-8B-Instruct data/abg_coqa_200_blackbox.json results/blackbox_llama_abg
196
+ ```
197
+
198
+ The detector's score is the cross-variant (`CROSS`) `EigValLaplacian_NLI_entail` AUROC in `results/.../analysis/uq_statistics.json`; the per-rule AUROCs correspond to Figure 3. The LLM-executed-rules ablation (Table 4) and the LLM-paraphrase baseline are in [`blackbox/README.md`](blackbox/README.md).
199
+
200
+ ## Data
201
+
202
+ | dataset | type | items (amb / unamb) | source |
203
+ |---|---|---|---|
204
+ | ABG-CoQA | conversational QA | 200 (100 / 100) | [Guo et al., 2021](https://github.com/MeiqiGuo/AKBC2021-Abg-CoQA) |
205
+ | AmbigQA-w-Ctx | open-domain QA + Wikipedia passage | 500 (250 / 250) | [Min et al., 2020](https://huggingface.co/datasets/sewon/ambig_qa) |
206
+ | AQuA | visual QA | 720 (540 / 180) | [Jang and Kim, 2026](https://huggingface.co/datasets/jihyoung/AQuA) |
207
+ | VQ-FA | visual QA (focus ambiguity) | 720 (422 / 298) | Chen et al., 2025 (VQ-FocusAmbiguity release) |
208
+
209
+ All question files are included in `data/`, and `data/build/` holds the scripts that created them. Please also follow the licenses of the original datasets.
210
+
211
+ ## Hardware
212
+
213
+ The quick-start AUROC and the unit tests run on a CPU. Our experiments ran on a single NVIDIA A100 80 GB. Gemma-3-27B's DiffMask attribution uses INT8 weights through bitsandbytes, which `scripts/run_whitebox_text.sh` turns on automatically for 27B models.
214
+
215
+ ## Tests
216
+
217
+ ```bash
218
+ pip install -e ".[dev]"
219
+ make check # compileall + pytest + quick-start AUROC
220
+ make dist-check # build the PyPI sdist / wheel and run twine check
221
+ ```
222
+
223
+ The tests cover the black-box rule library, the shared prompt/data helpers, the EigV implementations, and the quick-start AUROC against the paper's numbers.
224
+
225
+ ## Citation
226
+
227
+ ```bibtex
228
+ @inproceedings{chen2026detect,
229
+ title = {Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in {LLMs}},
230
+ author = {Chen, Tiejin and Liu, Xiaoou and Clifford, Michael and Moradipari, Ahmadreza and
231
+ Chen, Yitao and Han, Kyungtae and Ammar, Nejib and Wei, Hua},
232
+ booktitle = {Proceedings of the Asia-Pacific Chapter of the Association for Computational Linguistics (AACL)},
233
+ year = {2026}
234
+ }
235
+ ```
236
+
237
+ ## License
238
+
239
+ MIT License, see [LICENSE](LICENSE).
@@ -0,0 +1,193 @@
1
+ # Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/input-ambiguity-detection.svg)](https://pypi.org/project/input-ambiguity-detection/)
4
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![CI](https://github.com/Xiao0o0o/input-ambiguity-detection/actions/workflows/ci.yml/badge.svg)](https://github.com/Xiao0o0o/input-ambiguity-detection/actions/workflows/ci.yml)
7
+
8
+ Code and data for the AACL 2026 paper **"Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in LLMs"** by Tiejin Chen\*, Xiaoou Liu\*, Michael Clifford, Ahmadreza Moradipari, Yitao Chen, Kyungtae Han, Nejib Ammar and Hua Wei (\*equal contribution).
9
+
10
+ ## Overview
11
+
12
+ LLMs often answer an ambiguous question as if it had a single meaning. A common way to detect ambiguity is to have an LLM paraphrase or clarify the question and measure how much the answers disagree. But to rephrase a question the model must first understand it, and understanding an ambiguous question means picking one reading. The rewrite can remove the very ambiguity it is meant to measure.
13
+
14
+ We instead perturb the input with **low-capacity, label-preserving, semantics-blind** edits. These are small surface changes that never choose an interpretation. We then measure how much the model's answers spread across the original and perturbed questions. Two detectors implement this:
15
+
16
+ | detector | access | how it perturbs | code |
17
+ |---|---|---|---|
18
+ | **White-box** | model internals | Vanilla Gradient, Logit Lens or DiffMask ranks the input tokens; the top-3 question words are replaced by WordNet synonyms | [`whitebox/`](whitebox/) |
19
+ | **Black-box** | text in, text out | a fixed library of 11 rules: POS-constrained WordNet synonyms, contraction expand/contract, register prefixes, wh-word templates | [`blackbox/`](blackbox/) |
20
+
21
+ Both pool the answers to the original and perturbed questions. An NLI model (`microsoft/deberta-large-mnli`) builds an agreement matrix over them, and **EigV(Agree)**, the eigenvalue dispersion of its graph Laplacian, is the ambiguity score. A higher score means a more likely ambiguous question.
22
+
23
+ ## Repository layout
24
+
25
+ ```
26
+ .
27
+ ├── data/ # the four evaluation sets (shared by both detectors)
28
+ │ ├── abg_coqa_200_input.json # ABG-CoQA, 200 items (100 ambiguous / 100 not)
29
+ │ ├── abg_coqa_200_blackbox.json # the same 200 items in the original ABG-CoQA format (black-box input)
30
+ │ ├── ambigqa_with_ctx_500_input.json # AmbigQA + Wikipedia context, 500 items (250 / 250)
31
+ │ ├── aqua_720_input.json # AQuA, 720 items (540 / 180)
32
+ │ ├── vqfa_720_input.json # VQ-FocusAmbiguity, 720 items (422 / 298)
33
+ │ └── build/ # scripts that built these files (+ images for AQuA / VQ-FA)
34
+ ├── whitebox/ # white-box detector → see whitebox/README.md
35
+ │ ├── text/ vision/ # Vanilla Gradient, Logit Lens, DiffMask attribution
36
+ │ └── pipeline/ # top-k WordNet perturbation, generation, NLI UQ, AUROC
37
+ ├── blackbox/ # black-box detector → see blackbox/README.md
38
+ │ ├── perturbation_rules.py # the 11-rule library
39
+ │ ├── run_perturbation.py # rules → vLLM sampling
40
+ │ ├── compute_uq.py analyze_uq.py # NLI UQ (per variant / pooled) → AUROC + plots
41
+ │ └── run_llm_perturbation.py run_paraphrase.py # LLM-executed rules (ablation), LLM paraphrase baseline
42
+ ├── scripts/ # one command per (model, dataset)
43
+ │ ├── run_whitebox_text.sh run_whitebox_vision.sh
44
+ │ └── run_blackbox.sh
45
+ ├── quickstart/ # every intermediate file of one paper run + a resumable script
46
+ ├── input_ambiguity/ # package entry point: the `input-ambiguity` CLI
47
+ ├── tests/
48
+ ├── pyproject.toml # PyPI package (installs whitebox/ and blackbox/ as input_ambiguity.*)
49
+ └── requirements.txt # full environment for both detectors
50
+ ```
51
+
52
+ ## Installation
53
+
54
+ From PyPI:
55
+
56
+ ```bash
57
+ pip install input-ambiguity-detection # white-box detector, NLI scoring, AUROC
58
+ pip install "input-ambiguity-detection[blackbox]" # + black-box detector (vLLM, lm-polygraph, spaCy)
59
+ pip install "input-ambiguity-detection[all]" # + INT8 DiffMask (bitsandbytes) and data/build/* deps
60
+ ```
61
+
62
+ From source, with the data, quick start and shell scripts (recommended to reproduce the paper):
63
+
64
+ ```bash
65
+ git clone https://github.com/Xiao0o0o/input-ambiguity-detection.git
66
+ cd input-ambiguity-detection
67
+ pip install -r requirements.txt # exact versions used for the release checks
68
+ pip install -e . --no-deps # optional: also installs the `input-ambiguity` command
69
+ ```
70
+
71
+ Then:
72
+
73
+ ```bash
74
+ python -m spacy download en_core_web_sm # POS tags for the black-box rules
75
+ export HF_CACHE_DIR=/path/to/hf_cache # optional; HF default cache otherwise
76
+ export HF_TOKEN=... # for meta-llama/Llama-3.1-8B-Instruct and google/gemma-3-*
77
+ ```
78
+
79
+ NLTK downloads WordNet and the POS tagger on first use (`make nltk-data` fetches them up front).
80
+
81
+ Every script is also available through the installed command, with the same arguments:
82
+
83
+ ```bash
84
+ input-ambiguity --help # list of commands
85
+ input-ambiguity rules # black-box rule variants for a few sample questions
86
+ input-ambiguity bb-perturb --help # = python blackbox/run_perturbation.py --help
87
+ input-ambiguity wb-vision-logit-lens --help # = python whitebox/vision/logit_lens_uncertainty.py --help
88
+ ```
89
+
90
+ ## Quick start
91
+
92
+ The quick start is one paper run: the white-box detector on AQuA with Qwen2.5-VL-3B-Instruct. Its per-question scores are stored, so the paper's AUROC can be checked on a CPU in seconds, in either of two ways.
93
+
94
+ **Option A: with the PyPI package** (no clone, no GPU, no model download; the scores ship with the package)
95
+
96
+ ```bash
97
+ pip install input-ambiguity-detection
98
+ input-ambiguity quickstart
99
+ ```
100
+
101
+ **Option B: with the code in this repository**
102
+
103
+ ```bash
104
+ git clone https://github.com/Xiao0o0o/input-ambiguity-detection.git
105
+ cd input-ambiguity-detection
106
+ pip install -r requirements.txt
107
+ bash quickstart/run_quickstart.sh # or: make quick-eval
108
+ ```
109
+
110
+ | setting | |
111
+ |---|---|
112
+ | model | Qwen2.5-VL-3B-Instruct |
113
+ | dataset | AQuA, 720 visual questions (540 ambiguous / 180 unambiguous) |
114
+ | detector | white-box, Logit Lens importance, top-3 words → WordNet synonyms (up to 4 variants) |
115
+ | sampling | original: 1 greedy + 2 sampled (T=0.5, top-p 0.9); each variant: 1 greedy |
116
+ | score | EigV(Agree), `microsoft/deberta-large-mnli` |
117
+
118
+ | method | quick-start AUROC | paper (Table 1) |
119
+ |---|---|---|
120
+ | EigV(Agree) baseline (K=10 samples, no perturbation) | 0.6435 | 0.644 |
121
+ | **Ours (White-Box, Logit Lens)** | **0.7083** | **0.708** |
122
+
123
+ Both options give the numbers above, which match the paper. Option B also stores every intermediate file of the run (attribution, perturbations, answers), and the same script resumes from any earlier stage: `uq` (recompute NLI from the stored answers), `generate`, `perturb` or `attribution` (from scratch), e.g. `bash quickstart/run_quickstart.sh uq`. Expected deviations when re-running those stages are listed in [`quickstart/README.md`](quickstart/README.md).
124
+
125
+ To see what the black-box rules do to a question, without a model:
126
+
127
+ ```bash
128
+ python blackbox/perturbation_rules.py
129
+ python blackbox/run_perturbation.py --dry_run --input_path data/abg_coqa_200_blackbox.json --output_path variants.json
130
+ ```
131
+
132
+ ## Running the detectors
133
+
134
+ **White-box**: attribution → top-3 words → WordNet perturbation → sampling → NLI UQ → AUROC, for all three importance methods and the K=10 EigV(Agree) baseline:
135
+
136
+ ```bash
137
+ bash scripts/run_whitebox_text.sh Qwen/Qwen3-4B-Instruct-2507 data/abg_coqa_200_input.json results/qwen3_abg
138
+ bash scripts/run_whitebox_text.sh meta-llama/Llama-3.1-8B-Instruct data/ambigqa_with_ctx_500_input.json results/llama_ambigqa
139
+ bash scripts/run_whitebox_vision.sh Qwen/Qwen2.5-VL-3B-Instruct data/aqua_720_input.json results/qwenvl_aqua
140
+ bash scripts/run_whitebox_vision.sh OpenGVLab/InternVL3-8B-hf data/vqfa_720_input.json results/internvl_vqfa
141
+ ```
142
+
143
+ The vision inputs need the AQuA / VQ-FA images: `python data/build/build_aqua_input.py` downloads AQuA, and `VQFA_ROOT=... python data/build/build_vqfa_input.py` builds VQ-FA from its release. Settings, output files, the two EigV variants and memory notes are documented in [`whitebox/README.md`](whitebox/README.md).
144
+
145
+ **Black-box**: 11 rules → N samples per variant (vLLM) → NLI UQ per variant and pooled → AUROC per rule and pooled:
146
+
147
+ ```bash
148
+ bash scripts/run_blackbox.sh Qwen/Qwen3-4B-Instruct-2507 data/abg_coqa_200_blackbox.json results/blackbox_qwen3_abg
149
+ bash scripts/run_blackbox.sh meta-llama/Llama-3.1-8B-Instruct data/abg_coqa_200_blackbox.json results/blackbox_llama_abg
150
+ ```
151
+
152
+ The detector's score is the cross-variant (`CROSS`) `EigValLaplacian_NLI_entail` AUROC in `results/.../analysis/uq_statistics.json`; the per-rule AUROCs correspond to Figure 3. The LLM-executed-rules ablation (Table 4) and the LLM-paraphrase baseline are in [`blackbox/README.md`](blackbox/README.md).
153
+
154
+ ## Data
155
+
156
+ | dataset | type | items (amb / unamb) | source |
157
+ |---|---|---|---|
158
+ | ABG-CoQA | conversational QA | 200 (100 / 100) | [Guo et al., 2021](https://github.com/MeiqiGuo/AKBC2021-Abg-CoQA) |
159
+ | AmbigQA-w-Ctx | open-domain QA + Wikipedia passage | 500 (250 / 250) | [Min et al., 2020](https://huggingface.co/datasets/sewon/ambig_qa) |
160
+ | AQuA | visual QA | 720 (540 / 180) | [Jang and Kim, 2026](https://huggingface.co/datasets/jihyoung/AQuA) |
161
+ | VQ-FA | visual QA (focus ambiguity) | 720 (422 / 298) | Chen et al., 2025 (VQ-FocusAmbiguity release) |
162
+
163
+ All question files are included in `data/`, and `data/build/` holds the scripts that created them. Please also follow the licenses of the original datasets.
164
+
165
+ ## Hardware
166
+
167
+ The quick-start AUROC and the unit tests run on a CPU. Our experiments ran on a single NVIDIA A100 80 GB. Gemma-3-27B's DiffMask attribution uses INT8 weights through bitsandbytes, which `scripts/run_whitebox_text.sh` turns on automatically for 27B models.
168
+
169
+ ## Tests
170
+
171
+ ```bash
172
+ pip install -e ".[dev]"
173
+ make check # compileall + pytest + quick-start AUROC
174
+ make dist-check # build the PyPI sdist / wheel and run twine check
175
+ ```
176
+
177
+ The tests cover the black-box rule library, the shared prompt/data helpers, the EigV implementations, and the quick-start AUROC against the paper's numbers.
178
+
179
+ ## Citation
180
+
181
+ ```bibtex
182
+ @inproceedings{chen2026detect,
183
+ title = {Detect Before You Disambiguate: Perturbation-Based Input Ambiguity Detection in {LLMs}},
184
+ author = {Chen, Tiejin and Liu, Xiaoou and Clifford, Michael and Moradipari, Ahmadreza and
185
+ Chen, Yitao and Han, Kyungtae and Ammar, Nejib and Wei, Hua},
186
+ booktitle = {Proceedings of the Asia-Pacific Chapter of the Association for Computational Linguistics (AACL)},
187
+ year = {2026}
188
+ }
189
+ ```
190
+
191
+ ## License
192
+
193
+ MIT License, see [LICENSE](LICENSE).
File without changes