Edycja 2026. Praktyczny kurs, który przeprowadzi programistów Python od podstawowych koncepcji chemicznych do projektowania systemów cheminformatycznych opartych na sztucznej inteligencji. Dowiedz się, jak używać RDKit, scikit-fingerprints oraz najnowocześniejszych technik głębokiego uczenia, takich jak Graph Neural Networks i Diffusion Models, do odkrywania nowych leków.
Obliczenia naukoweChemoinformatykaDeep Learning w nauce
Wprowadzamy RDKit i podstawową koncepcję reprezentacji chemii w języku Python. Słuchacze dowiedzą się, jak inicjować obiekty molekularne z ciągów znaków i zrozumieją kluczową rolę tego frameworka w odkrywaniu leków za pomocą sztucznej inteligencji.
3m 18s
2
Operacje I/O w cheminformatyce
Dowiedz się, jak bezpiecznie wczytywać i eksportować ogromne zbiory danych chemicznych. Omawiamy odczytywanie plików SDF i SMILES, obsługę błędów parsowania oraz zapisywanie danych z powrotem na dysk.
3m 52s
3
Przeszukiwanie grafów molekularnych
Odkryj, jak cząsteczki są reprezentowane jako struktury danych w postaci grafów. Badamy iterowanie po atomach, analizowanie wiązań i identyfikowanie układów pierścieniowych w cząsteczkach.
3m 34s
4
Wyszukiwanie podstruktur
Opanuj sztukę odpytywania cząsteczek za pomocą SMARTS. Krok po kroku pokazujemy, jak znajdować określone grupy funkcyjne i wzorce w złożonych strukturach chemicznych.
4m 27s
5
Generowanie fingerprintów i podobieństwo molekularne
Sprawdź, jak tłumaczyć grafy molekularne na matematyczne wektory bitowe. Omawiamy klucze MACCS, Morgan fingerprints oraz obliczanie podobieństwa Tanimoto.
4m 33s
6
Przełamywanie płaszczyzny 2D
Przejdź od płaskich rysunków 2D do realistycznych geometrii 3D. Omawiamy dodawanie jawnych atomów wodoru i generowanie wiarygodnych konformerów 3D przy użyciu ETKDG.
4m 42s
7
Przyspieszanie inżynierii cech
Połącz cheminformatykę ze standardowym data science za pomocą scikit-fingerprints. Badamy generowanie ponad 30 typów fingerprintów molekularnych bezpośrednio w interfejsie scikit-learn.
4m 17s
8
Wydajna cheminformatyka
Dowiedz się, jak wydajnie przetwarzać ogromne zbiory danych chemicznych. Zagłębiamy się w wykorzystanie zrównoleglenia CPU za pomocą Joblib oraz oszczędzanie pamięci przy użyciu macierzy rzadkich z biblioteki SciPy.
4m 22s
9
Potoki ML End-to-End
Połącz przetwarzanie, generowanie fingerprintów i predykcję w jedną, przejrzystą architekturę. Budujemy solidne potoki scikit-learn, które płynnie integrują generowanie konformerów 3D i przewidywanie właściwości.
4m 03s
10
Przewidywanie powinowactwa wiązania
Poznaj realia przewidywania powinowactwa wiązania białko-ligand. Porównujemy wydajność prostych modeli drzewiastych 2D ze złożonymi 3D Graph Neural Networks.
4m 24s
11
LLM kontra klasyczne fingerprinty
Odkryj, jak Natural Language Processing znajduje zastosowanie w chemii. Zestawiamy osadzenia wektorowe z Large Language Models z klasycznymi strukturalnymi fingerprintami RDKit w celu przewidywania bioaktywności.
4m 27s
12
Active Learning w wirtualnym badaniu przesiewowym
Dowiedz się, jak iteracyjnie odkrywać najlepszych kandydatów na leki bez wyczerpującego testowania. Zagłębiamy się w pętle Active Learning i strategie zachłannej selekcji, aby zmaksymalizować wskaźnik trafień.
4m 20s
13
Wyzwanie klifów aktywności
Zbadaj kruchość relacji struktura-aktywność. Omawiamy „klify aktywności” – sytuacje, w których drobna zmiana strukturalna powoduje ogromną zmianę w sile działania leku.
4m 06s
14
Similarity-Quantized Relative Learning
Rozwiąż problem klifów aktywności, zmieniając sposób uczenia się modeli. Badamy framework SQRL, który trenuje sztuczną inteligencję do przewidywania względnych różnic we właściwościach między ściśle filtrowanymi parami molekularnymi.
3m 41s
15
Rewolucja Generative AI
Przejdź od przewidywania właściwości do wyobrażania sobie zupełnie nowych cząsteczek. Mapujemy krajobraz molekularnych zadań generatywnych: generowanie De Novo, optymalizacja i generowanie konformerów.
3m 47s
16
Intuicja stojąca za dyfuzją molekularną
Rozkładamy na czynniki pierwsze podstawową koncepcję Diffusion Models bez skomplikowanej matematyki. Słuchacze zrozumieją proces w przód (dodawanie szumu do cząsteczki) oraz proces odwrotny (halucynowanie nowych struktur).
4m 19s
17
Łączenie przestrzeni generatywnych 2D i 3D
Badamy, jak sztuczna inteligencja w rzeczywistości reprezentuje generowane przez siebie cząsteczki. Porównujemy generowanie płaskich grafów topologicznych 2D z generowaniem złożonych geometrycznych chmur punktów 3D oraz wyzwania związane z każdym z tych podejść.
4m 22s
18
Generowanie uwzględniające cel i dokowanie
Odkryj projektowanie generatywne uwzględniające kontekst. Omawiamy generowanie nowych cząsteczek bezpośrednio wewnątrz kieszeni wiążącej białka chorobowego, aby zmaksymalizować powinowactwo wiązania.
2m 07s
19
Pułapka rozmiaru w ewaluacji generatywnej
Dowiedz się, dlaczego standardowe benchmarki dla modeli generatywnych mogą być głęboko wadliwe. Ujawniamy zakłócający wpływ rozmiaru wygenerowanej biblioteki na metryki takie jak Fréchet ChemNet Distance.
4m 12s
20
Nawigowanie po halucynacjach De Novo
Inteligentnie oceniaj cząsteczki wygenerowane przez AI. Badamy kompromis między eksploracją a eksploatacją (exploration-exploitation tradeoff) w prawdopodobieństwach modelu oraz sposoby filtrowania częstych, niskiej jakości „chemicznych halucynacji”.
4m 10s
21
Ograniczenia próbkowania cząsteczek
Zrozum, dlaczego techniki NLP zawodzą w chemii. Porównujemy Temperature sampling z Top-k i Top-p oraz wyjaśniamy, dlaczego ograniczone słownictwo chemiczne zmienia wszystko.
4m 14s
22
Wdrażanie cheminformatyki w chmurze
Przenieś swój potok AI na produkcję. Omawiamy pakowanie RDKit i modeli uczenia maszynowego w kontenery Docker oraz skalowanie obciążeń w infrastrukturze chmurowej.
4m 46s
Odcinki
1
Cyfrowa cząsteczka
3m 18s
Wprowadzamy RDKit i podstawową koncepcję reprezentacji chemii w języku Python. Słuchacze dowiedzą się, jak inicjować obiekty molekularne z ciągów znaków i zrozumieją kluczową rolę tego frameworka w odkrywaniu leków za pomocą sztucznej inteligencji.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 1 z 22. Zanim zaczniesz przewidywać toksyczność leku za pomocą modelu machine learningowego, musisz rozwiązać fundamentalny problem. Potrzebujesz sposobu, aby nauczyć Pythona, czym właściwie jest cząsteczka. Standardowe typy danych, takie jak stringi i listy, nie rozumieją atomów, wiązań ani struktur pierścieniowych. Aby wypełnić tę lukę, potrzebujesz uniwersalnego translatora między chemią a kodem. Właśnie to zapewnia RDKit, wprowadzając koncepcję cyfrowej cząsteczki.
RDKit to branżowy standard i open-source'owy toolkit do chemoinformatyki. Pod spodem jest to wysokowydajna biblioteka C++, ale wystawia potężny, intuicyjny interfejs w Pythonie. Istnieje, ponieważ obliczeniowa reprezentacja struktur chemicznych jest zaskakująco trudna. Matematycznie rzecz biorąc, cząsteczka to graf. Atomy to węzły, a wiązania chemiczne to krawędzie łączące te węzły. Jeśli spróbujesz zbudować własny parser grafów od zera za każdym razem, gdy chcesz analizować dane chemiczne, spędzisz cały czas na debugowaniu edge case'ów. RDKit abstrahuje tę złożoność, zarządzając logiką grafu pod spodem.
Aby wczytać cząsteczkę do Pythona, najpierw potrzebujesz tekstowej reprezentacji jej struktury. Najpopularniejszym formatem jest string SMILES. SMILES używa standardowych znaków do reprezentowania połączeń chemicznych. Na przykład izolowany atom węgla to po prostu wielkie C. Benzen, czyli pierścień z sześciu atomów węgla z naprzemiennymi wiązaniami podwójnymi, zapisuje się jako małe c, jedynkę, cztery kolejne małe c i ostatnie małe c, po którym następuje jedynka, aby zamknąć pierścień.
Oto kluczowa sprawa. Ten string SMILES to po prostu zwykły tekst. Dla Pythona jest on nie do odróżnienia od hasła czy ścieżki do pliku. Nie możesz obliczyć masy cząsteczkowej z surowego stringa. Aby robić prawdziwą chemię, musisz go przekonwertować na obiekt cząsteczki RDKit. Robisz to, importując moduł Chem z RDKit. Następnie wywołujesz specjalną funkcję zaprojektowaną do tworzenia cząsteczki ze stringa SMILES i przekazujesz do niej swoją zmienną tekstową.
Kiedy przekazujesz string SMILES benzenu do tej funkcji, RDKit odwala całą czarną robotę. Parsuje tekst, buduje graf węzłów i krawędzi, przypisuje rzędy wiązań i waliduje podstawowe reguły chemiczne, takie jak wartościowości atomów. Jeśli string reprezentuje prawidłową cząsteczkę, funkcja zwraca obiekt cząsteczki. Jeśli przekażesz jej chemicznie niemożliwą strukturę lub literówkę, funkcja bezpiecznie failuje. Wypisuje warning w konsoli i zwraca obiekt null. Z tego powodu zawsze powinieneś sprawdzić, czy twój obiekt cząsteczki faktycznie istnieje, zanim przekażesz go do następnego kroku programu.
Kiedy już masz ten zwalidowany obiekt cząsteczki w pamięci, otwiera się przed tobą cały ekosystem RDKit. Nie pracujesz już z tekstem; pracujesz z obliczalnym grafem chemicznym. Kluczowy wniosek jest taki, że stringi SMILES służą wyłącznie do przechowywania i transferu danych, natomiast obiekty cząsteczek RDKit służą do obliczeń. Wszystko, co robisz w chemii obliczeniowej, zaczyna się od tej konwersji.
Jeśli chciałbyś wesprzeć nasz podcast, wyszukaj DevStoriesEU na Patreonie – to bardzo nam pomaga. To wszystko na dzisiaj. Dzięki za wysłuchanie i koduj dalej!
2
Operacje I/O w cheminformatyce
3m 52s
Dowiedz się, jak bezpiecznie wczytywać i eksportować ogromne zbiory danych chemicznych. Omawiamy odczytywanie plików SDF i SMILES, obsługę błędów parsowania oraz zapisywanie danych z powrotem na dysk.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 2 z 22. Pojedyncza brakująca współrzędna w zbiorze danych z milionem cząsteczek może zcrashować twój cały pipeline. Jeśli założysz, że każdy rekord tekstowy w pliku od dostawcy to idealnie sformatowana chemia, twój skrypt w Pythonie w końcu rzuci krytyczny exception w połowie dziesięciogodzinnego joba. Zabezpieczenie się przed brudnymi danymi podczas przenoszenia struktur do i ze skryptów to podstawa, i właśnie to dzisiaj ogarniemy, mówiąc o I/O w Cheminformatics.
Kiedy dostajesz standardowy plik structure-data, czyli SDF, pełen potencjalnych ligandów, potrzebujesz sposobu, żeby go sparsować. W RDKit domyślnym narzędziem do tego jest SD molecule supplier. Inicjujesz go, przekazując ścieżkę do pliku jako string. Ten obiekt suppliera działa bardzo podobnie do pythonowej listy. Możesz po nim iterować w pętli, możesz sprawdzić jego całkowitą długość i możesz wyciągnąć konkretny rekord po jego indeksie. Robi to, szybko skanując plik, żeby znaleźć miejsce, w którym zaczyna się każda cząsteczka, co pozwala ci skakać po danych.
Czasami nie możesz skanować do przodu. Jeśli pipujesz dane bezpośrednio ze streamu internetowego albo czytasz ogromny plik gzipped chunk po chunku, nie masz random accessu. W takich sytuacjach używasz Forward SD molecule suppliera. Zamiast ścieżki do pliku, przekazujesz mu otwarty file object. Ten forward supplier to ścisły iterator. Odczytuje jedną cząsteczkę, parsuje ją i natychmiast przechodzi do następnej. Nie możesz zapytać o jego długość i nie możesz poprosić o pięćdziesiątą cząsteczkę bez odczytania pierwszych czterdziestu dziewięciu. Wymieniasz elastyczność na niskie zużycie pamięci i kompatybilność ze streamami.
Oto kluczowa informacja. Niezależnie od tego, którego suppliera używasz, RDKit nie rzuca pythonowego exception, gdy napotka uszkodzoną cząsteczkę. Jeśli blok tekstu w twoim pliku ma nieprawidłową walencyjność albo literówkę w formatowaniu, RDKit wypisze komunikat o błędzie w konsoli, ale rzeczywisty obiekt Pythona, który zwróci dla tej iteracji pętli, będzie po prostu typu None.
Jeśli weźmiesz ten obiekt None i spróbujesz obliczyć jego wagę albo zapisać go do nowego pliku, twój skrypt zcrashuje. Obsługa tego jest prosta, ale kluczowa. Pierwsza linijka wewnątrz twojej pętli parsującej musi zawsze sprawdzać, czy zwrócona cząsteczka to None. Jeśli to None, używasz instrukcji continue, żeby przejść do następnego rekordu. To po cichu odfiltrowuje śmieciowe dane i sprawia, że twój pipeline działa dalej.
Kiedy już bezpiecznie sparsujesz i przefiltrujesz swoje prawidłowe cząsteczki, zazwyczaj musisz zapisać wyniki. Do tego używasz SD writera. Inicjujesz writera, przekazując docelową ścieżkę do pliku wyjściowego. Wewnątrz swojej bezpiecznej pętli, zaraz po checku na None, przekazujesz prawidłowy obiekt cząsteczki do writera za pomocą jego metody write. Kiedy pętla skończy przetwarzać każdy ligand, wywołujesz metodę close na writerze, żeby upewnić się, że wszystkie dane bezpiecznie zflushują się na dysk. Możesz też opakować writera w standardowy pythonowy context manager, żeby zamykał się automatycznie po zakończeniu bloku.
Żeby złożyć to wszystko w skrypt do czyszczenia danych: po pierwsze, utwórz SD writera dla pliku wyjściowego. Po drugie, utwórz SD molecule suppliera dla pliku wejściowego. Przeiteruj po supplierze. Sprawdź, czy bieżący element to None, a jeśli tak, pomiń go. Jeśli jest poprawny, przekaż go do writera. Na końcu zamknij writera. Zawsze traktuj zewnętrzne zbiory danych chemicznych jako z natury brudne; weryfikacja, czy sparsowana cząsteczka nie jest None, to najtańsza polisa ubezpieczeniowa, jaką kiedykolwiek będzie miał twój kod.
To wszystko w tym odcinku. Dzięki za słuchanie i buduj dalej!
3
Przeszukiwanie grafów molekularnych
3m 34s
Odkryj, jak cząsteczki są reprezentowane jako struktury danych w postaci grafów. Badamy iterowanie po atomach, analizowanie wiązań i identyfikowanie układów pierścieniowych w cząsteczkach.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 3 z 22. Dla komputera cząsteczka nie jest obiektem fizycznym zajmującym przestrzeń. To po prostu graf węzłów i krawędzi czekających na parsowanie. Jeśli nie potrafisz sprawnie poruszać się po tym grafie, nie możesz analizować struktury chemicznej. To prowadzi nas bezpośrednio do przechodzenia przez graf molekularny.
W RDKit obiekt cząsteczki pełni rolę podstawowego kontenera dla tej struktury danych grafu. Aby sprawdzić węzły, używasz metody GetAtoms. Zwraca ona iterowalną sekwencję zawierającą wszystkie obiekty atomów w cząsteczce. Możesz napisać prostą pętlę, aby przejść przez tę sekwencję element po elemencie. Wyobraź sobie konkretny scenariusz: załóżmy, że musisz wyciągnąć liczby atomowe wszystkich swoich węzłów. Wewnątrz pętli możesz wywołać metodę GetIdx, aby znaleźć unikalny identyfikator numeryczny obecnego atomu, oraz metodę GetAtomicNum, aby dowiedzieć się, jaki to dokładnie pierwiastek chemiczny. Iterując po niej, systematycznie przetwarzasz każdy węzeł.
Same węzły nie definiują chemii. Potrzebujesz też łączących je krawędzi, do których dostęp uzyskujesz za pomocą metody GetBonds. Podobnie jak w przypadku atomów, daje to iterowalną sekwencję obiektów wiązań. Wiązanie zna swoje dokładne miejsce w grafie. Wywołując metody GetBeginAtomIdx i GetEndAtomIdx na obiekcie wiązania, wyciągasz konkretne identyfikatory numeryczne dwóch atomów, które ono łączy. Możesz również odczytać typ wiązania, sprawdzając, czy jest to połączenie pojedyncze, podwójne, czy aromatyczne. I tu pojawia się kluczowa kwestia. RDKit traktuje wiązania jako first-class objects w hierarchii grafu, co oznacza, że możesz je odpytywać niezależnie, zamiast wyciągać je z właściwości atomów.
Nawigacja po poszczególnych węzłach i krawędziach to standardowa logika grafów, ale grafy chemiczne często zawierają cykle, lepiej znane jako pierścienie. Nie musisz pisać własnych algorytmów do wyszukiwania cykli. RDKit wylicza te cykle z góry, gdy tworzona jest instancja cząsteczki. Dostęp do tych danych uzyskujesz za pomocą metody GetRingInfo. Zwraca ona dedykowany obiekt z informacjami o pierścieniach, a nie zwykłą listę.
Jeśli twoim zadaniem jest po prostu policzenie pierścieni w cząsteczce, wywołujesz metodę NumRings bezpośrednio na tym obiekcie. Gdy potrzebujesz głębszych detali strukturalnych, możesz odpytać ten sam obiekt o właściwość AtomRings. Daje ci to kolekcję sekwencji, w której każda sekwencja zawiera dokładne indeksy atomów tworzących jeden konkretny pierścień w grafie. Możesz nawet przekazać indeks atomu do obiektu z informacjami o pierścieniach, aby zapytać, czy ten konkretny węzeł uczestniczy w pierścieniu o określonym rozmiarze, na przykład w cyklu pięcio- lub sześcioczłonowym.
Przechodzenie przez cząsteczkę to ostatecznie chainowanie tych podstawowych operacji. Pobierasz informacje o pierścieniach, aby sprawdzić makrostrukturę, iterujesz po atomach, aby odczytać dane na poziomie węzłów, takie jak liczby atomowe, i iterujesz po wiązaniach, aby zmapować konkretne połączenia krawędzi. Kiedy przestajesz postrzegać cząsteczkę jako byt fizyczny, a zaczynasz widzieć w niej przewidywalną kolekcję indeksowanych węzłów, krawędzi i wyliczonych z góry cykli, wyciąganie właściwości strukturalnych staje się standardowym zadaniem parsowania danych. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
4
Wyszukiwanie podstruktur
4m 27s
Opanuj sztukę odpytywania cząsteczek za pomocą SMARTS. Krok po kroku pokazujemy, jak znajdować określone grupy funkcyjne i wzorce w złożonych strukturach chemicznych.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 4 z 22. Nie próbowałbyś parsować tysięcy logów tekstowych bez użycia wyrażeń regularnych. Podobnie, nie powinieneś próbować filtrować baz danych chemicznych bez wzorców SMARTS. Znalezienie konkretnych grup funkcyjnych w dużych datasetach wymaga dedykowanej logiki strukturalnej i właśnie to zapewnia Substructure Searching.
Załóżmy, że masz bibliotekę kandydatów na leki. Twoim celem jest oflagowanie i wyizolowanie każdej cząsteczki zawierającej konkretną, znaną toksyczną grupę funkcyjną. Najpierw definiujesz tę toksyczną grupę za pomocą stringa SMARTS. SMARTS to rozszerzenie SMILES zaprojektowane specjalnie do odpytywania o wzorce molekularne, pozwalające na określenie wildcardów, konkretnych typów wiązań lub struktur pierścieniowych. Przekazujesz ten string do funkcji RDKit, która tworzy cząsteczkę z formatu SMARTS. W ten sposób generujesz swój obiekt query. Twoje cząsteczki docelowe, czyli kandydaci na leki, są już standardowymi obiektami molecule w RDKit.
Aby przefiltrować bibliotekę, bierzesz cząsteczkę kandydującą i wywołujesz metodę o nazwie has substructure match. Przekazujesz do tej metody swój obiekt query. Metoda ta ewaluuje cząsteczkę kandydującą pod kątem wzorca i zwraca prostą wartość boolean. True oznacza, że toksyczna grupa znajduje się gdzieś w kandydacie. False oznacza, że jest czysty. Ponieważ ta metoda zatrzymuje wyszukiwanie w momencie znalezienia pojedynczego prawidłowego matcha, jest wysoce zoptymalizowana. Możesz zapętlić to sprawdzenie boolean w całej bibliotece, aby szybko podzielić ogromny dataset na bezpieczne i oflagowane podzbiory.
A co, jeśli sama wiedza o obecności toksycznej grupy nie wystarczy? Być może toksyczność skaluje się wraz z liczbą wystąpień tej grupy, albo musisz wyizolować dokładną lokalizację toksycznych atomów dla biologa strukturalnego. W tym celu używasz metody o nazwie get substructure matches, w liczbie mnogiej. Wywołujesz ją na swojej cząsteczce kandydującej, ponownie przekazując obiekt query. Zamiast booleana, metoda ta zmusza silnik wyszukiwania do zmapowania każdego możliwego wystąpienia wzorca.
Zwraca tuplę zawierającą inne tuple. Każda wewnętrzna tupla reprezentuje jeden kompletny match twojego wzorca. Liczby całkowite wewnątrz tych tupel to dokładne indeksy atomów w cząsteczce kandydującej. Oto kluczowa kwestia. Kolejność tych indeksów idealnie odzwierciedla kolejność atomów zdefiniowaną w twoim oryginalnym stringu SMARTS. Oznacza to, że zawsze dokładnie wiesz, który atom w targecie odpowiada której części twojego query. Jeśli toksyczna grupa pojawia się trzy razy w kandydacie, otrzymujesz trzy wewnętrzne tuple. Możesz policzyć tuple, aby znaleźć częstotliwość wzorca, lub przekazać te konkretne indeksy atomów do funkcji rysującej, aby wizualnie podświetlić toksyczne regiony. Jeśli potrzebujesz tylko indeksów atomów pierwszego znalezionego matcha, możesz użyć pojedynczej metody get substructure match, aby zaoszczędzić czas przetwarzania.
Musisz również uwzględnić stereochemię. Domyślnie substructure matching w RDKit całkowicie ignoruje chiralność. Zarówno wiązanie klinowe, jak i kreskowe zwrócą match dla podstawowego query SMARTS. Jeśli docelowa toksyczność występuje tylko w przypadku określonego stereoizomeru, to domyślne zachowanie wygeneruje false positives w twoim screeningu leków. Aby to naprawić, przekazujesz argument o nazwie use chirality i ustawiasz go na true podczas wywoływania dowolnej z metod matchujących. RDKit będzie wtedy egzekwował reguły stereochemiczne w oparciu o konkretną konfigurację zdefiniowaną w twoim query.
Prawdziwą siłą Substructure Searching jest to, że mapuje ono czysto logiczne tekstowe query bezpośrednio na fizyczną topologię twojego datasetu, wypełniając lukę między abstrakcyjnymi wzorcami stringów a konkretnymi współrzędnymi atomowymi. To wszystko w tym odcinku. Dzięki za wysłuchanie i twórz dalej!
5
Generowanie fingerprintów i podobieństwo molekularne
4m 33s
Sprawdź, jak tłumaczyć grafy molekularne na matematyczne wektory bitowe. Omawiamy klucze MACCS, Morgan fingerprints oraz obliczanie podobieństwa Tanimoto.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 5 z 22. Modele AI tak naprawdę nie rozumieją atomów i wiązań. Rozumieją tylko liczby. Jeśli chcesz, aby algorytm porównywał dwie struktury, potrzebujesz sposobu na przełożenie chemii na matematykę. Fingerprinting i podobieństwo molekularne to dokładnie to, jak wypełniamy tę lukę.
Cząsteczka w RDKit jest zasadniczo grafem matematycznym. Atomy działają jak węzły, a wiązania jak krawędzie. Aby wykonać szybkie obliczenia na tych grafach, konwertujemy je na wektory bitowe, które są po prostu długimi tablicami jedynek i zer. Ta tablica to tak zwany fingerprint. Logika jest prosta. Jeśli w cząsteczce występuje określona cecha strukturalna, konkretny bit w tablicy jest ustawiany na jeden. Jeśli tej cechy brakuje, bit pozostaje zerem. Konwertując złożone grafy molekularne na standardowe wektory bitowe, możemy łatwo porównywać je matematycznie.
RDKit oferuje kilka algorytmów do generowania fingerprintów. Domyślny fingerprint w RDKit wykorzystuje podejście topologiczne. Analizuje on liniowe ścieżki w cząsteczce. System zaczyna od atomu i podąża wzdłuż połączonych wiązań do określonej długości, zazwyczaj od jednego do siedmiu wiązań. Każda znaleziona unikalna ścieżka jest przepuszczana przez funkcję hashującą, która przypisuje tę ścieżkę do konkretnej pozycji w wektorze bitowym.
Chociaż ścieżki topologiczne są użyteczne, współczesna cheminformatyka w dużym stopniu opiera się na fingerprintach Morgana, często nazywanych fingerprintami kołowymi. Zamiast śledzić liniowe ścieżki, algorytmy Morgana analizują sąsiedztwo promieniujące na zewnątrz od każdego pojedynczego atomu. Generując fingerprint Morgana, musisz zdefiniować promień. Promień równy zero oznacza, że algorytm rejestruje tylko pojedyncze atomy. Promień równy jeden obejmuje każdy atom plus jego bezpośrednio połączonych sąsiadów. Promień równy dwa rozszerza ten okrąg o jedno wiązanie dalej. Algorytm kataloguje wszystkie te nakładające się na siebie środowiska kołowe, hashuje je i ustawia odpowiednie bity na jeden. Zazwyczaj składamy te hashe w wektor o stałej długości, na przykład dwa tysiące czterdzieści osiem bitów, aby zużycie pamięci było przewidywalne. Fingerprinty Morgana o promieniu dwa są standardem w branży, ponieważ doskonale wychwytują grupy funkcyjne i lokalny kontekst chemiczny.
Spójrzmy na konkretny scenariusz. Masz dwie nieco różniące się cząsteczki. Może współdzielą dużą strukturę rdzenia, ale jedna ma dołączoną dodatkową grupę metylową. Chcesz określić ilościowo, jak bardzo się pokrywają. Najpierw wczytujesz obie cząsteczki do RDKit. Następnie generujesz fingerprint Morgana dla każdej z nich, ustawiając promień na dwa. Masz teraz dwa odrębne wektory bitowe. Aby obliczyć, jak bardzo są do siebie podobne, obliczasz ich podobieństwo Tanimoto.
Oto kluczowa sprawa. Podobieństwo Tanimoto ignoruje zera. Bierze pod uwagę tylko te cechy, które faktycznie występują. Matematyka to proste intersection over union. RDKit zlicza liczbę bitów ustawionych na jeden w obu fingerprintach i dzieli to przez całkowitą liczbę bitów ustawionych na jeden w którymkolwiek z nich. Jeśli oba wektory pasują do siebie idealnie, wynik Tanimoto wynosi jeden przecinek zero. Jeśli nie mają żadnych wspólnych cech, wynik wynosi zero przecinek zero. Dla naszych dwóch cząsteczek różniących się pojedynczą grupą metylową, środowiska kołowe wokół rdzenia będą w większości pasować, podczas gdy środowiska w pobliżu mutacji będą się różnić. Możesz uzyskać wynik Tanimoto równy zero przecinek osiemdziesiąt pięć, co daje ci precyzyjną wartość liczbową ich strukturalnego pokrycia.
Pamiętaj, że mapowanie złożonej cząsteczki do stałej tablicy bitów oznacza utratę części danych, a wysoki wynik Tanimoto gwarantuje strukturalne pokrycie, a nie biologiczną równoważność.
Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
6
Przełamywanie płaszczyzny 2D
4m 42s
Przejdź od płaskich rysunków 2D do realistycznych geometrii 3D. Omawiamy dodawanie jawnych atomów wodoru i generowanie wiarygodnych konformerów 3D przy użyciu ETKDG.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 6 z 22. Rysunek 2D może wyglądać świetnie na ekranie, ale leki istnieją w przestrzeni 3D. Jeśli ignorujesz geometrię, ignorujesz rzeczywistość. Dzisiaj przełamujemy płaszczyznę 2D i generujemy poprawne współrzędne 3D dla twoich cząsteczek.
Kiedy odczytujesz cząsteczkę ze standardowego stringu SMILES, nie ma ona żadnych współrzędnych. Jest to po prostu graf topologiczny połączonych atomów. Nawet jeśli wczytasz strukturę z pliku z rysunkiem 2D, współrzędne te są rozmieszczone tylko po to, żeby człowiek mógł je łatwiej odczytać. Aby wykonać dokowanie, obliczyć pole powierzchni lub przeprowadzić symulacje fizyczne, potrzebujesz fizycznie realistycznej struktury 3D.
Absolutnie pierwszym krokiem przed wygenerowaniem jakiejkolwiek geometrii 3D jest dodanie atomów wodoru. W standardowym stringu SMILES atomy wodoru są implicit. Traktuje się je jako podstawową właściwość ciężkich atomów, które po prostu wypełniają wymagania walencyjne. Jednak w przestrzeni fizycznej atomy wodoru zajmują rzeczywistą objętość. Tworzą one zawadę przestrzenną i dyktują kąty wiązań wokół nich. Jeśli spróbujesz obliczyć strukturę 3D bez uprzedniego dodania atomów wodoru jako explicit, uzyskana geometria zapadnie się w sobie, a kąty wiązań będą całkowicie błędne. RDKit udostępnia funkcję AddHs, która zamienia te atomy wodoru typu implicit na rzeczywiste węzły w twoim grafie molekularnym, wraz z wiązaniami. Zawsze musisz uruchomić tę funkcję przed przejściem do 3D.
Kiedy masz już kompletną cząsteczkę, musisz obliczyć jej współrzędne przestrzenne. Ponieważ pojedyncze wiązania mogą się swobodnie obracać, elastyczny ligand nie ma tylko jednego statycznego kształtu. Może przyjmować wiele różnych kształtów, zwanych konformacjami. Aby wygenerować sensowną konformację, RDKit używa domyślnej metody ETKDG. Skrót ten oznacza Experimental Torsion-angle Preference with Distance Geometry.
Oto kluczowa sprawa. Metody starszej generacji opierały się wyłącznie na czystej matematyce. Używały distance geometry do odgadywania położenia atomów na podstawie znanych długości i kątów wiązań. Często prowadziło to do powstawania dziwnych, wysokoenergetycznych kształtów, wymagających intensywnego czyszczenia obliczeniowego. ETKDG rozwiązuje ten problem, łącząc matematykę distance geometry z regułami empirycznymi pochodzącymi z Cambridge Structural Database. Wie, jak rzeczywiste, fizyczne cząsteczki w naturalny sposób wolą się zginać i skręcać, i wymusza na algorytmie geometrii respektowanie tych naturalnych preferencji.
Weźmy konkretny scenariusz. Masz bardzo elastyczny ligand i musisz zrozumieć wszystkie sposoby, w jakie może się on zwinąć, aby zmieścić się w kieszeni wiążącej białko. Wygenerowanie pojedynczej konformacji nie wystarczy, aby uchwycić to zachowanie. Potrzebujesz całego ensemble. RDKit obsługuje to za pomocą funkcji EmbedMultipleConfs. Przekazujesz swoją cząsteczkę z jej atomami wodoru typu explicit i określasz, że chcesz pięćdziesiąt konformerów.
RDKit następnie uruchomi algorytm ETKDG pięćdziesiąt razy, zaczynając od różnych random seeds, aby wygenerować pięćdziesiąt odrębnych geometrii 3D. Przechowuje wszystkie pięćdziesiąt tych kształtów w oryginalnym obiekcie molecule. Nie dostajesz z powrotem pięćdziesięciu oddzielnych cząsteczek; dostajesz jedną cząsteczkę, która zawiera pięćdziesiąt różnych zestawów współrzędnych. Następnie możesz przeiterować przez te zestawy współrzędnych, aby mierzyć odległości lub obliczać energię. Ponieważ ETKDG w dużej mierze opiera się na rzeczywistych danych kryształów, początkowe struktury, które dostarcza, są zazwyczaj bardzo wysokiej jakości, prosto z funkcji.
Cząsteczka nie jest płaskim rysunkiem i rzadko jest po prostu pojedynczym, sztywnym kształtem; jest obiektem dynamicznym, a próbkowanie jej wielu konformerów daje ci prawdziwe granice jej fizycznego zachowania. Jeśli chcesz pomóc w utrzymaniu podcastu, możesz nas wesprzeć, wyszukując DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za słuchanie i twórzcie dalej!
7
Przyspieszanie inżynierii cech
4m 17s
Połącz cheminformatykę ze standardowym data science za pomocą scikit-fingerprints. Badamy generowanie ponad 30 typów fingerprintów molekularnych bezpośrednio w interfejsie scikit-learn.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 7 z 22. Pisanie customowych pętli do ekstrakcji fingerprintów dla każdego nowego projektu jest żmudne i podatne na błędy. Przechodzisz z fingerprintu ECFP na MACCS key i nagle musisz przepisać cały swój blok preprocessingu. Scikit-fingerprints to biblioteka, która rozwiązuje ten problem, sprawiając, że ekstrakcja feature'ów molekularnych jest tak prosta, jak wywołanie standardowego transform ze scikit-learn.
Cząsteczki są zasadniczo reprezentowane jako grafy. Większość algorytmów machine learningu wymaga jednak wektorów wielowymiarowych. Molekularne fingerprinty to algorytmy feature extraction, które wypełniają tę lukę, kodując informacje strukturalne w numerycznych arrayach. Problem polega na tym, że standardowe narzędzia open source do obliczania tych fingerprintów, takie jak RDKit, Open Babel czy Chemistry Development Kit, są napisane w C++ lub Javie. Ich pythonowe wrappery nie są natywnie zgodne z API scikit-learn. W efekcie piszesz customowe data loadery, konwertery formatów i podatne na błędy pętle, tylko po to, żeby nadać danym kształt, który twój klasyfikator będzie w stanie przetworzyć.
Scikit-fingerprints zmienia tę architekturę. Implementuje ponad 30 różnych molekularnych fingerprintów jako standardowe, bezstanowe transformery scikit-learn. Wszystkie klasy fingerprintów dziedziczą z klas bazowych scikit-learn. Oznacza to, że wpinają się bezpośrednio w standardowe pipeline'y machine learningowe i feature unions.
Weźmy pod uwagę standardowy workflow. Zazwyczaj piszesz dwudziestolinijkową customową pętlę w RDKit, żeby iterować po datasecie, walidować cząsteczki, ekstrahować circular fingerprints i stackować wyniki w array. Dzięki tej bibliotece zastępujesz cały ten blok boilerplate'u jednym krokiem. Tworzysz obiekt o nazwie ECFP Fingerprint i przekazujesz go bezpośrednio do pipeline'u scikit-learn tuż przed swoim modelem random forest. Kiedy wywołujesz metodę fit na swoim pipeline'ie z danymi treningowymi i zmiennymi docelowymi, transformer fingerprintu przetwarza wejścia i zwraca gęsty array NumPy bezpośrednio do modelu.
Oto kluczowa informacja. Nie musisz konwertować swoich reprezentacji tekstowych na obiekty molekuł RDKit przed przekazaniem ich do transformera. Dla dowolnego dwuwymiarowego fingerprintu opartego na topologii grafu, metoda transform bezpośrednio akceptuje standardową pythonową listę stringów SMILES. Biblioteka automatycznie obsługuje konwersję wewnętrzną. Ponieważ stringi SMILES nie zawsze są unikalne lub chemicznie poprawne, biblioteka udostępnia również klasę Molecule Standardizer. Klasa ta stosuje kroki sanityzacji zalecane przez RDKit, aby zapewnić jakość danych przed rozpoczęciem ekstrakcji.
Biblioteka obsługuje również trójwymiarowe fingerprinty oparte na konformacji przestrzennej. Te algorytmy przestrzenne wymagają obiektów molekuł RDKit z obliczonymi konformerami. Generowanie konformerów może być niestabilne, dlatego pakiet zawiera klasę Conformer Generator, która wykorzystuje konkretny algorytm znany jako ETKDG w wersji 3. Zapewnia on niezawodne wartości domyślne, maksymalizujące wydajność dla prostych cząsteczek, a jednocześnie minimalizujące błędy obliczeniowe dla złożonych związków. Umieszczasz conformer generator na początku swojego pipeline'u, po nim dodajesz trójwymiarowy transformer fingerprintu, a na końcu imputer do obsługi brakujących wartości.
Zamykając złożoną logikę chemiczną w standardowych klasach transformerów, biblioteka abstrahuje od specyficznego dla tej dziedziny boilerplate'u. Konfigurujesz opcje takie jak długość wektora wyjściowego lub to, czy chcesz wariant binarny, czy zliczeniowy, po prostu przekazując parametry do konstruktora transformera. W rezultacie tuning hiperparametrów dla molekularnych fingerprintów staje się równie prosty, jak tuning głębokości drzewa decyzyjnego.
To tyle w tym odcinku. Do usłyszenia następnym razem!
8
Wydajna cheminformatyka
4m 22s
Dowiedz się, jak wydajnie przetwarzać ogromne zbiory danych chemicznych. Zagłębiamy się w wykorzystanie zrównoleglenia CPU za pomocą Joblib oraz oszczędzanie pamięci przy użyciu macierzy rzadkich z biblioteki SciPy.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 8 z 22. Obliczanie złożonych podstruktur na ogromnym datasecie może łatwo wywalić twoją maszynę błędami out-of-memory, chyba że dokładnie wiesz, jak zarządzać swoim data footprintem. Techniką, która rozwiązuje ten problem, jest High-Performance Cheminformatics.
Kiedy ekstrahujesz cechy z cząsteczki, często używasz fingerprintów opartych na podstrukturach. Fingerprint Klekoty-Rotha to klasyczny przykład. Aby go obliczyć, twój komputer porównuje cząsteczkę z tysiącami predefiniowanych wzorców chemicznych, znanych jako wzorce SMARTS. Skanuje on graf molekularny w kółko, aby sprawdzić, czy występują w nim określone grupy funkcyjne lub motywy strukturalne. Robienie tego sekwencyjnie dla kilku cząsteczek jest okej. Ale robienie tego dla datasetu liczącego czterysta tysięcy cząsteczek to już poważny bottleneck obliczeniowy.
Obliczanie molekularnych fingerprintów to zadanie typu embarrassingly parallel. Analiza strukturalna jednej cząsteczki ma absolutnie zerową zależność od analizy kolejnej cząsteczki w twoim datasecie. Ponieważ nie współdzielą one stanu, możesz obliczać je całkowicie jednocześnie. Aby efektywnie to skalować w Pythonie, wykorzystujesz bibliotekę Joblib, a konkretnie polegasz na executorze Loky.
Kiedy inicjujesz proces, wejściowy dataset jest dzielony na chunki odpowiadające dokładnie twoim dostępnym rdzeniom CPU. Jeśli masz 16-rdzeniowy procesor, twoje cząsteczki wejściowe są dzielone na 16 oddzielnych batchy. Każdy worker Pythona bierze jeden batch i zaczyna niezależnie wykonywać pattern matching SMARTS. Techniczną przeszkodą przy multiprocessingu w Pythonie jest zazwyczaj koszt przenoszenia danych między workerami a głównym procesem. Loky omija to, używając memory mappingu. Zamiast serializować końcowe tablice fingerprintów i wysyłać je przez inter-process communication, workery piszą bezpośrednio do współdzielonej przestrzeni w pamięci. Dla ciężkich obliczeniowo fingerprintów, takich jak Klekota-Roth, rozłożenie workloadu na 16 rdzeni daje prawie piętnastokrotny speedup.
To załatwia sprawę czasu przetwarzania. Drugim krytycznym bottleneckiem jest pamięć systemowa.
Pojedynczy wektor fingerprintu Klekoty-Rotha jest długi. Jeśli przetwarzasz setki tysięcy cząsteczek, generujesz ogromną macierz wyników. Domyślnie biblioteki numeryczne zwracają ten wynik jako dense array w NumPy. Każda pojedyncza pozycja w tej macierzy alokuje pamięć, niezależnie od tego, czy jej wartość to jeden, czy zero.
Chemiczne fingerprinty są w przeważającej mierze sparse. Zazwyczaj tylko jeden lub dwa procent żądanych cech strukturalnych jest faktycznie obecnych w danej cząsteczce. Zdecydowana większość twojej wynikowej macierzy składa się z zer. To właśnie przechowywanie tych zer wywołuje błędy out-of-memory na dużych datasetach. Rozwiązaniem jest zmiana formatu wyjściowego na sparse matrix z biblioteki SciPy, a konkretnie użycie formatu Compressed Sparse Row. Sparse matrix fundamentalnie zmienia sposób przechowywania danych. Zamiast budować sztywną siatkę w pamięci, zapisuje tylko wartości niezerowych elementów wraz z ich współrzędnymi wiersza i kolumny.
Weźmy pod uwagę rzeczywisty scenariusz z użyciem datasetu PCBA, który zawiera nieco poniżej czterystu czterdziestu tysięcy cząsteczek. Uruchamiasz obliczanie fingerprintu Klekoty-Rotha na całym datasecie, używając swoich 16 rdzeni. Równoległe wykonanie kończy się sprawnie. Jeśli zostawisz output jako domyślny dense array, ta jedna macierz zużyje nieco ponad dwa gigabajty RAM-u. Jeśli zamiast tego poinstruujesz obliczenia, by zwróciły sparse array ze SciPy, ten sam dataset zmniejszy swój footprint do zaledwie 23 megabajtów. Osiągasz osiemdziesięcioośmiokrotną redukcję zużycia pamięci bez utraty ani jednego kawałka chemicznej informacji, a reprezentacja sparse w ogóle nie wpływa negatywnie na twój czas obliczeń.
Oto kluczowy wniosek. Nie potrzebujesz ogromnego klastra obliczeniowego, by przetwarzać setki tysięcy cząsteczek, pod warunkiem, że przestaniesz płacić podatek pamięciowy za przechowywanie zer i upewnisz się, że przekazywanie twoich danych pomija standardowy overhead inter-process communication.
To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
9
Potoki ML End-to-End
4m 03s
Połącz przetwarzanie, generowanie fingerprintów i predykcję w jedną, przejrzystą architekturę. Budujemy solidne potoki scikit-learn, które płynnie integrują generowanie konformerów 3D i przewidywanie właściwości.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 9 z 22. Złożony skrypt do wirtualnego screeningu 3D wymagał kiedyś setek linii podatnego na błędy kodu. Musiałeś ręcznie generować konformery, obsługiwać błędy, obliczać wiele deskryptorów i sklejać arraye, zanim w ogóle dotknąłeś modelu. Teraz możesz zaprojektować cały proces w jednej, eleganckiej definicji pipeline'u, używając End-to-End ML Pipelines.
W machine learningu pipeline to sekwencja kroków przetwarzania danych i końcowy estimator, zgrupowane w jeden obiekt. W cheminformatyce, szczególnie przy danych strukturalnych 3D, preprocessing jest wyjątkowo pofragmentowany. Bierzesz surowe stringi SMILES, obliczasz współrzędne 3D, odpalasz optymalizacje force field, wyciągasz feature'y, naprawiasz missing values i na koniec trenujesz classifier. Robienie tego ręcznie oznacza pisanie customowych pętli i pośrednich struktur danych, które łatwo się sypią i powodują wycieki pamięci. Przejdziemy przez budowę kompletnego pipeline'u w scikit-learn, który bierze surowe SMILES i przekazuje je prosto do Random Forest classifiera.
Pierwszym krokiem w sekwencji jest generowanie konformerów. Inicjalizujesz generator konformerów i przekazujesz go jako pierwszy etap pipeline'u. Czyta on input 2D i oblicza struktury 3D. Możesz go skonfigurować tak, aby optymalizował geometrię używając force field, takiego jak MMFF94. Automatycznie zrównolegla tę ciężką robotę na wszystkich dostępnych rdzeniach procesora.
Teraz, drugim elementem jest feature extraction. W zadaniach 3D, łączenie różnych deskryptorów geometrii pozwala uchwycić więcej informacji molekularnych. Używasz FeatureUnion ze scikit-learn do jednoczesnego obliczenia fingerprintów GETAWAY i WHIM. Obie te klasy fingerprintów działają jak stateless transformery w pipeline'ie. Biorą one konformery 3D z poprzedniego kroku, równolegle obliczają swoje deskryptory i konkatenują wyniki w jedną, szeroką feature matrix.
Następnie musisz obsłużyć błędy obliczeniowe. Algorytmy deskryptorów 3D czasami nie radzą sobie z przetwarzaniem bardzo złożonych lub naprężonych cząsteczek, co skutkuje missing values w twojej matrix. Pipeline ogarnia to bez customowego error handlingu. Wrzucasz SimpleImputer bezpośrednio po FeatureUnion. Jeśli obliczenia GETAWAY lub WHIM zwrócą missing value, imputer to wyłapuje i zastępuje średnią tego feature'a w całym twoim dataset'cie.
Na koniec zamykasz pipeline swoim modelem predykcyjnym, którym w tym przypadku jest Random Forest classifier.
Aby zaprojektować to w kodzie, wywołujesz funkcję make_pipeline. Wewnątrz tego wywołania przekazujesz swój generator konformerów. Następnie przekazujesz FeatureUnion zawierający twoje fingerprinty GETAWAY i WHIM. Potem wchodzi SimpleImputer, a na końcu Random Forest classifier. Całą tę sekwencję przypisujesz do jednej zmiennej.
Kiedy wywołujesz metodę fit na tej zmiennej pipeline'u, przekazujesz swoje surowe treningowe stringi SMILES i target labels. Stringi przepływają sekwencyjnie przez generator konformerów, do FeatureUnion w celu wygenerowania fingerprintów, przez imputer, żeby oczyścić dane, i prosto do classifiera na trening. Kiedy nadchodzi czas na ewaluację, wywołanie metody predict na twoich testowych stringach SMILES wymusza, aby nowe dane podążały dokładnie tą samą ścieżką.
Oto kluczowa kwestia. State i routing danych są w całości zarządzane przez obiekt pipeline'u, co oznacza, że nigdy nie trzymasz w pamięci pośrednich dense arrayów ani nie piszesz customowych data loaderów dla swoich konformerów.
To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
10
Przewidywanie powinowactwa wiązania
4m 24s
Poznaj realia przewidywania powinowactwa wiązania białko-ligand. Porównujemy wydajność prostych modeli drzewiastych 2D ze złożonymi 3D Graph Neural Networks.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 10 z 22. Budujesz potężną, trójwymiarową grafową sieć neuronową, karmiąc ją współrzędnymi przestrzennymi każdego atomu w kieszeni białkowej. Następnie odpalasz proste drzewo decyzyjne oparte na gradient boostingu, które patrzy tylko na dwuwymiarowy szkic leku. Benchmark dobiega końca, a twój najnowocześniejszy model przestrzenny właśnie został pokonany przez algorytm sprzed dwóch dekad. Powód, dla którego twoja ciężka sieć poległa, leży w tym, jak podchodzimy do przewidywania powinowactwa wiązania.
Przewidywanie powinowactwa wiązania to proces obliczeniowy, w którym szacujemy, jak mocno mała cząsteczka, czyli ligand, przyłącza się do konkretnego białka docelowego. W procesie odkrywania leków, znalezienie cząsteczki, która silnie się wiąże, to główny cel. Żeby to osiągnąć, inżynierowie zazwyczaj wybierają jedną z dwóch ścieżek. Pierwsza jest bardzo złożona. Używasz trójwymiarowych sieci neuronowych, takich jak GraphNet czy TensorNet. Modele te przyjmują na wejściu dokładną konformację związanego kompleksu białko-ligand. Wykorzystują warstwy message passing, żeby nauczyć się dokładnych odległości przestrzennych i cech kwantowo-mechanicznych między atomami leku a atomami kieszeni białkowej.
Druga ścieżka całkowicie ignoruje białko. Odrzucasz współrzędne przestrzenne i używasz klasycznego, dwuwymiarowego modelu, takiego jak XGBoost. Dane wejściowe to tutaj po prostu skonkatenowany wektor fingerprintów molekularnych. Obliczasz cechy strukturalne na podstawie samego ligandu, w zasadzie zamieniając dwuwymiarowy rysunek związku chemicznego w tablicę liczb, i wrzucasz to bezpośrednio do modelu opartego na drzewach.
Żeby zobaczyć, jak te podejścia wypadają w porównaniu, badacze testują je na ustandaryzowanych zbiorach testowych. Jednym z najbardziej wymownych jest benchmark Merck FEP. Ten dataset naśladuje typowy scenariusz virtual screeningu, nazywany serią kongeneryczną. W serii kongenerycznej wszystkie testowane ligandy dzielą dokładnie ten sam chemiczny scaffold i wiążą się z dokładnie tym samym miejscem na pojedynczym białku docelowym. Jedyne różnice między cząsteczkami to niewielkie wariacje strukturalne, takie jak różne odgałęzienia chemiczne przyłączone do głównego rdzenia.
I tu pojawia się kluczowy wniosek. Podczas ewaluacji na datasecie Merck, ciężkie modele trójwymiarowe osiągnęły wynik korelacji na poziomie około 0,3. Prosty, dwuwymiarowy model XGBoost uzyskał znacznie wyższy wynik, osiągając 0,45. Tanie obliczeniowo drzewo decyzyjne wyraźnie pokonało zaawansowane grafowe sieci neuronowe.
Dzieje się tak ze względu na to, na czym modele są zmuszone się skupić. W serii kongenerycznej, białko docelowe i kieszeń wiążąca nie ulegają zmianie. Model trójwymiarowy zużywa ogromne zasoby obliczeniowe na mapowanie środowiska przestrzennego, które pozostaje statyczne w każdym pojedynczym przypadku testowym. Co gorsza, modele te są bardzo wrażliwe na drobne wariacje we współrzędnych atomowych. Niewielkie, arbitralne przesunięcie w ułożeniu atomu wodoru podczas przygotowywania danych wprowadza szum, który rozprasza sieć grafową. Model dwuwymiarowy odnosi sukces właśnie dlatego, że jest ślepy na białko. Patrząc tylko na cechy ligandu, opiera się na jedynych zmiennych, które faktycznie zmieniają się z testu na test. Drzewo decyzyjne koreluje te bezpośrednie wariacje strukturalne leku z ostateczną siłą wiązania, całkowicie omijając szum środowiska przestrzennego.
Ciężkie modele trójwymiarowe są nadal bardzo cenne, gdy musisz generalizować na zupełnie inne, niewidziane wcześniej białka docelowe, gdzie geometria kieszeni jest nieznana. Ale kiedy optymalizujesz konkretną rodzinę leków pod kątem pojedynczego, znanego targetu, karmienie głębokiej sieci stałymi danymi środowiskowymi jest nieefektywne i podatne na błędy. Najpotężniejszym narzędziem predykcyjnym jest często to, które odfiltrowuje statyczne środowisko i modeluje tylko te zmienne, które ulegają zmianie. To tyle na dzisiaj. Do usłyszenia następnym razem!
11
LLM kontra klasyczne fingerprinty
4m 27s
Odkryj, jak Natural Language Processing znajduje zastosowanie w chemii. Zestawiamy osadzenia wektorowe z Large Language Models z klasycznymi strukturalnymi fingerprintami RDKit w celu przewidywania bioaktywności.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 11 z 22. Co, jeśli najlepszym sposobem na opisanie cząsteczki dla modelu uczenia maszynowego nie jest ręcznie stworzony wzór strukturalny, ale potraktowanie jej SMILES string dokładnie tak, jak zdania w języku naturalnym? Możesz tracić cenne compute cycles na generowanie złożonych deskryptorów chemicznych, tylko po to, by przegrać z modelem tekstowym. To napięcie leży u podstaw starcia LLM-ów z klasycznymi fingerprintami.
Kiedy przewidujesz, jak mocno ligand wiąże się z białkiem, twój model potrzebuje matematycznego opisu ligandu. Tradycyjna ścieżka opiera się na klasycznych, strukturalnych fingerprintach obliczanych przez narzędzia takie jak RDKit. Przepuszczasz cząsteczkę przez deterministyczny algorytm i otrzymujesz statyczny wektor. Morgan fingerprint zlicza koliste podstruktury wokół atomów. MACCS keys sprawdzają cząsteczkę pod kątem predefiniowanej listy chemicznych wzorców.
Ograniczeniem tych klasycznych fingerprintów jest ich sztywność. Kodują one specyficzne, niezmienne reguły. Nie możesz zrobić ich fine-tuningu. Jeśli konkretny niuans strukturalny ma znaczenie dla bardzo specyficznej kieszeni wiążącej, ale algorytm fingerprintu nie został zaprojektowany tak, by go wychwycić, ta informacja jest całkowicie tracona, zanim model predykcyjny w ogóle zobaczy dane.
Zamiast hardcodować chemiczne reguły, możemy użyć pre-trained chemicznego Large Language Model, takiego jak BioT5, GPT2 czy BERT. Te modele są pre-trained na milionach SMILES strings. Uczą się gramatyki chemii w sposób nienadzorowany. Kiedy przekazujesz ligand do LLM, nie zwraca on stałej listy kontrolnej grup funkcyjnych. Zwraca bogaty vector embedding. Każdy znak lub token w tym SMILES string dostaje swój własny wektor kontekstowy.
Aby zrozumieć różnicę, spójrz, jak te reprezentacje trafiają do modeli predykcyjnych. Najpierw weź pod uwagę model XGBoost używający klasycznych MACCS keys. Generujesz MACCS fingerprint, co daje prostą binarną tablicę. Przekazujesz ten stały wektor do XGBoost, który próbuje zmapować te surowe cechy obecności lub braku na powinowactwo wiązania. W testach benchmarkowych na seriach kongenerycznych, ta konkretna kombinacja konsekwentnie daje najsłabsze wyniki. Ręcznie tworzone cechy są po prostu zbyt toporne.
Teraz zamień tę architekturę na BioT5 embedding przekazywany do Transformer head. Najpierw przekazujesz surowy SMILES string do modelu BioT5. Zwraca to sekwencję embeddings per token. Następnie przekazujesz tę sekwencję do Transformer head. Oto kluczowa sprawa. Transformer wykorzystuje attention mechanism. Analizuje całą sekwencję token embeddings i dynamicznie uczy się, które części cząsteczki mają największe znaczenie dla wiązania się z tym konkretnym celem. Inteligentnie waży cechy przed zwróceniem przewidywanego powinowactwa wiązania.
Jeśli spróbujesz wziąć dokładnie te same tokeny BioT5, zsumować je w jeden płaski wektor i przekazać do XGBoost, wydajność predykcyjna znacznie spadnie. Sum pooling uśrednia szczegóły na poziomie tokenów. Transformer head odnosi sukces właśnie dlatego, że zachowuje i wykorzystuje granularny kontekst tej tekstowej reprezentacji.
To przejście od statycznych tablic do dynamicznych embeddings oferuje ogromne korzyści praktyczne. LLM embeddings są bardzo wszechstronne i mogą być poddane fine-tuningowi do specjalistycznych downstream tasks. Są również znacznie bardziej kompaktowe niż masywne, klasyczne bit vectors, co oszczędza pamięć podczas przechowywania dużych bibliotek molekularnych. Co więcej, generowanie text embeddings działa na GPU, co jest drastycznie szybsze niż obliczanie tradycyjnych RDKit fingerprints na CPU.
Era ręcznego wskazywania algorytmom, które podstruktury chemiczne mają znaczenie, dobiega końca; modele, które działają najlepiej, to te, które mogą odczytać cząsteczkę i same podjąć decyzję. Jeśli chcesz wesprzeć program, wyszukaj DevStoriesEU na Patreonie. Dzięki za wspólnie spędzony czas. Mam nadzieję, że dowiedziałeś się czegoś nowego.
12
Active Learning w wirtualnym badaniu przesiewowym
4m 20s
Dowiedz się, jak iteracyjnie odkrywać najlepszych kandydatów na leki bez wyczerpującego testowania. Zagłębiamy się w pętle Active Learning i strategie zachłannej selekcji, aby zmaksymalizować wskaźnik trafień.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 12 z 22. Odpalanie złożonych symulacji fizycznych na milionie cząsteczek jest potwornie wolne. Potrzebujesz sposobu na znalezienie absolutnie najlepszych kandydatów, testując zaledwie ułamek swojego datasetu. Właśnie to robi Active Learning dla Virtual Screeningu.
Kiedy oceniasz bibliotekę chemiczną, obliczanie dokładnych powinowactw wiązania za pomocą metod fizyki obliczeniowej jest niezwykle kosztowne. Po prostu nie możesz sobie pozwolić na symulację każdego pojedynczego związku. Zamiast tego testujesz mały batch, wykorzystujesz te wyniki do trenowania modelu machine learningowego i pozwalasz mu przewidzieć powinowactwa dla reszty biblioteki. Następnie testujesz najbardziej obiecujące predykcje, aktualizujesz model i powtarzasz proces. Ten iteracyjny cykl to właśnie Active Learning.
Spójrzmy na konkretny scenariusz. Badasz serię kongeneryczną dziesięciu tysięcy związków celujących w konkretne białko, takie jak Tyk2. Twoim celem jest znalezienie topowego jednego procenta aktywnych cząsteczek. Aby zrobić to efektywnie, polegasz na strategii greedy. Strategia greedy oznacza, że twój model zawsze wybiera związki o najwyższym przewidywanym powinowactwie wiązania do kolejnej rundy testów.
Ustawiasz batch size na sześćdziesiąt cząsteczek na rundę. Ta liczba to praktyczny kompromis dla realnego workflow. Jest na tyle mała, że możesz szybko odpalić wymagające symulacje fizyczne na tym batchu, ale wystarczająco duża, by dostarczyć twojemu modelowi solidną porcję nowych danych. Odpalasz testy na tych sześćdziesięciu związkach, aby uzyskać ich rzeczywiste powinowactwa wiązania, i natychmiast przekazujesz te dane do dwuwymiarowego modelu opartego na drzewach, takiego jak XGBoost. Model XGBoost uczy się wzorców, ocenia pozostałe, nieprzetestowane cząsteczki z puli dziesięciu tysięcy związków i wybiera kolejnych sześćdziesięciu kandydatów.
I tu pojawia się kluczowy wniosek. To, jak wybierzesz pierwszy batch sześćdziesięciu cząsteczek, decyduje o tym, jak szybko uczy się cały twój system. Standardowy Active Learning często domyślnie przyjmuje losowy baseline. Wybierasz sześćdziesiąt cząsteczek całkowicie losowo, testujesz je i trenujesz swój pierwszy model. Ale losowa selekcja daje twojemu modelowi słaby punkt wyjścia, wypełniając początkowy training set głównie nieaktywnymi związkami.
Rozwiązaniem jest zainicjowanie pętli Active Learningu za pomocą pretrenowanej, trójwymiarowej sieci neuronowej. Ten model 3D został już wytrenowany na ogromnym, ogólnym datasecie różnorodnych kompleksów białek i ligandów. Ponieważ rozumie ogólną fizykę wiązania opartą na interakcjach strukturalnych, może ocenić twoje dziesięć tysięcy związków, zanim pętla Active Learningu w ogóle się rozpocznie.
Najpierw używasz pretrenowanego modelu 3D do predykcji powinowactwa dla całej puli. Następnie bierzesz topowe sześćdziesiąt cząsteczek zidentyfikowanych w tym prescreeningu i odpalasz na nich swoje ciężkie symulacje fizyczne. Teraz masz wysoce wzbogacony zestaw danych początkowych. Przekazujesz ten początkowy, wysokiej jakości dataset do swojego modelu XGBoost. Od tego momentu model XGBoost przejmuje cykl. Trenuje na zweryfikowanych danych, robi predykcje dla pozostałej puli i wybiera kolejnych sześćdziesięciu kandydatów metodą greedy.
Ta kombinacja generuje ogromne przyspieszenie w hit discovery. Ogólny model 3D zapewnia bogaty punkt wyjścia, a model XGBoost szybko adaptuje się do specyficznej przestrzeni chemicznej twojej serii kongenerycznej. Inicjując pętlę pretrenowanym modelem 3D zamiast random samplingiem, możesz znaleźć osiemdziesiąt procent z topowego jednego procenta binderów po przetestowaniu mniej niż dziesięciu procent całego datasetu. Rozpoczęcie pętli od ogólnego prescreeningu 3D daje twoim specjalistycznym modelom bezkonkurencyjną przewagę na starcie.
To wszystko w tym odcinku. Dzięki za wysłuchanie i keep building!
13
Wyzwanie klifów aktywności
4m 06s
Zbadaj kruchość relacji struktura-aktywność. Omawiamy „klify aktywności” – sytuacje, w których drobna zmiana strukturalna powoduje ogromną zmianę w sile działania leku.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 13 z 22. W chemii pojedynczy atom nie na swoim miejscu może zamienić silny, ratujący życie lek w obojętny proszek. Te nagłe spadki aktywności biologicznej nazywane są klifami aktywności i są absolutną zmorą tradycyjnych modeli AI.
Klif aktywności występuje, gdy masz parę cząsteczek o dużym podobieństwie strukturalnym, ale znacząco różnych poziomach aktywności. Wyobraź sobie konkretny scenariusz. Masz dwie cząsteczki, które współdzielą dziewięćdziesiąt procent swojego szkieletu strukturalnego. Pierwsza cząsteczka mocno wiąże się z celem biologicznym. Druga cząsteczka jest całkowicie nieaktywna. Jedyną fizyczną różnicą między nimi jest pojedyncza grupa metylowa przyłączona do konkretnego pierścienia. Dla człowieka, chemika medycznego, ta konkretna modyfikacja strukturalna niesie mnóstwo informacji. Mówi mu dokładnie, gdzie są granice kieszeni receptora. Dla standardowego modelu machine learning, to katastrofalne zaburzenie.
Oto kluczowy wniosek. Większość podejść deep learning w chemioinformatyce jest zbudowana tak, by przewidywać absolutne wartości właściwości. Niezależnie od tego, czy używasz graph neural network, czy chemical language model, architektura jest w gruncie rzeczy zaprojektowana tak, aby mapować struktury chemiczne na ciągłą przestrzeń matematyczną. Głównym założeniem zahardkodowanym w tych modelach jest to, że podobne struktury molekularne powinny mapować się na podobne właściwości biologiczne. Kiedy standardowy model przetwarza nasze dwie niemal identyczne cząsteczki, generuje reprezentacje, które leżą tuż obok siebie w tej matematycznej przestrzeni. Ponieważ inputy są blisko siebie, model naturalnie zwraca niemal identyczne predykcje absolutnej siły działania dla obu.
Klify aktywności całkowicie łamią to założenie o gładkiej, ciągłej przestrzeni chemicznej. Stanowią one poważną nieciągłość. Model spodziewa się łagodnego wzgórza, a napotyka pionowy spadek. Ten problem jest mocno potęgowany przez naturę danych w drug discovery. Eksperymentalne datasety są powszechnie znane z tego, że są ograniczone i zaszumione. Kiedy trenujesz deep neural network na rzadkich danych, model ma problemy z generalizacją. Aby zminimalizować ogólny błąd na całym training secie, sieć uczy się szerokich, globalnych wzorców. Wygładza lokalne nieregularności. Kiedy napotyka klif aktywności, standardowy cel regression traktuje ten nagły skok wariancji jako eksperymentalny szum albo outlier. Model ignoruje najważniejszą lokalną informację strukturalną, bo nie pasuje ona do globalnego trendu.
Właśnie dlatego przewidywanie klifów aktywności pozostaje jednym z najtrudniejszych problemów w predykcji właściwości molekularnych. Modele są zmuszone uczyć się nieciągłej przestrzeni chemicznej bezpośrednio z ograniczonych danych. Ponieważ skupiają się całkowicie na absolutnych predykcjach dla pojedynczych cząsteczek, kompletnie ignorują cenne informacje ukryte we względnych różnicach między dopasowanymi parami cząsteczek. W wielu przypadkach prostsze tree-based models ostatecznie radzą sobie lepiej niż złożone sieci neuronowe na tych datasetach, po prostu dlatego, że modele deep learning zbytnio wygładzają reprezentacje.
Założenie, że podobne struktury chemiczne zawsze dają podobne aktywności biologiczne, to użyteczny statystyczny baseline, ale nie jest to prawo fizyki. Klify aktywności to brutalna, nieciągła rzeczywistość relacji struktura-aktywność i dowodzą, że predykcja absolutnych właściwości w próżni zawsze zawiedzie na marginesach. Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
14
Similarity-Quantized Relative Learning
3m 41s
Rozwiąż problem klifów aktywności, zmieniając sposób uczenia się modeli. Badamy framework SQRL, który trenuje sztuczną inteligencję do przewidywania względnych różnic we właściwościach między ściśle filtrowanymi parami molekularnymi.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 14 z 22. Zamiast zmuszać AI do zapamiętywania absolutnej potencji każdej istniejącej cząsteczki, co by było, gdybyś po prostu nauczył ją pytać, czym dana cząsteczka różni się od swojego najbliższego znanego sąsiada? Ta zmiana perspektywy rozwiązuje poważny problem generalizacji w reżimach low-data i stanowi rdzeń frameworka o nazwie Similarity-Quantized Relative Learning, czyli SQRL.
Zwykle predykcja właściwości molekularnych traktuje każdą cząsteczkę jako izolowany data point. Model próbuje zmapować strukturę bezpośrednio na absolutną wartość właściwości. Przy małych, zaszumionych datasetach, modele deep learningowe mają trudności z budowaniem dokładnej globalnej mapy przestrzeni chemicznej. Wcześniejsze próby pairwise learningu próbowały rozwiązać ten problem, parując każdą cząsteczkę z każdą inną cząsteczką w training secie. To podejście zalewa dane porównaniami między zupełnie niepowiązanymi strukturami, zagłuszając użyteczny lokalny sygnał. SQRL rozwiązuje ten problem, ograniczając training data do par cząsteczek o wysokim stopniu podobieństwa strukturalnego. Model uczy się przewidywać względną różnicę w ich właściwościach, znaną jako delta y.
Osiąga się to poprzez konkretny krok dopasowania datasetu. Nie podajesz modelowi pojedynczych cząsteczek. Podajesz mu pary, ale tylko wtedy, gdy przejdą przez rygorystyczny próg podobieństwa. Przejdźmy przez tę logikę. Zaczynasz od swojego standardowego training setu cząsteczek i ich znanych potencji. Najpierw obliczasz pairwise distances między wszystkimi cząsteczkami, używając metryki takiej jak odległość Tanimoto na Morgan fingerprints.
Oto kluczowa kwestia. Ustawiasz próg odległości, alfa. Użyjmy progu odległości Tanimoto równego zero przecinek siedem. Iterujesz przez wszystkie możliwe pary cząsteczek. Jeśli odległość między cząsteczką A a cząsteczką B wynosi zero przecinek siedem lub więcej, odrzucasz tę parę całkowicie. Jeśli odległość jest ściśle mniejsza od zero przecinek siedem, dodajesz tę parę do swojego nowego, relatywnego training setu. Target variable dla tej nowej pary nie jest już absolutną potencją. Jest to dokładna liczbowa różnica w potencji między cząsteczką A a cząsteczką B.
Teraz trenujesz swoją sieć neuronową. Sieć generuje matematyczną reprezentację dla cząsteczki A i reprezentację dla cząsteczki B. Odejmuje reprezentację cząsteczki B od reprezentacji cząsteczki A. Powstały wektor różnicowy jest przepuszczany przez final layer w celu przewidzenia delty y. Odfiltrowując szum niepodobnych par, sieć jest zmuszona skupić się wyłącznie na lokalnych zmianach chemicznych o wysokim sygnale. Uczy się dokładnie, jak określona modyfikacja strukturalna wpływa na aktywność. To sprawia, że model jest bardzo wrażliwy na activity cliffs.
To tyle, jeśli chodzi o trening, ale co z predykcją dla zupełnie nowej cząsteczki? Gdy pojawia się nowa struktura, system skanuje oryginalne training data, aby znaleźć pojedynczego najbliższego sąsiada strukturalnego w oparciu o tę samą metrykę odległości Tanimoto. Sieć ewaluuje nową cząsteczkę względem tego najbliższego sąsiada i przewiduje względną deltę. Na koniec bierzesz znaną absolutną potencję sąsiada, dodajesz przewidzianą deltę i masz swoją ostateczną predykcję. Ograniczając training space do par o wysokim stopniu podobieństwa, przestajesz wymagać od modelu uczenia się całego chemicznego wszechświata, a zamiast tego trenujesz go, aby stał się ekspertem w zakresie lokalnych gradientów chemicznych.
To wszystko w tym odcinku. Dzięki za wysłuchanie i twórz dalej!
15
Rewolucja Generative AI
3m 47s
Przejdź od przewidywania właściwości do wyobrażania sobie zupełnie nowych cząsteczek. Mapujemy krajobraz molekularnych zadań generatywnych: generowanie De Novo, optymalizacja i generowanie konformerów.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 15 z 22. Przez lata AI w chemii polegało wyłącznie na selekcji. Wrzucałeś do modelu tysiące istniejących cząsteczek, a on po prostu przewidywał, które z nich są najmniej beznadziejne. Jeśli idealnej cząsteczki nie było w twojej bibliotece przesiewowej, model nie mógł ci pomóc. Rewolucja Generative AI całkowicie odwróciła tę dynamikę. Zamiast tylko filtrować to, co już istnieje, możemy teraz poinstruować modele, żeby wymyślały zupełnie nową materię chemiczną. To przejście od predykcji do kreacji dzieli się na dwa główne molekularne zadania generatywne: generowanie de novo i optymalizację molekularną. Generowanie de novo polega na tworzeniu nowych struktur molekularnych od zera. Model zaczyna od reprezentacji losowego szumu i iteracyjnie go udoskonala, aż powstanie poprawna struktura chemiczna. Kiedy robimy to bez żadnych ograniczeń, nazywamy to unconditional generation. Model swobodnie eksploruje ogromną przestrzeń chemiczną, żeby wygenerować coś zupełnie nowego. Choć jest to przydatne do szerokich odkryć, zazwyczaj potrzebujesz większej kontroli. To prowadzi nas do conditional generation, a konkretnie property-based generation. Tutaj to ty dyktujesz output. Podajesz konkretne ograniczenia, takie jak docelowa bioaktywność czy wymagany poziom syntezowalności, a model ogranicza generowanie do cząsteczek, które spełniają te kryteria. Często nazywa się to inverse molecule design, ponieważ zaczynasz od pożądanych właściwości i zmuszasz model do pracy wstecz, żeby zbudował strukturę molekularną, która je dostarczy. Generowanie de novo ma potężne możliwości, ale rzadko zaczynasz projekt z zerową wiedzą. Zazwyczaj masz już jakiś związek wiodący. I tu wkracza optymalizacja molekularna. W przeciwieństwie do zadań de novo, optymalizacja molekularna skupia się na modyfikacji znanej struktury, zamiast zaczynać od czystej karty. Bierzesz istniejącą cząsteczkę i udoskonalasz ją, żeby poprawić jej właściwości. Załóżmy, że masz umiarkowanie skuteczny scaffold leku. Wiąże się z twoim celem, ale jego bioaktywność jest zbyt niska, żeby mogło stać się sensownym lekiem. Używając modelu generatywnego, możesz przeprowadzić ukierunkowaną optymalizację molekularną. Jednym z podejść jest scaffold hopping. Instruujesz model, żeby zastąpił główny scaffold molekularny nowym, zachowując przy tym pierwotną aktywność biologiczną. Jest to bardzo skuteczne przy odkrywaniu strukturalnie nowych związków, które omijają istniejące patenty, zachowując jednocześnie nienaruszone zachowanie funkcjonalne. Innym podejściem jest R-group design. W tym scenariuszu blokujesz swój główny scaffold i instruujesz model generatywny, żeby automatycznie zoptymalizował jego łańcuchy boczne. Model generuje nowe grupy R, szukając konkretnych modyfikacji łańcuchów bocznych, które poprawią tę kulejącą bioaktywność. Nie wyrzucasz swojej umiarkowanie skutecznej cząsteczki, tylko pozwalasz AI obliczyć precyzyjne poprawki strukturalne potrzebne, żeby przepchnąć ją przez linię mety. I tu jest kluczowy wniosek. Przejście od predictive AI do generative AI oznacza, że nie jesteś już ograniczony cząsteczkami, które masz pod ręką. Niezależnie od tego, czy generujesz customową cząsteczkę od zera, czy algorytmicznie podmieniasz łańcuchy boczne istniejącego leku, traktujesz przestrzeń chemiczną jako programowalne medium. To wszystko w tym odcinku. Dzięki za słuchanie i twórz dalej!
16
Intuicja stojąca za dyfuzją molekularną
4m 19s
Rozkładamy na czynniki pierwsze podstawową koncepcję Diffusion Models bez skomplikowanej matematyki. Słuchacze zrozumieją proces w przód (dodawanie szumu do cząsteczki) oraz proces odwrotny (halucynowanie nowych struktur).
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 16 z 22. Aby nauczyć AI, jak wymyślić nową cząsteczkę, najpierw musisz ją nauczyć, jak całkowicie ją zniszczyć. Wydaje się to działać zupełnie na odwrót, ale ta systematyczna destrukcja to dokładnie ten sam mechanizm, który służy do generowania nowych leków od zera. To jest główna idea stojąca za Denoising Diffusion Probabilistic Models.
Tradycyjne projektowanie molekularne jest niezwykle pracochłonne. Jeśli chcesz zautomatyzować odkrywanie nowych związków, potrzebujesz modelu zdolnego do eksploracji ogromnej przestrzeni chemicznej bez generowania nieprawidłowych bzdur. Wczesne deep generative models próbowały bezpośrednio mapować tę przestrzeń. Denoising Diffusion Probabilistic Models, czyli DDPMs, idą inną drogą. Traktują generowanie cząsteczek jako problem progresywnego denoisingu.
Ten framework jest podzielony na dwa odrębne łańcuchy Markowa: forward process i reverse process.
Forward process polega wyłącznie na degradacji danych. Bierzesz prawidłowy, znany lek ze swojego training setu. W ustalonej sekwencji kroków, stopniowo rozmywasz jego współrzędne atomowe, wstrzykując czysty Gaussian noise. Ilość szumu dodawanego w każdym kroku jest kontrolowana przez ustalony hyperparameter schedule. W pierwszym kroku nieznacznie zaburzasz atomy. Cząsteczka jest nieco zniekształcona, ale wciąż wyraźnie rozpoznawalna. Przy pięćdziesiątym kroku struktura jest już mocno wykrzywiona. W ostatnim kroku, zazwyczaj oznaczanym jako krok T, oryginalna cząsteczka całkowicie znika. Zostajesz z losową chmurą nieustrukturyzowanego Gaussian noise.
Ten forward process nie wymaga sieci neuronowej. To czysto matematyczne zaburzenie. Służy to kluczowemu celowi, ponieważ generuje ground truth dla naszych danych treningowych.
Oto kluczowe spostrzeżenie. Ponieważ kontrolowaliśmy dokładną ilość szumu dodawanego w każdym pojedynczym kroku, mamy idealny zapis krok po kroku, jak ta cząsteczka się rozpadła.
To właśnie w reverse process do gry wkracza sieć neuronowa. Model jest trenowany, aby przejść dokładnie tę samą ścieżkę wstecz. Karmimy sieć zaburzoną cząsteczką w określonym time stepie. Następnie prosimy ją o przewidzenie konkretnego szumu, który został dodany, aby osiągnąć ten stan. Oceniamy model, porównując jego predykcję szumu z rzeczywistym szumem, który wstrzyknęliśmy podczas fazy forward. Aktualizujemy parametry modelu, aby zminimalizować tę różnicę. Z czasem sieć uczy się krok po kroku denoisować dane, stopniowo przywracając oryginalną dystrybucję danych.
Aby wygenerować zupełnie nową cząsteczkę, wykonujesz ten reverse process od zera. Najpierw samplujesz całkowicie losową chmurę Gaussian noise. Następnie przekazujesz ten szum do swojej wytrenowanej sieci neuronowej, wraz z początkowym numerem kroku. Sieć ocenia input, przewiduje potrzebną korektę strukturalną i zwraca nieco mniej zaszumioną chmurę atomów.
Zapętlasz ten proces odejmowania. Przekazujesz nowy output z powrotem do sieci na kolejny krok w dół. Z każdą iteracją losowa chmura się zacieśnia. Model stale usuwa szum. Gdy cofasz się do kroku zerowego, współrzędne atomowe wskakują na swoje miejsce i wyłania się prawidłowa struktura chemiczna. Wyciągasz zupełnie nową cząsteczkę z początkowego szumu.
Model nie tylko zapamiętuje bazę danych istniejących leków; on po prostu uczy się uniwersalnego procesu usuwania chaosu, aby pozostawić po sobie stabilną chemię. Jeśli chcesz wesprzeć podcast, możesz wyszukać DevStoriesEU na Patreon. Dzięki za wysłuchanie i twórzcie dalej!
17
Łączenie przestrzeni generatywnych 2D i 3D
4m 22s
Badamy, jak sztuczna inteligencja w rzeczywistości reprezentuje generowane przez siebie cząsteczki. Porównujemy generowanie płaskich grafów topologicznych 2D z generowaniem złożonych geometrycznych chmur punktów 3D oraz wyzwania związane z każdym z tych podejść.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 17 z 22. To, że model potrafi narysować płaski graf 2D cząsteczki, to jedno. Zupełnie innym inżynieryjnym koszmarem jest wygenerowanie stabilnej, geometrycznej chmury atomów w 3D. Możesz kazać modelowi generatywnemu zbudować piękną chmurę punktów 3D leku, która idealnie wypełnia docelową kieszeń białkową, tylko po to, by patrzeć, jak całość rozpada się w post-processingu, gdy system nie potrafi odgadnąć, gdzie powinny znaleźć się rzeczywiste wiązania kowalencyjne. Rozwiązaniem tego problemu jest łączenie generatywnych przestrzeni 2D i 3D.
W chemii generatywnej modalności danych determinują, co twój model jest w stanie zrozumieć. Pierwsza modalność to topologiczna przestrzeń 2D. Pomyśl o tym jak o standardowym grafie molekularnym. Węzły reprezentują atomy określonego typu, a krawędzie – łączące je wiązania chemiczne. Model zwraca macierz sąsiedztwa, która mówi ci dokładnie, co jest z czym połączone. Grafowe sieci neuronowe świetnie sobie z tym radzą. Problem polega na tym, że cząsteczki istnieją w świecie fizycznym, a nie na papierze. Graf 2D daje ci topologię wiązań, ale całkowicie ignoruje geometryczną strukturę 3D. Bez współrzędnych przestrzennych nie jesteś w stanie dokładnie obliczyć właściwości kwantowych ani przeprowadzić projektowania leków opartego na strukturze.
Aby to naprawić, modele przeszły na generowanie cząsteczek bezpośrednio w geometrycznej przestrzeni 3D. Tutaj na wyjściu otrzymujesz chmurę punktów. Model definiuje typy atomów oraz ich dokładne współrzędne X, Y i Z. Techniczną przeszkodą jest tutaj utrzymanie ekwiwariancji SE 3, co zapewnia, że cząsteczka pozostaje matematycznie spójna niezależnie od tego, jak zostanie obrócona lub przesunięta w przestrzeni. I tu pojawia się kluczowy wniosek. Generowanie w czystej przestrzeni 3D oznacza, że model nie generuje jawnie wiązań chemicznych. Po prostu umieszcza atomy w przestrzeni. Musisz wywnioskować topologię wiązań później, za pomocą algorytmów post-processingu. To wprowadza poważne błędy. Wracając do scenariusza z kieszenią na lek, twój model może ułożyć atomy w kształt, który fizycznie pasuje do celu, ale ponieważ podczas generowania w ogóle nie brał pod uwagę topologii wiązań, etap post-processingu może wywnioskować niemożliwe wiązania kowalencyjne. W przypadku większych cząsteczek, bezpośrednie generowanie stabilnej struktury 3D bez żadnych wskazówek topologicznych często daje suboptymalne rozwiązanie.
To prowadzi nas do generowania w połączonej przestrzeni 2D i 3D, co pozwala na jednoczesne stworzenie kompletnej struktury molekularnej. Model zwraca typy atomów, dyskretną macierz sąsiedztwa dla wiązań i ciągłe współrzędne przestrzenne – wszystko naraz. Dzięki połączeniu tych dwóch przestrzeni, modalności ograniczają i korygują się nawzajem podczas procesu generowania. Topologia 2D działa jak blueprint, kierując strukturą 3D, aby upewnić się, że układy przestrzenne są chemicznie wykonalne. Jednocześnie geometria 3D dopracowuje graf 2D, sugerując sensowne wzorce wiązań na podstawie bliskości przestrzennej.
Głównym wyzwaniem technicznym w tym połączonym podejściu jest zarządzanie dwoma fundamentalnie różnymi typami danych. Zmuszasz model do obsługi dyskretnych struktur topologicznych, takich jak typy wiązań, równolegle z ciągłymi strukturami geometrycznymi, takimi jak wartości współrzędnych. Różne architektury rozwiązują to w różny sposób. Framework o nazwie JODO traktuje zarówno struktury topologiczne, jak i geometryczne jako zmienne ciągłe, aby przetwarzać je razem. Inny model, MUDiff, obsługuje je oddzielnie, stosując proces dyskretny dla topologii i proces ciągły dla geometrii.
Nie możesz niezawodnie generować nowych, funkcjonalnych leków, zgadując ich fizyczny kształt i mając nadzieję, że wiązania chemiczne same się później ułożą. Prawdziwe generowanie molekularne wymaga, aby topologiczny blueprinting i pozycjonowanie przestrzenne oddziaływały na siebie i uzupełniały się w dokładnie tych samych obliczeniach. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
18
Generowanie uwzględniające cel i dokowanie
2m 07s
Odkryj projektowanie generatywne uwzględniające kontekst. Omawiamy generowanie nowych cząsteczek bezpośrednio wewnątrz kieszeni wiążącej białka chorobowego, aby zmaksymalizować powinowactwo wiązania.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 18 z 22. Po co prosić algorytm o wygenerowanie miliona losowych kluczy i testowanie ich jeden po drugim, skoro może po prostu spojrzeć bezpośrednio na zamek i wykuć customowy klucz prosto w dziurce? Tradycyjne drug discovery często opiera się na generowaniu ogromnych bibliotek kandydatów i ich filtrowaniu, ale to marnuje potężne zasoby obliczeniowe. Target-Aware Generation i Docking rozwiązuje ten problem, bezpośrednio wykorzystując trójwymiarową geometrię biologicznego targetu do budowania lub umieszczania cząsteczek.
W tych taskach generatywnych pracujemy wyłącznie w trójwymiarowej przestrzeni geometrycznej. Target-aware generation, znane również jako structure-based drug design, buduje nową cząsteczkę bezpośrednio w oparciu o strukturę 3D target binding pocket. Weźmy konkretny scenariusz z białkiem wirusowym. To białko ma bardzo specyficzną geometryczną wnękę. Zamiast generować cząsteczki w próżni, conditional diffusion model analizuje dokładne granice przestrzenne i właściwości chemiczne tej wnęki. Następnie customowo buduje nową strukturę ligandu bezpośrednio wewnątrz pocketu.
Model startuje z chmurą zaszumionych współrzędnych 3D i typów atomów zlokalizowanych w binding site. W kolejnych krokach robi denoise tej chmury. Ponieważ generowanie jest warunkowane przez target pocket, model umieszcza atomy i tworzy struktury, które naturalnie dopełniają wnękę, dążąc do zagwarantowania wysokiego affinity interakcji. Oto kluczowy insight. Algorytm nie tylko zgaduje kształt; on explicite uczy się relacji przestrzennej między targetem a potencjalnymi binderami. Niektóre podejścia wykorzystują nawet interaction-based retrieval, zaciągając dane ze znanych ligandów o wysokim affinity, aby dodatkowo nakierować generowanie tych target-specific cząsteczek.
To pokrywa temat generowania całkowicie nowej cząsteczki od zera wewnątrz pocketu. Ale często będziesz mieć już istniejącą cząsteczkę i będziesz musiał dokładnie wiedzieć, jak oddziałuje ona z biologicznym targetem. I to prowadzi nas do molecular docking.
Molecular docking przewiduje binding pose, aby ocenić binding affinity i specyficzność. W diffusion framework, modele przyjmują znaną cząsteczkę i strukturę targetu jako inputy. Zamiast generować tożsamość chemiczną, diffusion process operuje wyłącznie na przestrzennej orientacji cząsteczki. Model startuje z ligandem w losowej, zaszumionej pozie 3D i iteracyjnie robi jego denoise. Dopracowuje współrzędne przestrzenne cząsteczki, aż ustawi się ona w prawidłowej konfiguracji wiązania wewnątrz protein pocket.
Zaawansowane modele do dockingu idą o krok dalej, traktując sam target jako elastyczny byt. Model o nazwie Re-Dock wykorzystuje technikę zwaną diffusion bridge do przewidywania binding poses ligandu, jednocześnie modelując ruch łańcuchów bocznych pocketu. Tworzy to realistyczny, elastyczny scenariusz dockingu, w którym zarówno ligand, jak i target adaptują się do siebie w fazie predykcji.
Kluczowa zmiana polega na tym, że diffusion models odciągnęły structural drug design od sztywnych, izolowanych aproksymacji. Traktując zarówno wygenerowany ligand, jak i biologiczny pocket jako ciągły, adaptowalny system geometryczny, model natywnie wyrzuca na output cząsteczki i poses, które są fizycznie osadzone w precyzyjnej rzeczywistości środowiska targetu.
To wszystko w tym odcinku. Dzięki za odsłuch i keep building!
19
Pułapka rozmiaru w ewaluacji generatywnej
4m 12s
Dowiedz się, dlaczego standardowe benchmarki dla modeli generatywnych mogą być głęboko wadliwe. Ujawniamy zakłócający wpływ rozmiaru wygenerowanej biblioteki na metryki takie jak Fréchet ChemNet Distance.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 19 z 22. Oceniasz swój nowy model chemii generatywnej, samplując tysiąc cząsteczek, a metryki wyglądają fatalnie. Generujesz sto tysięcy z tego samego modelu i nagle okazuje się światowej klasy. Skala zmienia wszystko. To zjawisko nazywa się Pułapką Rozmiaru w Ewaluacji Generatywnej.
Generatywne pipeline'y odkrywania leków zazwyczaj przebiegają w trzech etapach. Trenujesz, generujesz i ewaluujesz. Kiedy specjaliści dochodzą do etapu ewaluacji, stają przed podstawowym pytaniem, ile projektów de novo wygenerować do benchmarkingu. Standardowa praktyka często domyślnie zakłada małe batche, zazwyczaj tysiąc lub dziesięć tysięcy stringów SMILES. Zespoły następnie przepuszczają te batche przez standardowe metryki dystrybucyjne. Najczęstszą jest Fréchet ChemNet Distance, czyli FCD. FCD mierzy, jak blisko wygenerowane przez ciebie cząsteczki znajdują się względem zbioru treningowego w przestrzeni chemicznej i biologicznej. Niższy wynik FCD oznacza, że wygenerowany rozkład ściśle pasuje do rozkładu docelowego. Inną popularną metryką jest Fréchet Descriptor Distance, czyli FDD, która porównuje rozkład właściwości fizykochemicznych, takich jak masa cząsteczkowa i topologiczna powierzchnia polarna. Zespoły rutynowo mierzą również Uniqueness, czyli odsetek wygenerowanych projektów, które są unikalne.
Oto kluczowy wniosek. Wszystkie te metryki są silnie zależne od fizycznego rozmiaru wygenerowanej biblioteki. Nie mierzą one bezwzględnej jakości modelu w próżni. Kiedy samplujesz zaledwie tysiąc cząsteczek, twoje wyniki FCD i FDD będą sztucznie zawyżone. Model wygląda tak, jakby nie zdołał nauczyć się rozkładu docelowego. Ale jeśli będziesz dalej samplować z tego samego modelu, zwiększając rozmiar biblioteki powyżej dziesięciu, pięćdziesięciu czy stu tysięcy cząsteczek, wynik FCD znacznie spadnie. Będzie spadał dalej, aż w końcu osiągnie plateau.
Dzieje się tak, ponieważ generatywne projektowanie cząsteczek polega na samplowaniu z bardzo złożonego, wyuczonego rozkładu prawdopodobieństwa. Malutka próbka tysiąca cząsteczek nie jest w stanie odpowiednio reprezentować pełnego zakresu outputu tego modelu. Algorytmy Fréchet distance potrzebują ogromnej liczby próbek, aby dokładnie uchwycić kształt wygenerowanej przestrzeni i porównać ją z przestrzenią fine-tuningu.
Rozważmy konkretny scenariusz, w którym porównujesz rekurencyjną sieć neuronową z transformerem. Jeśli ewaluujesz sieć rekurencyjną na stu tysiącach projektów, a transformera tylko na dziesięciu tysiącach, sieć rekurencyjna prawdopodobnie pokaże znacznie lepsze wyniki FCD i FDD. Ta różnica w wydajności nie ma nic wspólnego z architekturą. To czysty artefakt wielkości próby. Metryki nie zbiegły się dla mniejszej biblioteki.
Ta pułapka działa w odwrotną stronę, gdy spojrzysz na wewnętrzną różnorodność. Uniqueness zachowuje się zupełnie inaczej w dużej skali. Przy tysiącu cząsteczek prawie każdy poprawny string SMILES, który wygeneruje twój model, może być unikalny. Model wydaje się bardzo kreatywny. Ale kiedy dociągniesz generowanie do stu tysięcy, Uniqueness gwałtownie spada. Model zaczyna się powtarzać. Jeśli uszeregujesz różne modele generatywne na podstawie Uniqueness w małej skali, różnice między nimi wydają się niewielkie. Zwiększ skalę, a przepaść między modelami drastycznie się powiększy. Względny ranking twoich modeli może się wręcz odwrócić w zależności od rozmiaru biblioteki, której użyjesz do ich zmierzenia.
Aby to naprawić, musisz traktować rozmiar biblioteki jako ścisłą zmienną kontrolną w swoim pipeline'ie. Nigdy nie możesz wiarygodnie porównywać FCD, FDD ani Uniqueness między bibliotekami o różnych rozmiarach. Aby zapewnić rzetelną ocenę, powinieneś ewaluować biblioteki zawierające co najmniej sto tysięcy projektów, aby metryki dystrybucyjne w pełni się zbiegły. Jeśli twoje metryki ewaluacyjne zmieniają się tylko dlatego, że pozwoliłeś pętli samplowania działać dłużej, mierzysz rozmiar próby, a nie inteligencję modelu. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
20
Nawigowanie po halucynacjach De Novo
4m 10s
Inteligentnie oceniaj cząsteczki wygenerowane przez AI. Badamy kompromis między eksploracją a eksploatacją (exploration-exploitation tradeoff) w prawdopodobieństwach modelu oraz sposoby filtrowania częstych, niskiej jakości „chemicznych halucynacji”.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 20 z 22. To, że generative AI wypluwa konkretną cząsteczkę dziesięć tysięcy razy, nie oznacza, że to potencjalny lek. Możesz założyć, że częstotliwość generowania wskazuje na chemiczną jakość lub trafność. Tak nie jest. Te bardzo częste outputy to często chemiczny odpowiednik halucynacji large language model. Sposobem na rozwiązanie tego problemu jest nawigowanie po halucynacjach de novo przy użyciu model likelihood.
Kiedy generujesz ogromną bibliotekę miliona stringów SMILES z fine-tuned chemical language model, musisz zdecydować, które cząsteczki potraktować priorytetowo w badaniach prospektywnych. Standardowym, błędnym podejściem jest po prostu wybieranie projektów, które model zwraca najczęściej. Wpadasz wtedy w tak zwany count trap. Zamiast odkrywać solidnych kandydatów na leki, kończysz na wyciąganiu podstawowych, powtarzalnych podstruktur, takich jak izolowane pierścienie benzenowe, proste aminy i zwykłe etery. To są powtarzające się halucynacje strukturalne. Model generuje je bez przerwy nie dlatego, że są wysokiej jakości, ale dlatego, że są syntaktycznie proste do zbudowania.
Aby wykryć i odfiltrować te halucynacje, oceniasz swoją bibliotekę przy użyciu model likelihood. Likelihood to metryka, która określa, jak dobrze wygenerowana sekwencja pokrywa się z rozkładem prawdopodobieństwa, którego model nauczył się podczas treningu. Dla autoregressive model obliczasz to, mnożąc sampling probability każdego pojedynczego tokena w wygenerowanym stringu SMILES. Najpierw obliczasz likelihood score dla całego miliona wygenerowanych projektów. Następnie sortujesz całą bibliotekę na podstawie tych wyników. Na koniec dzielisz posortowaną bibliotekę na dziesięć równych grup, czyli decyli, od najniższego do najwyższego likelihood.
I tu robi się ciekawie. Analiza tych decyli ujawnia ścisły tradeoff między eksploracją a eksploatacją. Dziesiąty decyl zawiera generacje o najwyższym likelihood. Te projekty reprezentują eksploatację. Mają niezwykle wysoką chemiczną poprawność, a ich generyczne scaffoldy Bemisa-Murcko ściśle pasują do znanych aktywnych cząsteczek z twoich training data. Model mocno eksploatuje to, o czym już wie, że działa. Minusem jest to, że tym topowym projektom brakuje nowości. Zawierają bardzo mało nowych podstruktur, ponieważ model gra bezpiecznie.
Schodząc do środkowych decyli, trafiasz na równowagę. Nowość i unikalne podstruktury osiągają szczyt w tym środkowym przedziale, podczas gdy poprawność pozostaje akceptowalna. Ale kiedy schodzisz do pierwszego decyla – dziesięciu procent cząsteczek o absolutnie najniższych likelihood scores – wpadasz w count trap. Jeśli wyizolujesz projekty, które model wygenerował ponad dziesięć razy w całym runie na milion cząsteczek, prawie wszystkie skupiają się w tym najniższym decylu. Mają niewiarygodnie niskie model likelihoods, a mimo to pojawiają się z ogromną częstotliwością. Ich strukturalne podobieństwo do twojego training set jest fatalne, a ich ogólna chemiczna poprawność leci w dół.
Binując swoją bibliotekę w ten sposób, dowodzisz matematycznie, że częstotliwość to fałszywy sygnał jakości. Możesz systematycznie odrzucać biny o niskim likelihood i wysokiej częstotliwości, i skupić swój computational screening na środkowych decylach, gdzie zachodzi prawdziwa chemiczna eksploracja. Najczęstsze outputy z generative chemical model są często jego najgorszymi, ale filtrowanie twojej biblioteki przez decyle likelihood zamienia ten szum w precyzyjną mapę tego, gdzie model eksploruje, a gdzie tylko halucynuje.
To wszystko w tym odcinku. Dzięki za odsłuch i keep building!
21
Ograniczenia próbkowania cząsteczek
4m 14s
Zrozum, dlaczego techniki NLP zawodzą w chemii. Porównujemy Temperature sampling z Top-k i Top-p oraz wyjaśniamy, dlaczego ograniczone słownictwo chemiczne zmienia wszystko.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 21 z 22. W przetwarzaniu języka naturalnego Top-p sampling generuje genialnie kreatywny tekst. Ale zastosuj tę samą logikę do generowania cząsteczek, a twoje AI będzie po prostu w nieskończoność wypisywać identyczne pierścienie węglowe. Przyczyna sprowadza się do ograniczeń przy samplingu cząsteczek.
Kiedy chemiczny model językowy generuje SMILES string, buduje cząsteczkę token po tokenie. Model przewiduje rozkład prawdopodobieństwa dla kolejnego tokena, a ty musisz wyciągnąć z tego rozkładu konkretny wybór. Przy generowaniu tekstu, programiści mocno polegają na Top-k i Top-p sampling, żeby dokonać tego wyboru. Top-k ogranicza model do k absolutnie najbardziej prawdopodobnych tokenów. Top-p ogranicza wybór do najmniejszej grupy tokenów, których łączne prawdopodobieństwo przekracza docelowy procent p.
Jeśli zastosujesz te metody do chemicznego modelu językowego, skończy się to katastrofą. Jeśli użyjesz Top-k sampling z k ustawionym na 3 w modelu LSTM trenowanym na drug targets, twój model doświadczy poważnego mode collapse. Zwróci chemicznie poprawne cząsteczki, ale będą one całkowicie powtarzalne.
Oto kluczowa kwestia. Problem wynika z rozmiaru chemicznego słownika. Model tekstowy wybiera spośród setek tysięcy słów. Chemiczny model językowy używa mocno ograniczonego alfabetu. Ma do dyspozycji tylko garstkę pierwiastków, takich jak węgiel, tlen i azot, plus tokeny składniowe do rozgałęzień i zamykania pierścieni.
Ponieważ chemiczny alfabet jest malutki, a poprawna chemia wymaga sztywnych reguł składniowych, takich jak zamykanie każdego otwartego pierścienia, bardzo mały podzbiór tokenów absolutnie dominuje w rozkładzie prawdopodobieństwa. Węgiel i podstawowe tokeny strukturalne są prawie zawsze wysoce prawdopodobne. Kiedy stosujesz Top-k lub Top-p sampling, odcinasz długi ogon rozkładu prawdopodobieństwa. Model jest zmuszony do wybierania wyłącznie z tego wąskiego pasma dominujących tokenów. Wpada w pułapkę filtrowania, w nieskończoność powtarzając dokładnie te same podstawowe szkielety.
Żeby uciec z tej pułapki, musisz użyć Temperature sampling. Zamiast odfiltrowywać tokeny, Temperature sampling stosuje parametr wygładzania do surowych wyników sieci neuronowej przed obliczeniem ostatecznych prawdopodobieństw. To zmienia kształt całego rozkładu.
Wyobraź sobie scenariusz, w którym odpalasz fine-tuned model LSTM, żeby wygenerować nowych kandydatów na leki. Dostosowujesz parametr Temperature, T, żeby ustawić kompromis między poprawnością a różnorodnością. Jeśli ustawisz T nisko, w okolicach 0.5, rozkład prawdopodobieństwa tworzy ostry szczyt. Model mocno eksploatuje najbardziej prawdopodobne tokeny. Twój output będzie miał ekstremalnie wysoką poprawność chemiczną, ale strukturom zabraknie nowości. Będą ściśle naśladować zbiór treningowy.
Jeśli zwiększysz T do 1.5 lub 2.0, spłaszczysz rozkład prawdopodobieństwa. Teraz te mniej prawdopodobne tokeny mają matematyczną szansę na sampling. Twój model zaczyna eksplorować nową przestrzeń chemiczną. Liczba unikalnych podstruktur w twojej wygenerowanej bibliotece gwałtownie rośnie. Znajdujesz wysoce nowatorskie cząsteczki. Haczyk polega na tym, że wyższe temperatury zwiększają losowość, przez co model popełnia więcej błędów składniowych, a to zmniejsza ogólny odsetek poprawnych SMILES strings.
Nie możesz na ślepo przenosić strategii generowania tekstu do projektowania molekularnego. Ponieważ chemiczne słownictwo jest z natury ograniczone, Temperature scaling pozostaje najskuteczniejszą dźwignią do balansowania między ścisłą poprawnością chemiczną a eksploracją nowych struktur.
Dzięki za wspólnie spędzony czas. Mam nadzieję, że dowiedziałeś się czegoś nowego.
22
Wdrażanie cheminformatyki w chmurze
4m 46s
Przenieś swój potok AI na produkcję. Omawiamy pakowanie RDKit i modeli uczenia maszynowego w kontenery Docker oraz skalowanie obciążeń w infrastrukturze chmurowej.
Cześć, tu Alex z DEV STORIES DOT EU. Python Cheminformatics & AI, odcinek 22 z 22. Zbudowałeś na swoim laptopie najnowocześniejszy pipeline do odkrywania leków oparty na AI, ale jak przebadać miliard cząsteczek przez weekend? Odpowiedź brzmi: Deploy cheminformatyki w chmurze.
Przenoszenie modelu ze środowiska lokalnego do rozproszonej architektury chmurowej zazwyczaj wysypuje się na warstwie zależności. RDKit nie jest biblioteką w czystym Pythonie. To duży codebase w C++, który wymaga systemowych zależności, a w szczególności bibliotek Boost C++. Jeśli stawiasz zwykłe serwery w chmurze i odpalasz standardowe skrypty instalacyjne, często trafiasz na błędy kompilatora albo brakujące pliki shared object. Oficjalna dokumentacja RDKit podkreśla, że budowanie ze źródeł wymaga konkretnego toolchaina C++. Chociaż istnieją prekompilowane pip wheele, najpewniejszym sposobem na zagwarantowanie, że wszystkie zależności pod spodem będą się zgadzać, jest użycie Condy. Jednak dynamiczna instalacja Condy na tysiącach tymczasowych cloud workerów zajmuje zbyt dużo czasu i wprowadza niestabilność sieci podczas scale-upu.
Oto kluczowy insight. Całkowicie omijasz problem zależności, wrapując swój pipeline w kontener Dockera. Piszesz plik konfiguracyjny, który określa bazowy system operacyjny. Wewnątrz tego kontenera instalujesz lekkie środowisko Condy, pullujesz skompilowane binarki RDKit i dodajesz swoje frameworki machine learningowe, takie jak PyTorch czy XGBoost. Na koniec kopiujesz pre-trenowane wagi modelu do obrazu. Zbudowanie tego obrazu zamraża cały stack w pojedynczym, niezmiennym artefakcie. Cloud provider musi jedynie wiedzieć, jak uruchomić standardowy kontener Dockera. Złożone zależności C++ są bezpiecznie zamknięte w środku.
Aby przetworzyć miliony cząsteczek, oddzielasz przepływ danych od swoich compute workerów za pomocą cloud message queue. Dzielisz swój ogromny dataset stringów SMILES na mniejsze, łatwe do zarządzania chunki. Umieszczasz te chunki w cloud object storage i wysyłasz message zawierający lokalizację chunka do kolejki.
Następnie kierujesz skalowalny cloud compute service na tę kolejkę. W przypadku ciężkich workloadów akcelerowanych przez GPU, deployujesz swój kontener za pomocą usługi takiej jak AWS Batch. W przypadku lżejszego inference'u opartego na CPU, serverlessowe platformy kontenerowe, takie jak Google Cloud Run czy AWS Lambda, doskonale sobie z tym radzą. Konfigurujesz compute service tak, aby automatycznie skalował się w zależności od głębokości kolejki. Jeśli czeka pięćdziesiąt tysięcy message'y, cloud controller podnosi jednocześnie tysiące identycznych kontenerów Dockera.
Każdy kontener łączy się z kolejką i przejmuje jeden message. Pobiera odpowiadający mu chunk stringów SMILES. RDKit konwertuje SMILES na grafy molekularne, oblicza wymagane deskryptory i przekazuje je do twojego modelu machine learningowego w celu inference'u. Kontener zapisuje cząsteczki o najwyższym wyniku bezpośrednio do zarządzanej cloudowej bazy danych. Po przetworzeniu chunka, worker usuwa message z kolejki i łapie następny. Gdy kolejka jest pusta, infrastruktura chmurowa automatycznie terminuje kontenery. Płacisz tylko za dokładną liczbę sekund compute'u, które faktycznie skonsumował twój kod.
Skalowanie cheminformatyki rzadko polega na pisaniu szybszych struktur pętli w Pythonie; chodzi o niezawodne pakowanie środowiska i wykorzystanie decoupled cloud architecture do równoległego przetwarzania danych. To kończy naszą serię o Python Cheminformatics i AI. Zachęcam cię do zapoznania się z oficjalną dokumentacją RDKit dotyczącą instalacji, wypróbowania konteneryzacji prostego skryptu hands-on, lub odwiedzenia DEV STORIES DOT EU, aby zasugerować tematy do przyszłych serii. To wszystko w tym odcinku. Dzięki za słuchanie i keep building!
Tap to start playing
Browsers block autoplay
Share this episode
Episode
—
Copy this episode in another language:
Ta strona nie używa plików cookie. Nasz dostawca hostingu może rejestrować Twój adres IP do celów analitycznych. Dowiedz się więcej.