gsarti commited on
Commit
8b6d1b6
β€’
1 Parent(s): d82cd6f

Finished code generator

Browse files
Files changed (5) hide show
  1. app.py +70 -30
  2. contents.py +18 -5
  3. img/pecore_ui_output_example.png +0 -0
  4. presets.py +96 -1
  5. style.py +4 -0
app.py CHANGED
@@ -27,11 +27,11 @@ from presets import (
27
  set_zephyr_preset,
28
  set_gemma_preset,
29
  set_mistral_instruct_preset,
 
30
  )
31
  from style import custom_css
32
  from utils import get_formatted_attribute_context_results
33
 
34
- from inseq import list_feature_attribution_methods, list_step_functions
35
  from inseq.commands.attribute_context.attribute_context import (
36
  AttributeContextArgs,
37
  attribute_context_with_model,
@@ -291,21 +291,37 @@ with gr.Blocks(css=custom_css) as demo:
291
  value="kl_divergence",
292
  label="Context sensitivity metric",
293
  info="Metric to use to measure context sensitivity of generated tokens.",
294
- choices=list_step_functions(),
 
 
 
 
 
 
 
295
  interactive=True,
296
  )
297
  attribution_method = gr.Dropdown(
298
  value="saliency",
299
  label="Attribution method",
300
  info="Attribution method identifier to identify relevant context tokens.",
301
- choices=list_feature_attribution_methods(),
 
 
 
 
302
  interactive=True,
303
  )
304
  attributed_fn = gr.Dropdown(
305
  value="contrast_prob_diff",
306
  label="Attributed function",
307
  info="Function of model logits to use as target for the attribution method.",
308
- choices=list_step_functions(),
 
 
 
 
 
309
  interactive=True,
310
  )
311
  gr.Markdown("#### Results Selection Parameters")
@@ -330,7 +346,7 @@ with gr.Blocks(css=custom_css) as demo:
330
  maximum=10,
331
  )
332
  attribution_std_threshold = gr.Number(
333
- value=1.0,
334
  label="Attribution threshold",
335
  info="Select N to keep attributed tokens with scores above N * std. 0 = above mean.",
336
  precision=1,
@@ -461,8 +477,23 @@ with gr.Blocks(css=custom_css) as demo:
461
  gr.Markdown(cci_explanation)
462
  with gr.Tab("πŸ”§ Usage Guide"):
463
  gr.Markdown(how_to_use)
464
- gr.HTML('<img src="file/img/pecore_ui_output_example.png" width=100% />')
465
  gr.Markdown(example_explanation)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  with gr.Tab("πŸ“š Citing PECoRe"):
467
  gr.Markdown(citation)
468
  with gr.Row(elem_classes="footer-container"):
@@ -479,36 +510,38 @@ with gr.Blocks(css=custom_css) as demo:
479
  tokenizer_kwargs,
480
  ]
481
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  attribute_input_button.click(
483
  lambda *args: [gr.DownloadButton(visible=False), gr.DownloadButton(visible=False)],
484
  inputs=[],
485
  outputs=[download_output_file_button, download_output_html_button],
486
  ).then(
487
  pecore,
488
- inputs=[
489
- input_current_text,
490
- input_context_text,
491
- output_current_text,
492
- output_context_text,
493
- model_name_or_path,
494
- attribution_method,
495
- attributed_fn,
496
- context_sensitivity_metric,
497
- context_sensitivity_std_threshold,
498
- context_sensitivity_topk,
499
- attribution_std_threshold,
500
- attribution_topk,
501
- input_template,
502
- output_template,
503
- contextless_input_template,
504
- contextless_output_template,
505
- special_tokens_to_keep,
506
- decoder_input_output_separator,
507
- model_kwargs,
508
- tokenizer_kwargs,
509
- generation_kwargs,
510
- attribution_kwargs,
511
- ],
512
  outputs=[
513
  pecore_output_highlights,
514
  download_output_file_button,
@@ -617,4 +650,11 @@ with gr.Blocks(css=custom_css) as demo:
617
  ],
618
  ).success(preload_model, inputs=load_model_args, cancels=load_model_event)
