AI for Genomic Medicine
What is Genomic Medicine?
Genomic medicine uses an individual's genetic information to guide diagnosis, treatment, and disease prevention. AI has revolutionized this field by enabling the analysis of massive genomic datasets that would take human researchers decades to process manually.
Core Concepts
- Genome: Complete set of DNA (3.2 billion base pairs) in a human cell
- Variant: A difference from the reference genome at a specific position
- SNP: Single Nucleotide Polymorphism â the most common type of genetic variation
- GWAS: Genome-Wide Association Study â links genetic variants to traits/diseases
- PRS: Polygenic Risk Score â aggregates effects of many variants into one risk number
The Human Genome: Scale and Complexity
Why AI is Essential
The human genome contains 3.2 billion base pairs. A single Whole Genome Sequencing (WGS) run produces ~90GB of raw data. Traditional variant calling tools (GATK) require:
- 6+ hours of processing time
- 40+ parameters to tune
- Expert bioinformatician oversight
DeepVariant (Google) uses a CNN to classify variants with 99.7% accuracy â outperforming all traditional methods.
Key Mathematical Foundations
Hardy-Weinberg Equilibrium
where and are allele frequencies. This equation tests whether a population is in genetic equilibrium â deviations suggest selection, migration, or non-random mating.
Polygenic Risk Score (PRS)
where is the effect size from GWAS and is the genotype dosage (0, 1, or 2 copies of the risk allele). PRS aggregates thousands of small-effect variants into a single risk predictor.
Phred-Scaled Quality Score
A Phred score of 30 means 1 in 1000 probability of error. Most clinical pipelines require Q ⼠20 for variant confidence.
Linkage Disequilibrium (LD)
LD measures non-random association between alleles at different loci. High LD means variants are inherited together â critical for PRS calculation and imputation.
Genomic AI Applications
| Application | Method | Accuracy | Clinical Utility |
|---|---|---|---|
| Variant Calling | DeepVariant | 99.7% | Diagnostic |
| PRS Calculation | LDpred2 | AUC 0.72 | Risk stratification |
| Gene Expression | Enformer | r=0.85 | Functional annotation |
| Splice Prediction | SpliceAI | 0.95 | Pathogenicity |
| Regulatory Effects | Basset | 0.82 | Variant interpretation |
Deep Variant Calling with DeepVariant
DeepVariant Architecture
DeepVariant converts the variant calling problem into an image classification task:
- Pileup Image: Reads are stacked at each genomic position, creating a "pileup image" with RGB-like channels
- CNN Classification: An Inception-v3 network (pretrained on ImageNet) classifies the pileup into genotype classes
- Genotype Output: Three classes â HOM_REF (homozygous reference), HET (heterozygous), HOM_ALT (homozygous alternate)
Why CNN for Genomics?
CNNs excel at detecting local patterns â just as they find edges in natural images, they find allele frequency patterns in pileup images. The convolutional filters learn to detect:
- Consistent alternate alleles across reads
- Strand bias (alleles appearing only on one strand)
- Base quality gradients
- Mapping quality distributions
import torch
import torch.nn as nn
import numpy as np
class DeepVariantCNN(nn.Module):
def __init__(self, num_classes=3):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(6, 32, kernel_size=5, padding=2),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.AdaptiveAvgPool2d((1, 1))
)
self.classifier = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(64, num_classes)
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
return self.classifier(x)
def create_pileup_image(reads, ref_seq, position, window=100):
"""Create a pileup image tensor from aligned reads."""
channels = 6 # A, C, G, T, mapping_qual, base_qual
image = np.zeros((channels, window * 2, 3))
for i, read in enumerate(reads):
start = max(0, position - window)
end = min(len(read.query_sequence), position + window)
for j in range(start, end):
base = read.query_sequence[j]
base_idx = {'A': 0, 'C': 1, 'G': 2, 'T': 3}.get(base, -1)
if base_idx >= 0:
image[base_idx, j - start, 0] = 1.0
image[4, j - start, 0] = read.mapping_quality / 60.0
image[5, j - start, 0] = read.query_qualities[j] / 40.0
return torch.tensor(image, dtype=torch.float32).unsqueeze(0)
model = DeepVariantCNN(num_classes=3)
dummy_input = torch.randn(1, 6, 200, 3)
output = model(dummy_input)
print(f'DeepVariant output: {output.shape}') # [1, 3] logits
Polygenic Risk Scores (PRS)
How PRS Works
- GWAS Discovery: Large GWAS studies identify thousands of SNPs associated with a disease
- Effect Size Estimation: Each SNP's effect size (β) is estimated from the GWAS
- LD Adjustment: LDpred2 adjusts for linkage disequilibrium between SNPs using Bayesian shrinkage
- Score Computation: PRS = Σ(βᾢ à Gᾢ) for all SNPs in the individual
Clinical Applications of PRS
| Disease | PRS AUC | Top SNPs Used | Clinical Action |
|---|---|---|---|
| Coronary Artery Disease | 0.72 | ~6.6M | Statin eligibility at age 40 |
| Breast Cancer | 0.68 | ~300K | Mammography screening age |
| Type 2 Diabetes | 0.65 | ~1.2M | Lifestyle intervention |
| Alzheimer's Disease | 0.78 | ~800K | Early cognitive screening |
| Schizophrenia | 0.70 | ~100K | Antipsychotic selection |
import numpy as np
class PRSCalculator:
def __init__(self, effect_sizes, ld_matrix=None):
self.effect_sizes = effect_sizes
self.ld_matrix = ld_matrix
def compute_prs(self, genotypes):
"""Compute polygenic risk score."""
if self.ld_matrix is not None:
ld_inv = np.linalg.inv(self.ld_matrix + 0.01 * np.eye(len(self.ld_matrix)))
adjusted_effects = ld_inv @ self.effect_sizes
else:
adjusted_effects = self.effect_sizes
return np.sum(adjusted_effects * genotypes)
def stratify_risk(self, prs_score, population_mean, population_std):
"""Stratify individual into risk categories."""
z_score = (prs_score - population_mean) / population_std
percentile = 0.5 * (1 + np.tanh(0.7 * z_score))
if percentile > 0.95:
return "Very High Risk", percentile, "Immediate specialist referral"
elif percentile > 0.80:
return "High Risk", percentile, "Enhanced screening"
elif percentile > 0.20:
return "Average Risk", percentile, "Population-level screening"
else:
return "Low Risk", percentile, "Standard screening"
# Example: Coronary Artery Disease PRS
np.random.seed(42)
n_snps = 6600000
effect_sizes = np.random.exponential(0.01, n_snps) * np.random.choice([-1, 1], n_snps)
genotypes = np.random.choice([0, 1, 2], n_snps, p=[0.25, 0.50, 0.25])
calculator = PRSCalculator(effect_sizes)
prs_score = calculator.compute_prs(genotypes)
risk_category, percentile, action = calculator.stratify_risk(prs_score, 0, 1)
print(f'PRS Score: {prs_score:.2f}')
print(f'Risk Category: {risk_category}')
print(f'Percentile: {percentile:.1%}')
print(f'Clinical Action: {action}')
SpliceAI: Predicting Splice Variants
What is Splicing?
Splicing removes introns (non-coding regions) from pre-mRNA to create mature mRNA. SpliceAI predicts whether a genetic variant disrupts this process.
SpliceAI Architecture
- Input: 10,000 nucleotides centered on the variant
- Network: 32-layer ResNet with residual connections
- Output: Probability of variant affecting donor or acceptor splice sites
- Accuracy: 0.95 for pathogenicity classification
import torch
import torch.nn as nn
class SpliceAIBlock(nn.Module):
def __init__(self, channels):
super().__init__()
self.conv1 = nn.Conv1d(channels, channels, kernel_size=11, padding=5)
self.bn1 = nn.BatchNorm1d(channels)
self.conv2 = nn.Conv1d(channels, channels, kernel_size=11, padding=5)
self.bn2 = nn.BatchNorm1d(channels)
self.relu = nn.ReLU()
def forward(self, x):
residual = x
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out = self.relu(out + residual)
return out
class SpliceAI(nn.Module):
def __init__(self, input_channels=4, num_classes=3):
super().__init__()
self.input_conv = nn.Conv1d(input_channels, 32, kernel_size=1)
self.blocks = nn.Sequential(*[SpliceAIBlock(32) for _ in range(32)])
self.classifier = nn.Conv1d(32, num_classes, kernel_size=1)
def forward(self, x):
x = self.input_conv(x)
x = self.blocks(x)
return self.classifier(x)
def one_hot_dna(sequence):
mapping = {'A': [1,0,0,0], 'C': [0,1,0,0], 'G': [0,0,1,0], 'T': [0,0,0,1]}
encoded = np.zeros((4, len(sequence)))
for i, base in enumerate(sequence):
if base in mapping:
encoded[:, i] = mapping[base]
return torch.tensor(encoded, dtype=torch.float32).unsqueeze(0)
# Example: SpliceAI prediction
model = SpliceAI(input_channels=4, num_classes=3)
sequence = "ACGTACGTACGT" * 833 # ~10,000 nucleotides
encoded = one_hot_dna(sequence)
output = model(encoded)
prediction = torch.softmax(output, dim=1)
print(f'SpliceAI output shape: {output.shape}')
print(f'Donor site probability: {prediction[0, 0, 5000]:.3f}')
Enformer: Gene Expression Prediction
Enformer is a transformer model that predicts gene expression from DNA sequence. Unlike SpliceAI (which looks at local splice sites), Enformer captures long-range regulatory interactions up to 200kb away.
Why Enformer Matters
- Regulatory variants: Many disease-causing variants don't change protein structure â they alter gene expression
- Long-range effects: Enhancers can be 100kb+ away from the gene they regulate
- Functional annotation: Enformer predictions help prioritize variants for clinical interpretation
Common Clinical Challenges
| Challenge | Problem | Solution |
|---|---|---|
| Variant Interpretation | ~40% of variants are "Variants of Unknown Significance" (VUS) | AI-powered functional prediction (SpliceAI, Enformer) |
| Population Bias | PRS trained on European populations perform poorly in other ancestries | Multi-ancestry GWAS and transfer learning |
| Data Privacy | Genomic data is uniquely identifiable | Federated learning and differential privacy |
| Clinical Actionability | Most PRS effects are small | Combine PRS with clinical risk factors |
Summary
Key Takeaways
- DeepVariant achieves 99.7% accuracy by treating variant calling as image classification
- Polygenic Risk Scores aggregate thousands of small-effect variants into clinically actionable risk predictors
- SpliceAI predicts whether variants disrupt splicing with 0.95 accuracy
- Enformer captures long-range regulatory interactions to predict gene expression from DNA sequence
- Population bias remains a critical challenge â PRS must be validated across diverse ancestries