Spaces:
Running
Running
MattStammers
commited on
Commit
·
067c9fa
1
Parent(s):
4b17270
readme improved
Browse files
app.py
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
import re
|
2 |
from pathlib import Path
|
3 |
|
@@ -8,7 +10,17 @@ import seaborn as sns
|
|
8 |
import yaml
|
9 |
|
10 |
import pteredactyl as pt
|
11 |
-
from pteredactyl.defaults import change_model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
sample_text = """
|
14 |
1. Dr. Huntington (Patient No: 1234567890) diagnosed Ms. Alzheimer with Alzheimer's disease during her last visit to the Huntington Medical Center on 12/12/2023. The prognosis was grim, but Dr. Huntington assured Ms. Alzheimer that the facility was well-equipped to handle her condition despite the lack of a cure for Alzheimer's.
|
@@ -68,6 +80,9 @@ def redact(text: str, model_name: str):
|
|
68 |
|
69 |
model_path = model_paths.get(model_name, "StanfordAIMI/stanford-deidentifier-base")
|
70 |
|
|
|
|
|
|
|
71 |
if model_path:
|
72 |
change_model(model_path)
|
73 |
else:
|
@@ -256,6 +271,12 @@ def redact_and_visualize(text: str, model_name: str):
|
|
256 |
reference_text, redacted_text
|
257 |
)
|
258 |
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
# Count entities and compute metrics
|
260 |
tp_count, fn_count, fp_count, tn_count = count_entities_and_compute_metrics(
|
261 |
reference_text_with_fn, redacted_text_with_fp
|
@@ -282,21 +303,70 @@ def redact_and_visualize(text: str, model_name: str):
|
|
282 |
|
283 |
|
284 |
hint = """
|
285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
|
287 |
-
|
|
|
|
|
|
|
288 |
|
289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
290 |
|
291 |
### Strengths
|
292 |
-
- The
|
|
|
|
|
293 |
|
294 |
-
-
|
295 |
|
296 |
### Limitations
|
297 |
-
- The tool was not designed initially to redact clinic letters as it was developed primarily on radiology reports in the US. We have made some augmentations to cover postcodes but these might not always work.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
299 |
-
|
|
|
|
|
300 |
"""
|
301 |
|
302 |
description = """
|
@@ -304,7 +374,7 @@ description = """
|
|
304 |
|
305 |
*Version:* **1.0** - Working Proof of Concept Demo with API option and webapp demonstration.
|
306 |
|
307 |
-
*Authors:* **Cai Davis
|
308 |
"""
|
309 |
|
310 |
iface = gr.Interface(
|
|
|
1 |
+
import logging
|
2 |
+
import logging.config
|
3 |
import re
|
4 |
from pathlib import Path
|
5 |
|
|
|
10 |
import yaml
|
11 |
|
12 |
import pteredactyl as pt
|
13 |
+
from pteredactyl.defaults import change_model
|
14 |
+
|
15 |
+
# Logging configuration. This is only done at root level
|
16 |
+
logging_config = yaml.safe_load(Path("logging.yaml").read_text())
|
17 |
+
logging.config.dictConfig(logging_config)
|
18 |
+
|
19 |
+
# Get the logger
|
20 |
+
log = logging.getLogger(__name__)
|
21 |
+
|
22 |
+
# Load the model
|
23 |
+
log.info("Starting App")
|
24 |
|
25 |
sample_text = """
|
26 |
1. Dr. Huntington (Patient No: 1234567890) diagnosed Ms. Alzheimer with Alzheimer's disease during her last visit to the Huntington Medical Center on 12/12/2023. The prognosis was grim, but Dr. Huntington assured Ms. Alzheimer that the facility was well-equipped to handle her condition despite the lack of a cure for Alzheimer's.
|
|
|
80 |
|
81 |
model_path = model_paths.get(model_name, "StanfordAIMI/stanford-deidentifier-base")
|
82 |
|
83 |
+
# Log the model being changed to
|
84 |
+
log.info(f"Changing to model: {model_path}")
|
85 |
+
|
86 |
if model_path:
|
87 |
change_model(model_path)
|
88 |
else:
|
|
|
271 |
reference_text, redacted_text
|
272 |
)
|
273 |
|
274 |
+
# Print the final texts with flags for debugging
|
275 |
+
log.debug("Final Reference Text with False Negatives:")
|
276 |
+
log.debug(reference_text_with_fn)
|
277 |
+
log.debug("\nFinal Redacted Text with False Positives:")
|
278 |
+
log.debug(redacted_text_with_fp)
|
279 |
+
|
280 |
# Count entities and compute metrics
|
281 |
tp_count, fn_count, fp_count, tn_count = count_entities_and_compute_metrics(
|
282 |
reference_text_with_fn, redacted_text_with_fp
|
|
|
303 |
|
304 |
|
305 |
hint = """
|
306 |
+
## Pteredactyl Gradio Webapp and API
|
307 |
+
|
308 |
+
Clinical patient identifiable information (cPII) presents a significant challenge in natural language processing (NLP) that has yet to be fully resolved but significant progress is being made [1,2].
|
309 |
+
|
310 |
+
This is why we created [Pteredactyl](https://pypi.org/project/pteredactyl/) - a python module to help with redaction of clinical free text.
|
311 |
+
|
312 |
+
## Tool Usage Instructions
|
313 |
+
|
314 |
+
When the input text is entered, the tool redacts the cPII from the entered text using NLP with labelled masking tokens and then assesses the models results. You can test the text against different models by selecting from the dropdown.
|
315 |
+
|
316 |
+
## Deployment Options
|
317 |
+
|
318 |
+
This webapp is available online as a gradio app on Huggingface: [Huggingface Gradio App](https://huggingface.co/spaces/MattStammers/pteredactyl_PII). It is also available as [source](https://github.com/SETT-Centre-Data-and-AI/PteRedactyl) or as a Docker Image: [Docker Image](https://registry.hub.docker.com/r/mattstammers/pteredactyl). All are MIT licensed.
|
319 |
+
|
320 |
+
Please note if deploying the docker image the port bindings are to 7860. The image can also be deployed from source using the following command:
|
321 |
|
322 |
+
```bat
|
323 |
+
docker build -t pteredactyl:latest .
|
324 |
+
docker run -d -p 7860:7860 --name pteredactyl-app pteredactyl:latest
|
325 |
+
```
|
326 |
|
327 |
+
## Information
|
328 |
+
|
329 |
+
A lot of work and experimentation has gone into the development of this tool. Because we believe in being fully transparent further details are given below.
|
330 |
+
|
331 |
+
|
332 |
+
### Methods:
|
333 |
+
|
334 |
+
We evaluated three open-source models from Huggingface: Stanford Base De-Identifier, Deberta PII, and Nikhilrk De-Identify using our Clinical_PII_Redaction_Test dataset. The text was tokenised, and all entities such as [PERSON], [ID], and [LOCATION] were tagged in the gold standard. Each model redacted cPII from clinical texts, and outputs were compared to the gold standard template to calculate the confusion matrix, accuracy, precision, recall, and F1 score.
|
335 |
+
|
336 |
+
### Results
|
337 |
+
|
338 |
+
The full results of the tool are given below in <i>Table 1</i> below.
|
339 |
+
|
340 |
+
| Metric | Stanford Base De-Identifier | Deberta PII | Nikhilrk De-Identify |
|
341 |
+
|------------|-----------------------------|-------------|----------------------|
|
342 |
+
| Accuracy | 0.98 | 0.85 | 0.68 |
|
343 |
+
| Precision | 0.91 | 0.93 | 0.28 |
|
344 |
+
| Recall | 0.94 | 0.16 | 0.49 |
|
345 |
+
| F1 Score | 0.93 | 0.28 | 0.36 |
|
346 |
+
<small><i>Table 1: Summary of Model Performance Metrics</i></small>
|
347 |
|
348 |
### Strengths
|
349 |
+
- The test benchmark [Clinical_PII_Redaction_Test](https://huggingface.co/datasets/MattStammers/Clinical_PII_Redaction_Test) intentionally exploits commonly observed weaknesses in NLP cPII token masking systems such as clinician/patient/diagnosis name similarity and commonly observed ID/username and location/postcode issues.
|
350 |
+
|
351 |
+
- [The Stanford De-Identifier Base Model](https://huggingface.co/StanfordAIMI/stanford-deidentifier-base)[1] is 99% accurate on our test set of radiology reports and achieves an F1 score of 93% on our challenging open-source benchmark. The others models are really to demonstrate the potential of Pteredactyl to deploy any transfomer model.
|
352 |
|
353 |
+
- We have submitted the code to [OHDSI](https://www.ohdsi.org/) as an abstract and aim strongly to incorporate this into a wider open-source effort to solve intractable clinical informatics problems.
|
354 |
|
355 |
### Limitations
|
356 |
+
- The tool was not designed initially to redact clinic letters as it was developed primarily on radiology reports in the US. We have made some augmentations to cover elements like postcodes using checksums but these might not always work. The same is true of NHS numbers as illustrated above.
|
357 |
+
|
358 |
+
- It may overly aggressively redact text because it was built as a research tool where precision is prized > recall. However, in our experience this is uncommon enough that it is still very useful.
|
359 |
+
|
360 |
+
- This is very much a research tool and should not be relied upon as a catch-all in any production-type capacity. The app makes the limitations very transparently obvious via the attached confusion matrix.
|
361 |
+
|
362 |
+
### Conclusion
|
363 |
+
The validation cohort introduced in this study proves to be a highly effective tool for discriminating the performance of open-source cPII redaction models. Intentionally exploiting common weaknesses in cNLP token masking systems offers a more rigorous cPII benchmark than many larger datasets provide.
|
364 |
+
|
365 |
+
We invite the open-source community to collaborate to improve the present results and enhance the robustness of cPII redaction methods by building on the work we have begun here [here](https://github.com/SETT-Centre-Data-and-AI/PteRedactyl).
|
366 |
|
367 |
+
### References:
|
368 |
+
1. Chambon PJ, Wu C, Steinkamp JM, Adleberg J, Cook TS, Langlotz CP. Automated deidentification of radiology reports combining transformer and “hide in plain sight” rule-based methods. J Am Med Inform Assoc. 2023 Feb 1;30(2):318–28.
|
369 |
+
2. Kotevski DP, Smee RI, Field M, Nemes YN, Broadley K, Vajdic CM. Evaluation of an automated Presidio anonymisation model for unstructured radiation oncology electronic medical records in an Australian setting. Int J Med Inf. 2022 Dec 1;168:104880.
|
370 |
"""
|
371 |
|
372 |
description = """
|
|
|
374 |
|
375 |
*Version:* **1.0** - Working Proof of Concept Demo with API option and webapp demonstration.
|
376 |
|
377 |
+
*Authors:* **Matt Stammers🧪, Cai Davis🥼 and Michael George🩺**
|
378 |
"""
|
379 |
|
380 |
iface = gr.Interface(
|