# Proteinstrukturmodellierung

# Hintergrund

Proteine, die von unseren Genen codiert werden, sind die grundlegenden Bausteine des Lebens und zeigen Komplexität und Dynamik. Sie erfüllen eine Vielzahl von Funktionen, wie z.B. das Erkennen von Licht für das Sehen, das Bekämpfen von Viren durch Antikörper und das Antrieb von Bewegungen bei Mikroben und Muskeln. Unser Ziel ist es, die Proteinstruktur zu analysieren, um ihre komplexe Zusammensetzung und Funktionen besser zu verstehen. Dadurch können wir Einblicke in die Feinheiten des Lebens gewinnen und Fortschritte in Bereichen wie Biochemie, Medizin und Biotechnologie erzielen. In dieser Demo nutzen wir speziell Vektorrepräsentationen von modernen Protein-Sprachmodellen mit der MyScale-Datenbank für die Suche nach ähnlichen Proteinen und die Vorhersage von Proteinaktivitäten.

# Wie kann man mit der Demo spielen?

demo

# Methode

Bisher haben sich Protein-Sprachmodelle darauf konzentriert, einzelne Sequenzen für Inferenz zu analysieren. In der traditionellen computergestützten Biologie werden separate Modelle für jede Familie von verwandten Sequenzen verwendet. Unsere Demo nutzt das ESMFold (opens new window)-Modell, um einen Datensatz von 12 Millionen Proteinsequenzen zu kodieren und mithilfe der MyScale-Datenbank Vektorsuche durchzuführen. Dadurch wird es einfach, Aufgaben wie die Suche nach Proteinen und die Vorhersage biologischer Aktivitäten durchzuführen.

# Protein-Encoder

ESMFold ist ein evolutionäres Skalen-Sprachmodell, das die Proteinstruktur vorhersagt, indem es jeder Aminosäure an jeder Position in einem Protein basierend auf ihrem Kontext im Rest der Sequenz eine Wahrscheinlichkeit zuweist. Die Vektorrepräsentation ist eine Schlüsselkomponente von ESMFold, da sie als universelle Codierung für die Proteinsequenz dient. Das Modell verwendet diese Repräsentation, um die kontextuellen Informationen jeder Aminosäure in der Sequenz und die Beziehungen zwischen verschiedenen Aminosäuren zu erfassen. Dadurch kann ESMFold eine Wahrscheinlichkeitsverteilung über die potenziellen Strukturen eines Proteins aus einer einzelnen Eingabesequenz generieren. Durch die Nutzung des Masked Language Modeling-Ziels während des Trainings hat ESMFold gelernt, genauere Vorhersagen zu generieren, was zu einer verbesserten Vorhersageleistung der Proteinstruktur führt.

# Vektorsuche mit MyScale

MyScale kombiniert die Leistung von SQL- und Vektor-Datenbanken, um schnelle Suchen auf Milliarden von Vektoren durchzuführen. Die neuesten Suchalgorithmen beseitigen die Herausforderungen der Suche nach ähnlichen Beispielen und des Hard-Negative-Minings. Hard-Negatives werden in nur Millisekunden gefunden und das Training des Klassifikators ist jetzt nur noch wenige Klicks auf der Webseite entfernt, was Ihnen Zeit spart und die Kosten für Ihre KI-Anwendungen reduziert. Darüber hinaus beschleunigt die verbesserte Datenverwaltung, die durch hybride SQL-Vektorabfragen implementiert wurde, Ihren Forschungs- und Entwicklungsprozess erheblich.

# Anwendung bei der Protein-Suche und Aktivitätsvorhersage

In dieser Demo präsentieren wir zwei Anwendungen: die Suche nach Proteinen und die Vorhersage der Proteinaktivität. Letzteres beinhaltet die Vorhersage der biologischen Auswirkungen von Proteinmutationen mithilfe vordefinierter Einbettungen von ESM. Beide Anwendungen nutzen die Vektorsuche in MyScale.

# Installation der Voraussetzungen

