Unimol Feinabstimmung: Praktischer Leitfaden für ein besseres molekulares Verständnis
Als ML-Ingenieur habe ich aus erster Hand die Kraft vortrainierter Modelle erlebt. In der Medikamentenforschung und Materialwissenschaft ist das molekulare Modellieren entscheidend. Unimol, ein leistungsstarkes vortrainiertes Modell zur molekularen Repräsentation, bietet einen erheblichen Fortschritt. Allerdings wird sein tatsächliches Potenzial durch Feinabstimmung freigesetzt. Dieser Artikel bietet einen praktischen, umsetzbaren Leitfaden zur Feinabstimmung von Unimol, der Ihnen hilft, diese Technologie für Ihre spezifischen molekularen Aufgaben zu nutzen.
Was ist Unimol und warum es feinabstimmen?
Unimol steht für UNIversale MOLecular Repräsentation. Es handelt sich um ein Deep-Learning-Modell, das auf einem riesigen Datensatz von molekularen Strukturen und Eigenschaften trainiert wurde. Diese Vortrainierung ermöglicht es Unimol, generierbare Merkmale und Beziehungen innerhalb von Molekülen zu lernen, was es hervorragend macht, chemische Intuition zu erfassen.
Während die vortrainierten Gewichte von Unimol gut sind, sind sie allgemein. Ihre spezifische Aufgabe – die Vorhersage von Bindungsaffinitäten, Löslichkeit oder Reaktionsverläufen – hat einzigartige Nuancen. Die Feinabstimmung passt diese allgemeinen Unimol-Repräsentationen an Ihr spezielles Fachgebiet und Datensatz an. Dieser Prozess verfeinert das Verständnis des Modells und führt zu deutlich verbesserten Vorhersageleistungen im Vergleich zur Verwendung von Unimol als festem Merkmals-Extractor oder zum Training eines Modells von Grund auf. Die Feinabstimmung von Unimol dreht sich um Spezialisierung.
Voraussetzungen für die Feinabstimmung von Unimol
Bevor Sie den Code erkunden, stellen Sie sicher, dass Sie Folgendes haben:
* **Eine klar definierte Aufgabe:** Was genau versuchen Sie vorherzusagen oder zu klassifizieren? Klare Ziele sind entscheidend.
* **Einen qualitativ hochwertigen Datensatz:** Dies ist von größter Bedeutung. Ihr Datensatz sollte relevant für Ihre Aufgabe, sauber und ausreichend groß sein. Für molekulare Aufgaben bedeutet dies SMILES-Strings, molekulare Graphen oder 3D-Koordinaten sowie die entsprechenden Zielwerte (z. B. experimentelle Messungen, Labels).
* **Rechnerische Ressourcen:** Die Feinabstimmung großer Modelle wie Unimol erfordert GPUs. Die spezifischen Anforderungen hängen von der Größe Ihres Datensatzes und der Modellarchitektur ab, aber rechnen Sie damit, mindestens eine moderne GPU (z. B. NVIDIA V100, A100) zu benötigen.
* **Vertrautheit mit Deep-Learning-Frameworks:** PyTorch wird häufig für Unimol verwendet. Grundkenntnisse im Datenladen, in der Modellerstellung und in Trainingsschleifen sind hilfreich.
* **Unimol-Bibliothek:** Sie müssen die Unimol-Bibliothek und ihre Abhängigkeiten installieren. Dies umfasst typischerweise `pip install unimol`.
Vorbereitung Ihrer molekularen Daten für die Feinabstimmung
Die Datenvorbereitung ist oft der zeitaufwändigste Teil eines jeden Machine-Learning-Projekts. Bei der Feinabstimmung von Unimol umfasst es mehrere Schritte:
1. Datensammlung und -bereinigung
Holen Sie sich Ihre experimentellen oder simulierten Daten. Stellen Sie Konsistenz in den Einheiten sicher, entfernen Sie Ausreißer und gehen Sie angemessen mit fehlenden Werten um. Validieren Sie für molekulare Strukturen SMILES-Strings oder stellen Sie sicher, dass die 3D-Koordinaten chemisch sinnvoll sind.
2. Molekulare Repräsentation
Unimol verwendet hauptsächlich 3D-molekulare Graphen-Repräsentationen. Während Sie oft 3D-Koordinaten aus SMILES generieren können, ist es allgemein besser, qualitativ hochwertige experimentelle oder optimierte 3D-Strukturen (z. B. von PDB, PubChem 3D) zu verwenden. Die Unimol-Bibliothek bietet Hilfsfunktionen, um verschiedene molekulare Formate in ihre interne Repräsentation zu konvertieren.
* **SMILES zu 3D:** Verwenden Sie RDKit oder ähnliche Bibliotheken, um Konformer zu generieren. Optimieren Sie dann diese Konformer mit einem Kraftfeld (z. B. MMFF94, UFF) für stabilere Strukturen.
* **Umgang mit mehreren Konformern:** Bei flexiblen Molekülen haben Sie möglicherweise mehrere energiearme Konformer. Entscheiden Sie, ob Sie einen einzigen repräsentativen Konformer (z. B. niedrigste Energie) verwenden oder Informationen aus mehreren Konformern einbeziehen möchten (z. B. durch das Mittelwerten von Vorhersagen oder die Verwendung eines Konformer-Ensembles).
3. Datensatzaufteilung
Teilen Sie Ihre Daten in Trainings-, Validierungs- und Testmengen auf. Eine gängige Aufteilung ist 80/10/10 oder 70/15/15. Stellen Sie sicher, dass Ihre Aufteilungen repräsentativ für die gesamte Datenverteilung sind. Für molekulare Daten sollten Sie stratifizierte Aufteilungen in Betracht ziehen, wenn Sie unausgewogene Klassen oder Eigenschaften haben. Auch das Scaffold-Splitting kann wichtig sein, um sicherzustellen, dass das Modell auf neuen chemischen Raum verallgemeinert, nicht nur auf neue Beispiele bestehender Scaffolds.
4. Erstellen eines PyTorch-Datensatzes und DataLoader
Die Unimol-Bibliothek erwartet Daten in einem bestimmten Format. Sie erstellen typischerweise einen benutzerdefinierten PyTorch `Dataset`, der Ihre molekularen Strukturen und Zielwerte lädt. Die Methode `__getitem__` Ihres Datensatzes sollte die molekularen Graphdaten (häufig als ein Dictionary mit Knoteneigenschaften, Kantenmerkmalen und Adjazenzinformationen) und das entsprechende Label/Wert zurückgeben.
“`python
import torch
from torch.utils.data import Dataset, DataLoader
from unimol.data import MoleculeDataset # Beispiel, tatsächliche Klasse kann variieren
from rdkit import Chem
from rdkit.Chem import AllChem
class CustomMolDataset(Dataset):
def __init__(self, smiles_list, targets_list):
self.smiles_list = smiles_list
self.targets_list = targets_list
def __len__(self):
return len(self.smiles_list)
def __getitem__(self, idx):
smiles = self.smiles_list[idx]
target = self.targets_list[idx]
# Generieren von 3D-Koordinaten (vereinfacht zur Veranschaulichung)
mol = Chem.MolFromSmiles(smiles)
if mol:
mol = Chem.AddHs(mol)
AllChem.EmbedMolecule(mol, AllChem.ETKDG())
AllChem.MMFFOptimizeMolecule(mol)
# Konvertieren RDKit mol in Unimols erwartetes Graphformat
# Dieser Teil hängt stark von den spezifischen Hilfsfunktionen der Unimol-Bibliothek ab.
# Es umfasst normalerweise das Extrahieren von Atommerkmalen, Bindungsmerkmalen und 3D-Koordinaten.
unimol_graph_data = self._mol_to_unimol_format(mol) # Platzhalterfunktion
return unimol_graph_data, torch.tensor(target, dtype=torch.float)
def _mol_to_unimol_format(self, mol):
# Platzhalter: Implementieren Sie die tatsächliche Konvertierung mit unimol.data-Hilfsfunktionen
# Dies wird das Extrahieren von Knoteneigenschaften (Atomtypen, Ladungen),
# Kantenmerkmalen (Bindungstypen) und 3D-Koordinaten beinhalten.
# unimol.data.data_utils.get_graph_from_mol ist ein wahrscheinlicher Kandidat.
return {“coords”: torch.rand(mol.GetNumAtoms(), 3), # Beispiel
“atom_features”: torch.rand(mol.GetNumAtoms(), 10), # Beispiel
“bond_features”: torch.rand(mol.GetNumBonds(), 5), # Beispiel
“edges”: torch.randint(0, mol.GetNumAtoms(), (mol.GetNumBonds(), 2))} # Beispiel
# Beispielverwendung (ersetzen Sie dies durch Ihre tatsächlichen Daten)
smiles_data = [“CCO”, “CC(=O)O”, “c1ccccc1”]
target_data = [1.2, 3.4, 5.6]
train_dataset = CustomMolDataset(smiles_data, target_data)
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
# Sie benötigen auch eine collate_fn für die Batch-Verarbeitung unterschiedlich großer Graphen.
# Die Unimol-Bibliothek bietet normalerweise eine Standard-collate_fn oder erwartet ein bestimmtes Eingabeformat.
“`
Einrichten des Unimol-Modells zur Feinabstimmung
Der Kern der Feinabstimmung von Unimol besteht darin, das vortrainierte Unimol-Modell zu laden und einen neuen „Kopf“ anzubringen, der für Ihre Aufgabe geeignet ist.
1. Laden des vortrainierten Unimol-Encoders
Die Unimol-Bibliothek bietet Funktionen zum Laden der vortrainierten Gewichte. Diese Gewichte repräsentieren den molekularen Encoder.
“`python
from unimol.models import UnimolModel
from unimol.config import UnimolConfig # Oder ähnliches Konfigurationsobjekt
# Vortrainierte Konfiguration laden (Pfad bei Bedarf anpassen)
config = UnimolConfig.from_pretrained(“path/to/unimol_base_config.json”)
# Vortrainiertes Unimol-Modell laden
# Möglicherweise müssen Sie den Pfad zu den tatsächlichen vortrainierten Gewichten (.pt oder .bin-Datei) angeben
unimol_encoder = UnimolModel.from_pretrained(
“path/to/unimol_base_weights.pt”, # Beispielpfad
config=config
)
unimol_encoder.eval() # In den Evaluierungsmodus setzen, wenn die Encoder-Schichten nicht zunächst trainiert werden
“`
2. Anbringen eines aufgaben-spezifischen Kopfs
Die Ausgabe des Unimol-Encoders ist eine molekulare Repräsentation (z. B. ein fester Vektor oder Knoteneinbettungen). Sie müssen ein kleines neuronales Netzwerk auf dieser Repräsentation hinzufügen, um Ihre spezifische Vorhersage durchzuführen.
* **Regression:** Zur Vorhersage kontinuierlicher Werte (z. B. Bindungsaffinität) ist eine einfache lineare Schicht oder ein kleines MLP (Mehrschicht-Perzeptron) üblich.
* **Klassifikation:** Zur Vorhersage diskreter Klassen (z. B. aktiv/inaktiv) verwenden Sie eine lineare Schicht gefolgt von einer Sigmoid- (für binär) oder Softmax-Aktivierung (für Mehrklassen).
“`python
import torch.nn as nn
class UnimolFineTuneModel(nn.Module):
def __init__(self, unimol_encoder, num_output_features, task_type=”regression”):
super().__init__()
self.unimol_encoder = unimol_encoder
self.task_type = task_type
# Die Ausgabedimension des Unimol-Encoders hängt von seiner Konfiguration ab.
# Es wird oft als `hidden_size` oder `embedding_dim` bezeichnet.
encoder_output_dim = self.unimol_encoder.args.encoder_embed_dim # Beispielzugriff
if task_type == “regression”:
self.prediction_head = nn.Sequential(
nn.Linear(encoder_output_dim, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, num_output_features) # num_output_features ist 1 für die Regression eines einzelnen Wertes
)
elif task_type == “classification”:
self.prediction_head = nn.Sequential(
nn.Linear(encoder_output_dim, 256),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(256, num_output_features) # num_output_features ist die Anzahl der Klassen
)
else:
raise ValueError(“Nicht unterstützter Aufgabentyp”)
def forward(self, unimol_graph_data):
# Der Unimol-Encoder gibt typischerweise ein Dictionary zurück. Wir benötigen die gepoolte Darstellung.
# Der genaue Schlüssel für die gepoolte Darstellung kann variieren (z.B. ‘mol_embedding’, ‘graph_embedding’).
encoder_output = self.unimol_encoder(
coords=unimol_graph_data[“coords”],
atom_features=unimol_graph_data[“atom_features”],
bond_features=unimol_graph_data[“bond_features”],
edges=unimol_graph_data[“edges”]
# Fügen Sie andere erforderliche Eingaben gemäß der Vorwärtsmethode von UnimolModel hinzu
)
# Vorausgesetzt, ‘mol_embedding’ ist die gepoolte Darstellung für das gesamte Molekül
pooled_representation = encoder_output[‘mol_embedding’]
prediction = self.prediction_head(pooled_representation)
return prediction
# Instanziieren Sie das feinabgestimmte Modell
fine_tuned_model = UnimolFineTuneModel(unimol_encoder, num_output_features=1, task_type=”regression”)
“`
Der Unimol-Fine-Tuning-Prozess
Jetzt kombinieren Sie Ihre Daten und das Modell für das Training.
1. Verlustfunktion und Optimierer definieren
* **Regression:** Mittlerer quadratischer Fehler (MSE) oder mittlerer absoluter Fehler (MAE) sind gängig.
* **Klassifizierung:** Binäre Kreuzentropie (BCE) für die binäre Klassifizierung, Kreuzentropie für Mehrklassen.
* **Optimierer:** AdamW ist ein guter Standard, oft mit einem Lernratenplaner.
“`python
optimizer = torch.optim.AdamW(fine_tuned_model.parameters(), lr=1e-5) # Beginnen Sie mit einer niedrigen Lernrate
criterion = nn.MSELoss() # Für Regression
“`
2. Schichten einfrieren (optional, aber empfohlen)
Anfänglich ist es oft vorteilhaft, die vorab trainierten Unimol-Encoder-Schichten einzufrieren und nur den neu hinzugefügten Vorhersagekopf zu trainieren. Dies verhindert, dass große Gradientenaktualisierungen die wertvollen vorab trainierten Gewichte korrumpieren. Nach einigen Epochen können Sie einige oder alle Encoder-Schichten wieder auftauen und mit einer sehr niedrigen Lernrate trainieren.
“`python
# Um die parametrischen unmol_encoder zu frieren
for param in fine_tuned_model.unimol_encoder.parameters():
param.requires_grad = False
# Nur Parameter in prediction_head werden aktualisiert
# Sie würden später auftauen:
# for param in fine_tuned_model.unimol_encoder.parameters():
# param.requires_grad = True
“`
3. Trainingsschleife
Die Trainingsschleife folgt den gängigen PyTorch-Praktiken. Iterieren Sie durch Epochen, verarbeiten Sie Batches, berechnen Sie den Verlust, propagieren Sie zurück und aktualisieren Sie die Gewichte.
“`python
device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)
fine_tuned_model.to(device)
num_epochs = 10
for epoch in range(num_epochs):
fine_tuned_model.train()
total_loss = 0
for batch_idx, (unimol_graph_data_batch, targets_batch) in enumerate(train_loader):
# Daten zum Gerät verschieben
# unimol_graph_data_batch muss verarbeitet werden, um seine Tensoren zum Gerät zu verschieben
# Beispiel: batch_coords = unimol_graph_data_batch[“coords”].to(device)
# batch_atom_features = unimol_graph_data_batch[“atom_features”].to(device)
# …
# Dies erfordert eine geeignete collate_fn in Ihrem DataLoader.
# Vereinfacht zur Illustration, vorausgesetzt unimol_graph_data_batch wurde bereits verschoben
# oder behandeln Sie das Verschieben innerhalb der Schleife für jeden Tensor im Dictionary.
# Verschieben Sie individuelle Tensoren innerhalb des Dictionaries zum Gerät
processed_graph_data = {k: v.to(device) for k, v in unimol_graph_data_batch.items()}
targets_batch = targets_batch.to(device)
optimizer.zero_grad()
predictions = fine_tuned_model(processed_graph_data)
loss = criterion(predictions.squeeze(), targets_batch) # .squeeze() für Einzelwertregression
loss.backward()
optimizer.step()
total_loss += loss.item()
avg_train_loss = total_loss / len(train_loader)
print(f”Epoch {epoch+1}, Train Loss: {avg_train_loss:.4f}”)
# Validierungsschritt (ähnlich implementieren)
fine_tuned_model.eval()
val_loss = 0
with torch.no_grad():
for batch_idx, (unimol_graph_data_batch, targets_batch) in enumerate(val_loader):
# Daten zum Gerät verschieben
processed_graph_data = {k: v.to(device) for k, v in unimol_graph_data_batch.items()}
targets_batch = targets_batch.to(device)
predictions = fine_tuned_model(processed_graph_data)
loss = criterion(predictions.squeeze(), targets_batch)
val_loss += loss.item()
avg_val_loss = val_loss / len(val_loader)
print(f”Epoch {epoch+1}, Val Loss: {avg_val_loss:.4f}”)
# Bestes Modell basierend auf Validierungsverlust speichern
# …
“`
4. Hyperparameteroptimierung
* **Lernrate:** Entscheidend. Experimentieren Sie mit Werten wie 1e-4, 5e-5, 1e-5, 5e-6. Ein Lernratenplaner (z.B. Cosinus-Abkühlung, ReduceLROnPlateau) ist oft hilfreich.
* **Batch-Größe:** Eingeschränkt durch den GPU-Speicher. Größere Batch-Größen können stabilere Gradienten liefern, erfordern jedoch mehr Speicher.
* **Anzahl der Epochen:** Überwachen Sie den Validierungsverlust, um Überanpassung zu vermeiden. Early Stopping ist wichtig.
* **Dropout:** Wenden Sie Dropout im Vorhersagekopf an, um zu regularisieren.
* **Gewichtsverfall:** Fügen Sie L2-Regularisierung zum Optimierer hinzu.
Bewertung und Bereitstellung
Nach dem Unimol-Fine-Tuning bewerten Sie Ihr Modell anhand des ungesehenen Testdatensatzes mit geeigneten Metriken:
* **Regression:** R-Quadrat, MAE, RMSE.
* **Klassifizierung:** Genauigkeit, Präzision, Rückruf, F1-Score, ROC-AUC.
Sobald Sie mit der Leistung zufrieden sind, speichern Sie Ihr fein abgestimmtes Modell. Für die Bereitstellung können Sie das gespeicherte Modell laden und es für die Inferenz neuer Molekulardaten verwenden.
“`python
# Modell speichern
torch.save(fine_tuned_model.state_dict(), “fine_tuned_unimol_model.pt”)
# Für die Inferenz laden
loaded_model = UnimolFineTuneModel(unimol_encoder, num_output_features=1, task_type=”regression”)
loaded_model.load_state_dict(torch.load(“fine_tuned_unimol_model.pt”))
loaded_model.to(device)
loaded_model.eval()
# Beispielinferenz
with torch.no_grad():
sample_mol_data = … # Bereiten Sie neue Molekulardaten vor
processed_sample_mol_data = {k: v.to(device) for k, v in sample_mol_data.items()}
prediction = loaded_model(processed_sample_mol_data)
print(“Vorhersage:”, prediction.item())
“`
Tipps für erfolgreiches Unimol-Fine-Tuning
* **Einfach anfangen:** Beginnen Sie mit einer niedrigen Lernrate und einem eingefrorenen Encoder. Tauchen Sie schrittweise Schichten auf und erhöhen Sie die Lernrate, wenn sich das Modell stabilisiert.
* **Metriken überwachen:** Achten Sie aufmerksam auf sowohl den Trainings- als auch den Validierungsverlust/-metriken. Achten Sie auf Anzeichen von Überanpassung (Trainingsverlust sinkt, Validierungsverlust steigt).
* **Datenaugumentation:** Für Molekulardaten kann dies die Generierung verschiedener Konformer, das Drehen von Molekülen oder das Anwenden kleiner Störungen umfassen. Dies hilft dem Modell, solidere Darstellungen zu lernen.
* **Transfer-Learning-Strategien:**
* **Merkmalsextraktion:** Verwenden Sie Unimol, um Einbettungen zu erzeugen, und trainieren Sie dann ein separates einfacheres Modell (z.B. SVM, XGBoost) auf diesen Einbettungen. Dies ist oft eine gute Basislinie.
* **Volles Fine-Tuning:** Trainieren Sie das gesamte Unimol-Modell (Encoder + Kopf) mit einer sehr niedrigen Lernrate. Dies bietet das höchste Potenzial für Leistung, erfordert jedoch mehr Rechenressourcen und sorgfältige Anpassung.
* **Schichtweises Fine-Tuning:** Tauchen Sie zuerst äußere Schichten auf und trainieren Sie dann schrittweise innere Schichten.
* **Mit Architekturen experimentieren:** Während ein einfacher linearer Kopf ein guter Ausgangspunkt ist, experimentieren Sie mit leicht komplexeren MLPs für den Vorhersagekopf.
* **Verwenden Sie Unimols Dienstprogramme:** Die Unimol-Bibliothek bietet verschiedene Werkzeuge zur Datenverarbeitung, Graphenkonstruktion und Modellladung. Machen Sie sich mit der API vertraut, um Ihren Workflow zu optimieren.
* **Vorberechnung:** Wenn die Generierung von 3D-Konformern langsam ist, sollten Sie in Betracht ziehen, sie vorab zu generieren und auf der Festplatte zu speichern, bevor Sie mit dem Training beginnen.
Das Unimol-Fine-Tuning ist ein leistungsstarker Ansatz zur Anpassung modernster molekularer Darstellungen an Ihre spezifischen Aufgaben. Indem Sie diese praktischen Schritte befolgen, können Sie bessere prädiktive Modelle in der Arzneimittelentdeckung, Materialwissenschaft und anderen molekularen Bereichen erreichen.
FAQ zum Unimol-Fine-Tuning
**Q1: Wie viele Daten benötige ich für das Unimol-Fine-Tuning?**
A1: Je mehr, desto besser. Während das Vortraining von Unimol bei Datenmangel hilft, profitiert das Fine-Tuning immer noch erheblich von größeren, vielfältigen Datensätzen. Für Regressionsaufgaben sind Hunderte bis Tausende von Datenpunkten oft ein guter Ausgangspunkt. Für Klassifikation, insbesondere mit mehreren Klassen, sind in der Regel mehr Daten erforderlich, um verschiedene Entscheidungsgrenzen zu lernen. Wenn Ihr Datensatz sehr klein ist (zehn von Proben), sollten Sie in Betracht ziehen, Unimol als festen Merkmals-Extraktor zu verwenden, anstatt das gesamte Modell fein abzustimmen.
**Q2: Was ist der Unterschied zwischen der Verwendung von Unimol als Merkmals-Extraktor und vollem Fine-Tuning?**
A2: Als Merkmals-Extraktor verwenden Sie das vorab trainierte Unimol-Modell, um molekulare Einbettungen (festgrößte Vektoren) für Ihre Moleküle zu erzeugen. Sie trainieren dann ein separates, einfacheres Modell (wie eine lineare Regression, SVM oder ein kleines MLP) auf diesen Einbettungen. Die Unimol-Gewichte bleiben fixiert. Beim vollständigen Fine-Tuning laden Sie das vorab trainierte Unimol-Modell und trainieren dann dessen Schichten weiter (neben einem neuen aufgabenspezifischen Kopf) auf Ihrem Datensatz. Vollständiges Fine-Tuning führt in der Regel zu besseren Ergebnissen, wenn Sie über genügend Daten und Rechenressourcen verfügen, da es die internen Darstellungen von Unimol an Ihre spezifische Aufgabe anpasst.
**Q3: Wie gehe ich mit 3D-Molekülstrukturen für Unimol um?**
A3: Unimol ist darauf ausgelegt, 3D-Molekülgrafik-Informationen zu verwenden. Wenn Sie nur SMILES-Strings haben, müssen Sie 3D-Konformer erzeugen. Tools wie RDKit können dies tun (z.B. `Chem.AllChem.EmbedMolecule`). Es wird empfohlen, diese Konformer dann mit einem Kraftfeld zu optimieren (z.B. `AllChem.MMFFOptimizeMolecule`), um chemisch plausiblere Strukturen zu erhalten. Für kritische Aufgaben ist es vorzuziehen, experimentell bestimmte 3D-Strukturen (aus Datenbanken wie PDB) oder hochrangig quantenchemisch optimierte Strukturen zu verwenden. Die Unimol-Bibliothek verwendet dann diese 3D-Koordinaten sowie Atom- und Bindungsmerkmale, um ihre interne grafische Darstellung zu erstellen.
🕒 Published: