Clinical NLP Systems
Clinical Named Entity Recognition (NER)
from transformers import AutoTokenizer, AutoModelForTokenClassification
class ClinicalNER:
def __init__(self, model_name="microsoft/BiomedNLP-PubMedBERT-base"):
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForTokenClassification.from_pretrained(
model_name, num_labels=12
)
self.label_map = {
0: 'O', 1: 'B-DISEASE', 2: 'I-DISEASE',
3: 'B-MEDICATION', 4: 'I-MEDICATION',
5: 'B-PROCEDURE', 6: 'I-PROCEDURE',
7: 'B-ANATOMY', 8: 'I-ANATOMY',
9: 'B-SYMPTOM', 10: 'I-SYMPTOM'
}
def extract_entities(self, text):
inputs = self.tokenizer(text, return_tensors="pt",
padding=True, truncation=True)
logits = self.model(**inputs).logits
predictions = torch.argmax(logits, dim=-1)[0]
return [(self.tokenizer.decode(inputs['input_ids'][0][i]),
self.label_map[p.item()])
for i, p in enumerate(predictions) if self.label_map[p.item()] != 'O']
BIO Tagging Scheme
| Tag | Meaning | Example |
|---|
| B-DISEASE | Start of disease entity | "diabetes" |
| I-DISEASE | Continuation | "mellitus type 2" |
| O | Outside entity | "the", "and" |
Clinical Text Classification
Multi-Task Learning
class MultiTaskClinicalClassifier(nn.Module):
def __init__(self, base_model, task_configs):
super().__init__()
self.encoder = base_model
self.task_heads = nn.ModuleDict()
for task_name, num_classes in task_configs.items():
self.task_heads[task_name] = nn.Linear(
base_model.config.hidden_size, num_classes
)
def forward(self, input_ids, attention_mask, task_name):
outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)
return self.task_heads[task_name](outputs.last_hidden_state[:, 0, :])
Clinical Relation Extraction
Common Relations
- TREATS: Drug treats condition
- CAUSES: Condition causes symptom
- ADMINISTERED_AS: Medication route
- DOSAGE_OF: Dosage information
Pre-training on Clinical Corpora
Masked Language Modeling
Evaluation
Handling Negation
class NegationDetector:
def __init__(self):
self.negation_cues = {
'no', 'not', 'denies', 'without', 'absent',
'negative', 'rules out', 'no evidence'
}
def is_negated(self, sentence, entity_span):
before = sentence[:entity_span[0]].lower().split()
for cue in self.negation_cues:
if cue in ' '.join(before[-10:]):
return True
return False
Best Practices
- Use domain-specific tokenizers for medical abbreviations
- Apply data augmentation with medical thesauri
- Implement active learning for annotation
- Validate across multiple institutions