Diese Demo wurde hauptsächlich mit den folgenden Bibliotheken erstellt, unter anderem:

  • transformers: Ausführen des ESMFold-Modells
  • clickhouse-connect: Datenbank-Client
  • streamlit: Python-Webserver zum Ausführen der App

Um die erforderlichen Voraussetzungen zu installieren, verwenden Sie den folgenden Befehl:

python3 -m pip install -r requirement.txt

Sie können die Daten über Fasta-Dateien unter https://github.com/facebookresearch/esm#bulk_fasta (opens new window) herunterladen, indem Sie den folgenden Befehl verwenden:

python esm/scripts/extract.py esm2_t33_650M_UR50D examples/data/some_proteins.fasta \
  examples/data/some_proteins_emb_esm2 --repr_layers 0 32 33 --include mean per_tok

# Erstellen einer Datenbank mit Vektoren

# Überprüfen der Daten

Schauen wir uns die Struktur der Fasta-Dateien an. Die Datei P62593.fasta enthält Proteinsequenz und Aktivität in einer Zeile und sieht so aus:

id>protein name>activity>protein sequence
>0|beta-lactamase_P20P|1.581033423 > MSIQHFRVALIPFFAAFCLPVFAHPETLVKVKDAEDQLGARVGYIELDLNSGKILESFRPEERFPMMSTFKVLLCGAVLSRVDAGQEQLGRRIHYSQNDLVEYSPVTEKHLTDGMTVRELCSAAITMSDNTAANLLLTTIGGPKELTAFLHNMGDHVTRLDRWEPELNEAIPNDERDTTMPAAMATTLRKLLTGELLTLASRQQLIDWMEADKVAGPLLRSALPAGWFIADKSGAGERGSRGIIAALGPDGKPSRIVVIYTTGSQATMDERNRQIAEIGASLIKHW

Basierend auf dem analysierten Datenformat können diese Metainformationen leicht mit pysam abgerufen werden:

from pysam import FastaFile
fasta = "P62593.fasta"
# FASTA-Datei einlesen
sequences_object = FastaFile(fasta)

# Erstellen einer MyScale-Tabelle

Bevor Sie fortfahren, benötigen Sie gültige Anmeldeinformationen, um sich bei unserer Datenbank-Engine anzumelden. Bitte schauen Sie sich die ausführliche Anleitung zum Python-Client auf dieser Seite an, um zu erfahren, wie Sie sich anmelden können.

So sieht die Tabellenstruktur in SQL aus:

CREATE TABLE esm_protein_indexer
( 
    id UInt64,
    activity Float32,
    seq String, 
    representations Array(Float32),
    CONSTRAINT representations CHECK length(vector) = 768
) 

# Extrahieren von Merkmalen und Befüllen der Datenbank

Das ESM-Modell verfügt über eine Zero-Shot-Fähigkeit und zeichnet sich durch die Extraktion semantischer Merkmale aus Proteinsequenzen aus. Es bietet sowohl die Extraktion von Merkmalen für einzelne Proteine als auch die Stapelverarbeitungsmethoden. Der Implementierungscode sieht wie folgt aus.

import torch
import esm
# Load ESM-2 model
model, alphabet = esm.pretrained.esm2_t33_650M_UR50D()
batch_converter = alphabet.get_batch_converter()model.eval()  # disables dropout for deterministic results
# Prepare data (first 2 sequences from ESMStructuralSplitDataset superfamily / 4)
data = [
    ("protein1", "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"),
    ("protein2", "KALTARQQEVFDLIRDHISQTGMPPTRAEIAQRLGFRSPNAAEEHLKALARKGVIEIVSGASRGIRLLQEE"),
    ("protein2 with mask","KALTARQQEVFDLIRD<mask>ISQTGMPPTRAEIAQRLGFRSPNAAEEHLKALARKGVIEIVSGASRGIRLLQEE"),
    ("protein3",  "K A <mask> I S Q"),
]
batch_labels, batch_strs, batch_tokens = batch_converter(data)
batch_lens = (batch_tokens != alphabet.padding_idx).sum(1)
# Extract per-residue representations (on CPU)
with torch.no_grad():
    results = model(batch_tokens, repr_layers=[33], return_contacts=True)
    token_representations = results["representations"][33]