619
 
 
 
 
 
 
 
 
620
  demo.launch(allowed_paths=["outputs/", "img/"])
 
27
  set_zephyr_preset,
28
  set_gemma_preset,
29
  set_mistral_instruct_preset,
30
+ update_code_snippets_fn,
31
  )
32
  from style import custom_css
33
  from utils import get_formatted_attribute_context_results
34
 
 
35
  from inseq.commands.attribute_context.attribute_context import (
36
  AttributeContextArgs,
37
  attribute_context_with_model,
 
291
  value="kl_divergence",
292
  label="Context sensitivity metric",
293
  info="Metric to use to measure context sensitivity of generated tokens.",
294
+ choices=[
295
+ "probability",
296
+ "logit",
297
+ "kl_divergence",
298
+ "contrast_logits_diff",
299
+ "contrast_prob_diff",
300
+ "pcxmi"
301
+ ],
302
  interactive=True,
303
  )
304
  attribution_method = gr.Dropdown(
305
  value="saliency",
306
  label="Attribution method",
307
  info="Attribution method identifier to identify relevant context tokens.",
308
+ choices=[
309
+ "saliency",
310
+ "input_x_gradient",
311
+ "value_zeroing",
312
+ ],
313
  interactive=True,
314
  )
315
  attributed_fn = gr.Dropdown(
316
  value="contrast_prob_diff",
317
  label="Attributed function",
318
  info="Function of model logits to use as target for the attribution method.",
319
+ choices=[
320
+ "probability",
321
+ "logit",
322
+ "contrast_logits_diff",
323
+ "contrast_prob_diff",
324
+ ],
325
  interactive=True,
326
  )
327
  gr.Markdown("#### Results Selection Parameters")
 
346
  maximum=10,
347
  )
348
  attribution_std_threshold = gr.Number(
349
+ value=2.0,
350
  label="Attribution threshold",
351
  info="Select N to keep attributed tokens with scores above N * std. 0 = above mean.",
352
  precision=1,
 
477
  gr.Markdown(cci_explanation)
478
  with gr.Tab("πŸ”§ Usage Guide"):
479
  gr.Markdown(how_to_use)
 
480
  gr.Markdown(example_explanation)
481
+ update_code_snippets = gr.Button("Update code snippets", variant="primary")
482
+ with gr.Row(equal_height=True):
483
+ python_code_snippet = gr.Code(
484
+ value="""Generate Python code snippet by pressing the button.""",
485
+ language="python",
486
+ label="Python",
487
+ interactive=False,
488
+ show_label=True,
489
+ )
490
+ shell_code_snippet = gr.Code(
491
+ value="""Generate Shell code snippet by pressing the button.""",
492
+ language="shell",
493
+ label="Shell",
494
+ interactive=False,
495
+ show_label=True,
496
+ )
497
  with gr.Tab("πŸ“š Citing PECoRe"):
498
  gr.Markdown(citation)
499
  with gr.Row(elem_classes="footer-container"):
 
510
  tokenizer_kwargs,
511
  ]
512
 
513
+ pecore_args = [
514
+ input_current_text,
515
+ input_context_text,
516
+ output_current_text,
517
+ output_context_text,
518
+ model_name_or_path,
519
+ attribution_method,
520
+ attributed_fn,
521
+ context_sensitivity_metric,
522
+ context_sensitivity_std_threshold,
523
+ context_sensitivity_topk,
524
+ attribution_std_threshold,
525
+ attribution_topk,
526
+ input_template,
527
+ output_template,
528
+ contextless_input_template,
529
+ contextless_output_template,
530
+ special_tokens_to_keep,
531
+ decoder_input_output_separator,
532
+ model_kwargs,
533
+ tokenizer_kwargs,
534
+ generation_kwargs,
535
+ attribution_kwargs,
536
+ ]
537
+
538
  attribute_input_button.click(
539
  lambda *args: [gr.DownloadButton(visible=False), gr.DownloadButton(visible=False)],
540
  inputs=[],
541
  outputs=[download_output_file_button, download_output_html_button],
542
  ).then(
543
  pecore,
544
+ inputs=pecore_args,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  outputs=[
546
  pecore_output_highlights,
547
  download_output_file_button,
 
650
  ],
651
  ).success(preload_model, inputs=load_model_args, cancels=load_model_event)
