Ediția 2026. Un curs practic care poartă dezvoltatorii Python de la concepte de bază de chimie la proiectarea sistemelor de cheminformatică bazate pe AI. Învață cum să folosești RDKit, scikit-fingerprints și tehnici de ultimă generație de deep learning precum Graph Neural Networks și Diffusion Models pentru descoperirea de medicamente.
Calcul științificChimioinformaticăDeep Learning pentru știință
Introducem RDKit și conceptul de bază al reprezentării chimiei în Python. Ascultătorii vor învăța cum să inițializeze obiecte moleculare din șiruri de caractere și să înțeleagă rolul central al framework-ului în descoperirea de medicamente cu AI.
4m 22s
2
I/O în cheminformatică
Învață cum să ingerezi și să exporți în siguranță dataset-uri chimice masive. Acoperim citirea fișierelor SDF și SMILES, gestionarea erorilor de parsare și scrierea datelor înapoi pe disc.
4m 19s
3
Parcurgerea grafurilor moleculare
Descoperă cum sunt reprezentate moleculele ca structuri de date de tip graf. Explorăm iterarea prin atomi, analizarea legăturilor și identificarea sistemelor de inele din cadrul moleculelor.
4m 05s
4
Căutarea de substructuri
Stăpânește arta interogării moleculelor folosind SMARTS. Trecem prin găsirea grupurilor funcționale specifice și a tiparelor în cadrul structurilor chimice complexe.
4m 43s
5
Fingerprinting și similaritate moleculară
Explorează cum să traduci grafurile moleculare în vectori matematici de biți. Acoperim MACCS keys, Morgan fingerprints și calcularea similarității Tanimoto.
4m 15s
6
Depășirea planului 2D
Tranziția de la desene 2D plane la geometrii 3D realiste. Discutăm despre adăugarea de hidrogeni expliciți și generarea de conformeri 3D de încredere folosind ETKDG.
4m 33s
7
Accelerarea procesului de feature engineering
Creează o punte între cheminformatică și data science-ul standard cu scikit-fingerprints. Explorăm generarea a peste 30 de tipuri de molecular fingerprints direct într-o interfață scikit-learn.
4m 17s
8
Cheminformatică de înaltă performanță
Învață cum să procesezi eficient dataset-uri chimice masive. Aprofundăm utilizarea paralelismului CPU cu Joblib și economisirea memoriei folosind matrice rare din SciPy.
4m 23s
9
Pipeline-uri de ML End-to-End
Combină procesarea, fingerprinting-ul și predicția într-o singură arhitectură curată. Construim pipeline-uri scikit-learn robuste care integrează perfect generarea de conformeri 3D și predicția proprietăților.
4m 19s
10
Predicția afinității de legare
Explorează realitatea predicției afinității de legare proteină-ligand. Comparăm performanța modelelor simple 2D bazate pe arbori cu cea a rețelelor complexe 3D Graph Neural Networks.
3m 59s
11
LLMs vs Fingerprints clasice
Descoperă cum se aplică Natural Language Processing în chimie. Punem față în față vector embeddings din Large Language Models cu structural fingerprints clasice din RDKit pentru predicția bioactivității.
4m 26s
12
Active Learning pentru screening virtual
Învață cum să descoperi iterativ cei mai buni candidați pentru medicamente fără testare exhaustivă. Aprofundăm buclele de active learning și strategiile de selecție greedy pentru a maximiza ratele de succes.
4m 20s
13
Provocarea Activity Cliff
Examinează fragilitatea relațiilor structură-activitate. Discutăm despre „activity cliffs” — unde o schimbare structurală minusculă provoacă o modificare masivă a potenței unui medicament.
3m 52s
14
Similarity-Quantized Relative Learning
Rezolvă problema activity cliff regândind modul în care învață modelele. Explorăm framework-ul SQRL, care antrenează AI-ul să prezică diferențele relative de proprietăți între perechi moleculare strict filtrate.
3m 42s
15
Revoluția Generative AI
Tranziția de la predicția proprietăților la imaginarea unor molecule complet noi. Cartografiem peisajul sarcinilor generative moleculare: generarea De Novo, optimizarea și generarea de conformeri.
3m 56s
16
Intuiția din spatele Molecular Diffusion
Descompunem conceptul de bază al diffusion models fără matematică grea. Ascultătorii vor înțelege procesul forward de adăugare a zgomotului la o moleculă și procesul reverse de halucinare a unor noi structuri.
3m 54s
17
Conectarea spațiilor generative 2D și 3D
Explorăm modul în care AI-ul reprezintă de fapt moleculele pe care le generează. Comparăm generarea de grafuri topologice 2D plane cu generarea de point clouds geometrice 3D complexe și provocările fiecăreia.
4m 27s
18
Generare Target-Aware și Docking
Descoperă designul generativ context-aware. Discutăm despre generarea de molecule noi direct în interiorul buzunarului de legare al unei proteine asociate cu o boală pentru a maximiza afinitatea de legare.
3m 38s
19
Capcana dimensiunii în evaluarea generativă
Învață de ce benchmark-urile standard pentru modelele generative pot fi profund viciate. Dezvăluim efectul de confuzie al dimensiunii bibliotecii generate asupra metricilor precum Fréchet ChemNet Distance.
4m 46s
20
Navigarea prin halucinațiile De Novo
Clasează inteligent moleculele generate de AI. Explorăm compromisul exploration-exploitation al probabilităților modelului și cum să filtrăm „halucinațiile chimice” frecvente, de calitate slabă.
4m 15s
21
Constrângeri în eșantionarea moleculelor
Înțelege de ce tehnicile de NLP eșuează în chimie. Comparăm Temperature sampling cu Top-k și Top-p, și de ce vocabularul chimic constrâns schimbă totul.
4m 35s
22
Implementarea cheminformaticii în Cloud
Du-ți pipeline-ul de AI în producție. Discutăm despre împachetarea RDKit și a modelelor de machine learning în containere Docker și scalarea volumelor de lucru pe infrastructura de cloud.
3m 55s
Episoade
1
Molecula digitală
4m 22s
Introducem RDKit și conceptul de bază al reprezentării chimiei în Python. Ascultătorii vor învăța cum să inițializeze obiecte moleculare din șiruri de caractere și să înțeleagă rolul central al framework-ului în descoperirea de medicamente cu AI.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics și AI, episodul 1 din 22. Înainte să poți prezice toxicitatea unui medicament cu un machine learning model, trebuie să rezolvi o problemă fundamentală. Ai nevoie de o metodă prin care să-l înveți pe Python ce este, de fapt, o moleculă. Tipurile de date standard, cum ar fi strings și lists, nu înțeleg atomii, legăturile chimice sau structurile inelare. Pentru a acoperi acest gol, ai nevoie de un traducător universal între chimie și cod. Exact asta oferă RDKit, introducând conceptul de moleculă digitală.
RDKit este toolkit-ul open-source, standard în industrie, pentru cheminformatică. În esență, este o library C++ de înaltă performanță, dar expune o interfață Python masivă și intuitivă. Există pentru că reprezentarea computațională a structurilor chimice este surprinzător de dificilă. O moleculă este matematic un graf. Atomii sunt nodes, iar legăturile chimice sunt edges care conectează acele nodes. Dacă încerci să construiești un graph parser custom de la zero de fiecare dată când vrei să analizezi date chimice, îți vei petrece tot timpul făcând debugging pe edge cases. RDKit abstractizează această complexitate, gestionând logica de graf under the hood.
Pentru a aduce o moleculă în Python, ai nevoie mai întâi de o reprezentare text a structurii sale. Cel mai comun format este un string SMILES. SMILES folosește caractere standard pentru a reprezenta conectivitatea chimică. De exemplu, un atom de carbon izolat este pur și simplu un C mare. Benzenul, care este un inel cu șase atomi de carbon cu legături duble alternante, este scris ca un c mic, numărul unu, încă patru caractere c mici și un c mic final urmat de numărul unu pentru a închide inelul.
Iată ideea cheie. Acel string SMILES este doar plain text. Pentru Python, este imposibil de distins de o parolă sau de un file path. Nu poți calcula greutatea moleculară dintr-un raw string. Pentru a face chimie reală, trebuie să îl convertești într-un molecule object RDKit. Faci asta importând modulul Chem din RDKit. Apoi, apelezi o funcție specifică, concepută pentru a crea o moleculă dintr-un string SMILES, și îi pasezi variabila ta text.
Când pasezi string-ul SMILES pentru benzen acestei funcții, RDKit face greul. Parsează textul, construiește graful de nodes și edges, atribuie ordinele de legătură și validează regulile chimice de bază, cum ar fi valențele atomice. Dacă string-ul reprezintă o moleculă validă, funcția returnează un molecule object. Dacă îi pasezi o structură chimic imposibilă sau un typo, funcția dă fail în siguranță. Afișează un warning în console și returnează un null object. Din acest motiv, ar trebui să verifici întotdeauna dacă acel molecule object există cu adevărat înainte de a-l pasa către următorul pas al programului tău.
Odată ce ai acel molecule object validat în memorie, întregul ecosistem RDKit se deblochează. Nu mai lucrezi cu text; lucrezi cu un graf chimic computabil. Concluzia esențială aici este că string-urile SMILES sunt strict pentru stocare și transfer de date, dar molecule objects din RDKit sunt pentru calcul. Tot ce faci în chimia computațională începe cu efectuarea acestei conversii.
Dacă vrei să ajuți la susținerea emisiunii, poți căuta DevStoriesEU pe Patreon — ne ajută foarte mult. Asta e tot pentru acest episod. Mersi că ai ascultat și continuă să construiești!
2
I/O în cheminformatică
4m 19s
Învață cum să ingerezi și să exporți în siguranță dataset-uri chimice masive. Acoperim citirea fișierelor SDF și SMILES, gestionarea erorilor de parsare și scrierea datelor înapoi pe disc.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 2 din 22. O singură coordonată lipsă într-un dataset cu un milion de molecule îți poate bloca întregul pipeline. Dacă presupui că fiecare înregistrare text din fișierul vendorului tău este chimie perfect formatată, scriptul tău Python va arunca până la urmă o excepție fatală la jumătatea unui job de zece ore. Să te aperi de datele murdare în timp ce muți structuri în și din scripturile tale este obligatoriu, și exact asta rezolvăm astăzi cu I/O în Cheminformatics.
Când primești un fișier standard structure-data, sau SDF, plin de potențiali liganzi, ai nevoie de o metodă să îl parsezi. În RDKit, tool-ul default pentru asta este SD molecule supplier. Îl inițializezi pasând file path-ul ca un string. Acest obiect supplier se comportă foarte asemănător cu o listă Python. Poți face loop prin el, îi poți cere lungimea totală și poți extrage o anumită înregistrare după numărul ei de index. Face asta scanând rapid fișierul ca să găsească unde începe fiecare moleculă, permițându-ți să sari prin date.
Uneori nu poți scana în avans. Dacă faci pipe la date direct dintr-un web stream, sau citești un fișier gzipped masiv chunk cu chunk, nu ai random access. Pentru aceste situații, folosești forward SD molecule supplier. În loc de un file path, îi pasezi un file object deschis. Acest forward supplier este un iterator strict. Citește o moleculă, o parsează și trece imediat la următoarea. Nu îi poți cere lungimea și nu poți cere a cincizecea moleculă fără să le citești pe primele patruzeci și nouă. Dai la schimb flexibilitatea pentru un memory usage redus și compatibilitate cu stream-urile.
Iată ideea cheie. Indiferent de ce supplier folosești, RDKit nu aruncă o excepție Python atunci când întâlnește o moleculă coruptă. Dacă un text block din fișierul tău are o valență invalidă sau un typo de formatare, RDKit va da output la un mesaj de eroare în consolă, dar obiectul Python efectiv pe care îl dă prin yield pentru acea iterație a loop-ului va fi pur și simplu de tipul None.
Dacă iei acel obiect None și încerci să-i calculezi greutatea sau să-l scrii într-un fișier nou, scriptul tău va da crash. Gestionarea acestei situații este simplă, dar critică. Prima linie din loop-ul tău de parsare trebuie să verifice mereu dacă molecula obținută prin yield este None. Dacă este None, folosești statement-ul continue ca să sari la următoarea înregistrare. Asta filtrează silențios datele garbage și îți menține pipeline-ul în funcțiune.
După ce ai parsat și filtrat în siguranță moleculele valide, de obicei trebuie să salvezi rezultatele. Pentru asta, folosești SD writer. Inițializezi writer-ul pasând output file path-ul dorit. În interiorul loop-ului tău sigur, imediat după verificarea de None, pasezi obiectul moleculă valid writer-ului folosind metoda sa write. După ce loop-ul termină de procesat fiecare ligand, apelezi metoda close pe writer ca să te asiguri că toate datele primesc flush pe disk în siguranță. De asemenea, poți face wrap la writer într-un context manager Python standard, astfel încât să se închidă automat la sfârșitul block-ului.
Ca să punem toate astea cap la cap pentru un script de data cleaning, în primul rând, creezi SD writer-ul pentru output file. În al doilea rând, creezi SD molecule supplier-ul pentru input file. Faci loop prin supplier. Verifici dacă item-ul curent este None, și dacă da, dai skip. Dacă este valid, îl pasezi writer-ului. Închizi writer-ul la final. Tratează mereu dataset-urile externe de chimie ca fiind inerent murdare; să verifici că o moleculă parsatǎ nu este None este cea mai ieftină poliță de asigurare pe care o va avea vreodată codul tău.
Asta e tot pentru acest episod. Mersi de audiție, și continuă să construiești!
3
Parcurgerea grafurilor moleculare
4m 05s
Descoperă cum sunt reprezentate moleculele ca structuri de date de tip graf. Explorăm iterarea prin atomi, analizarea legăturilor și identificarea sistemelor de inele din cadrul moleculelor.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 3 din 22. Pentru un computer, o moleculă nu este un obiect fizic care ocupă spațiu. Este strict un graf de noduri și muchii care așteaptă să fie parsat. Dacă nu poți naviga eficient prin acel graf subiacent, nu poți analiza structura chimică. Acest lucru ne aduce direct la traversarea grafurilor moleculare.
În RDKit, un obiect de tip moleculă acționează ca un container principal pentru această structură de date a grafului. Pentru a inspecta nodurile, folosești metoda GetAtoms. Aceasta returnează o secvență iterabilă care conține toate obiectele de tip atom din moleculă. Poți scrie un loop simplu pentru a parcurge această secvență pas cu pas. Pentru un scenariu concret, să presupunem că trebuie să extragi numerele atomice ale tuturor nodurilor tale. În interiorul loop-ului tău, poți apela metoda GetIdx pentru a găsi identificatorul numeric unic pentru atomul curent și metoda GetAtomicNum pentru a afla exact ce element chimic este. Iterând prin ea, procesezi fiecare nod în mod sistematic.
Nodurile singure nu definesc chimia. De asemenea, ai nevoie de muchiile care le conectează, pe care le accesezi folosind metoda GetBonds. La fel ca în cazul atomilor, aceasta oferă o secvență iterabilă de obiecte de tip bond. Un bond își cunoaște locul exact în graf. Apelând metodele GetBeginAtomIdx și GetEndAtomIdx pe un obiect de tip bond, extragi identificatorii numerici specifici ai celor doi atomi pe care îi conectează. De asemenea, poți citi tipul de bond, determinând dacă este o conexiune simplă, dublă sau aromatică. Iată ideea principală. RDKit tratează bond-urile ca first-class objects în ierarhia grafului, ceea ce înseamnă că le interoghezi independent, în loc să le extragi din proprietățile atomilor.
Navigarea nodurilor și muchiilor individuale ține de logica standard a grafurilor, dar grafurile chimice prezintă frecvent cicluri, mai cunoscute sub numele de rings. Nu este nevoie să îți scrii proprii algoritmi de traversare pentru găsirea ciclurilor. RDKit precalculează aceste cicluri atunci când molecula este instanțiată. Accesezi aceste date prin metoda GetRingInfo. Aceasta returnează un obiect dedicat de tip ring info, în loc de o simplă listă.
Dacă task-ul tău este pur și simplu să afli numărul de rings din moleculă, apelezi metoda NumRings direct pe acest obiect de tip ring info. Când ai nevoie de detalii structurale mai profunde, poți solicita aceluiași obiect proprietatea AtomRings. Aceasta îți oferă o colecție de secvențe, unde fiecare secvență conține indecșii atomici exacți care alcătuiesc un anumit ring din graf. Poți chiar să pasezi un index atomic obiectului de tip ring info pentru a întreba dacă acel nod specific participă la un ring de o anumită dimensiune, cum ar fi un ciclu cu cinci sau șase membri.
Traversarea unei molecule înseamnă, în cele din urmă, chaining-ul acestor operații de bază. Iei ring info-ul pentru a verifica macrostructura, faci un loop peste atomi pentru a citi date la nivel de nod, cum ar fi numerele atomice, și faci un loop peste bond-uri pentru a mapa conexiunile specifice ale muchiilor. Odată ce nu mai vezi o moleculă ca pe o entitate fizică și începi să o vezi ca pe o colecție previzibilă de noduri indexate, muchii și cicluri precalculate, extragerea proprietăților structurale devine un task standard de data parsing. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
4
Căutarea de substructuri
4m 43s
Stăpânește arta interogării moleculelor folosind SMARTS. Trecem prin găsirea grupurilor funcționale specifice și a tiparelor în cadrul structurilor chimice complexe.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 4 din 22. Nu ai încerca să parsezi mii de log-uri text fără să folosești expresii regulate. În mod similar, nu ar trebui să încerci să filtrezi bazele de date chimice fără pattern-uri SMARTS. Găsirea unor grupuri funcționale specifice în dataset-uri mari necesită o logică structurală dedicată, și exact asta oferă Substructure Searching.
Să presupunem că ai o librărie de medicamente candidate. Scopul tău este să marchezi și să izolezi orice moleculă care conține un grup funcțional toxic specific, cunoscut. Mai întâi, definești acel grup toxic folosind un string SMARTS. SMARTS este o extensie a SMILES concepută special pentru a face query pe pattern-uri moleculare, permițându-ți să specifici wildcard-uri, tipuri specifice de legături sau structuri inelare. Pasezi acest string de text funcției RDKit care creează o moleculă din SMARTS. Aceasta generează obiectul tău query. Moleculele tale țintă, medicamentele candidate, sunt deja obiecte moleculă standard în RDKit.
Pentru a filtra librăria, iei o moleculă candidată și apelezi metoda numită has substructure match. Pasezi obiectul tău query în această metodă. Ea evaluează molecula candidată pe baza pattern-ului și returnează o valoare booleană simplă. True înseamnă că grupul toxic există undeva în interiorul candidatului. False înseamnă că este curat. Deoarece această metodă oprește căutarea în momentul în care găsește un singur match valid, este extrem de optimizată. Poți face un loop cu această verificare booleană peste întreaga ta librărie pentru a împărți rapid un dataset masiv în subseturi sigure și marcate.
Acum, ce te faci dacă doar să știi că grupul toxic este prezent nu e suficient? Poate că toxicitatea crește odată cu numărul de apariții ale grupului sau trebuie să izolezi locația exactă a atomilor toxici pentru un biolog structural. Pentru asta, folosești metoda numită get substructure matches, la plural. Apelezi această metodă pe molecula candidată, pasând din nou obiectul query. În loc de un boolean, această metodă forțează motorul de căutare să mapeze fiecare apariție posibilă a pattern-ului.
Ea returnează un tuple care conține alte tuple. Fiecare tuple interior reprezintă un match complet al pattern-ului tău. Integer-urile din interiorul acestor tuple sunt indicii atomici exacți din cadrul moleculei candidate. Iată detaliul cheie. Ordinea acestor indici reflectă perfect ordinea atomilor definiți în string-ul SMARTS original. Asta înseamnă că știi întotdeauna exact care atom din țintă corespunde cărei părți din query-ul tău. Dacă grupul toxic apare de trei ori în candidat, obții trei tuple interne. Poți număra tuplele pentru a găsi frecvența pattern-ului sau poți pasa acei indici atomici specifici într-o funcție de desen pentru a evidenția vizual regiunile toxice. Dacă ai nevoie doar de indicii atomici ai primului match pe care îl găsește, poți folosi metoda la singular get substructure match pentru a economisi timp de procesare.
De asemenea, trebuie să iei în considerare stereochimia. By default, substructure matching-ul din RDKit ignoră complet chiralitatea. O legătură wedge și o legătură dash vor declanșa ambele un match pentru un query SMARTS de bază. Dacă toxicitatea țintei tale apare doar cu un anumit stereoizomer, acest comportament default va genera rezultate fals pozitive în screening-ul tău de medicamente. Pentru a remedia acest lucru, pasezi un argument numit use chirality și îl setezi pe true atunci când apelezi oricare dintre metodele de matching. RDKit va aplica apoi reguli stereochimice bazate pe configurația specifică definită în query-ul tău.
Adevărata putere a Substructure Searching-ului constă în faptul că mapează un query de text pur logic direct pe topologia fizică a dataset-ului tău, eliminând decalajul dintre pattern-urile abstracte de tip string și coordonatele atomice concrete. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
5
Fingerprinting și similaritate moleculară
4m 15s
Explorează cum să traduci grafurile moleculare în vectori matematici de biți. Acoperim MACCS keys, Morgan fingerprints și calcularea similarității Tanimoto.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 5 din 22. Modelele AI nu înțeleg de fapt atomii și legăturile. Ele înțeleg doar numere. Dacă vrei ca un algoritm să compare două structuri, ai nevoie de o modalitate de a traduce chimia în matematică. Fingerprinting-ul și similaritatea moleculară reprezintă exact modul prin care facem această punte.
O moleculă în RDKit este în esență un graf matematic. Atomii acționează ca noduri, iar legăturile acționează ca muchii. Pentru a efectua calcule rapide pe aceste grafuri, le convertim în bit vectors, care sunt doar array-uri lungi de unu și zero. Acest array se numește fingerprint. Logica este simplă. Dacă o anumită caracteristică structurală există în moleculă, un anumit bit din array este setat pe unu. Dacă acea caracteristică lipsește, bitul rămâne zero. Prin convertirea grafurilor moleculare complexe în bit vectors standard, le putem compara cu ușurință matematic.
RDKit oferă mai mulți algoritmi de fingerprinting. Fingerprint-ul default din RDKit folosește o abordare topologică. Acesta analizează path-urile liniare prin moleculă. Sistemul începe de la un atom și urmărește legăturile conectate până la o lungime specifică, de obicei între una și șapte legături. Fiecare path unic pe care îl găsește este trecut printr-o funcție de hashing, care atribuie acel path unei poziții specifice în bit vector.
Deși path-urile topologice sunt utile, cheminformatica modernă se bazează în mare măsură pe fingerprint-urile Morgan, adesea numite fingerprint-uri circulare. În loc să urmărească path-uri liniare, algoritmii Morgan analizează vecinătatea care radiază spre exterior de la fiecare atom. Atunci când generezi un fingerprint Morgan, trebuie să definești o rază. O rază de zero înseamnă că algoritmul înregistrează doar atomii individuali. O rază de unu capturează fiecare atom plus vecinii săi imediați conectați. O rază de doi extinde acel cerc cu încă o legătură. Algoritmul cataloghează toate aceste medii circulare suprapuse, le face hash și setează biții corespunzători pe unu. De obicei, facem fold la aceste hash-uri într-un vector cu lungime fixă, cum ar fi două mii patruzeci și opt de biți, pentru a menține utilizarea memoriei previzibilă. Fingerprint-urile Morgan cu o rază de doi sunt standardul în industrie, deoarece capturează excelent grupurile funcționale și contextul chimic local.
Să analizăm un scenariu concret. Ai două molecule ușor diferite. Poate că împart o structură centrală mare, dar una are atașată o grupare metil suplimentară. Vrei să cuantifici cât de mult se suprapun. Mai întâi, citești ambele molecule în RDKit. Apoi, generezi un fingerprint Morgan pentru fiecare, setând raza la doi. Acum ai doi bit vectors distincți. Pentru a calcula cât de asemănătoare sunt, calculezi similaritatea lor Tanimoto.
Iată ideea cheie. Similaritatea Tanimoto ignoră zerourile. Ține cont doar de feature-urile care sunt de fapt prezente. Matematica este simplă: intersection over union. RDKit numără biții setați pe unu în ambele fingerprint-uri și împarte la numărul total de biți setați pe unu în oricare dintre fingerprint-uri. Dacă cei doi vectori se potrivesc perfect, scorul Tanimoto este unu punct zero. Dacă nu au niciun feature în comun, scorul este zero punct zero. Pentru cele două molecule ale noastre care diferă printr-o singură grupare metil, mediile circulare din jurul nucleului se vor potrivi în mare parte, în timp ce mediile din apropierea mutației vor diferi. S-ar putea să obții un scor Tanimoto de zero punct optzeci și cinci, ceea ce îți oferă o valoare numerică precisă pentru suprapunerea lor structurală.
Reține că maparea unei molecule complexe la un array fix de biți înseamnă pierderea unor date, iar un scor Tanimoto ridicat garantează suprapunerea structurală, nu echivalența biologică.
Mersi că ai petrecut câteva minute cu mine. Până data viitoare, numai bine.
6
Depășirea planului 2D
4m 33s
Tranziția de la desene 2D plane la geometrii 3D realiste. Discutăm despre adăugarea de hidrogeni expliciți și generarea de conformeri 3D de încredere folosind ETKDG.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 6 din 22. Un desen bidimensional ar putea arăta grozav pe ecran, dar medicamentele există în spațiul tridimensional. Dacă ignori geometria, ignori realitatea. Astăzi, spargem planul 2D și generăm coordonate 3D corecte pentru moleculele tale.
Când citești o moleculă dintr-un string SMILES standard, aceasta nu are deloc coordonate. Este strict un graf topologic de atomi conectați. Chiar dacă încarci o structură dintr-un fișier cu un desen 2D, acele coordonate sunt doar spațiate pentru a fi ușor de citit de către oameni. Pentru a face docking, a calcula aria suprafeței sau a rula simulări fizice, ai nevoie de o structură 3D realistă din punct de vedere fizic.
Absolut primul pas înainte de a genera orice geometrie 3D este adăugarea hidrogenilor. Într-un string SMILES standard, hidrogenii sunt impliciți. Ei sunt tratați ca o proprietate de bază a atomilor grei, îndeplinind pur și simplu cerințele de valență. Dar în spațiul fizic, hidrogenii ocupă volum real. Ei creează hindranță sterică și dictează unghiurile legăturilor din jurul lor. Dacă încerci să calculezi o structură 3D fără a adăuga mai întâi în mod explicit hidrogenii, geometria rezultată se va prăbuși, iar unghiurile de legătură vor fi complet greșite. RDKit oferă o funcție numită AddHs care convertește acești hidrogeni impliciți în noduri reale în graful tău molecular, complet cu legături. Trebuie să rulezi întotdeauna această funcție înainte de a trece la 3D.
Odată ce ai o moleculă completă, trebuie să calculezi coordonatele ei spațiale. Deoarece legăturile simple se pot roti liber, un ligand flexibil nu are o singură formă statică. Poate adopta multe forme diferite, cunoscute sub numele de conformații. Pentru a genera o conformație viabilă, RDKit folosește o metodă default numită ETKDG. Asta vine de la Experimental Torsion-angle Preference with Distance Geometry.
Iată ideea cheie. Metodele din generația mai veche se bazau în întregime pe matematică pură. Ele foloseau geometria distanței pentru a ghici pozițiile atomice pe baza lungimilor și unghiurilor de legătură cunoscute. Acest lucru ducea adesea la forme ciudate, cu energie ridicată, care necesitau un cleanup computațional intens. ETKDG rezolvă această problemă prin combinarea matematicii geometriei distanței cu reguli empirice derivate din Cambridge Structural Database. Știe cum preferă moleculele reale, fizice, să se îndoaie și să se răsucească, și obligă algoritmul de geometrie să respecte aceste preferințe naturale.
Să luăm un scenariu concret. Ai un ligand extrem de flexibil și trebuie să înțelegi toate modurile diferite în care s-ar putea plia pentru a se potrivi într-un binding pocket al unei proteine. Generarea unei singure conformații nu este suficientă pentru a surprinde acest comportament. Ai nevoie de un ansamblu. RDKit gestionează acest lucru cu o funcție numită EmbedMultipleConfs. Pasezi molecula cu hidrogenii ei expliciți și specifici că vrei cincizeci de conformeri.
RDKit va rula apoi algoritmul ETKDG de cincizeci de ori separat, pornind de la random seeds diferite, pentru a genera cincizeci de geometrii 3D distincte. Stochează toate aceste cincizeci de forme în interiorul obiectului moleculă original. Nu primești înapoi cincizeci de molecule separate; primești o singură moleculă care deține cincizeci de seturi distincte de coordonate. Apoi poți itera prin aceste seturi de coordonate pentru a măsura distanțe sau a calcula energii. Deoarece ETKDG se bazează în mare măsură pe date cristalografice din lumea reală, structurile inițiale pe care le oferă sunt de obicei de foarte înaltă calitate, direct din funcție.
O moleculă nu este un desen plat și rareori este doar o singură formă rigidă; este un obiect dinamic, iar eșantionarea conformerilor săi multipli îți oferă adevăratele limite ale comportamentului său fizic. Dacă vrei să ajuți la continuarea podcastului, ne poți sprijini căutând DevStoriesEU pe Patreon. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
7
Accelerarea procesului de feature engineering
4m 17s
Creează o punte între cheminformatică și data science-ul standard cu scikit-fingerprints. Explorăm generarea a peste 30 de tipuri de molecular fingerprints direct într-o interfață scikit-learn.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 7 din 22. Să scrii loop-uri custom pentru extragerea de fingerprint-uri la fiecare proiect nou este obositor și predispus la erori. Treci de la un fingerprint ECFP la o cheie MACCS și, dintr-o dată, trebuie să rescrii întregul bloc de preprocesare. Scikit-fingerprints este o librărie care rezolvă asta, făcând feature extraction-ul molecular la fel de simplu ca apelarea unui transform scikit-learn standard.
Moleculele sunt reprezentate fundamental ca grafuri. Majoritatea algoritmilor de machine learning, însă, necesită vectori multidimensionali. Fingerprint-urile moleculare sunt algoritmii de feature extraction care acoperă acest gol, codificând informațiile structurale în array-uri numerice. Problema este că tool-urile open-source standard pentru calcularea acestor fingerprint-uri, cum ar fi RDKit, Open Babel sau Chemistry Development Kit, sunt scrise în C++ sau Java. Wrapper-ele lor de Python nu se aliniază nativ cu API-ul scikit-learn. Ajungi să scrii data loadere custom, convertoare de format și loop-uri predispuse la erori doar pentru a-ți aduce datele într-o formă pe care un clasificator o poate consuma.
Scikit-fingerprints schimbă această arhitectură. Implementează peste 30 de fingerprint-uri moleculare diferite ca transformere scikit-learn standard, stateless. Toate clasele de fingerprint-uri moștenesc din clasele de bază scikit-learn. Asta înseamnă că se integrează direct în pipeline-urile standard de machine learning și în feature unions.
Gândește-te la un workflow standard. În mod normal, ai scrie un loop custom de douăzeci de linii în RDKit pentru a itera printr-un dataset, a valida moleculele, a extrage fingerprint-uri circulare și a pune rezultatele într-un array. Cu această librărie, înlocuiești întregul bloc de boilerplate cu un singur pas. Creezi un obiect numit ECFP Fingerprint și îl pasezi direct într-un pipeline scikit-learn chiar înainte de modelul tău random forest. Când apelezi metoda fit pe pipeline-ul tău cu datele de training și variabilele target, transformer-ul de fingerprint-uri procesează inputurile și dă ca output un array NumPy dens direct către model.
Iată ideea cheie. Nu trebuie să convertești reprezentările text în obiecte moleculare RDKit înainte de a le da transformer-ului. Pentru orice fingerprint bidimensional bazat pe topologia de graf, metoda transform acceptă direct o listă Python standard de string-uri SMILES. Librăria gestionează automat conversia internă. Deoarece string-urile SMILES nu sunt întotdeauna unice sau valide din punct de vedere chimic, librăria oferă și o clasă Molecule Standardizer. Această clasă aplică pașii de sanitizare recomandați de RDKit pentru a asigura calitatea datelor înainte să înceapă extragerea.
Librăria suportă, de asemenea, fingerprint-uri tridimensionale care se bazează pe conformația spațială. Acești algoritmi spațiali necesită obiecte moleculare RDKit cu conformeri calculați. Generarea de conformeri poate fi instabilă, așa că pachetul include o clasă Conformer Generator care folosește un algoritm specific cunoscut sub numele de ETKDG versiunea 3. Asta oferă default-uri fiabile care maximizează eficiența pentru moleculele simple, minimizând în același timp eșecurile de calcul pentru compușii complecși. Pui conformer generator-ul la începutul pipeline-ului tău, îl urmezi cu un transformer de fingerprint-uri tridimensionale și termini cu un imputer pentru a gestiona orice valori lipsă.
Prin încapsularea logicii chimice complexe în clase transformer standard, librăria abstractizează boilerplate-ul specific domeniului. Configurezi opțiuni precum lungimea vectorului de output sau dacă vrei o variantă binară sau de count, pur și simplu pasând parametri către constructorul transformer-ului. Rezultatul este că tuning-ul hiperparametrilor pentru fingerprint-urile moleculare devine la fel de simplu ca tuning-ul adâncimii unui decision tree.
Asta e tot pentru acest episod. Ne auzim data viitoare!
8
Cheminformatică de înaltă performanță
4m 23s
Învață cum să procesezi eficient dataset-uri chimice masive. Aprofundăm utilizarea paralelismului CPU cu Joblib și economisirea memoriei folosind matrice rare din SciPy.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics și AI, episodul 8 din 22. Calculul substructurilor complexe pe un dataset masiv îți poate bloca ușor mașina cu erori de out-of-memory, dacă nu știi exact cum să-ți gestionezi amprenta de date. Tehnica care rezolvă asta este High-Performance Cheminformatics.
Când extragi features dintr-o moleculă, folosești des fingerprints bazate pe substructură. Fingerprint-ul Klekota-Roth este un exemplu clasic. Pentru a-l calcula, mașina ta verifică o moleculă cu mii de pattern-uri chimice predefinite, cunoscute ca pattern-uri SMARTS. Scanează graful molecular iar și iar pentru a vedea dacă există anumite grupuri funcționale sau motive structurale. Să faci asta secvențial pentru câteva molecule este în regulă. Să o faci pentru un dataset de patru sute de mii de molecule este un bottleneck computațional sever.
Calculul de fingerprints moleculare este un task embarrassingly parallel. Analiza structurală a unei molecule are dependență absolut zero de analiza următoarei molecule din dataset-ul tău. Pentru că nu au un state comun, le poți calcula complet simultan. Pentru a scala asta eficient în Python, folosești Joblib, bazându-te în special pe executorul Loky.
Când inițiezi procesul, dataset-ul de input este împărțit în chunk-uri care corespund exact nucleelor CPU disponibile. Dacă ai un procesor cu 16 nuclee, moleculele tale de input sunt împărțite în 16 batch-uri separate. Fiecare proces worker Python ia un batch și începe să execute independent pattern matching-ul SMARTS. Obstacolul tehnic la multiprocessing în Python este de obicei costul mutării datelor între workeri și procesul principal. Loky ocolește asta folosind memory mapping. În loc să serializeze array-urile finale de fingerprints și să le trimită prin inter-process communication, workerii scriu direct într-un spațiu de shared memory. Pentru fingerprints care necesită multe resurse computaționale, cum ar fi Klekota-Roth, distribuirea workload-ului pe 16 nuclee aduce un speedup de aproape cincisprezece ori.
Asta rezolvă timpul de procesare. Al doilea bottleneck critic este memoria sistemului.
Un singur vector de fingerprint Klekota-Roth este lung. Dacă procesezi sute de mii de molecule, generezi o matrice masivă de rezultate. By default, librăriile numerice returnează acest rezultat ca un array NumPy dens. Fiecare poziție din acea matrice alocă memorie, indiferent dacă valoarea este unu sau zero.
Aceste chemical fingerprints sunt extrem de sparse. De obicei, doar unu sau două procente din features-urile structurale cerute sunt de fapt prezente într-o anumită moleculă. Marea majoritate a matricei tale rezultate este formată din zerouri. Stocarea acelor zerouri este ceea ce declanșează erorile de out-of-memory pe dataset-uri mari. Soluția este schimbarea formatului de output la o matrice sparse SciPy, mai exact folosind formatul Compressed Sparse Row. O matrice sparse schimbă fundamental modul în care sunt stocate datele. În loc să construiască un grid rigid în memorie, înregistrează doar valorile elementelor non-zero, alături de coordonatele lor de rând și coloană.
Ia în considerare un scenariu real folosind dataset-ul PCBA, care conține puțin sub patru sute patruzeci de mii de molecule. Rulezi calculul de fingerprint Klekota-Roth pe întregul dataset folosind cele 16 nuclee ale tale. Execuția paralelă se termină eficient. Dacă lași output-ul ca un array dens default, această singură matrice va consuma puțin peste doi Gigabytes de RAM. Dacă instruiești calculul să returneze în schimb un sparse array SciPy, exact același dataset scade la o amprentă de doar 23 de Megabytes. Obții o reducere de optzeci și opt de ori a memoriei fără să pierzi nicio informație chimică, iar reprezentarea sparse nu are absolut niciun impact negativ asupra timpului tău de calcul.
Iată ideea cheie. Nu ai nevoie de un compute cluster masiv pentru a procesa sute de mii de molecule, cu condiția să nu mai plătești taxa de memorie pentru stocarea zerourilor și să te asiguri că transmiterea datelor sare peste overhead-ul standard de inter-process communication.
Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
9
Pipeline-uri de ML End-to-End
4m 19s
Combină procesarea, fingerprinting-ul și predicția într-o singură arhitectură curată. Construim pipeline-uri scikit-learn robuste care integrează perfect generarea de conformeri 3D și predicția proprietăților.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 9 din 22. Un script complex de screening virtual 3D necesita în trecut sute de linii de cod fragil. Trebuia să generezi manual conformeri, să gestionezi erorile, să calculezi mai mulți descriptori și să îmbini array-urile înainte măcar să ajungi la un model. Acum, poți arhitecta întregul proces într-o singură definiție elegantă de pipeline, folosind ML Pipelines end-to-end.
În machine learning, un pipeline este o secvență de pași de procesare a datelor și un estimator final, grupați într-un singur obiect. În cheminformatică, în special cu date structurale 3D, preprocesarea este notoriu de fragmentată. Iei string-uri SMILES brute, calculezi coordonate 3D, rulezi optimizări de force field, extragi features, repari missing values și, în final, antrenezi un clasificator. Să faci asta manual înseamnă să scrii loop-uri custom și structuri de date intermediare care crapă ușor și au memory leaks. Vom parcurge construirea unui pipeline scikit-learn complet, care duce string-urile SMILES brute direct într-un clasificator Random Forest.
Primul pas din secvență este generarea de conformeri. Inițializezi un generator de conformeri și îl pasezi ca primă etapă a pipeline-ului. Acesta citește input-ul 2D și calculează structurile 3D. Îl poți configura să optimizeze geometria folosind un force field precum MMFF94. Paralelizează automat această muncă grea pe toate core-urile CPU disponibile.
Acum, a doua parte a acestui proces este extragerea de features. Pentru task-uri 3D, combinarea diferiților descriptori geometrici captează mai multă informație moleculară. Folosești un feature union din scikit-learn pentru a calcula simultan fingerprint-urile GETAWAY și WHIM. Ambele clase de fingerprint-uri acționează ca stateless transformers în pipeline. Ele preiau conformerii 3D din pasul anterior, calculează descriptorii respectivi în paralel și concatenează rezultatele într-o singură feature matrix lată.
Mai departe, trebuie să gestionezi erorile de calcul. Algoritmii de descriptori 3D uneori eșuează în a procesa molecule extrem de complexe sau tensionate, rezultând în missing values în matricea ta. Pipeline-ul gestionează asta fără custom error handling. Adaugi un simple imputer direct după feature union. Dacă un calcul GETAWAY sau WHIM generează un missing value, imputer-ul îl detectează și îl înlocuiește cu media acelui feature din dataset-ul tău.
În cele din urmă, închei pipeline-ul cu modelul tău predictiv, care în acest caz este un clasificator Random Forest.
Pentru a arhitecta asta în cod, apelezi funcția make pipeline. În interiorul acelui apel de funcție, pasezi generatorul tău de conformeri. Apoi, pasezi feature union-ul care conține fingerprint-urile tale GETAWAY și WHIM. Apoi vine simple imputer-ul și, în final, clasificatorul Random Forest. Atribui întreaga secvență unei singure variabile.
Când apelezi metoda fit pe acea variabilă de pipeline, pasezi string-urile SMILES brute de training și etichetele target. String-urile curg secvențial prin generatorul de conformeri, în feature union pentru fingerprinting, prin imputer pentru a curăța datele și direct în clasificator pentru training. Când vine momentul evaluării, apelarea metodei predict pe string-urile SMILES de test forțează noile date să urmeze exact aceeași cale.
Iată ideea principală. State-ul și rutarea datelor sunt gestionate în întregime de obiectul pipeline, ceea ce înseamnă că nu ții niciodată dense arrays intermediare în memorie și nu scrii custom data loaders pentru conformerii tăi.
Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
10
Predicția afinității de legare
3m 59s
Explorează realitatea predicției afinității de legare proteină-ligand. Comparăm performanța modelelor simple 2D bazate pe arbori cu cea a rețelelor complexe 3D Graph Neural Networks.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 10 din 22. Construiești o rețea masivă tridimensională de tip graph neural network, dându-i ca input coordonatele spațiale pentru fiecare atom dintr-un buzunar proteic. Apoi rulezi un model simplu de tip gradient boosted decision tree, care se uită doar la reprezentarea bidimensională a medicamentului. Benchmark-ul se termină, iar modelul tău spațial de ultimă generație tocmai a fost bătut de un algoritm de acum două decenii. Motivul pentru care rețeaua ta complexă a eșuat are legătură cu modul în care gestionăm predicția afinității de legare.
Predicția afinității de legare este procesul computațional prin care estimăm cât de strâns se atașează o moleculă mică, sau un ligand, de o țintă proteică specifică. În drug discovery, găsirea unei molecule care se leagă puternic este scopul principal. Pentru a face asta, inginerii aleg de obicei una din două căi. Prima este extrem de complexă. Folosești rețele neuronale tridimensionale precum GraphNet sau TensorNet. Aceste modele primesc ca input conformația exactă de legare a complexului proteină-ligand. Ele folosesc layere de message passing pentru a învăța distanțele spațiale precise și feature-urile de mecanică cuantică dintre atomii medicamentului și atomii buzunarului proteic.
A doua cale ignoră complet proteina. Renunți la coordonatele spațiale și folosești un model bidimensional clasic, cum ar fi XGBoost. Input-ul aici este doar un vector concatenat de molecular fingerprints. Calculezi feature-urile structurale doar din ligand, transformând practic desenul bidimensional al substanței chimice într-un array de numere, și dai asta ca input direct în modelul tree-based.
Pentru a vedea cum se compară aceste abordări, cercetătorii le rulează pe test sets standardizate. Unul dintre cele mai revelatoare este benchmark-ul Merck FEP. Acest dataset imită un scenariu comun de virtual screening, numit serie congenerică. Într-o serie congenerică, toți liganzii testați împart exact același scaffold chimic central și se leagă de exact același situs pe o singură țintă proteică. Singurele diferențe dintre molecule sunt mici variații structurale, cum ar fi diferite ramificații chimice atașate la nucleul principal.
Iată ideea cheie. Când au fost evaluate pe dataset-ul Merck, modelele tridimensionale complexe au obținut un scor de corelație în jur de zero virgulă trei. Modelul simplu bidimensional XGBoost a obținut un scor semnificativ mai mare, ajungând la zero virgulă patru cinci. Modelul decision tree, ieftin din punct de vedere computațional, a depășit clar rețelele avansate de tip graph neural networks.
Asta se întâmplă din cauza lucrurilor pe care modelele sunt forțate să se concentreze. Într-o serie congenerică, ținta proteică și buzunarul de legare nu se schimbă. Modelul tridimensional consumă resurse computaționale masive pentru a mapa un mediu spațial care rămâne static în fiecare test case. Mai rău, aceste modele sunt foarte sensibile la variații minuscule ale coordonatelor atomice. O ușoară schimbare arbitrară în modul în care este plasat un atom de hidrogen în timpul pregătirii datelor introduce noise care distrage atenția rețelei de tip graph. Modelul bidimensional are succes tocmai pentru că este orb față de proteină. Uitându-se doar la feature-urile ligandului, se bazează pe singurele variabile care se schimbă efectiv de la un test la altul. Modelul decision tree corelează acele variații structurale directe ale medicamentului cu puterea finală de legare, ocolind complet noise-ul mediului spațial.
Modelele tridimensionale complexe sunt încă foarte valoroase atunci când trebuie să generalizezi pe ținte proteice complet diferite, noi, unde geometria buzunarului este necunoscută. Dar când optimizezi o familie specifică de medicamente pentru o singură țintă cunoscută, să dai constant ca input date de mediu într-o rețea deep este ineficient și predispus la erori. Cel mai puternic tool predictiv este adesea cel care filtrează mediul static și modelează doar variabilele care se schimbă. Asta e tot pentru acest episod. Ne auzim data viitoare!
11
LLMs vs Fingerprints clasice
4m 26s
Descoperă cum se aplică Natural Language Processing în chimie. Punem față în față vector embeddings din Large Language Models cu structural fingerprints clasice din RDKit pentru predicția bioactivității.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 11 din 22. Cum ar fi dacă cel mai bun mod de a descrie o moleculă unui model de machine learning nu ar fi printr-o formulă structurală creată manual, ci tratând acel SMILES string exact ca pe o propoziție în limbaj natural? S-ar putea să consumi compute cycles valoroase generând descriptori chimici complecși, doar ca să fii depășit de un model text. Această tensiune este fix esența dezbaterii LLMs vs Classical Fingerprints.
Atunci când prezici cât de strâns se leagă un ligand de o proteină, modelul tău are nevoie de o descriere matematică a ligandului. Abordarea tradițională se bazează pe amprente structurale clasice calculate de tool-uri precum RDKit. Treci o moleculă printr-un algoritm determinist și primești un vector static. O amprentă Morgan numără substructurile circulare din jurul atomilor. Cheile MACCS verifică molecula folosind o listă predefinită de pattern-uri chimice.
Limitarea acestor amprente clasice este rigiditatea lor. Ele codează reguli specifice, care nu pot fi schimbate. Nu le poți da fine-tune. Dacă o anumită nuanță structurală contează pentru un binding pocket foarte specific, dar algoritmul amprentei nu a fost conceput explicit să o capteze, acea informație se pierde complet înainte ca modelul predictiv măcar să vadă datele.
În loc să facem hardcoding la regulile chimice, putem folosi un Large Language Model chimic pre-antrenat, cum ar fi BioT5, GPT2 sau BERT. Aceste modele sunt pre-antrenate pe milioane de SMILES strings. Ele învață gramatica chimiei într-un mod unsupervised. Când pasezi un ligand către un LLM, acesta nu scoate un checklist fix de grupuri funcționale. Produce un vector embedding bogat. Fiecare caracter sau token din acel SMILES string primește propriul său vector contextual.
Ca să înțelegi diferența, uită-te la modul în care aceste reprezentări intră în modelele predictive. Mai întâi, ia în considerare un model XGBoost care folosește chei MACCS clasice. Generezi amprenta MACCS, care rezultă într-un array binar simplu. Pasezi acel vector fix către XGBoost, care încearcă să mapeze acele feature-uri brute de prezență-sau-absență la afinitatea de legare. În testele de benchmark pe serii congenerice, această combinație specifică produce în mod constant cea mai slabă performanță. Feature-urile create manual sunt pur și simplu prea rudimentare.
Acum, schimbă acea arhitectură cu un embedding BioT5 trimis către un Transformer head. Mai întâi pasezi acel raw SMILES string modelului BioT5. Acesta returnează o secvență de embedding-uri per token. Apoi pasezi acea secvență într-un Transformer head. Aici este ideea cheie. Transformer-ul folosește un attention mechanism. Se uită peste întreaga secvență de token embeddings și învață dinamic care părți ale moleculei contează cel mai mult pentru legarea la acest target specific. Ponderează feature-urile în mod inteligent înainte de a da ca output afinitatea de legare prezisă.
Dacă încerci să iei exact aceleași token-uri BioT5, să le aduni într-un singur flat vector și să îl dai către XGBoost, performanța predictivă scade semnificativ. Sum pooling-ul estompează detaliile la nivel de token. Acel Transformer head are succes tocmai pentru că păstrează și exploatează contextul granular al reprezentării de tip text.
Această trecere de la array-uri statice la embedding-uri dinamice oferă beneficii practice masive. Embedding-urile LLM sunt extrem de versatile și pot primi fine-tune pentru downstream tasks specializate. Ele sunt, de asemenea, mult mai compacte decât acei bit vectors clasici și masivi, ceea ce economisește memorie la stocarea bibliotecilor moleculare mari. În plus, generarea de text embeddings rulează pe un GPU, ceea ce este drastic mai rapid decât calcularea amprentelor RDKit tradiționale pe un CPU.
Era în care spuneam manual algoritmilor ce substructuri chimice contează se apropie de sfârșit; modelele care au cele mai bune performanțe sunt cele care sunt lăsate să citească molecula și să decidă singure. Dacă vrei să ajuți la susținerea emisiunii, poți căuta DevStoriesEU pe Patreon. Mersi că ai fost alături de mine. Sper că ai învățat ceva nou.
12
Active Learning pentru screening virtual
4m 20s
Învață cum să descoperi iterativ cei mai buni candidați pentru medicamente fără testare exhaustivă. Aprofundăm buclele de active learning și strategiile de selecție greedy pentru a maximiza ratele de succes.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 12 din 22. Rularea simulărilor fizice complexe pe un milion de molecule este imposibil de lentă. Ai nevoie de o modalitate de a găsi cei mai buni candidați testând doar o mică parte din dataset-ul tău. Exact asta face Active Learning for Virtual Screening.
Când evaluezi o bibliotecă chimică, calcularea afinităților de legare precise folosind metode de fizică computațională este incredibil de costisitoare. Pur și simplu nu îți poți permite să simulezi fiecare compus în parte. În schimb, testezi un batch mic, folosești acele rezultate pentru a antrena un model de machine learning și lași acel model să prezică afinitățile pentru restul bibliotecii. Apoi testezi cele mai promițătoare predicții, actualizezi modelul și repeți procesul. Acest ciclu iterativ este active learning.
Să ne uităm la un scenariu concret. Explorezi o serie congeneră de zece mii de compuși care vizează o anumită proteină, cum ar fi Tyk2. Scopul tău este să găsești top unu la sută din moleculele active. Pentru a face acest lucru eficient, te bazezi pe o strategie de selecție greedy. O strategie greedy înseamnă că modelul tău alege întotdeauna compușii cu cele mai mari afinități de legare prezise pentru următoarea rundă de testare.
Setezi batch size-ul la șaizeci de molecule pe rundă. Acest număr atinge un echilibru practic pentru un workflow din lumea reală. Este suficient de mic pentru a putea rula rapid simulări fizice solicitante pe acest batch, dar suficient de mare pentru a oferi o cantitate substanțială de date noi modelului tău. Rulezi testele pe acești șaizeci de compuși pentru a obține afinitățile lor reale de legare și introduci imediat aceste date într-un model 2D tree-based, cum ar fi XGBoost. Modelul XGBoost învață tiparele, calculează un score pentru moleculele netestate rămase din pool-ul de zece mii de compuși și selectează următorii șaizeci de candidați.
Iată ideea cheie. Modul în care alegi primul batch de șaizeci de molecule dictează cât de repede învață întregul tău sistem. Active learning-ul standard se bazează adesea pe un baseline random. Selectezi șaizeci de molecule complet la întâmplare, le testezi și antrenezi primul model. Dar selecția random oferă modelului tău un punct de plecare slab, umplând training set-ul inițial cu compuși în mare parte inactivi.
Soluția este să inițializezi loop-ul de active learning folosind o rețea neuronală 3D pretrained. Acest model 3D a fost deja antrenat pe un dataset masiv, general, cu diverse complexe de proteine și liganzi. Deoarece înțelege fizica generală a legăturilor bazată pe interacțiuni structurale, poate da un score celor zece mii de compuși înainte ca loop-ul de active learning să înceapă măcar.
Mai întâi, folosești modelul 3D pretrained pentru a prezice afinitățile pentru întregul pool. Apoi, iei primele șaizeci de molecule identificate prin acest prescreening și rulezi simulările fizice complexe pe ele. Acum ai un set de date inițiale extrem de îmbogățit. Dai acest dataset inițial, de înaltă calitate, modelului tău XGBoost. Din acest moment, modelul XGBoost preia ciclul. Se antrenează pe datele verificate, face predicții pentru pool-ul rămas și selectează greedy următorii șaizeci de candidați.
Această combinație generează o accelerare masivă în hit discovery. Modelul 3D general oferă un punct de plecare bogat, iar modelul XGBoost se adaptează rapid la spațiul chimic specific al seriei tale congenerice. Prin inițializarea cu un model 3D pretrained în loc de random sampling, poți găsi optzeci la sută din top unu la sută dintre binders după testarea a mai puțin de zece la sută din întregul dataset. Începerea loop-ului cu un prescreening 3D general oferă modelelor tale specializate un avantaj imbatabil.
Asta e tot pentru acest episod. Mersi că ai ascultat și continuă să construiești!
13
Provocarea Activity Cliff
3m 52s
Examinează fragilitatea relațiilor structură-activitate. Discutăm despre „activity cliffs” — unde o schimbare structurală minusculă provoacă o modificare masivă a potenței unui medicament.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 13 din 22. În chimie, un singur atom nelalocul lui poate transforma un medicament puternic, care salvează vieți, într-o pulbere inertă. Aceste scăderi bruște ale potenței biologice se numesc activity cliffs, și sunt inamicul absolut al modelelor tradiționale de AI.
Un activity cliff apare atunci când ai o pereche de molecule cu o similaritate structurală ridicată, dar cu niveluri de activitate semnificativ diferite. Ia în considerare un scenariu concret. Ai două molecule care au în comun nouăzeci la sută din framework-ul lor structural. Prima moleculă se leagă strâns de o țintă biologică. A doua moleculă este complet inactivă. Singura diferență fizică dintre ele este o singură grupare metil atașată la un inel specific. Pentru un specialist uman în chimie medicinală, această modificare structurală specifică este extrem de informativă. Îi spune exact unde sunt limitele buzunarului receptorului. Pentru un model standard de machine learning, este o perturbare catastrofală.
Iată ideea cheie. Majoritatea abordărilor de deep learning în cheminformatică sunt construite pentru a prezice valori absolute ale proprietăților. Indiferent dacă folosești un graph neural network sau un chemical language model, arhitectura este fundamental concepută pentru a mapa structurile chimice într-un spațiu matematic continuu. Presupunerea de bază hardcodată în aceste modele este că structurile moleculare similare ar trebui să se mapeze la proprietăți biologice similare. Atunci când un model standard procesează cele două molecule aproape identice ale noastre, generează reprezentări care sunt chiar una lângă alta în acel spațiu matematic. Deoarece inputurile sunt apropiate, modelul generează în mod natural ca output predicții de potență absolută aproape identice pentru ambele.
Aceste activity cliffs încalcă fundamental această presupunere a unui spațiu chimic continuu și neted. Ele reprezintă o discontinuitate severă. Modelul se așteaptă la o pantă ușoară, dar întâlnește o cădere verticală. Această problemă este puternic amplificată de natura datelor din drug discovery. Dataseturile experimentale sunt notoriu de limitate și noisy. Când antrenezi un deep neural network pe date sparse, modelul se chinuie să generalizeze. Pentru a minimiza eroarea generală pe întregul training set, rețeaua învață pattern-uri largi, globale. Netezește iregularitățile locale. Când întâlnește un activity cliff, obiectivul standard de regression tratează acel salt brusc în varianță ca experimental noise sau ca pe un outlier. Modelul ignoră cea mai importantă informație structurală locală, deoarece nu se potrivește cu trendul global.
De aceea, prezicerea de activity cliffs rămâne una dintre cele mai dificile probleme în predicția proprietăților moleculare. Modelele sunt forțate să învețe un spațiu chimic discontinuu direct din date limitate. Deoarece se concentrează în întregime pe predicții absolute pentru molecule individuale, ele ignoră complet informațiile valoroase ascunse în diferențele relative dintre matched molecular pairs. În multe cazuri, modele tree-based mai simple ajung de fapt să depășească performanțele unor neural networks complexe pe aceste dataseturi, pur și simplu pentru că modelele de deep learning fac over-smoothing pe reprezentări.
Presupunerea că structuri chimice similare produc întotdeauna activități biologice similare este un baseline statistic util, dar nu este o lege fizică. Aceste activity cliffs sunt realitatea brutală și discontinuă a relațiilor structură-activitate, și dovedesc că prezicerea proprietăților absolute în vid va eșua întotdeauna la margini. Mulțumesc că ai petrecut câteva minute cu mine. Până data viitoare, numai bine.
14
Similarity-Quantized Relative Learning
3m 42s
Rezolvă problema activity cliff regândind modul în care învață modelele. Explorăm framework-ul SQRL, care antrenează AI-ul să prezică diferențele relative de proprietăți între perechi moleculare strict filtrate.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 14 din 22. În loc să forțezi un AI să memoreze potența absolută a fiecărei molecule existente, ce-ar fi dacă l-ai învăța pur și simplu să întrebe cum diferă o moleculă de cel mai apropiat vecin cunoscut al ei? Această schimbare de perspectivă rezolvă o problemă majoră de generalizare în scenariile cu date puține și este nucleul unui framework numit Similarity-Quantized Relative Learning, sau SQRL.
În mod normal, predicția proprietăților moleculare tratează fiecare moleculă ca un data point izolat. Modelul încearcă să mapeze o structură direct la o valoare absolută a proprietății. Cu datasets mici și zgomotoase, modelele de deep learning au dificultăți în a construi o hartă globală precisă a spațiului chimic. Încercările anterioare de pairwise learning au încercat să remedieze acest lucru prin asocierea fiecărei molecule cu fiecare altă moleculă din training set. Această abordare inundă datele cu comparații între structuri complet neînrudite, acoperind semnalul local util. SQRL remediază acest lucru prin restricționarea training data la perechi de molecule care sunt foarte similare din punct de vedere structural. Modelul învață să prezică diferența relativă dintre proprietățile lor, cunoscută sub numele de delta y.
Acest lucru se realizează printr-un pas specific de dataset matching. Nu îi dai modelului molecule individuale. Îi dai perechi, dar numai dacă acestea trec de un prag strict de similaritate. Să parcurgem logica. Începi cu training set-ul standard de molecule și potențele cunoscute ale acestora. Mai întâi, calculezi distanțele pairwise dintre toate moleculele folosind o metrică precum distanța Tanimoto pe Morgan fingerprints.
Iată ideea cheie. Setezi un prag de distanță, alfa. Să folosim un prag de distanță Tanimoto de zero virgulă șapte. Iterezi prin toate perechile posibile de molecule. Dacă distanța dintre molecula A și molecula B este zero virgulă șapte sau mai mare, elimini complet perechea. Dacă distanța este strict mai mică decât zero virgulă șapte, adaugi această pereche la noul tău training set relativ. Target variable-ul pentru această nouă pereche nu mai este o potență absolută. Este diferența numerică exactă de potență dintre molecula A și molecula B.
Acum îți antrenezi neural network-ul. Network-ul generează o reprezentare matematică pentru molecula A și o reprezentare pentru molecula B. Scade reprezentarea lui B din reprezentarea lui A. Vectorul diferențial rezultat este trecut printr-un layer final pentru a prezice delta y. Prin filtrarea zgomotului perechilor disimilare, network-ul este forțat să se concentreze exclusiv pe modificările chimice locale, high-signal. Învață exact cum o modificare structurală specifică modifică activitatea. Acest lucru face ca modelul să fie extrem de sensibil la activity cliffs.
Acest lucru acoperă training-ul, dar cum rămâne cu prezicerea unei molecule complet noi? Când apare o structură nouă, sistemul scanează training data originală pentru a găsi acel singur nearest neighbor structural pe baza aceleiași metrici de distanță Tanimoto. Network-ul evaluează noua moleculă în raport cu acest nearest neighbor și prezice delta relativă. În cele din urmă, iei potența absolută cunoscută a vecinului, adaugi delta prezisă și ai predicția finală. Prin restricționarea training space-ului la perechi foarte similare, nu îi mai ceri modelului să învețe întregul univers chimic și, în schimb, îl antrenezi să devină un expert în gradienți chimici locali.
Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
15
Revoluția Generative AI
3m 56s
Tranziția de la predicția proprietăților la imaginarea unor molecule complet noi. Cartografiem peisajul sarcinilor generative moleculare: generarea De Novo, optimizarea și generarea de conformeri.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 15 din 22. Ani de zile, AI-ul în chimie a fost pur și simplu un act de triaj. Alimentai un model cu mii de molecule existente, iar el pur și simplu prezicea care dintre ele erau cele mai puțin proaste. Dacă molecula ideală nu se afla în screening library-ul tău, modelul nu te putea ajuta. Revoluția Generative AI a inversat fundamental această dinamică. În loc să filtrăm doar ceea ce există deja, acum putem instrui modelele să inventeze materie chimică complet nouă. Această trecere de la predicție la creație se împarte în două task-uri generative moleculare majore: generarea de novo și optimizarea moleculară. Generarea de novo implică crearea de noi structuri moleculare de la zero. Modelul începe cu o reprezentare de random noise și o rafinează iterativ într-o structură chimică validă. Când acest lucru se face fără nicio constrângere, se numește generare necondiționată. Modelul explorează liber vastul spațiu chimic pentru a produce ceva complet nou. Deși acest lucru este util pentru o descoperire mai amplă, de obicei ai nevoie de mai mult control. Asta ne aduce la generarea condiționată, mai exact la property-based generation. Aici, tu dictezi output-ul. Oferi constrângeri specifice, cum ar fi o bioactivitate target sau un nivel necesar de sintetizabilitate, iar modelul își restricționează generarea la moleculele care îndeplinesc acele criterii. Asta este adesea denumită inverse molecule design, deoarece începi cu proprietățile pe care le vrei și forțezi modelul să lucreze backward pentru a construi o structură moleculară care le oferă. Generarea de novo este puternică, dar rareori începi un proiect cu zero cunoștințe existente. De obicei, ai deja un lead compound. Aici intervine optimizarea moleculară. Spre deosebire de task-urile de novo, optimizarea moleculară se concentrează pe modificarea unei structuri cunoscute, în loc să pornească de la zero. Iei o moleculă existentă și o rafinezi pentru a-i îmbunătăți proprietățile. Să presupunem că ai un drug scaffold moderat eficient. Se leagă de target-ul tău, dar bioactivitatea sa este prea scăzută pentru a fi un medicament viabil. Folosind un model generativ, poți face o optimizare moleculară targetată. O abordare este scaffold hopping. Instruiești modelul să înlocuiască core molecular scaffold-ul cu unul nou, păstrând în același timp activitatea biologică originală. Asta este foarte eficient pentru descoperirea de compuși noi din punct de vedere structural, care evită patentele existente, păstrând în același timp comportamentul funcțional intact. O altă abordare este R-group design. În acest scenariu, îți blochezi core scaffold-ul pe poziție și instruiești modelul generativ să îi optimizeze automat side chain-urile. Modelul generează noi R-groups, căutând modificările specifice de side chain care îmbunătățesc acea bioactivitate scăzută. Nu îți arunci molecula moderat eficientă, ci lași AI-ul să calculeze tweak-urile structurale precise, necesare pentru a o împinge peste linia de sosire. Iată ideea cheie. Tranziția de la predictive AI la generative AI înseamnă că nu mai ești limitat de moleculele pe care le ai la îndemână. Indiferent dacă generezi o moleculă custom de la zero sau schimbi algoritmic side chain-urile unui medicament existent, tratezi spațiul chimic ca pe un mediu programabil. Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
16
Intuiția din spatele Molecular Diffusion
3m 54s
Descompunem conceptul de bază al diffusion models fără matematică grea. Ascultătorii vor înțelege procesul forward de adăugare a zgomotului la o moleculă și procesul reverse de halucinare a unor noi structuri.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 16 din 22. Pentru a învăța un AI cum să inventeze o moleculă nouă, trebuie mai întâi să-l înveți cum să o distrugă complet. Pare complet pe dos, dar această distrugere sistematică este exact mecanismul folosit pentru a genera medicamente noi de la zero. Asta este intuiția de bază din spatele Denoising Diffusion Probabilistic Models.
Designul molecular tradițional necesită incredibil de multă muncă. Dacă vrei să automatizezi descoperirea de compuși noi, ai nevoie de un model capabil să exploreze un chemical space vast fără să genereze rezultate invalide și fără sens. Primele deep generative models au încercat să mapeze direct acest spațiu. Denoising Diffusion Probabilistic Models, sau DDPMs, o iau pe o cale diferită. Ele tratează generarea moleculară ca pe o problemă progresivă de denoising.
Acest framework este împărțit în două Markov chains distincte: forward process și reverse process.
Acest forward process se referă strict la degradarea datelor. Iei un medicament valid, cunoscut, din training set-ul tău. Pe parcursul unei secvențe fixe de pași, îi estompezi progresiv coordonatele atomice injectând Gaussian noise pur. Cantitatea de noise adăugată la fiecare pas este controlată de un hyperparameter schedule bine stabilit. La pasul unu, perturbi ușor atomii. Molecula este puțin distorsionată, dar încă clar recognoscibilă. Până la pasul cincizeci, structura este sever deformată. La pasul final, denumit de obicei pasul T, molecula originală dispare complet. Rămâi cu un nor random de Gaussian noise nestructurat.
Acest forward process nu necesită o rețea neuronală. Este o corupere matematică strictă. Servește unui scop vital, deoarece generează acel ground truth pentru datele noastre de training.
Iată ideea cheie. Pentru că am controlat cantitatea exactă de noise adăugată la fiecare pas, avem o înregistrare perfectă, pas cu pas, a modului în care molecula s-a destrămat.
În acest reverse process intervine rețeaua neuronală. Modelul este antrenat să parcurgă exact acea cale înapoi. Dăm rețelei o moleculă coruptă la un anumit time step. Apoi îi cerem să prezică acel noise specific care a fost adăugat pentru a ajunge în acea stare. Evaluăm modelul comparând predicția sa de noise cu acel noise real pe care l-am injectat în timpul fazei de forward. Actualizăm parametrii modelului pentru a minimiza această diferență. În timp, rețeaua învață să facă denoising pe date pas cu pas, restabilind treptat distribuția originală a datelor.
Pentru a genera o moleculă complet nouă, execuți acest reverse process de la zero. Mai întâi, dai sample la un nor complet random de Gaussian noise. Apoi, pasezi acel noise în rețeaua ta neuronală antrenată, împreună cu numărul pasului de start. Rețeaua evaluează inputul, prezice corecția structurală necesară și returnează un nor de atomi cu ceva mai puțin noise.
Faci un loop cu acest proces de scădere. Pasezi noul output înapoi în rețea pentru următorul pas în jos. Cu fiecare iterație, norul random se strânge. Modelul elimină continuu acel noise. Pe măsură ce faci pași înapoi spre pasul zero, coordonatele atomice se fixează la locul lor și apare o structură chimică validă. Extragi o moleculă complet nouă din acel noise inițial.
Modelul nu doar memorează o bază de date cu medicamente existente; pur și simplu învață procesul universal de eliminare a haosului pentru a lăsa în urmă o chimie stabilă. Dacă vrei să susții emisiunea, poți căuta DevStoriesEU pe Patreon. Mulțumesc că asculți și continuă să construiești!
17
Conectarea spațiilor generative 2D și 3D
4m 27s
Explorăm modul în care AI-ul reprezintă de fapt moleculele pe care le generează. Comparăm generarea de grafuri topologice 2D plane cu generarea de point clouds geometrice 3D complexe și provocările fiecăreia.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 17 din 22. Una e ca un model să deseneze un graf 2D plat al unei molecule. E un cu totul alt coșmar ingineresc să generezi un nor geometric 3D stabil de atomi. Poți avea un model generativ care să construiască un point cloud 3D superb al unui medicament, care umple perfect buzunarul unei proteine target, doar ca să vezi cum totul se destramă în post-processing, când sistemul nu reușește să ghicească unde ar trebui să fie de fapt legăturile covalente. Soluția pentru această ruptură este unirea spațiilor generative 2D și 3D.
În chimia generativă, modalitățile datelor dictează ce poate înțelege modelul tău. Prima modalitate este spațiul topologic 2D. Gândește-te la asta ca la un graf molecular standard. Nodurile reprezintă atomi cu tipuri specifice, iar muchiile reprezintă legăturile chimice care îi conectează. Modelul dă ca output o matrice de adiacență care îți spune exact ce este conectat cu ce. Rețelele Graph Neural Networks se descurcă bine cu asta. Problema este că moleculele există în lumea fizică, nu pe hârtie. Un graf 2D îți oferă topologia de legare, dar ignoră complet structura geometrică 3D. Fără coordonate spațiale, nu poți calcula cu exactitate proprietățile cuantice și nu poți face structure-based drug design.
Pentru a remedia asta, modelele au trecut la generarea de molecule direct în spațiul geometric 3D. Aici, output-ul este un point cloud. Modelul definește tipurile de atomi și coordonatele lor poziționale exacte X, Y și Z. Obstacolul tehnic aici este menținerea echivarianței SE 3, asigurând faptul că molecula rămâne consistentă din punct de vedere matematic, indiferent de modul în care este rotită sau translată în spațiu. Iată ideea cheie. Generarea în spațiu 3D pur înseamnă că modelul nu generează explicit legăturile chimice. El doar plasează atomii în spațiu. Trebuie să deduci topologia de legare ulterior, prin algoritmi de post-processing. Asta introduce erori majore. Revenind la scenariul cu buzunarul proteic, modelul tău ar putea aranja atomii într-o formă care se potrivește fizic cu target-ul, dar pentru că nu a luat niciodată în considerare topologia de legare în timpul generării, pasul de post-processing ar putea deduce legături covalente imposibile. Pentru molecule mai mari, generarea directă a unei structuri 3D stabile fără nicio îndrumare topologică duce adesea la o soluție suboptimală.
Asta ne aduce la generarea în joint space 2D și 3D, care produce simultan o structură moleculară completă. Modelul dă ca output tipurile de atomi, matricea de adiacență discretă pentru legături și coordonatele spațiale continue, toate deodată. Prin unirea acestor două spații, modalitățile se constrâng și se corectează reciproc în timpul procesului de generare. Topologia 2D acționează ca un blueprint, ghidând structura 3D pentru a se asigura că aranjamentele spațiale sunt fezabile din punct de vedere chimic. În același timp, geometria 3D rafinează graful 2D sugerând pattern-uri de legături plauzibile, bazate pe proximitatea spațială.
Principala provocare tehnică în această abordare joint este gestionarea a două tipuri de date fundamental diferite. Practic, forțezi modelul să gestioneze structuri topologice discrete, cum ar fi tipurile de legături, alături de structuri geometrice continue, cum ar fi valorile coordonatelor. Arhitecturi diferite rezolvă acest lucru diferit. Un framework numit JODO tratează atât structurile topologice, cât și pe cele geometrice ca variabile continue, pentru a le procesa împreună. Un alt model, MUDiff, le gestionează separat, aplicând un proces discret pentru topologie și un proces continuu pentru geometrie.
Nu poți genera în mod fiabil medicamente noi și funcționale ghicind forma fizică și sperând că legăturile chimice se vor aranja de la sine ulterior. Generarea moleculară reală necesită ca blueprinting-ul topologic și poziționarea spațială să interacționeze și să se completeze reciproc în exact același calcul. Asta e tot pentru acest episod. Mersi că m-ai ascultat și continuă să construiești!
18
Generare Target-Aware și Docking
3m 38s
Descoperă designul generativ context-aware. Discutăm despre generarea de molecule noi direct în interiorul buzunarului de legare al unei proteine asociate cu o boală pentru a maximiza afinitatea de legare.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 18 din 22. De ce să ceri unui algoritm să genereze un milion de chei random și să le testeze una câte una, când ar putea pur și simplu să se uite direct la încuietoare și să creeze o cheie custom chiar în gaura cheii? Procesul tradițional de drug discovery se bazează adesea pe generarea unor librării vaste de candidați și filtrarea lor, dar asta irosește resurse computaționale imense. Target-Aware Generation și Docking rezolvă asta folosind direct geometria 3D a țintei biologice pentru a construi sau plasa molecule.
În aceste task-uri generative, lucrăm în întregime în spațiul geometric 3D. Target-aware generation, cunoscută și sub numele de structure-based drug design, construiește o moleculă nouă bazându-se direct pe structura 3D a unui binding pocket țintă. Să luăm un scenariu concret care implică o proteină virală. Această proteină are o cavitate geometrică extrem de specifică. În loc să genereze molecule în vid, un conditional diffusion model analizează limitele spațiale exacte și proprietățile chimice ale acelei cavități. Apoi, crește custom o nouă structură de ligand direct în interiorul pocket-ului.
Modelul începe cu un nor de coordonate 3D noisy și tipuri de atomi localizați în interiorul binding site-ului. Pe parcursul unor pași succesivi, face denoise acestui nor. Pentru că generarea este condiționată de pocket-ul țintă, modelul plasează atomi și formează structuri care completează în mod natural cavitatea, cu scopul de a garanta o afinitate de interacțiune ridicată. Iată ideea cheie. Algoritmul nu doar ghicește o formă; el învață explicit relația spațială dintre țintă și potențialii binders. Unele abordări încorporează chiar și interaction-based retrieval, trăgând date de la liganzi cunoscuți cu afinitate ridicată pentru a ghida și mai mult generarea acestor molecule target-specific.
Asta acoperă generarea unei molecule complet noi from scratch în interiorul unui pocket. Dar de multe ori o să ai o moleculă existentă și va trebui să știi exact cum interacționează cu o țintă biologică. Asta ne aduce la molecular docking.
Molecular docking-ul prezice binding pose-ul pentru a evalua afinitatea și specificitatea de legare. Într-un diffusion framework, modelele iau o moleculă cunoscută și o structură țintă ca input-uri. În loc să genereze identitate chimică, procesul de diffusion operează exclusiv pe orientarea spațială a moleculei. Modelul începe cu ligandul într-un 3D pose random și noisy, și îi face denoise iterativ. Rafinează coordonatele spațiale ale moleculei până când aceasta se așază în configurația corectă de legare în interiorul pocket-ului proteinei.
Modelele avansate de docking duc asta cu un pas mai departe, tratând ținta în sine ca pe o entitate flexibilă. Un model numit Re-Dock folosește o tehnică numită diffusion bridge pentru a prezice binding pose-urile ligandului, modelând simultan mișcarea sidechain-urilor din pocket. Asta creează un scenariu de docking realist și flexibil, în care atât ligandul, cât și ținta se adaptează unul la celălalt în timpul fazei de predicție.
Schimbarea critică aici este că modelele de diffusion au îndepărtat structural drug design-ul de aproximările rigide și izolate. Tratând atât ligandul generat, cât și pocket-ul biologic ca pe un sistem geometric continuu și adaptabil, modelul generează nativ ca output molecule și pose-uri care sunt ancorate fizic în realitatea precisă a mediului țintă.
Asta e tot pentru acest episod. Mersi că m-ai ascultat și spor la construit!
19
Capcana dimensiunii în evaluarea generativă
4m 46s
Învață de ce benchmark-urile standard pentru modelele generative pot fi profund viciate. Dezvăluim efectul de confuzie al dimensiunii bibliotecii generate asupra metricilor precum Fréchet ChemNet Distance.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 19 din 22. Îți evaluezi noul model de chimie generativă făcând sampling pe o mie de molecule, iar metricile arată groaznic. Generezi o sută de mii din exact același model și, dintr-o dată, rezultatele sunt de clasă mondială. Scale-ul schimbă totul. Acest fenomen se numește Size Trap în evaluarea generativă.
Pipeline-urile de generative drug discovery urmează, în general, trei etape. Faci train, generezi și evaluezi. Când practicienii ajung în etapa de evaluare, se confruntă cu o întrebare de bază despre câte designuri de novo să genereze pentru benchmarking. Practica standard folosește adesea batch-uri mici, de obicei o mie sau zece mii de string-uri SMILES. Echipele rulează apoi aceste batch-uri prin metrici distribuționale standard. Cea mai comună este Fréchet ChemNet Distance, sau FCD. FCD măsoară cât de aproape sunt moleculele tale generate de training set-ul tău în spațiul chimic și biologic. Un scor FCD mai mic înseamnă că distribuția generată se potrivește foarte bine cu distribuția ta target. O altă metrică comună este Fréchet Descriptor Distance, sau FDD, care compară distribuția proprietăților fizico-chimice precum greutatea moleculară și topological surface area. De asemenea, echipele măsoară frecvent Uniqueness, care este fracția de designuri generate care sunt distincte.
Iată ideea cheie. Toate aceste metrici depind enorm de dimensiunea fizică a librăriei generate. Ele nu măsoară calitatea absolută a modelului într-un vid. Când faci sampling pe doar o mie de molecule, scorurile tale FCD și FDD vor fi artificial de mari. Modelul pare că a eșuat în a învăța distribuția target. Dar dacă continui să faci sampling din exact același model, împingând dimensiunea librăriei peste zece mii, cincizeci de mii sau o sută de mii de molecule, scorul FCD scade semnificativ. Acesta continuă să scadă până când, în cele din urmă, atinge un platou.
Acest lucru se întâmplă deoarece designul generativ de molecule implică sampling-ul dintr-o distribuție de probabilitate învățată extrem de complexă. Un sample minuscul de o mie de molecule nu poate reprezenta în mod adecvat întregul scope al acelui output al modelului. Algoritmii de distanță Fréchet au nevoie de un număr masiv de sample-uri pentru a capta cu precizie forma spațiului generat și a o compara cu spațiul de fine-tuning.
Ia în considerare un scenariu concret în care compari o rețea neuronală recurentă cu un transformer. Dacă evaluezi rețeaua recurentă folosind o sută de mii de designuri, dar evaluezi transformer-ul folosind doar zece mii, rețeaua recurentă va afișa probabil scoruri FCD și FDD mult superioare. Diferența de performanță nu are nicio legătură cu arhitectura. Este pur și simplu un artefact al sample size-ului. Metricile nu au convers pentru librăria mai mică.
Această capcană funcționează invers atunci când te uiți la diversitatea internă. Uniqueness se comportă complet diferit la scale. La o mie de molecule, aproape fiecare string SMILES valid pe care modelul tău îl generează ar putea fi unic. Modelul pare extrem de creativ. Dar pe măsură ce împingi generarea spre o sută de mii, uniqueness-ul scade brusc. Modelul începe să se repete. Dacă faci un ranking pentru diferite modele generative pe baza uniqueness-ului la un scale mic, diferențele dintre ele par minore. Împinge scale-ul mai sus, iar decalajul dintre modele se mărește dramatic. Ranking-ul relativ al modelelor tale se va inversa, de fapt, în funcție de dimensiunea librăriei pe care o folosești pentru a le măsura.
Pentru a repara asta, trebuie să tratezi dimensiunea librăriei ca o variabilă de control strictă în pipeline-ul tău. Nu poți compara niciodată în mod fiabil FCD, FDD sau Uniqueness între librării de dimensiuni diferite. Pentru a asigura o evaluare robustă, ar trebui să evaluezi librării care conțin cel puțin o sută de mii de designuri, astfel încât metricile distribuționale să conveargă complet. Dacă metricile tale de evaluare se modifică pur și simplu pentru că lași sampling loop-ul să ruleze mai mult timp, măsori dimensiunea sample-ului, nu inteligența modelului. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
20
Navigarea prin halucinațiile De Novo
4m 15s
Clasează inteligent moleculele generate de AI. Explorăm compromisul exploration-exploitation al probabilităților modelului și cum să filtrăm „halucinațiile chimice” frecvente, de calitate slabă.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 20 din 22. Doar pentru că un AI generativ scoate o anumită moleculă de zece mii de ori nu înseamnă că este un medicament viabil. Ai putea presupune că frecvența de generare indică calitatea sau relevanța chimică. Nu e așa. Acele output-uri foarte frecvente sunt adesea echivalentul chimic al unui large language model care halucinează. Mecanismul pentru a rezolva asta este navigarea halucinațiilor de novo folosind likelihood-ul modelului.
Când generezi o bibliotecă masivă de un milion de string-uri SMILES dintr-un chemical language model fine-tuned, trebuie să decizi ce molecule să prioritizezi pentru studii prospective. O abordare standard, dar greșită, este pur și simplu să selectezi design-urile pe care modelul le dă ca output cel mai des. Asta creează un count trap. În loc să descoperi candidați robuști pentru medicamente, ajungi să extragi substructuri de bază, repetitive, cum ar fi inele benzenice izolate, amine simple și eteri de bază. Astea sunt halucinații structurale recurente. Modelul le generează constant nu pentru că sunt de înaltă calitate, ci pentru că sunt simplu de construit din punct de vedere sintactic.
Pentru a expune și filtra aceste halucinații, îți evaluezi biblioteca folosind likelihood-ul modelului. Likelihood-ul este o metrică ce surprinde cât de bine se aliniază o secvență generată cu distribuția de probabilitate pe care modelul a învățat-o în timpul training-ului. Pentru un model autoregresiv, calculezi asta înmulțind probabilitatea de sampling a fiecărui token individual din string-ul SMILES generat. Mai întâi, calculezi scorul de likelihood pentru toate cele un milion de design-uri generate. Apoi, sortezi întreaga bibliotecă pe baza acestor scoruri. În cele din urmă, împarți biblioteca sortată în zece grupuri egale, sau decile, variind de la cel mai mic likelihood la cel mai mare.
Aici devine interesant. Analizarea acestor decile dezvăluie un tradeoff strict între explorare și exploatare. A zecea decilă conține generările cu cel mai mare likelihood. Aceste design-uri reprezintă exploatarea. Au o validitate chimică extrem de ridicată, iar scaffold-urile lor generice Bemis-Murcko se potrivesc îndeaproape cu moleculele active cunoscute din datele tale de training. Modelul exploatează la maximum ceea ce știe deja că funcționează. Dezavantajul este că acestor design-uri top-tier le lipsește noutatea. Conțin foarte puține substructuri noi, deoarece modelul merge la sigur.
Coborând la decilele intermediare, dai de un echilibru. Noutatea și substructurile unice ating un peak în acest interval de mijloc, în timp ce validitatea rămâne acceptabilă. Dar când cobori la prima decilă — acel zece la sută din molecule cu cele mai mici scoruri absolute de likelihood — te lovești de count trap. Dacă izolezi design-urile pe care modelul le-a generat de mai mult de zece ori pe parcursul întregului run de un milion de molecule, aproape toate se grupează în această decilă inferioară. Au likelihood-uri incredibil de mici, dar apar cu o frecvență masivă. Similitudinea lor structurală cu training set-ul tău este teribilă, iar validitatea lor chimică generală se prăbușește.
Împărțind biblioteca în bin-uri în acest fel, dovedești matematic că frecvența este un semnal fals pentru calitate. Poți elimina sistematic bin-urile cu likelihood scăzut și frecvență ridicată și îți poți concentra screening-ul computațional pe decilele intermediare, unde are loc explorarea chimică reală. Cele mai frecvente output-uri ale unui model chimic generativ sunt adesea cele mai slabe, dar filtrarea bibliotecii tale după decile de likelihood transformă acel zgomot într-o hartă precisă a zonelor în care modelul explorează și a celor în care pur și simplu halucinează.
Asta e tot pentru acest episod. Mersi că ai ascultat și continuă să construiești!
21
Constrângeri în eșantionarea moleculelor
4m 35s
Înțelege de ce tehnicile de NLP eșuează în chimie. Comparăm Temperature sampling cu Top-k și Top-p, și de ce vocabularul chimic constrâns schimbă totul.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 21 din 22. În procesarea limbajului natural, sampling-ul Top-p produce un text extrem de creativ. Dar dacă aplici exact aceeași logică la generarea de molecule, AI-ul tău va printa pur și simplu inele de carbon identice la nesfârșit. Motivul se reduce la constrângerile de sampling al moleculelor.
Când un model de limbaj chimic generează un string SMILES, acesta construiește molecula token cu token. Modelul prezice o distribuție de probabilitate pentru următorul token, iar tu trebuie să extragi o alegere specifică din acea distribuție. În generarea de text, practicienii se bazează enorm pe sampling-ul Top-k și Top-p pentru a face această alegere. Top-k restricționează modelul la cele mai probabile k tokenuri. Top-p restricționează selecția la cel mai mic grup de tokenuri ale căror probabilități combinate depășesc un procent țintă p.
Dacă aplici aceste metode unui model de limbaj chimic, ele eșuează catastrofal. Dacă folosești sampling-ul Top-k cu k setat la 3 pe un LSTM antrenat pe ținte medicamentoase, modelul tău va suferi un mode collapse sever. Va da ca output molecule valide din punct de vedere chimic, dar ele vor fi complet repetitive.
Iată ideea cheie. Eșecul provine din dimensiunea vocabularului chimic. Un model de text selectează din sute de mii de cuvinte. Un model de limbaj chimic folosește un alfabet extrem de restrâns. Are doar o mână de elemente precum carbonul, oxigenul și azotul, plus tokenuri de sintaxă pentru ramificare și închiderea inelelor.
Pentru că alfabetul chimic este minuscul și pentru că o chimie validă necesită reguli de sintaxă rigide, cum ar fi închiderea fiecărui inel deschis, un subset foarte mic de tokenuri domină absolut distribuția de probabilitate. Carbonul și tokenurile structurale de bază sunt aproape mereu foarte probabile. Când aplici sampling-ul Top-k sau Top-p, tai coada lungă a distribuției de probabilitate. Modelul este forțat să aleagă exclusiv din acea bandă îngustă de tokenuri dominante. Rămâne prins într-o capcană de filtrare, repetând exact aceleași scaffold-uri de bază la nesfârșit.
Pentru a scăpa de această capcană, trebuie să folosești Temperature sampling. În loc să filtreze tokenurile, Temperature sampling aplică un parametru de netezire scorurilor brute ale rețelei neuronale înainte de a calcula probabilitățile finale. Asta modifică forma întregii distribuții.
Ia în considerare un scenariu în care rulezi un model LSTM fine-tuned pentru a genera noi candidați de medicamente. Ajustezi parametrul Temperature, T, pentru a regla compromisul dintre validitate și diversitate. Dacă setezi T la o valoare scăzută, în jur de 0.5, distribuția de probabilitate formează un vârf ascuțit. Modelul exploatează intens tokenurile cele mai probabile. Output-ul tău va avea o validitate chimică extrem de ridicată, dar structurile vor fi lipsite de noutate. Ele vor imita îndeaproape training set-ul.
Dacă crești T până la 1.5 sau 2.0, aplatizezi distribuția de probabilitate. Acum, tokenurile mai puțin probabile au o șansă matematică de a fi alese prin sampling. Modelul tău începe să exploreze un nou spațiu chimic. Numărul de substructuri unice din biblioteca generată crește brusc. Găsești molecule extrem de noi. Compromisul este că temperaturile mai ridicate cresc randomness-ul, făcând modelul să facă mai multe erori de sintaxă, ceea ce reduce procentul general de stringuri SMILES valide.
Nu poți porta orbește strategiile de generare de text în designul molecular. Pentru că vocabularul chimic este inerent limitat, Temperature scaling rămâne cea mai eficientă pârghie pentru a echilibra validitatea chimică strictă cu explorarea de structuri noi.
Mersi că ai stat pe aici. Sper că ai învățat ceva nou.
22
Implementarea cheminformaticii în Cloud
3m 55s
Du-ți pipeline-ul de AI în producție. Discutăm despre împachetarea RDKit și a modelelor de machine learning în containere Docker și scalarea volumelor de lucru pe infrastructura de cloud.
Salut, sunt Alex de la DEV STORIES DOT EU. Python Cheminformatics & AI, episodul 22 din 22. Ai construit un pipeline de drug discovery bazat pe AI de ultimă generație pe laptopul tău, dar cum scanezi un miliard de molecule în weekend? Răspunsul este să faci deploy la Cheminformatics în Cloud.
Mutarea unui model dintr-un mediu local într-o arhitectură cloud distribuită eșuează de obicei la nivelul de dependențe. RDKit nu este o library Python pură. Este un codebase C++ mare care necesită dependențe la nivel de sistem, în special acele libraries Boost C++. Dacă faci provision la servere cloud generice și rulezi scripturi de instalare standard, te lovești frecvent de erori de compilare sau de fișiere shared object lipsă. Documentația oficială RDKit subliniază că un build din sursă necesită un toolchain C++ specific. Deși există pip wheels precompilate, cel mai robust mod de a garanta că toate dependențele de la bază se aliniază este să folosești Conda. Totuși, instalarea dinamică a Conda pe mii de cloud workers temporari durează prea mult și introduce instabilitate în rețea în timpul unui scale-up.
Iată ideea cheie. Ocolești complet problema dependențelor făcând wrap la pipeline-ul tău într-un container Docker. Scrii un fișier de configurare care specifică un sistem de operare de bază. În interiorul acelui container, instalezi un environment Conda lightweight, dai pull la binarele RDKit compilate și adaugi framework-urile tale de machine learning, cum ar fi PyTorch sau XGBoost. La final, copiezi weights-urile modelului tău pre-antrenat în image. Când dai build la acest image, îngheți întregul stack într-un singur artefact imuabil. Cloud provider-ul trebuie doar să știe cum să ruleze un container Docker standard. Dependențele complexe C++ sunt blocate în siguranță în interior.
Pentru a procesa milioane de molecule, îți separi fluxul de date de compute workers folosind un message queue în cloud. Partiționezi dataset-ul tău masiv de strings SMILES în chunks mai mici, ușor de gestionat. Plasezi aceste chunks într-un object storage în cloud și trimiți un mesaj care conține locația chunk-ului către queue.
Apoi, direcționezi un serviciu scalabil de cloud compute către acest queue. Pentru workloads grele, accelerate de GPU, faci deploy la container folosind un serviciu precum AWS Batch. Pentru o inferență mai ușoară, bazată pe CPU, platformele de containere serverless precum Google Cloud Run sau AWS Lambda gestionează perfect acest lucru. Configurezi serviciul de compute să facă scale automat în funcție de adâncimea queue-ului. Dacă sunt cincizeci de mii de mesaje în așteptare, cloud controller-ul dă spin up simultan la mii de containere Docker identice.
Fiecare container se conectează la queue și preia un mesaj. Descarcă chunk-ul corespunzător de strings SMILES. RDKit convertește SMILES în grafuri moleculare, calculează descriptorii necesari și îi transmite modelului tău de machine learning pentru inferență. Containerul scrie moleculele cu cel mai mare scor direct într-o bază de date cloud managed. Odată ce chunk-ul este procesat, worker-ul șterge mesajul din queue și îl preia pe următorul. Când queue-ul este gol, infrastructura cloud termină automat containerele. Plătești doar pentru secundele exacte de compute pe care codul tău le-a consumat efectiv.
Scalarea cheminformaticii constă rareori în scrierea unor structuri de loop mai rapide în Python; este vorba despre împachetarea fiabilă a environment-ului tău și utilizarea unei arhitecturi cloud decuplate pentru a procesa datele în paralel. Asta încheie seria noastră despre Python Cheminformatics și AI. Te încurajez să citești documentația oficială RDKit despre instalare, să încerci să containerizezi un script simplu hands-on, sau să vizitezi devstories dot eu pentru a sugera subiecte pentru seriile viitoare. Asta e tot pentru acest episod. Mulțumesc pentru audiție și continuă să construiești!
Tap to start playing
Browsers block autoplay
Share this episode
Episode
—
Copy this episode in another language:
Acest site nu folosește cookie-uri. Furnizorul nostru de hosting ar putea înregistra adresa ta IP în scopuri de analiză. Află mai multe.