File size: 7,950 Bytes
7adc41d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | #!/usr/bin/env python3
"""GenomeClip usage examples.
This script demonstrates how to use GenomeClip to encode DNA sequence
embeddings and text embeddings into a shared 512-dim space.
Prerequisites:
pip install torch transformers
Usage:
python example.py
"""
import torch
import torch.nn.functional as F
from transformers import AutoModel
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 1. Load GenomeClip
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MODEL_PATH = "your-username/GenomeClip-v1" # or a local path
model = AutoModel.from_pretrained(MODEL_PATH, trust_remote_code=True)
model.eval()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
print(f"Loaded GenomeClip on {device}")
print(f" seq_input_dim = {model.config.seq_input_dim}")
print(f" text_input_dim = {model.config.text_input_dim}")
print(f" projection_dim = {model.config.projection_dim}")
print(f" seq_pooling = {model.config.seq_pooling}")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 2. Prepare dummy inputs (replace with real embeddings in practice)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# In practice:
# seq_emb = AlphaGenome embeddings_128bp for each gene β (L, 3072)
# text_emb = OpenAI text-embedding-3-large for gene desc β (3072,)
batch_size = 4
seq_lengths_list = [120, 80, 50, 200] # variable token counts per gene
# Simulate per-token sequence embeddings (L2-normalized, as used in training)
max_len = max(seq_lengths_list)
seq_emb = torch.randn(batch_size, max_len, 3072, device=device)
seq_emb = F.normalize(seq_emb, dim=-1) # L2-normalize each token
seq_lengths = torch.tensor(seq_lengths_list, device=device)
# Simulate text embeddings
text_emb = torch.randn(batch_size, 3072, device=device)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 3. Encode sequence embeddings only
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
with torch.no_grad():
seq_repr = model.encode_sequence(seq_emb, seq_lengths)
print("=== Encode sequence only ===")
print(f" Input: seq_emb {tuple(seq_emb.shape)}, seq_lengths {tuple(seq_lengths.shape)}")
print(f" Output: seq_repr {tuple(seq_repr.shape)}")
print(f" Norms: {seq_repr.norm(dim=-1).tolist()} (should be ~1.0)")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 4. Encode text embeddings only
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
with torch.no_grad():
text_repr = model.encode_text(text_emb)
print("=== Encode text only ===")
print(f" Input: text_emb {tuple(text_emb.shape)}")
print(f" Output: text_repr {tuple(text_repr.shape)}")
print(f" Norms: {text_repr.norm(dim=-1).tolist()} (should be ~1.0)")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 5. Cross-modal similarity (cosine, since both are L2-normalized)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
similarity = seq_repr @ text_repr.t() # (B, B)
print("=== Cross-modal similarity matrix ===")
print(f" Shape: {tuple(similarity.shape)}")
for i in range(batch_size):
row = ", ".join(f"{similarity[i, j]:.4f}" for j in range(batch_size))
print(f" seq[{i}] vs text[0..{batch_size-1}]: [{row}]")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 6. Forward with both modalities (computes contrastive loss)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
with torch.no_grad():
out = model(
seq_embeddings=seq_emb,
text_embeddings=text_emb,
seq_lengths=seq_lengths,
)
print("=== Forward with both modalities ===")
print(f" seq_repr: {tuple(out.seq_repr.shape)}")
print(f" text_repr: {tuple(out.text_repr.shape)}")
print(f" loss: {out.loss.item():.4f} (InfoNCE)")
print(f" logits: {tuple(out.logits.shape)}")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 7. Pooled (mean) sequence input β already-pooled (3072,) vectors
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# If you already have gene-level pooled AlphaGenome embeddings (3072,),
# you can pass them directly (2D tensor). The model auto-expands to L=1.
seq_pooled = torch.randn(batch_size, 3072, device=device)
seq_pooled = F.normalize(seq_pooled, dim=-1)
with torch.no_grad():
pooled_repr = model.encode_sequence(seq_pooled) # no seq_lengths needed
print("=== Pooled (2D) sequence input ===")
print(f" Input: seq_pooled {tuple(seq_pooled.shape)}")
print(f" Output: pooled_repr {tuple(pooled_repr.shape)}")
print()
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 8. Cross-modal retrieval example
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
print("=== Cross-modal retrieval ===")
# Simulate a database of 100 gene sequence embeddings
n_genes = 100
db_seq = F.normalize(torch.randn(n_genes, 3072, device=device), dim=-1)
with torch.no_grad():
db_seq_repr = model.encode_sequence(db_seq) # (100, 512)
# Query with a single text embedding
query_text = torch.randn(1, 3072, device=device)
with torch.no_grad():
query_repr = model.encode_text(query_text) # (1, 512)
# Find top-5 most similar genes
scores = (query_repr @ db_seq_repr.t()).squeeze(0) # (100,)
top5_indices = scores.argsort(descending=True)[:5]
print(f" Database: {n_genes} genes")
print(f" Top-5 matching gene indices: {top5_indices.tolist()}")
print(f" Top-5 scores: {scores[top5_indices].tolist()}")
print()
print("Done!")
|