652
 
653
+ update_code_snippets.click(
654
+ update_code_snippets_fn,
655
+ inputs=pecore_args,
656
+ outputs=[python_code_snippet, shell_code_snippet],
657
+
658
+ )
659
+
660
  demo.launch(allowed_paths=["outputs/", "img/"])
contents.py CHANGED
@@ -33,18 +33,31 @@ cci_explanation = """
33
  """
34
 
35
  how_to_use = """
36
- <h3>How to use this demo</h3>
37
 
38
  <p>This demo provides a convenient UI for the Inseq implementation of PECoRe (the <a href="https://inseq.org/en/latest/main_classes/cli.html#attribute-context"><code>inseq attribute-context</code></a> CLI command).</p>
39
  <p>In the demo tab, fill in the input and context fields with the text you want to analyze, and click the <code>Run PECoRe</code> button to produce an output where the tokens selected by PECoRe in the model generation and context are highlighted. For more details on the parameters and their meaning, check the <code>Parameters</code> tab.</p>
40
 
41
- <h3>Interpreting PECoRe results</h3>
42
  """
43
 
44
  example_explanation = """
45
- <p>The example shows the output of the <a href='https://huggingface.co/gsarti/cora_mgen' target='_blank'>CORA Multilingual QA</a> model used as default in the interface, using default settings.</p>
46
- <p>
47
-
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  """
49
 
50
  citation = r"""
 
33
  """
34
 
35
  how_to_use = """
36
+ <h2>How to use this demo</h3>
37
 
38
  <p>This demo provides a convenient UI for the Inseq implementation of PECoRe (the <a href="https://inseq.org/en/latest/main_classes/cli.html#attribute-context"><code>inseq attribute-context</code></a> CLI command).</p>
39
  <p>In the demo tab, fill in the input and context fields with the text you want to analyze, and click the <code>Run PECoRe</code> button to produce an output where the tokens selected by PECoRe in the model generation and context are highlighted. For more details on the parameters and their meaning, check the <code>Parameters</code> tab.</p>
40
 
41
+ <h2>Interpreting PECoRe results</h3>
42
  """
43
 
44
  example_explanation = """
45
+ <p>Consider the following example, showing inputs and outputs of the <a href='https://huggingface.co/gsarti/cora_mgen' target='_blank'>CORA Multilingual QA</a> model provided as default in the interface, using default settings.</p>
46
+ <img src="file/img/pecore_ui_output_example.png" width=100% />
47
+ <p>The PECoRe CTI step identified two context-sensitive tokens in the generation (<code>287</code> and <code>,</code>), while the CCI step associated each of those with the most influential tokens in the context. It can be observed that in both cases similar tokens from the passage stating the number of inhabitants are identified as salient (<code>235</code> and <code>,</code> for the generated <code>287</code>, while <code>had</code> is also found salient for the generated <code>,</code>).</p>
48
+ <h2>Usage tips</h3>
49
+ <ol>
50
+ <li>The <code>πŸ“‚ Download output</code> button allows you to download the full JSON output produced by the Inseq CLI. It includes, among other things, the full set of CTI and CCI scores produced by PECoRe, tokenized versions of the input context and generated output and the full arguments used for the CLI call.</li>
51
+ <li>The <code>πŸ” Download HTML</code> button allows you to download an HTML view of the output similar to the one visualized in the demo.
52
+ <li>By default, all generated tokens <b>above the mean CTI score</b> for the generated text are highlighted as context-sensitive. This might be reasonable for short answers, but the threshold can be raised by increasing the <code>Context sensitivity threshold</code> parameter to ensure only very sensitive tokens are picked up in longer replies.</li>
53
+ <li>Relatedly, all context tokens receiving <b>CCI scores >2 standard deviations</b> above the context mean are highlighted as influential. This might be reasonable for contexts with at least 50-100 tokens, but the threshold can be lowered by decreasing the <code>Attribution threshold</code> parameter to be more lenient in the selection for shorter contexts.</li>
54
+ <li>When using a model, make sure that the <b>contextual and contextless templates are set to match the expected format</b>. You can use presets to auto-fill these for the provided models.</li>
55
+ <li>If you are using an encoder-decoder expecting an output context (e.g. the multilingual MT preset), the <b>output context should be provided manually</b> before running PECoRe in the <code>Generation context</code> parameter. This is a requirement for the demo because the splitting between output context and current cannot be reliably performed in an automatic way. However, the <code>inseq attribute-context</code> CLI command actually support various strategies, including prompting users for a split and/or trying an automatic source-target alignment. </li>
56
+ </ol>
57
+ <h2>Using PECoRe from Python with Inseq</h3>
58
+ <p>This demo is useful for testing out various models and methods for PECoRe attribution, but the <a href="https://inseq.org/en/latest/main_classes/cli.html#attribute-context"><code>inseq attribute-context</code></a> CLI command is the way to go if you want to run experiments on several examples, or if you want to exploit the full customizability of the Inseq API.</p>
59
+ <p>The utility we provide in this section allows you to generate Python and Shell code calling the Inseq CLI with the parameters you set in the interface. This is useful to understand how to use the Inseq API and quickly get up to speed with running PECoRe on your own models and data.</p>
60
+ <p>Once you are satisfied with the parameters you set (including context/query strings in the <code>πŸ‘ Demo</code> tab), just press the button and get your code snippets ready for usage! πŸ€—</p>
61
  """