Sie können auch Einbettungen in Stapelverarbeitung aus einer FASTA-Datei extrahieren.

python scripts/extract.py esm2_t33_650M_UR50D examples/data/some_proteins.fasta \
  examples/data/some_proteins_emb_esm2 --repr_layers 0 32 33 --include mean per_tok

Wir haben bereits eine Zero-Shot-Learning-Pipeline mit dem Proteinsequenzmerkmal als Klassifikator erstellt. Jetzt sind wir ziemlich nah dran, die Tabelle zu erstellen. Es fehlt nur noch ein Puzzlestück: das Einfügen von Daten in MyScale. So sieht es aus:

# Sie müssen den Merkmalsvektor in Python-Listen umwandeln
fields = ['id', 'seq','representations','activity']
# den Vektor einfach wie normales SQL einfügen
client.insert("esm_protein_indexer_768", data, column_names=fields)

Für detaillierte Informationen zur Verwendung der INSERT-Klausel können Sie die offizielle Dokumentation konsultieren.

# Protein-Suche

Um mithilfe der Protein-Einbettungen, die aus dem ESM-Modell gewonnen wurden, zu suchen, extrahieren wir die Einbettung der Suchsequenz und verwenden SQL, um die Einbettungen der fünf nächstgelegenen Proteinsequenzen in MyScale zu lokalisieren. Das Ergebnis wird dann zurückgegeben.

def esm_search(client, model, sequnce, batch_converter, top_k=5):
    data = [("protein1", sequnce)]
    batch_labels, batch_strs, batch_tokens = batch_converter(data)
    with torch.no_grad():
        results = model(batch_tokens, repr_layers=[33], return_contacts=True)
    token_representations = results["representations"][33]
    token_list = token_representations.tolist()[0][0][0]
    query = f"SELECT activity, distance(representations, {token_list}) as dist "
    query += "FROM default.esm_protein_indexer_768"
    query += f" ORDER BY dist LIMIT {top_k}"
    result = client.query(query).named_results()
    result_temp_coords = [i['coords'] for i in result]
    result_temp_seq = [i['seq'] for i in result]
    return result_temp_coords, result_temp_seq

# KNN für Aktivitätsvorhersage

Die KNN-Methode sagt die aktuelle Aktivität des Proteins voraus, indem sie den Durchschnitt der Aktivitäten der 10 nächsten Nachbarn verwendet. Dieser Ansatz erfordert kein zusätzliches Training und Feinabstimmung und hat eine relativ hohe Genauigkeit.

Die Daten in MyScale enthalten:

  • die mutierte ß-Lactamase-Sequenz, bei der eine einzelne Aminosäure mutiert ist (ausgetauscht mit einer anderen Aminosäure)
  • den Zielwert im letzten Feld des Headers, der die skalierte Wirkung der Mutation beschreibt

So sieht die Funktion aus:

def knn_search(client, sequence):
    model, alphabet = esm.pretrained.esm2_t33_650M_UR50D()
    batch_converter = alphabet.get_batch_converter()
    model.eval()
    data = [("protein1", sequence)]
    batch_labels, batch_strs, batch_tokens = batch_converter(data)
    batch_lens = (batch_tokens != alphabet.padding_idx).sum(1)
    with torch.no_grad():
        results = model(batch_tokens, repr_layers=[33], return_contacts=True)
    token_representations = results["representations"][33]
    token_list = token_representations.tolist()[0][0]
    result = client.query(f"SELECT activity, distance(representations, {token_list}) as dist FROM default.esm_protein_indexer ORDER BY dist LIMIT 10").named_results()
    activity_sum = sum(i['activity'] for i in result)
    avg_activity = activity_sum / len(result)
    return avg_activity

# Am Ende

Referenzen:

  1. Evolutionary Scale Modeling: https://github.com/facebookresearch/esm (opens new window)
  2. KNN: https://towardsdatascience.com/machine-learning-basics-with-the-k-nearest-neighbors-algorithm-6a6e71d01761 (opens new window)