62
 
63
  citation = r"""
img/pecore_ui_output_example.png CHANGED
presets.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  SYSTEM_PROMPT = "You are a helpful assistant that provide concise and accurate answers."
2
 
3
  def set_cora_preset():
@@ -77,4 +79,97 @@ def set_mistral_instruct_preset():
77
  "[INST]{context}\n{current}[/INST]" # input_template
78
  "[INST]{current}[/INST]" # input_current_text_template
79
  "\n" # decoder_input_output_separator
80
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
  SYSTEM_PROMPT = "You are a helpful assistant that provide concise and accurate answers."
4
 
5
  def set_cora_preset():
 
79
  "[INST]{context}\n{current}[/INST]" # input_template
80
  "[INST]{current}[/INST]" # input_current_text_template
81
  "\n" # decoder_input_output_separator
82
+ )
83
+
84
+ def update_code_snippets_fn(
85
+ input_current_text: str,
86
+ input_context_text: str,
87
+ output_current_text: str,
88
+ output_context_text: str,
89
+ model_name_or_path: str,
90
+ attribution_method: str,
91
+ attributed_fn: str | None,
92
+ context_sensitivity_metric: str,
93
+ context_sensitivity_std_threshold: float,
94
+ context_sensitivity_topk: int,
95
+ attribution_std_threshold: float,
96
+ attribution_topk: int,
97
+ input_template: str,
98
+ output_template: str,
99
+ contextless_input_template: str,
100
+ contextless_output_template: str,
101
+ special_tokens_to_keep: str | list[str] | None,
102
+ decoder_input_output_separator: str,
103
+ model_kwargs: str,
104
+ tokenizer_kwargs: str,
105
+ generation_kwargs: str,
106
+ attribution_kwargs: str,
107
+ ) -> tuple[str, str]:
108
+ def get_kwargs_str(kwargs: str, name: str, pad: str = " " * 4) -> str:
109
+ kwargs_dict = json.loads(kwargs)
110
+ return nl + pad + name + '=' + str(kwargs_dict) + ',' if kwargs_dict else ''
111
+ nl = "\n"
112
+ tq = "\"\"\""
113
+ # Python
114
+ python = f"""#!pip install inseq
115
+ import inseq
116
+ from inseq.commands.attribute_context import attribute_context_with_model
117
+
118
+ inseq_model = inseq.load_model(
119
+ "{model_name_or_path}",
120
+ "{attribution_method}",{get_kwargs_str(model_kwargs, "model_kwargs")}{get_kwargs_str(tokenizer_kwargs, "tokenizer_kwargs")}
121
+ )
122
+
123
+ pecore_args = AttributeContextArgs(
124
+ save_path="pecore_output.json",
125
+ viz_path="pecore_output.html",
126
+ model_name_or_path="{model_name_or_path}",
127
+ attribution_method="{attribution_method}",
128
+ attributed_fn="{attributed_fn}",
129
+ context_sensitivity_metric="{context_sensitivity_metric}",
130
+ special_tokens_to_keep={special_tokens_to_keep},
131
+ context_sensitivity_std_threshold={context_sensitivity_std_threshold},
132
+ attribution_std_threshold={attribution_std_threshold},
133
+ input_current_text=\"\"\"{input_current_text}\"\"\",
134
+ input_template=\"\"\"{input_template}\"\"\",
135
+ output_template="{output_template}",
136
+ contextless_input_current_text=\"\"\"{contextless_input_template}\"\"\",
137
+ contextless_output_current_text=\"\"\"{contextless_output_template}\"\"\",
138
+ context_sensitivity_topk={context_sensitivity_topk if context_sensitivity_topk > 0 else None},
139
+ attribution_topk={attribution_topk if attribution_topk > 0 else None},
140
+ input_context_text={tq + input_context_text + tq if input_context_text else None},
141
+ output_context_text={tq + output_context_text + tq if output_context_text else None},
142
+ output_current_text={tq + output_current_text + tq if output_current_text else None},
143
+ decoder_input_output_separator={tq + decoder_input_output_separator + tq if decoder_input_output_separator else None},{get_kwargs_str(model_kwargs, "model_kwargs")}{get_kwargs_str(tokenizer_kwargs, "tokenizer_kwargs")}{get_kwargs_str(generation_kwargs, "generation_kwargs")}{get_kwargs_str(attribution_kwargs, "attribution_kwargs")}
144
+ )
145
+ out = attribute_context_with_model(pecore_args, loaded_model)"""
146
+ # Bash
147
+ bash = f"""pip install inseq
148
+ inseq attribute-context \\
149
+ --save-path pecore_output.json \\
150
+ --viz-path pecore_output.html \\
151
+ --model-name-or-path "{model_name_or_path}" \\
152
+ --attribution-method "{attribution_method}" \\
153
+ --attributed-fn "{attributed_fn}" \\
154
+ --context-sensitivity-metric "{context_sensitivity_metric}" \\
155
+ --special-tokens-to-keep {" ".join(special_tokens_to_keep)} \\
156
+ --context-sensitivity-std-threshold {context_sensitivity_std_threshold} \\
157
+ --attribution-std-threshold {attribution_std_threshold} \\
158
+ --input-current-text "{input_current_text}" \\
159
+ --input-template "{input_template}" \\
160
+ --output-template "{output_template}" \\
161
+ --contextless-input-current-text "{contextless_input_template}" \\
162
+ --contextless-output-current-text "{contextless_output_template}" \\
163
+ --context-sensitivity-topk {context_sensitivity_topk if context_sensitivity_topk > 0 else None} \\
164
+ --attribution-topk {attribution_topk if attribution_topk > 0 else None} \\
165
+ --input-context-text "{input_context_text}" \\
166
+ --output-context-text "{output_context_text}" \\
167
+ --output-current-text "{output_current_text}" \\
168
+ --decoder-input-output-separator "{decoder_input_output_separator}" \\
169
+ --model-kwargs "{str(model_kwargs).replace(nl, "")}" \\
170
+ --tokenizer-kwargs "{str(tokenizer_kwargs).replace(nl, "")} \\
171
+ --generation-kwargs "{str(generation_kwargs).replace(nl, "")}" \\
172
+ --attribution-kwargs "{str(attribution_kwargs).replace(nl, "")}"
173
+ """
174
+ return python, bash
175
+
style.py CHANGED
@@ -38,4 +38,8 @@ custom_css = """
38
  .footer-custom-block a {
39
  margin-right: 15px;
40
  }
 
 
 
 
41
  """
 
38
  .footer-custom-block a {
39
  margin-right: 15px;
40
  }
41
+
42
+ ol {
43
+ padding-left: 30px;
44
+ }
45
  """