Voltar ao catálogo
Season 19 22 Episódios 1h 28m 2026

Python Cheminformatics & AI

Edição de 2026. Um curso prático que leva os programadores de Python desde os conceitos básicos de química até à conceção de sistemas de quimioinformática impulsionados por IA. Aprenda a utilizar o RDKit, scikit-fingerprints e técnicas de deep learning de ponta, como Graph Neural Networks e Diffusion Models, para a descoberta de fármacos.

Computação Científica Quimioinformática Deep Learning para a Ciência
Python Cheminformatics & AI
A Reproduzir
Click play to start
0:00
0:00
1
A Molécula Digital
Apresentamos o RDKit e o conceito central da representação da química em Python. Os ouvintes vão aprender a inicializar objetos moleculares a partir de strings e a compreender o papel central da framework na descoberta de fármacos com IA.
3m 38s
2
I/O em Quimioinformática
Aprenda a ingerir e exportar com segurança datasets químicos massivos. Abordamos a leitura de ficheiros SDF e SMILES, o tratamento de erros de parsing e a escrita de dados de volta para o disco.
3m 52s
3
Travessia de Grafos Moleculares
Descubra como as moléculas são representadas como estruturas de dados em grafo. Exploramos a iteração sobre átomos, a análise de ligações e a identificação de sistemas de anéis dentro das moléculas.
3m 43s
4
Pesquisa de Subestruturas
Domine a arte de consultar moléculas utilizando SMARTS. Mostramos passo a passo como encontrar grupos funcionais e padrões específicos dentro de estruturas químicas complexas.
3m 58s
5
Fingerprinting e Similaridade Molecular
Explore como traduzir grafos moleculares em vetores de bits matemáticos. Abordamos as MACCS keys, os Morgan fingerprints e o cálculo da Tanimoto similarity.
4m 09s
6
Quebrar o Plano 2D
Faça a transição de desenhos 2D planos para geometrias 3D realistas. Discutimos a adição de hidrogénios explícitos e a geração de confórmeros 3D fiáveis utilizando o ETKDG.
4m 27s
7
Acelerar a Feature Engineering
Crie uma ponte entre a quimioinformática e a ciência de dados padrão com o scikit-fingerprints. Exploramos a geração de mais de 30 tipos de fingerprints moleculares diretamente numa interface do scikit-learn.
4m 11s
8
Quimioinformática de Alto Desempenho
Aprenda a processar datasets químicos massivos de forma eficiente. Mergulhamos na utilização de paralelismo de CPU com o Joblib e na poupança de memória utilizando matrizes esparsas do SciPy.
4m 10s
9
Pipelines de ML End-to-End
Combine o processamento, o fingerprinting e a previsão numa única arquitetura limpa. Construímos pipelines robustas no scikit-learn que integram perfeitamente a geração de confórmeros 3D e a previsão de propriedades.
3m 51s
10
Prever a Afinidade de Ligação
Explore a realidade da previsão da afinidade de ligação proteína-ligando. Comparamos o desempenho de modelos 2D simples baseados em árvores com as complexas Graph Neural Networks 3D.
4m 14s
11
LLMs vs Fingerprints Clássicos
Descubra como o Natural Language Processing se aplica à química. Colocamos frente a frente os embeddings vetoriais de Large Language Models e os fingerprints estruturais clássicos do RDKit para prever a bioatividade.
4m 16s
12
Active Learning para Rastreio Virtual
Aprenda a descobrir iterativamente os melhores candidatos a fármacos sem testes exaustivos. Mergulhamos em loops de active learning e estratégias de seleção greedy para maximizar as taxas de sucesso.
4m 35s
13
O Desafio dos Activity Cliffs
Examine a fragilidade das relações estrutura-atividade. Discutimos os 'activity cliffs' — onde uma pequena alteração estrutural causa uma mudança massiva na potência de um fármaco.
3m 45s
14
Similarity-Quantized Relative Learning
Resolva o problema dos activity cliffs repensando a forma como os modelos aprendem. Exploramos a framework SQRL, que treina a IA para prever diferenças relativas de propriedades entre pares moleculares estritamente filtrados.
3m 27s
15
A Revolução da Generative AI
Faça a transição da previsão de propriedades para a imaginação de moléculas inteiramente novas. Mapeamos o panorama das tarefas generativas moleculares: geração De Novo, otimização e geração de confórmeros.
3m 38s
16
A Intuição da Molecular Diffusion
Desconstruímos o conceito central dos Diffusion Models sem a matemática pesada. Os ouvintes vão compreender o processo direto de adicionar ruído a uma molécula e o processo inverso de alucinar novas estruturas.
3m 44s
17
Unir os Espaços Generativos 2D e 3D
Exploramos como a IA representa realmente as moléculas que gera. Comparamos a geração de grafos topológicos 2D planos com a geração de point clouds geométricas 3D complexas, e os desafios de cada uma.
4m 01s
18
Target-Aware Generation e Docking
Descubra a conceção generativa context-aware. Discutimos a geração de novas moléculas diretamente dentro da bolsa de ligação de uma proteína de doença para maximizar a afinidade de ligação.
3m 51s
19
A Armadilha do Tamanho na Avaliação Generativa
Aprenda por que razão os benchmarks padrão para modelos generativos podem ser profundamente falhos. Revelamos o efeito de confusão do tamanho da biblioteca gerada em métricas como a Fréchet ChemNet Distance.
4m 34s
20
Navegar pelas Alucinações De Novo
Classifique as moléculas geradas por IA de forma inteligente. Exploramos o tradeoff de exploration-exploitation das probabilidades do modelo e como filtrar 'alucinações químicas' frequentes e de baixa qualidade.
3m 54s
21
Restrições de Sampling de Moléculas
Compreenda por que razão as técnicas de NLP falham na química. Comparamos o Temperature sampling com o Top-k e o Top-p, e por que razão o vocabulário químico restrito muda tudo.
4m 29s
22
Fazer o Deploy de Quimioinformática na Cloud
Leve a sua pipeline de IA para produção. Discutimos o empacotamento do RDKit e de modelos de machine learning em contentores Docker e o escalonamento de cargas de trabalho em infraestruturas cloud.
4m 12s

Episódios

1

A Molécula Digital

3m 38s

Apresentamos o RDKit e o conceito central da representação da química em Python. Os ouvintes vão aprender a inicializar objetos moleculares a partir de strings e a compreender o papel central da framework na descoberta de fármacos com IA.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 1 de 22. Antes de poderes prever a toxicidade de um medicamento com um modelo de machine learning, tens de resolver um problema fundamental. Precisas de uma forma de ensinar ao Python o que é realmente uma molécula. Tipos de dados standard, como strings e lists, não percebem nada de átomos, ligações ou estruturas de anéis. Para colmatar essa falha, precisas de um tradutor universal entre química e código. É exatamente isso que o RDKit oferece, introduzindo o conceito da molécula digital. O RDKit é o toolkit open-source de quimioinformática standard da indústria. Na sua essência, é uma library C++ de alta performance, mas expõe uma interface Python massiva e intuitiva. Ele existe porque representar estruturas químicas computacionalmente é surpreendentemente difícil. Matematicamente, uma molécula é um grafo. Os átomos são os nodes, e as ligações químicas são as edges que ligam esses nodes. Se tentares construir um parser de grafos custom do zero sempre que quiseres analisar dados químicos, vais passar o teu tempo todo a fazer o debug de edge cases. O RDKit abstrai essa complexidade, gerindo a lógica do grafo nos bastidores. Para teres uma molécula no Python, primeiro precisas de uma representação em texto da sua estrutura. O formato mais comum é uma string SMILES. O SMILES usa caracteres standard para representar a conectividade química. Por exemplo, um átomo de carbono isolado é simplesmente um C maiúsculo. O benzeno, que é um anel de seis carbonos com ligações duplas alternadas, escreve-se com um c minúsculo, o número um, mais quatro caracteres c minúsculos, e um c minúsculo final seguido do número um para fechar o anel. Aqui está o ponto chave. Essa string SMILES é apenas plain text. Para o Python, é indistinguível de uma password ou de um file path. Não podes calcular o peso molecular a partir de uma raw string. Para fazeres química a sério, tens de a converter num objeto de molécula do RDKit. Tratas disso importando o módulo Chem do RDKit. A seguir, chamas uma função específica desenhada para criar uma molécula a partir de uma string SMILES, e passas-lhe a tua variável de texto. Quando passas a string SMILES do benzeno para esta função, o RDKit faz o trabalho pesado. Ele faz o parse do texto, constrói o grafo de nodes e edges, atribui as ordens de ligação, e valida regras químicas básicas, como as valências atómicas. Se a string representar uma molécula válida, a função faz o return de um objeto de molécula. Se lhe passares uma estrutura quimicamente impossível ou um typo, a função falha de forma segura. Faz o print de um warning na tua consola e devolve um objeto null. Por causa disto, deves sempre verificar se o teu objeto de molécula realmente existe antes de o passares para o próximo step do teu programa. Assim que tiveres esse objeto de molécula validado em memória, todo o ecossistema do RDKit fica desbloqueado. Já não estás a trabalhar com texto; estás a trabalhar com um grafo químico computável. A conclusão essencial aqui é que as strings SMILES servem estritamente para storage e transferência de dados, mas os objetos de molécula do RDKit são para computação. Tudo o que fazes em química computacional começa com essa conversão. Se quiseres ajudar a apoiar o programa, podes procurar por DevStoriesEU no Patreon — ajuda-nos imenso. Por este episódio é tudo. Obrigado por ouvires, e continua a desenvolver!
2

I/O em Quimioinformática

3m 52s

Aprenda a ingerir e exportar com segurança datasets químicos massivos. Abordamos a leitura de ficheiros SDF e SMILES, o tratamento de erros de parsing e a escrita de dados de volta para o disco.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 2 de 22. Uma única coordenada em falta num dataset de um milhão de moléculas pode fazer crashar todo o teu pipeline. Se assumires que cada registo de texto no teu ficheiro de fornecedor é química perfeitamente formatada, o teu script Python vai acabar por lançar uma exception fatal a meio de um job de dez horas. Defenderes-te contra dirty data enquanto moves estruturas para dentro e para fora dos teus scripts é obrigatório, e é exatamente isso que resolvemos hoje com I/O em Quimioinformática. Quando recebes um standard structure-data file, ou SDF, cheio de potenciais ligandos, precisas de uma forma de fazer o seu parse. No RDKit, a ferramenta default para isto é o SD molecule supplier. Inicializas isto passando o file path como uma string. Este objecto supplier funciona de forma muito parecida com uma list em Python. Podes fazer um loop sobre ele, podes pedir o seu length total, e podes extrair um registo específico pelo seu número de index. Ele faz isto através de um scan rápido ao ficheiro para encontrar onde cada molécula começa, permitindo-te saltar pelos dados. Às vezes não podes fazer scan antecipadamente. Se estiveres a fazer pipe de dados diretamente de uma web stream, ou a ler um ficheiro gzipped massivo chunk a chunk, não tens random access. Para estas situações, usas o forward SD molecule supplier. Em vez de um file path, passas-lhe um file object aberto. Este forward supplier é um iterator estrito. Lê uma molécula, faz o seu parse, e passa imediatamente para a próxima. Não podes pedir o seu length, e não podes pedir a quinquagésima molécula sem ler as primeiras quarenta e nove. Trocas flexibilidade por baixo uso de memória e compatibilidade com streams. Aqui está o insight principal. Independentemente de qual supplier uses, o RDKit não lança uma exception de Python quando encontra uma molécula corrompida. Se um bloco de texto no teu ficheiro tiver uma valência inválida ou um typo de formatação, o RDKit vai fazer output de uma mensagem de erro para a consola, mas o objecto Python real que ele faz yield para essa iteração do loop será simplesmente o tipo None. Se pegares nesse objecto None e tentares calcular o seu peso ou fazer write para um novo ficheiro, o teu script vai crashar. Lidar com isto é simples, mas crítico. A primeiríssima linha dentro do teu loop de parsing deve sempre verificar se a molécula retornada é None. Se for None, usas o statement continue para saltar para o próximo registo. Isto filtra silenciosamente os garbage data e mantém o teu pipeline a correr. Depois de fazeres o parse e filtrares as tuas moléculas válidas com segurança, normalmente precisas de guardar os resultados. Para isto, usas o SD writer. Inicializas o writer passando o file path de output desejado. Dentro do teu loop seguro, logo a seguir à tua verificação de None, passas o objecto de molécula válido para o writer usando o seu método write. Assim que o loop terminar de processar cada ligando, chamas o método close no writer para garantir que todos os dados fazem flush para o disco em segurança. Também podes envolver o writer num context manager standard de Python para que ele se feche automaticamente quando o bloco terminar. Para juntar tudo isto num script de data cleaning, primeiro, cria o teu SD writer para o ficheiro de output. Segundo, cria o teu SD molecule supplier para o ficheiro de input. Faz um loop pelo supplier. Verifica se o item atual é None, e se for, salta-o. Se for válido, entrega-o ao writer. Fecha o writer no final. Trata sempre os datasets de química externos como inerentemente sujos; verificar se uma molécula que sofreu parse não é None é a apólice de seguro mais barata que o teu código alguma vez terá. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
3

Travessia de Grafos Moleculares

3m 43s

Descubra como as moléculas são representadas como estruturas de dados em grafo. Exploramos a iteração sobre átomos, a análise de ligações e a identificação de sistemas de anéis dentro das moléculas.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 3 de 22. Para um computador, uma molécula não é um objeto físico que ocupa espaço. É estritamente um grafo de nós e arestas à espera de ser parsed. Se não consegues navegar de forma eficiente por esse grafo subjacente, não consegues analisar a estrutura química. Isto leva-nos diretamente ao traversal de grafos moleculares. No RDKit, um objeto molecule atua como um container primário para esta estrutura de dados em grafo. Para inspecionar os nós, usas o método GetAtoms. Isto retorna uma sequência iterável que contém todos os objetos atom na molécula. Podes escrever um loop simples para percorrer esta sequência um por um. Para um cenário concreto, supõe que precisas de extrair os números atómicos de todos os teus nós. Dentro do teu loop, podes chamar o método GetIdx para encontrar o identificador numérico único do atom atual, e o método GetAtomicNum para descobrir exatamente qual é o elemento químico. Ao iterar, processas cada nó sistematicamente. Os nós, por si só, não definem a química. Também precisas das arestas que os ligam, às quais acedes usando o método GetBonds. Tal como acontece com os atoms, isto fornece uma sequência iterável de objetos bond. Um bond conhece a sua posição exata no grafo. Ao chamar os métodos GetBeginAtomIdx e GetEndAtomIdx num objeto bond, extrais os identificadores numéricos específicos dos dois atoms que ele liga. Também podes ler o bond type, determinando se é uma ligação simples, dupla ou aromática. Aqui está o ponto chave. O RDKit trata os bonds como first-class objects na hierarquia do grafo, o que significa que os consultas de forma independente, em vez de os extraíres das propriedades dos atoms. Navegar por nós e arestas individuais é lógica standard de grafos, mas os grafos químicos frequentemente apresentam ciclos, mais conhecidos como anéis. Não precisas de escrever os teus próprios algoritmos de traversal para encontrar ciclos. O RDKit pré-calcula estes ciclos quando a molécula é instanciada. Acedes a estes dados através do método GetRingInfo. Isto retorna um objeto ring info dedicado, em vez de uma simples lista. Se a tua tarefa for simplesmente contar o número de anéis na molécula, chamas o método NumRings diretamente neste objeto ring info. Quando precisares de detalhes estruturais mais profundos, podes consultar a propriedade AtomRings deste mesmo objeto. Isto dá-te uma coleção de sequências, onde cada sequência contém os índices exatos dos atoms que compõem um anel específico no grafo. Podes até passar um atom index ao objeto ring info para perguntar se esse nó específico participa num anel de um tamanho particular, como um ciclo de cinco ou seis membros. Fazer o traversal de uma molécula é, no fundo, encadear estas operações básicas. Pegas no ring info para verificar a macroestrutura, fazes um loop pelos atoms para ler dados ao nível do nó, como números atómicos, e fazes um loop pelos bonds para mapear as conexões de arestas específicas. Assim que deixas de ver uma molécula como uma entidade física e começas a vê-la como uma coleção previsível de nós indexados, arestas e ciclos pré-calculados, a extração de propriedades estruturais torna-se uma tarefa standard de data parsing. É tudo por este episódio. Obrigado por ouvires, e continua a construir!
4

Pesquisa de Subestruturas

3m 58s

Domine a arte de consultar moléculas utilizando SMARTS. Mostramos passo a passo como encontrar grupos funcionais e padrões específicos dentro de estruturas químicas complexas.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 4 de 22. Tu não tentarias fazer o parse de milhares de logs de texto sem usar regular expressions. Da mesma forma, não deverias tentar filtrar bases de dados químicas sem padrões SMARTS. Encontrar grupos funcionais específicos em grandes datasets requer uma lógica estrutural dedicada, e é exatamente isso que o Substructure Searching oferece. Supõe que tens uma biblioteca de candidatos a fármacos. O teu objetivo é sinalizar e isolar qualquer molécula que contenha um grupo funcional tóxico específico e conhecido. Primeiro, defines esse grupo tóxico usando uma string SMARTS. O SMARTS é uma extensão do SMILES desenhada especificamente para fazer queries a padrões moleculares, permitindo-te especificar wildcards, tipos de ligação específicos ou estruturas de anel. Passas esta string de texto para a função do RDKit que cria uma molécula a partir do SMARTS. Isto gera o teu query object. As tuas moléculas-alvo, os candidatos a fármacos, já são molecule objects standard do RDKit. Para filtrar a biblioteca, pegas numa molécula candidata e chamas o método chamado has substructure match. Passas o teu query object para este método. Ele avalia a molécula candidata em relação ao padrão e devolve um valor boolean simples. True significa que o grupo tóxico existe algures dentro do candidato. False significa que está limpo. Como este método para a pesquisa no momento em que encontra um único match válido, é altamente otimizado. Podes fazer um loop desta verificação boolean por toda a tua biblioteca para dividir rapidamente um dataset massivo em subsets seguros e sinalizados. Agora, e se simplesmente saber que o grupo tóxico está presente não for suficiente? Talvez a toxicidade aumente com o número de vezes que o grupo aparece, ou precises de isolar a localização exata dos átomos tóxicos para um biólogo estrutural. Para isto, usas o método chamado get substructure matches, no plural. Chamas isto na tua molécula candidata, passando novamente o query object. Em vez de um boolean, este método força o motor de pesquisa a mapear todas as ocorrências possíveis do padrão. Ele devolve um tuple que contém outros tuples. Cada tuple interno representa um match completo do teu padrão. Os inteiros dentro destes tuples são os índices exatos dos átomos dentro da molécula candidata. Aqui está o ponto chave. A ordem desses índices espelha perfeitamente a ordem dos átomos definidos na tua string SMARTS original. Isto significa que sabes sempre exatamente qual o átomo no alvo que corresponde a que parte da tua query. Se o grupo tóxico aparecer três vezes no candidato, obténs três tuples internos. Podes contar os tuples para encontrar a frequência do padrão, ou passar esses índices de átomos específicos para uma função de desenho para destacar visualmente as regiões tóxicas. Se precisares apenas dos índices dos átomos do primeiro match que ele encontra, podes usar o método singular get substructure match para poupar tempo de processamento. Também deves ter em conta a estereoquímica. Por default, o substructure matching do RDKit ignora completamente a quiralidade. Uma ligação em cunha e uma ligação tracejada vão ambas acionar um match para uma query SMARTS básica. Se a toxicidade do teu alvo ocorrer apenas com um estereoisómero específico, este comportamento default vai gerar falsos positivos no teu drug screen. Para corrigir isto, passas um argumento chamado use chirality e defines-o como true ao chamar qualquer um dos métodos de matching. O RDKit vai então aplicar regras estereoquímicas com base na configuração específica definida na tua query. O verdadeiro poder do Substructure Searching é que ele mapeia uma query de texto puramente lógica diretamente na topologia física do teu dataset, servindo de ponte entre padrões de string abstratos e coordenadas atómicas concretas. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
5

Fingerprinting e Similaridade Molecular

4m 09s

Explore como traduzir grafos moleculares em vetores de bits matemáticos. Abordamos as MACCS keys, os Morgan fingerprints e o cálculo da Tanimoto similarity.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 5 de 22. Os modelos de IA não compreendem realmente átomos e ligações. Eles só compreendem números. Se queres que um algoritmo compare duas estruturas, precisas de uma forma de traduzir a química para matemática. Fingerprinting e similaridade molecular é exatamente a forma como preenchemos essa lacuna. Uma molécula no RDKit é essencialmente um graph matemático. Os átomos atuam como nodes, e as ligações atuam como edges. Para fazer cálculos rápidos nestes graphs, convertemo-los em bit vectors, que são simplesmente longos arrays de uns e zeros. Este array é chamado de fingerprint. A lógica é simples. Se uma feature estrutural específica existe na molécula, um bit específico no array é alterado para um. Se essa feature não existir, o bit fica a zero. Ao converter graphs moleculares complexos em bit vectors standard, podemos compará-los matematicamente com facilidade. O RDKit oferece vários algoritmos de fingerprinting. O fingerprint default do RDKit usa uma abordagem topológica. Ele analisa caminhos lineares através da molécula. O sistema começa num átomo e percorre as ligações conectadas até um comprimento específico, tipicamente entre uma e sete ligações. Cada caminho único que encontra é passado por uma função de hashing, que atribui esse caminho a uma posição específica no bit vector. Embora os caminhos topológicos sejam úteis, a quimioinformática moderna depende fortemente dos Morgan fingerprints, muitas vezes chamados de circular fingerprints. Em vez de traçar caminhos lineares, os algoritmos de Morgan analisam a vizinhança que irradia a partir de cada átomo. Ao gerar um Morgan fingerprint, tens de definir um radius. Um radius de zero significa que o algoritmo regista apenas os átomos individuais. Um radius de um captura cada átomo mais os seus vizinhos conectados imediatos. Um radius de dois expande esse círculo mais uma ligação. O algoritmo cataloga todos estes ambientes circulares sobrepostos, faz o hash deles, e altera os bits correspondentes para um. Normalmente, fazemos o fold destes hashes para um vector de tamanho fixo, como dois mil e quarenta e oito bits, para manter o uso de memória previsível. Os Morgan fingerprints com um radius de dois são o standard da indústria porque capturam grupos funcionais e o contexto químico local de forma excecional. Vejamos um cenário concreto. Tens duas moléculas ligeiramente diferentes. Talvez partilhem uma grande estrutura central, mas uma delas tem um grupo metilo extra ligado. Queres quantificar o quanto se sobrepõem. Primeiro, lês ambas as moléculas para o RDKit. A seguir, geras um Morgan fingerprint para cada uma, definindo o radius para dois. Agora tens dois bit vectors distintos. Para calcular o quão semelhantes são, calculas a sua Tanimoto similarity. Aqui está a ideia principal. A Tanimoto similarity ignora os zeros. Só se importa com as features que estão realmente presentes. A matemática é uma simples intersection over union. O RDKit conta o número de bits a um em ambos os fingerprints, e divide isso pelo número total de bits a um em qualquer um dos fingerprints. Se os dois vectors coincidirem perfeitamente, o Tanimoto score é um ponto zero. Se não partilharem quaisquer features, o score é zero ponto zero. Para as nossas duas moléculas que diferem por um único grupo metilo, os ambientes circulares à volta do core vão na sua maioria coincidir, enquanto os ambientes perto da mutação vão diferir. Podes obter um Tanimoto score de zero ponto oitenta e cinco, dando-te um valor numérico preciso para a sua sobreposição estrutural. Lembra-te que mapear uma molécula complexa para um array fixo de bits significa perder alguns dados, e um Tanimoto score alto garante sobreposição estrutural, não equivalência biológica. Obrigado por passares uns minutos comigo. Até à próxima, fica bem.
6

Quebrar o Plano 2D

4m 27s

Faça a transição de desenhos 2D planos para geometrias 3D realistas. Discutimos a adição de hidrogénios explícitos e a geração de confórmeros 3D fiáveis utilizando o ETKDG.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 6 de 22. Um desenho bidimensional pode parecer ótimo num ecrã, mas os fármacos existem no espaço tridimensional. Se ignorares a geometria, ignoras a realidade. Hoje, vamos quebrar o plano 2D e gerar coordenadas 3D adequadas para as tuas moléculas. Quando lês uma molécula a partir de uma string SMILES padrão, ela não tem quaisquer coordenadas. É estritamente um grafo topológico de átomos ligados. Mesmo que carregues uma estrutura a partir de um ficheiro de desenho 2D, essas coordenadas estão apenas espaçadas para facilitar a leitura humana. Para fazeres docking, calculares a área de superfície ou correres simulações físicas, precisas de uma estrutura 3D fisicamente realista. O primeiro passo absoluto antes de gerar qualquer geometria 3D é adicionar hidrogénios. Numa string SMILES padrão, os hidrogénios são implícitos. São tratados como uma propriedade básica dos átomos pesados, simplesmente a preencher os requisitos de valência. Mas no espaço físico, os hidrogénios ocupam um volume real. Eles criam impedimento estérico e ditam os ângulos das ligações à sua volta. Se tentares calcular uma estrutura 3D sem adicionares explicitamente os hidrogénios primeiro, a geometria resultante vai colapsar sobre si mesma e os ângulos de ligação vão estar completamente errados. O RDKit fornece uma função chamada AddHs que converte esses hidrogénios implícitos em nós reais no teu grafo molecular, completos com ligações. Deves sempre correr esta função antes de passares para 3D. Assim que tiveres uma molécula completa, precisas de calcular as suas coordenadas espaciais. Como as ligações simples podem rodar livremente, um ligando flexível não tem apenas uma forma estática. Pode adotar muitas formas diferentes, conhecidas como conformações. Para gerar uma conformação viável, o RDKit usa um método por defeito chamado ETKDG. Isto significa Experimental Torsion-angle Preference with Distance Geometry. Aqui está o ponto chave. Os métodos de gerações anteriores dependiam inteiramente de matemática pura. Usavam a geometria de distâncias para adivinhar as posições atómicas com base em comprimentos e ângulos de ligação conhecidos. Isto frequentemente levava a formas estranhas e de alta energia que exigiam uma limpeza computacional pesada. O ETKDG resolve isto combinando a matemática da geometria de distâncias com regras empíricas derivadas da Cambridge Structural Database. Sabe como as moléculas reais e físicas preferem realmente dobrar-se e torcer-se, e força o algoritmo de geometria a respeitar essas preferências naturais. Pensa num cenário concreto. Tens um ligando altamente flexível e precisas de perceber todas as diferentes maneiras como ele se pode dobrar para encaixar numa bolsa de ligação da proteína. Gerar uma única conformação não é suficiente para capturar esse comportamento. Precisas de um ensemble. O RDKit lida com isto através de uma função chamada EmbedMultipleConfs. Passas a tua molécula com os seus hidrogénios explícitos e especificas que queres cinquenta confórmeros. O RDKit vai então correr o algoritmo ETKDG cinquenta vezes separadas, partindo de diferentes seeds aleatórias, para gerar cinquenta geometrias 3D distintas. Armazena todas estas cinquenta formas dentro do objeto da molécula original. Não recebes cinquenta moléculas separadas de volta; recebes uma molécula que contém cinquenta conjuntos de coordenadas distintos. Podes então fazer um loop por estes conjuntos de coordenadas para medir distâncias ou calcular energias. Como o ETKDG é fortemente baseado em dados cristalográficos do mundo real, as estruturas iniciais que fornece são geralmente de altíssima qualidade, logo à saída da função. Uma molécula não é um desenho plano e raramente é apenas uma única forma rígida; é um objeto dinâmico, e fazer a amostragem dos seus múltiplos confórmeros dá-te os verdadeiros limites do seu comportamento físico. Se quiseres ajudar a manter o programa no ar, podes apoiar-nos procurando por DevStoriesEU no Patreon. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
7

Acelerar a Feature Engineering

4m 11s

Crie uma ponte entre a quimioinformática e a ciência de dados padrão com o scikit-fingerprints. Exploramos a geração de mais de 30 tipos de fingerprints moleculares diretamente numa interface do scikit-learn.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 7 de 22. Escrever loops customizados de extração de fingerprints para cada novo projeto é tedioso e propenso a erros. Mudas de um fingerprint ECFP para uma MACCS key e, de repente, tens de reescrever todo o teu bloco de preprocessing. O scikit-fingerprints é uma library que resolve isto, tornando a extração de features moleculares tão simples como chamar um transform standard do scikit-learn. As moléculas são fundamentalmente representadas como grafos. A maioria dos algoritmos de machine learning, no entanto, requer vetores multidimensionais. Os fingerprints moleculares são os algoritmos de extração de features que preenchem esta lacuna, codificando informação estrutural em arrays numéricos. O problema é que as tools open-source standard para calcular estes fingerprints, como o RDKit, o Open Babel ou o Chemistry Development Kit, estão escritas em C++ ou Java. Os seus wrappers em Python não se alinham nativamente com a API do scikit-learn. Acabas por escrever data loaders customizados, conversores de formato e loops propensos a erros só para colocar os teus dados num formato que um classifier possa consumir. O scikit-fingerprints muda esta arquitetura. Implementa mais de 30 fingerprints moleculares diferentes como transformers standard e stateless do scikit-learn. Todas as classes de fingerprints herdam das base classes do scikit-learn. Isto significa que se integram diretamente em pipelines de machine learning e feature unions standard. Considera um workflow standard. Normalmente, escreverias um loop customizado de vinte linhas no RDKit para iterar sobre um dataset, validar as moléculas, extrair fingerprints circulares e empilhar os resultados num array. Com esta library, substituis todo esse bloco de boilerplate por um único passo. Crias um objeto chamado ECFP Fingerprint e passas diretamente para um pipeline do scikit-learn, logo antes do teu modelo de random forest. Quando chamas o método fit no teu pipeline com os teus dados de treino e variáveis target, o transformer de fingerprints processa os inputs e devolve um array NumPy denso diretamente para o modelo. Aqui está o insight principal. Não precisas de converter as tuas representações de texto em objetos de molécula do RDKit antes de as passares para o transformer. Para qualquer fingerprint bidimensional baseado em topologia de grafos, o método transform aceita diretamente uma lista standard de strings SMILES de Python. A library lida com a conversão interna automaticamente. Como as strings SMILES nem sempre são únicas ou quimicamente válidas, a library também fornece uma classe Molecule Standardizer. Esta classe aplica os passos de sanitização recomendados pelo RDKit para garantir a qualidade dos dados antes do início da extração. A library também suporta fingerprints tridimensionais que dependem da conformação espacial. Estes algoritmos espaciais exigem objetos de molécula do RDKit com conformers calculados. Gerar conformers pode ser instável, por isso o package inclui uma classe Conformer Generator que usa um algoritmo específico conhecido como ETKDG versão 3. Isto fornece defaults fiáveis que maximizam a eficiência para moléculas simples, minimizando falhas de cálculo em compostos complexos. Colocas o conformer generator no início do teu pipeline, seguido por um transformer de fingerprints tridimensional, e terminas com um imputer para lidar com quaisquer missing values. Ao encapsular a lógica complexa de química dentro de classes de transformers standard, a library abstrai o boilerplate específico do domínio. Configuras opções como o comprimento do vetor de output ou se queres uma variante binária ou de contagem simplesmente passando parâmetros para o construtor do transformer. O resultado é que fazer o tuning de hyperparameters para fingerprints moleculares torna-se tão simples como ajustar a profundidade de uma decision tree. É tudo por agora. Até à próxima!
8

Quimioinformática de Alto Desempenho

4m 10s

Aprenda a processar datasets químicos massivos de forma eficiente. Mergulhamos na utilização de paralelismo de CPU com o Joblib e na poupança de memória utilizando matrizes esparsas do SciPy.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Python Cheminformatics e AI, episódio 8 de 22. Calcular subestruturas complexas num dataset massivo pode facilmente dar crash à tua máquina com erros de out-of-memory, a menos que saibas exatamente como gerir o teu data footprint. A técnica que resolve isto é o High-Performance Cheminformatics. Quando extrais features de uma molécula, usas frequentemente fingerprints baseados em subestruturas. O fingerprint de Klekota-Roth é um exemplo clássico. Para o calcular, a tua máquina compara uma molécula com milhares de padrões químicos predefinidos, conhecidos como SMARTS patterns. Examina o molecular graph repetidamente para ver se existem grupos funcionais ou motivos estruturais específicos. Fazer isto sequencialmente para algumas moléculas não tem problema. Fazê-lo para um dataset de quatrocentas mil moléculas é um bottleneck computacional severo. O cálculo de fingerprints moleculares é uma tarefa embarrassingly parallel. A análise estrutural de uma molécula tem absolutamente zero dependência da análise da próxima molécula no teu dataset. Como não partilham state, podes computá-los de forma totalmente simultânea. Para escalar isto de forma eficaz em Python, utilizas o Joblib, dependendo especificamente do executor Loky. Quando inicias o processo, o dataset de input é dividido em chunks que correspondem precisamente aos teus CPU cores disponíveis. Se tiveres um processador de 16 cores, as tuas moléculas de input são divididas em 16 batches separados. Cada Python worker process pega num batch e começa a executar o SMARTS pattern matching de forma independente. O obstáculo técnico com o multiprocessing em Python é geralmente o custo de mover dados entre os workers e o main process. O Loky contorna isto usando memory mapping. Em vez de serializar os final fingerprint arrays e enviá-los através de inter-process communication, os workers escrevem diretamente num espaço de shared memory. Para fingerprints computacionalmente pesados como o de Klekota-Roth, distribuir o workload por 16 cores resulta num speedup de quase quinze vezes. Isto resolve o tempo de processamento. O segundo bottleneck crítico é a memória do sistema. Um único vetor de fingerprint de Klekota-Roth é longo. Se processares centenas de milhares de moléculas, geras uma matriz de resultados massiva. Por default, as bibliotecas numéricas devolvem este resultado como um dense NumPy array. Cada posição nessa matriz aloca memória, independentemente de o valor ser um ou zero. Os fingerprints químicos são incrivelmente sparse. Normalmente, apenas um ou dois por cento das features estruturais solicitadas estão realmente presentes numa determinada molécula. A grande maioria da tua matriz resultante consiste em zeros. Armazenar esses zeros é o que desencadeia os erros de out-of-memory em grandes datasets. A solução é mudar o formato de output para uma SciPy sparse matrix, especificamente usando o formato Compressed Sparse Row. Uma sparse matrix muda fundamentalmente a forma como os dados são armazenados. Em vez de construir uma grid rígida na memória, regista apenas os valores dos elementos non-zero, juntamente com as suas coordenadas de linha e coluna. Considera um cenário real usando o dataset PCBA, que contém pouco menos de quatrocentas e quarenta mil moléculas. Executas o cálculo do fingerprint de Klekota-Roth em todo o dataset usando os teus 16 cores. A execução paralela termina de forma eficiente. Se deixares o output como um default dense array, esta única matriz vai consumir pouco mais de dois Gigabytes de RAM. Ao instruir o cálculo a devolver um SciPy sparse array em vez disso, esse exato mesmo dataset cai para um footprint de apenas 23 Megabytes. Consegues uma redução de oitenta e oito vezes na memória sem perderes uma única informação química, e a sparse representation não afeta de todo negativamente o teu tempo de computação. Aqui está o ponto-chave. Não precisas de um compute cluster massivo para processar centenas de milhares de moléculas, desde que pares de pagar a memory tax por armazenar zeros e garantas que o teu data passing salta o overhead de standard inter-process communication. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
9

Pipelines de ML End-to-End

3m 51s

Combine o processamento, o fingerprinting e a previsão numa única arquitetura limpa. Construímos pipelines robustas no scikit-learn que integram perfeitamente a geração de confórmeros 3D e a previsão de propriedades.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 9 de 22. Um script complexo de virtual screening 3D costumava exigir centenas de linhas de código frágil. Tinhas de gerar conformers manualmente, lidar com falhas, calcular múltiplos descritores e unir os arrays antes sequer de tocares num modelo. Agora, podes arquitetar todo o processo numa única e elegante definição de pipeline usando End-to-End ML Pipelines. Em machine learning, um pipeline é uma sequência de etapas de processamento de dados e um estimator final agrupados num único objeto. Em quimioinformática, especialmente com dados estruturais 3D, o pré-processamento é notoriamente fragmentado. Pegas em strings SMILES brutas, calculas coordenadas 3D, corres otimizações de force field, extrais features, corriges missing values e, finalmente, treinas um classifier. Fazer isto manualmente significa escrever loops customizados e estruturas de dados intermédias que quebram facilmente e causam memory leaks. Vamos ver como construir um pipeline completo de scikit-learn que leva strings SMILES brutas diretamente para um classifier Random Forest. O primeiro passo na sequência é a geração de conformers. Inicializas um conformer generator e passas-o como o primeiro stage do pipeline. Ele lê o input 2D e calcula as estruturas 3D. Podes configurá-lo para otimizar a geometria usando um force field como o MMFF94. Ele paraleliza automaticamente este processamento pesado por todos os cores de CPU disponíveis. Agora, a segunda parte é a feature extraction. Para tarefas 3D, combinar diferentes descritores de geometria captura mais informação molecular. Usas uma feature union do scikit-learn para calcular as fingerprints GETAWAY e WHIM simultaneamente. Ambas estas classes de fingerprints atuam como stateless transformers no pipeline. Elas recebem os conformers 3D do passo anterior, calculam os seus respetivos descritores em paralelo e concatenam os resultados numa única e ampla feature matrix. A seguir, tens de lidar com falhas de computação. Os algoritmos de descritores 3D às vezes falham ao processar moléculas altamente complexas ou tensionadas, resultando em missing values na tua matriz. O pipeline lida com isto sem error handling customizado. Adicionas um simple imputer logo após a feature union. Se um cálculo GETAWAY ou WHIM devolver um missing value, o imputer deteta-o e substitui-o pela média dessa feature em todo o teu dataset. Finalmente, terminas o pipeline com o teu modelo preditivo, que neste caso é um classifier Random Forest. Para arquitetar isto em código, chamas a função make pipeline. Dentro dessa chamada de função, passas o teu conformer generator. A seguir, passas a feature union que contém as tuas fingerprints GETAWAY e WHIM. Depois vem o simple imputer e, por último, o classifier Random Forest. Atribuis toda esta sequência a uma única variável. Quando chamas o método fit nessa variável do pipeline, passas as tuas strings SMILES de training brutas e as tuas target labels. As strings fluem sequencialmente pelo conformer generator, para a feature union para fingerprinting, pelo imputer para limpar os dados, e diretamente para o classifier para training. Quando chega a hora de avaliar, chamar o método predict nas tuas strings SMILES de test força os novos dados a seguirem exatamente o mesmo caminho. Aqui está o ponto-chave. O state e o data routing são geridos inteiramente pelo objeto pipeline, o que significa que nunca manténs dense arrays intermédios em memória, nem escreves data loaders customizados para os teus conformers. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
10

Prever a Afinidade de Ligação

4m 14s

Explore a realidade da previsão da afinidade de ligação proteína-ligando. Comparamos o desempenho de modelos 2D simples baseados em árvores com as complexas Graph Neural Networks 3D.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 10 de 22. Configuras uma enorme graph neural network tridimensional, alimentando-a com as coordenadas espaciais de cada átomo num pocket da proteína. A seguir, corres uma gradient boosted decision tree simples que olha apenas para o sketch bidimensional do fármaco. O benchmark termina, e o teu modelo espacial de ponta acabou de ser batido por um algoritmo com duas décadas. A razão pela qual a tua network pesada falhou tem origem na forma como lidamos com a previsão da binding affinity. Prever a binding affinity é o processo computacional de estimar a força com que uma pequena molécula, ou ligando, se liga a um alvo proteico específico. Na drug discovery, encontrar uma molécula que se ligue fortemente é o grande objetivo. Para fazer isto, os engenheiros normalmente seguem um de dois caminhos. O primeiro é altamente complexo. Usas neural networks tridimensionais como GraphNet ou TensorNet. Estes modelos recebem a conformação exata de ligação do complexo proteína-ligando. Eles usam message passing layers para aprender as distâncias espaciais precisas e as features mecânico-quânticas entre os átomos do fármaco e os átomos do pocket da proteína. O segundo caminho ignora completamente a proteína. Descartas as coordenadas espaciais e usas um modelo bidimensional clássico como o XGBoost. O input aqui é apenas um vetor concatenado de molecular fingerprints. Calculas as features estruturais apenas do ligando, transformando essencialmente o desenho bidimensional do composto químico num array de números, e alimentas isso diretamente no tree-based model. Para ver como estas abordagens se comparam, os investigadores correm-nas contra test sets padronizados. Um dos mais reveladores é o benchmark Merck FEP. Este dataset simula um cenário comum de virtual screening chamado série congenérica. Numa série congenérica, todos os ligandos testados partilham exatamente o mesmo scaffold químico central e ligam-se exatamente ao mesmo local numa única proteína-alvo. As únicas diferenças entre as moléculas são pequenas variações estruturais, como diferentes ramificações químicas ligadas ao núcleo principal. Aqui está o insight principal. Quando avaliados no dataset da Merck, os modelos tridimensionais pesados alcançaram um correlation score à volta de zero vírgula três. O modelo bidimensional simples XGBoost obteve uma pontuação significativamente maior, atingindo zero vírgula quatro cinco. A decision tree computacionalmente barata superou claramente as graph neural networks avançadas. Isto acontece por causa daquilo em que os modelos são forçados a focar-se. Numa série congenérica, a proteína-alvo e o binding pocket não mudam. O modelo tridimensional gasta recursos computacionais massivos a mapear um ambiente espacial que permanece estático em cada test case. Pior ainda, estes modelos são altamente sensíveis a pequenas variações nas coordenadas atómicas. Uma ligeira alteração arbitrária na forma como um átomo de hidrogénio é posicionado durante a preparação de dados introduz ruído que distrai a graph network. O modelo bidimensional tem sucesso precisamente por ser cego à proteína. Ao olhar apenas para as features do ligando, baseia-se nas únicas variáveis que realmente mudam de um teste para o outro. A decision tree correlaciona essas variações estruturais diretas no fármaco com a força de ligação final, contornando completamente o ruído do ambiente espacial. Modelos tridimensionais pesados ainda são altamente valiosos quando precisas de generalizar para alvos proteicos completamente diferentes e nunca vistos, onde a geometria do pocket é desconhecida. Mas quando estás a otimizar uma família específica de fármacos para um único alvo conhecido, alimentar uma deep network com dados ambientais constantes é ineficiente e propenso a erros. A ferramenta preditiva mais poderosa é muitas vezes aquela que filtra o ambiente estático e modela apenas as variáveis que mudam. É tudo por este episódio. Até à próxima!
11

LLMs vs Fingerprints Clássicos

4m 16s

Descubra como o Natural Language Processing se aplica à química. Colocamos frente a frente os embeddings vetoriais de Large Language Models e os fingerprints estruturais clássicos do RDKit para prever a bioatividade.

Download
Olá, daqui é o Alex do DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 11 de 22. E se a melhor forma de descrever uma molécula a um modelo de machine learning não for através de uma fórmula estrutural feita à mão, mas sim tratando a sua string SMILES exatamente como uma frase em linguagem natural? Podes estar a gastar ciclos de computação valiosos a gerar descritores químicos complexos, apenas para seres superado por um modelo de texto. Essa tensão está no centro do debate entre LLMs e fingerprints clássicos. Ao prever a afinidade de ligação de um ligando a uma proteína, o teu modelo precisa de uma descrição matemática do ligando. A abordagem tradicional baseia-se em fingerprints estruturais clássicos calculados por ferramentas como o RDKit. Passas uma molécula por um algoritmo determinístico e recebes um vetor estático. Um fingerprint de Morgan conta subestruturas circulares à volta dos átomos. As MACCS keys comparam a molécula com uma lista predefinida de padrões químicos. A limitação destes fingerprints clássicos é a sua rigidez. Eles codificam regras específicas e imutáveis. Não podes fazer fine-tuning deles. Se uma nuance estrutural particular for importante para um binding pocket altamente específico, mas o algoritmo do fingerprint não tiver sido explicitamente desenhado para a captar, essa informação perde-se completamente antes mesmo de o modelo preditivo ver os dados. Em vez de fazer hardcode de regras químicas, podemos usar um Large Language Model, ou LLM, químico pré-treinado, como o BioT5, o GPT2 ou o BERT. Estes modelos são pré-treinados em milhões de strings SMILES. Eles aprendem a gramática da química de forma não supervisionada. Quando passas um ligando para um LLM, ele não faz output de uma checklist fixa de grupos funcionais. Ele faz output de um embedding vetorial rico. Cada caráter ou token nessa string SMILES recebe o seu próprio vetor contextual. Para entenderes a diferença, repara em como estas representações alimentam os modelos preditivos. Primeiro, considera um modelo XGBoost a usar MACCS keys clássicas. Geras o fingerprint MACCS, o que resulta num simples array binário. Passas esse vetor fixo para o XGBoost, que tenta mapear essas features brutas de presença ou ausência para a afinidade de ligação. Em testes de benchmark em séries congenéricas, esta combinação específica apresenta consistentemente a pior performance. As features feitas à mão são simplesmente demasiado básicas. Agora, troca essa arquitetura por um embedding BioT5 alimentado a uma head Transformer. Primeiro, passas a string SMILES raw para o modelo BioT5. Isto devolve uma sequência de embeddings por token. A seguir, passas essa sequência para uma head Transformer. Aqui está o insight principal. O Transformer usa um mecanismo de attention. Ele olha para toda a sequência de embeddings de tokens e aprende dinamicamente que partes da molécula importam mais para a ligação a este target específico. Ele pesa as features de forma inteligente antes de fazer output da afinidade de ligação prevista. Se tentares pegar nesses exatos mesmos tokens BioT5, somá-los num único vetor flat, e alimentar isso ao XGBoost, a performance preditiva cai significativamente. O sum pooling dilui os detalhes ao nível do token. A head Transformer tem sucesso precisamente porque preserva e explora o contexto granular da representação tipo texto. Esta mudança de arrays estáticos para embeddings dinâmicos oferece enormes benefícios práticos. Os embeddings de LLMs são altamente versáteis e podem sofrer fine-tuning para downstream tasks especializadas. Eles também são muito mais compactos do que os enormes bit vectors clássicos, o que poupa memória ao armazenar grandes bibliotecas moleculares. Além disso, a geração de text embeddings corre numa GPU, o que é drasticamente mais rápido do que calcular fingerprints tradicionais do RDKit numa CPU. A era de dizer manualmente aos algoritmos que subestruturas químicas importam está a chegar ao fim; os modelos com melhor performance são aqueles a quem é permitido ler a molécula e decidir por si mesmos. Se quiseres apoiar o programa, podes procurar por DevStoriesEU no Patreon. Obrigado por estares aí. Espero que tenhas aprendido algo novo.
12

Active Learning para Rastreio Virtual

4m 35s

Aprenda a descobrir iterativamente os melhores candidatos a fármacos sem testes exaustivos. Mergulhamos em loops de active learning e estratégias de seleção greedy para maximizar as taxas de sucesso.

Download
Olá, daqui é o Alex do DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 12 de 22. Correr simulações físicas complexas num milhão de moléculas é incrivelmente lento. Precisas de uma forma de encontrar os melhores candidatos testando apenas uma pequena fração do teu dataset. É exatamente isso que o Active Learning para Virtual Screening faz. Quando avalias uma library química, calcular binding affinities precisas usando métodos de física computacional é incrivelmente caro. Simplesmente não te podes dar ao luxo de simular cada composto individualmente. Em vez disso, testas um pequeno batch, usas esses resultados para treinar um modelo de machine learning, e deixas que esse modelo preveja as afinidades para o resto da library. A seguir, testas as previsões mais promissoras, atualizas o modelo e repetes o processo. Este ciclo iterativo é o active learning. Vamos olhar para um cenário concreto. Estás a explorar uma série congenérica de dez mil compostos que têm como alvo uma proteína específica, como a Tyk2. O teu objetivo é encontrar o top um por cento das moléculas ativas. Para fazeres isto de forma eficiente, dependes de uma estratégia de seleção greedy. Uma estratégia greedy significa que o teu modelo escolhe sempre os compostos com as maiores binding affinities previstas para a próxima ronda de testes. Defines o teu batch size para sessenta moléculas por ronda. Este número atinge um equilíbrio prático para um workflow do mundo real. É pequeno o suficiente para poderes correr simulações físicas exigentes no batch rapidamente, mas grande o suficiente para fornecer uma quantidade substancial de novos dados ao teu modelo. Corres os teus testes nestes sessenta compostos para obter as suas verdadeiras binding affinities, e alimentas imediatamente esses dados num modelo bidimensional baseado em árvores, como o XGBoost. O modelo XGBoost aprende os padrões, faz o score das restantes moléculas não testadas na pool de dez mil compostos, e seleciona os próximos sessenta candidatos. Aqui está o insight principal. A forma como escolhes o primeiro batch de sessenta moléculas dita a rapidez com que todo o teu sistema aprende. O active learning standard reverte muitas vezes para uma baseline aleatória. Selecionas sessenta moléculas completamente ao acaso, testas-as e treinas o teu primeiro modelo. Mas a seleção aleatória dá ao teu modelo um mau ponto de partida, enchendo o training set inicial com compostos maioritariamente inativos. A solução é inicializar o loop de active learning usando uma neural network tridimensional pré-treinada. Este modelo 3D já foi treinado num dataset massivo e geral de diversos complexos de proteínas e ligantes. Como compreende a física de ligação geral com base em interações estruturais, consegue fazer o score dos teus dez mil compostos antes mesmo do loop de active learning começar. Primeiro, usas o modelo 3D pré-treinado para prever as afinidades para toda a pool. Depois, pegas nas top sessenta moléculas identificadas por este prescreening e corres as tuas simulações físicas pesadas nelas. Agora tens um conjunto de dados iniciais altamente enriquecido. Passas este dataset inicial de alta qualidade para o teu modelo XGBoost. A partir deste ponto, o modelo XGBoost assume o ciclo. Ele treina nos dados verificados, prevê a restante pool, e seleciona de forma greedy os próximos sessenta candidatos. Esta combinação gera uma aceleração massiva na descoberta de hits. O modelo 3D geral fornece um ponto de partida rico, e o modelo XGBoost adapta-se rapidamente ao espaço químico específico da tua série congenérica. Ao inicializar com um modelo 3D pré-treinado em vez de random sampling, consegues encontrar oitenta por cento do top um por cento de binders depois de testares menos de dez por cento de todo o dataset. Iniciar o teu loop com um prescreening 3D geral dá aos teus modelos especializados um avanço imbatível. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
13

O Desafio dos Activity Cliffs

3m 45s

Examine a fragilidade das relações estrutura-atividade. Discutimos os 'activity cliffs' — onde uma pequena alteração estrutural causa uma mudança massiva na potência de um fármaco.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 13 de 22. Em química, um único átomo fora do lugar pode transformar um fármaco potente que salva vidas num pó inerte. Estas quedas repentinas na potência biológica chamam-se activity cliffs, e são o némesis absoluto dos modelos tradicionais de AI. Um activity cliff ocorre quando tens um par de moléculas com alta semelhança estrutural, mas níveis de atividade significativamente diferentes. Considera um cenário concreto. Tens duas moléculas que partilham noventa por cento da sua framework estrutural. A primeira molécula liga-se fortemente a um alvo biológico. A segunda molécula é completamente inativa. A única diferença física entre elas é um único grupo metilo ligado a um anel específico. Para um químico medicinal humano, esta modificação estrutural específica é altamente informativa. Diz-lhe exatamente onde estão os limites do pocket do recetor. Para um modelo standard de machine learning, é uma disrupção catastrófica. Aqui está o insight principal. A maioria das abordagens de deep learning em quimioinformática são construídas para prever valores absolutos de propriedades. Quer estejas a usar uma graph neural network ou um chemical language model, a arquitetura é fundamentalmente desenhada para mapear estruturas químicas num espaço matemático contínuo. A premissa central hardcoded nestes modelos é que estruturas moleculares semelhantes devem mapear para propriedades biológicas semelhantes. Quando um modelo standard processa as nossas duas moléculas quase idênticas, gera representações que estão mesmo ao lado uma da outra nesse espaço matemático. Como os inputs estão próximos, o modelo naturalmente gera outputs com previsões de potência absoluta quase idênticas para ambas. Os activity cliffs violam fundamentalmente esta premissa de um espaço químico contínuo e suave. Representam uma descontinuidade severa. O modelo espera uma colina suave, mas encontra uma queda vertical. Este problema é fortemente amplificado pela natureza dos dados de drug discovery. Os datasets experimentais são notoriamente limitados e ruidosos. Quando treinas uma deep neural network com dados esparsos, o modelo tem dificuldade em generalizar. Para minimizar o erro geral em todo o training set, a rede aprende padrões globais amplos. Suaviza as irregularidades locais. Quando encontra um activity cliff, o objetivo standard de regression trata esse salto repentino na variância como ruído experimental ou um outlier. O modelo ignora a informação estrutural local mais crítica porque não se ajusta à tendência global. É por isso que prever activity cliffs continua a ser um dos problemas mais difíceis na previsão de propriedades moleculares. Os modelos são forçados a aprender um espaço químico descontínuo diretamente a partir de dados limitados. Como se focam inteiramente em previsões absolutas para moléculas individuais, ignoram completamente a informação valiosa escondida nas diferenças relativas entre matched molecular pairs. Em muitos casos, modelos tree-based mais simples acabam por superar neural networks complexas nestes datasets, simplesmente porque os modelos de deep learning fazem over-smoothing das representações. A premissa de que estruturas químicas semelhantes resultam sempre em atividades biológicas semelhantes é uma baseline estatística útil, mas não é uma lei física. Os activity cliffs são a realidade brutal e descontínua das relações estrutura-atividade, e provam que prever propriedades absolutas no vácuo vai sempre falhar nas margens. Obrigado por passares uns minutos comigo. Até à próxima, fica bem.
14

Similarity-Quantized Relative Learning

3m 27s

Resolva o problema dos activity cliffs repensando a forma como os modelos aprendem. Exploramos a framework SQRL, que treina a IA para prever diferenças relativas de propriedades entre pares moleculares estritamente filtrados.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 14 de 22. Em vez de forçar uma IA a memorizar a potência absoluta de cada molécula existente, e se a ensinasses simplesmente a perguntar como uma molécula difere do seu vizinho conhecido mais próximo? Esta mudança de perspetiva resolve um grande problema de generalização em regimes de poucos dados, e é o núcleo de uma framework chamada Similarity-Quantized Relative Learning, ou SQRL. Normalmente, a previsão de propriedades moleculares trata cada molécula como um data point isolado. O modelo tenta mapear uma estrutura diretamente para um valor de propriedade absoluto. Com datasets pequenos e ruidosos, os modelos de deep learning têm dificuldade em construir um mapa global preciso do espaço químico. Tentativas anteriores de pairwise learning tentaram corrigir isto emparelhando cada molécula com todas as outras moléculas no training set. Esta abordagem inunda os dados com comparações entre estruturas completamente sem relação, abafando o sinal local útil. O SQRL corrige isto restringindo os training data a pares de moléculas que são estruturalmente muito semelhantes. O modelo aprende a prever a diferença relativa nas suas propriedades, conhecida como delta y. Isto é alcançado através de um passo específico de correspondência no dataset. Não alimentas o modelo com moléculas individuais. Alimentas com pares, mas apenas se passarem um threshold de similaridade rigoroso. Vamos analisar a lógica. Começas com o teu training set padrão de moléculas e as suas potências conhecidas. Primeiro, calculas as distâncias pairwise entre todas as moléculas usando uma métrica como a distância de Tanimoto em Morgan fingerprints. Aqui está o ponto-chave. Defines um threshold de distância, alfa. Vamos usar um threshold de distância de Tanimoto de zero vírgula sete. Iteras por todos os pares de moléculas possíveis. Se a distância entre a molécula A e a molécula B for zero vírgula sete ou superior, descartas o par completamente. Se a distância for estritamente menor que zero vírgula sete, adicionas este par ao teu novo training set relativo. A target variable para este novo par já não é uma potência absoluta. É a diferença numérica exata na potência entre a molécula A e a molécula B. Agora treinas a tua neural network. A network gera uma representação matemática para a molécula A, e uma representação para a molécula B. Subtrai a representação de B da representação de A. Esse vetor de diferença resultante é passado por uma layer final para prever o delta y. Ao filtrar o ruído de pares dissimilares, a network é forçada a concentrar-se exclusivamente em mudanças químicas locais de high-signal. Aprende exatamente como um ajuste estrutural específico altera a atividade. Isto torna o modelo altamente sensível a activity cliffs. Isto cobre o training, mas e quanto a prever uma molécula totalmente nova? Quando entra uma nova estrutura, o sistema examina os training data originais para encontrar o único vizinho estrutural mais próximo com base nessa mesma métrica de distância de Tanimoto. A network avalia a nova molécula em relação a este vizinho mais próximo e prevê o delta relativo. Finalmente, pegas na potência absoluta conhecida do vizinho, adicionas o delta previsto, e tens a tua previsão final. Ao restringir o training space a pares altamente similares, paras de pedir ao modelo que aprenda todo o universo químico e, em vez disso, treinas o modelo para se tornar um especialista em gradientes químicos locais. Isto é tudo por este episódio. Obrigado por ouvires, e continua a construir!
15

A Revolução da Generative AI

3m 38s

Faça a transição da previsão de propriedades para a imaginação de moléculas inteiramente novas. Mapeamos o panorama das tarefas generativas moleculares: geração De Novo, otimização e geração de confórmeros.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 15 de 22. Durante anos, a AI na química foi puramente um ato de triagem. Alimentavas um modelo com milhares de moléculas existentes, e ele simplesmente previa quais eram as menos terríveis. Se a molécula ideal não estivesse na tua screening library, o modelo não te conseguia ajudar. A revolução da Generative AI mudou fundamentalmente essa dinâmica. Em vez de apenas filtrar o que já existe, agora podemos instruir os modelos a inventar matéria química inteiramente nova. Esta mudança da previsão para a criação divide-se em duas grandes tarefas de geração molecular: de novo generation e molecular optimization. A de novo generation envolve a criação de novas estruturas moleculares do zero. O modelo começa com uma representação de random noise e refina-a iterativamente numa estrutura química válida. Quando isto é feito sem quaisquer constraints, chama-se unconditional generation. O modelo explora livremente o vasto chemical space para produzir algo totalmente novo. Embora isso seja útil para uma descoberta ampla, normalmente precisas de mais controlo. Isto leva-nos à conditional generation, especificamente à property-based generation. Aqui, tu ditas o output. Forneces constraints específicas, como uma target bioactivity ou um nível necessário de synthesizability, e o modelo restringe a sua geração a moléculas que cumpram esses critérios. A isto chama-se frequentemente inverse molecule design, porque começas com as propriedades que queres e forças o modelo a trabalhar de trás para a frente para construir uma estrutura molecular que as forneça. A de novo generation é poderosa, mas raramente começas um projeto com zero conhecimento prévio. Normalmente, já tens um lead compound. É aqui que entra a molecular optimization. Ao contrário das de novo tasks, a molecular optimization foca-se em modificar uma estrutura conhecida, em vez de começar do zero. Pegas numa molécula existente e refinas-a para melhorar as suas propriedades. Supõe que tens um drug scaffold moderadamente eficaz. Ele liga-se ao teu target, mas a sua bioactivity é demasiado baixa para ser um fármaco viável. Usando um generative model, podes realizar uma targeted molecular optimization. Uma abordagem é o scaffold hopping. Instruis o modelo a substituir o core molecular scaffold por um novo, mantendo a atividade biológica original. Isto é altamente eficaz para descobrir compostos estruturalmente novos que escapam a patentes existentes, mantendo o comportamento funcional intacto. Outra abordagem é o R-group design. Neste cenário, fixas o teu core scaffold e instruis o generative model a otimizar automaticamente as suas side chains. O modelo gera novos R-groups, à procura das modificações específicas nas side chains que melhorem essa bioactivity deficiente. Não estás a descartar a tua molécula moderadamente eficaz, estás a deixar a AI calcular os ajustes estruturais precisos necessários para a levar a cruzar a meta. Aqui está o insight principal. A transição da predictive AI para a generative AI significa que já não estás limitado às moléculas que tens à mão. Quer estejas a gerar uma molécula customizada do zero ou a trocar algoritmicamente as side chains de um fármaco existente, estás a tratar o chemical space como um meio programável. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
16

A Intuição da Molecular Diffusion

3m 44s

Desconstruímos o conceito central dos Diffusion Models sem a matemática pesada. Os ouvintes vão compreender o processo direto de adicionar ruído a uma molécula e o processo inverso de alucinar novas estruturas.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 16 de 22. Para ensinar uma IA a inventar uma nova molécula, primeiro tens de a ensinar a destruir uma por completo. Parece um contrassenso, mas esta destruição sistemática é exatamente o mecanismo usado para gerar novos medicamentos do zero. Esta é a intuição central dos Denoising Diffusion Probabilistic Models. O design molecular tradicional dá imenso trabalho. Se quiseres automatizar a descoberta de novos compostos, precisas de um modelo capaz de explorar um vasto espaço químico sem gerar resultados inválidos e sem sentido. Os primeiros deep generative models tentaram mapear este espaço diretamente. Os Denoising Diffusion Probabilistic Models, ou DDPMs, seguem um caminho diferente. Eles tratam a geração molecular como um problema progressivo de denoising. A framework divide-se em duas Markov chains distintas: o forward process e o reverse process. O forward process trata estritamente da degradação de dados. Pegas num medicamento válido e conhecido do teu training set. Numa sequência fixa de steps, desfocas progressivamente as suas coordenadas atómicas através da injeção de puro ruído gaussiano. A quantidade de ruído adicionada em cada step é controlada por um hyperparameter schedule definido. No step um, perturbas ligeiramente os átomos. A molécula fica um pouco distorcida, mas ainda claramente reconhecível. No step cinquenta, a estrutura fica severamente deformada. No step final, geralmente denotado como step T, a molécula original desaparece por completo. Ficas apenas com uma nuvem aleatória de ruído gaussiano não estruturado. Este forward process não requer uma neural network. É uma corrupção matemática rigorosa. Serve um propósito vital, pois gera a ground truth para os nossos training data. Aqui está o insight principal. Como controlámos a quantidade exata de ruído adicionada em cada step, temos um registo perfeito, step-by-step, de como a molécula se desintegrou. O reverse process é onde a neural network entra em ação. O modelo é treinado para percorrer esse exato caminho de trás para a frente. Alimentamos a network com uma molécula corrompida num time step específico. De seguida, pedimos-lhe que preveja o ruído específico que foi adicionado para atingir esse estado. Avaliamos o modelo comparando a sua previsão de ruído com o ruído real que injetámos durante a fase forward. Atualizamos os parâmetros do modelo para minimizar essa diferença. Com o tempo, a network aprende a fazer o denoising dos dados step by step, restaurando gradualmente a distribuição original dos dados. Para gerar uma molécula completamente nova, executas este reverse process do zero. Primeiro, fazes o sample de uma nuvem de ruído gaussiano completamente aleatória. Depois, passas esse ruído para a tua neural network treinada, juntamente com o número do step inicial. A network avalia o input, prevê a correção estrutural necessária e retorna uma nuvem de átomos ligeiramente menos ruidosa. Fazes um loop a este processo de subtração. Passas o novo output de volta para a network para o step seguinte. A cada iteração, a nuvem aleatória torna-se mais compacta. O modelo remove continuamente o ruído. À medida que recuas em direção ao step zero, as coordenadas atómicas encaixam no lugar e uma estrutura química válida emerge. Extrais uma molécula completamente nova a partir da estática inicial. O modelo não se limita a memorizar uma database de medicamentos existentes; ele simplesmente aprende o processo universal de remover o caos para deixar para trás uma química estável. Se quiseres apoiar o programa, podes procurar por DevStoriesEU no Patreon. Obrigado por ouvires, e continua a desenvolver!
17

Unir os Espaços Generativos 2D e 3D

4m 01s

Exploramos como a IA representa realmente as moléculas que gera. Comparamos a geração de grafos topológicos 2D planos com a geração de point clouds geométricas 3D complexas, e os desafios de cada uma.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 17 de 22. Uma coisa é um modelo desenhar um grafo 2D plano de uma molécula. É um pesadelo de engenharia completamente diferente gerar uma point cloud geométrica 3D estável de átomos. Podes ter um modelo generativo a construir uma bela point cloud 3D de um fármaco que preenche perfeitamente a pocket de uma proteína-alvo, só para veres tudo desmoronar no post-processing quando o sistema falha ao adivinhar onde as ligações covalentes reais devem ficar. A solução para esta desconexão é fazer a ponte entre os espaços generativos 2D e 3D. Na química generativa, as modalidades de dados ditam o que o teu modelo consegue entender. A primeira modalidade é o espaço topológico 2D. Pensa nisto como um grafo molecular standard. Os nodes representam átomos com tipos específicos, e as edges representam as ligações químicas que os ligam. O modelo faz output de uma matriz de adjacência que te diz exatamente o que está ligado a quê. As Graph Neural Networks lidam bem com isto. O problema é que as moléculas existem no mundo físico, não no papel. Um grafo 2D dá-te a topologia de ligação, mas ignora completamente a estrutura geométrica 3D. Sem coordenadas espaciais, não consegues calcular com precisão as propriedades quânticas ou fazer structure-based drug design. Para resolver isto, os modelos passaram a gerar moléculas diretamente no espaço geométrico 3D. Aqui, o output é uma point cloud. O modelo define os tipos de átomos e as suas coordenadas posicionais exatas em X, Y e Z. O obstáculo técnico aqui é manter a equivariância SE 3, garantindo que a molécula se mantém matematicamente consistente, independentemente de como é rodada ou transladada no espaço. Aqui está o insight principal. Gerar num espaço puramente 3D significa que o modelo não gera explicitamente as ligações químicas. Ele apenas posiciona os átomos no espaço. Tens de inferir a topologia de ligação depois, através de algoritmos de post-processing. Isto introduz erros enormes. Voltando ao cenário da pocket do fármaco, o teu modelo pode organizar os átomos numa forma que encaixa fisicamente no alvo, mas, como nunca considerou a topologia de ligação durante a geração, o passo de post-processing pode inferir ligações covalentes impossíveis. Para moléculas maiores, gerar diretamente uma estrutura 3D estável sem qualquer orientação topológica resulta frequentemente numa solução subótima. Isto leva-nos à geração num joint space 2D e 3D, que produz uma estrutura molecular completa em simultâneo. O modelo faz output dos tipos de átomos, da matriz de adjacência discreta para as ligações e das coordenadas espaciais contínuas, tudo de uma vez. Ao fazer a ponte entre estes dois espaços, as modalidades restringem-se e corrigem-se mutuamente durante o processo de geração. A topologia 2D atua como um blueprint, guiando a estrutura 3D para garantir que os arranjos espaciais são quimicamente viáveis. Ao mesmo tempo, a geometria 3D refina o grafo 2D, sugerindo padrões de ligação plausíveis com base na proximidade espacial. O principal desafio técnico nesta abordagem conjunta é gerir dois tipos de dados fundamentalmente diferentes. Estás a forçar o modelo a lidar com estruturas topológicas discretas, como tipos de ligações, em conjunto com estruturas geométricas contínuas, como valores de coordenadas. Diferentes arquiteturas resolvem isto de maneiras diferentes. Uma framework chamada JODO trata tanto as estruturas topológicas como as geométricas como variáveis contínuas para as processar em conjunto. Outro modelo, o MUDiff, lida com elas separadamente, aplicando um processo discreto para a topologia e um processo contínuo para a geometria. Não consegues gerar fármacos novos e funcionais de forma fiável apenas a adivinhar a forma física e a esperar que as ligações químicas se resolvam sozinhas mais tarde. A verdadeira geração molecular requer que o blueprinting topológico e o posicionamento espacial interajam e se complementem na exata mesma computação. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
18

Target-Aware Generation e Docking

3m 51s

Descubra a conceção generativa context-aware. Discutimos a geração de novas moléculas diretamente dentro da bolsa de ligação de uma proteína de doença para maximizar a afinidade de ligação.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 18 de 22. Porquê pedir a um algoritmo para gerar um milhão de chaves aleatórias e testá-las uma a uma, quando ele pode simplesmente olhar diretamente para a fechadura e forjar uma chave personalizada mesmo lá dentro? A descoberta tradicional de fármacos depende muitas vezes da geração de vastas bibliotecas de candidatos e da sua filtragem, mas isso desperdiça imensos recursos computacionais. Target-Aware Generation e Docking resolvem este problema utilizando diretamente a geometria tridimensional do alvo biológico para construir ou posicionar moléculas. Nestas tarefas generativas, trabalhamos inteiramente no espaço geométrico 3D. A Target-aware generation, também conhecida como structure-based drug design, constrói uma nova molécula baseada diretamente na estrutura 3D de um binding pocket alvo. Imagina um cenário concreto que envolva uma proteína viral. Esta proteína tem uma cavidade geométrica altamente específica. Em vez de gerar moléculas no vácuo, um modelo de difusão condicional analisa os limites espaciais exatos e as propriedades químicas dessa cavidade. A seguir, ele cria uma nova estrutura de ligante personalizada diretamente dentro do pocket. O modelo começa com uma cloud de coordenadas 3D com ruído e tipos de átomos localizados dentro do binding site. Ao longo de passos sucessivos, ele faz o denoise desta cloud. Como a geração é condicionada ao pocket alvo, o modelo posiciona átomos e forma estruturas que complementam naturalmente a cavidade, com o objetivo de garantir uma alta afinidade de interação. Aqui está o ponto chave. O algoritmo não adivinha apenas uma forma; ele aprende explicitamente a relação espacial entre o alvo e os potenciais ligantes. Algumas abordagens até incorporam retrieval baseado em interação, extraindo dados de ligantes conhecidos de alta afinidade para guiar ainda mais a geração destas moléculas específicas para o alvo. Isto cobre a geração de uma molécula completamente nova de raiz dentro de um pocket. Mas, muitas vezes, terás uma molécula existente e vais precisar de saber exatamente como ela interage com um alvo biológico. Isto leva-nos ao molecular docking. O molecular docking prevê a binding pose para avaliar a afinidade e a especificidade da ligação. Numa framework de difusão, os modelos recebem uma molécula conhecida e uma estrutura alvo como inputs. Em vez de gerar identidade química, o processo de difusão opera puramente na orientação espacial da molécula. O modelo começa com o ligante numa pose 3D aleatória e com ruído e, iterativamente, faz o seu denoise. Ele refina as coordenadas espaciais da molécula até que ela assente na configuração de ligação correta dentro do pocket da proteína. Modelos de docking avançados levam isto um passo à frente, tratando o próprio alvo como uma entidade flexível. Um modelo chamado Re-Dock utiliza uma técnica chamada diffusion bridge para prever as binding poses do ligante, enquanto modela simultaneamente o movimento das sidechains do pocket. Isto cria um cenário de docking realista e flexível, onde tanto o ligante como o alvo se adaptam um ao outro durante a fase de predição. A mudança crucial aqui é que os modelos de difusão afastaram o structural drug design de aproximações rígidas e isoladas. Ao tratar tanto o ligante gerado como o pocket biológico como um sistema geométrico contínuo e adaptável, o modelo faz o output nativo de moléculas e poses que estão fisicamente fundamentadas na realidade precisa do ambiente alvo. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
19

A Armadilha do Tamanho na Avaliação Generativa

4m 34s

Aprenda por que razão os benchmarks padrão para modelos generativos podem ser profundamente falhos. Revelamos o efeito de confusão do tamanho da biblioteca gerada em métricas como a Fréchet ChemNet Distance.

Download
Olá, daqui fala o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 19 de 22. Avalias o teu novo modelo de química generativa fazendo o sampling de mil moléculas, e as métricas parecem péssimas. Geras cem mil exatamente do mesmo modelo, e de repente parece de classe mundial. A escala muda tudo. Este fenómeno chama-se Size Trap na Generative Evaluation. Os pipelines de generative drug discovery geralmente seguem três fases. Treinas, geras e avalias. Quando os profissionais chegam à fase de avaliação, deparam-se com uma questão básica sobre quantos designs de novo devem gerar para benchmarking. A prática standard costuma usar por defeito batches pequenos, tipicamente mil ou dez mil strings SMILES. As equipas depois passam estas batches por métricas distribucionais standard. A mais comum é a Fréchet ChemNet Distance, ou FCD. A FCD mede o quão próximas as tuas moléculas geradas estão do teu training set no espaço químico e biológico. Um score FCD mais baixo significa que a tua distribuição gerada corresponde de perto à tua distribuição alvo. Outra métrica comum é a Fréchet Descriptor Distance, ou FDD, que compara a distribuição de propriedades físico-químicas como o peso molecular e a área de superfície topológica. As equipas também costumam medir a Uniqueness, que é a fração de designs gerados que são distintos. Aqui está o insight principal. Todas estas métricas dependem fortemente do tamanho físico da library gerada. Elas não medem a qualidade absoluta do modelo num vácuo. Quando fazes o sampling de apenas mil moléculas, os teus scores de FCD e FDD serão artificialmente altos. O modelo parece ter falhado em aprender a distribuição alvo. Mas se continuares a fazer o sampling desse mesmo modelo, aumentando o tamanho da library para lá das dez mil, cinquenta mil ou cem mil moléculas, o score FCD cai significativamente. Continua a diminuir até eventualmente atingir um plateau. Isto acontece porque o generative molecule design envolve fazer o sampling de uma distribuição de probabilidade aprendida altamente complexa. Uma amostra minúscula de mil moléculas não consegue representar adequadamente todo o âmbito do output desse modelo. Os algoritmos de Fréchet distance precisam de um número massivo de samples para capturar com precisão a forma do espaço gerado e compará-la com o espaço de fine-tuning. Considera um cenário concreto em que estás a comparar uma recurrent neural network com um transformer. Se avaliares a recurrent network usando cem mil designs, mas avaliares o transformer usando apenas dez mil, a recurrent network provavelmente apresentará scores FCD e FDD vastamente superiores. O gap de performance não tem nada a ver com a arquitetura. É puramente um artefacto do tamanho da sample. As métricas não convergiram para a library mais pequena. Esta armadilha funciona ao contrário quando olhas para a diversidade interna. A Uniqueness comporta-se de maneira completamente diferente em escala. Às mil moléculas, quase todas as strings SMILES válidas que o teu modelo gera podem ser únicas. O modelo parece altamente criativo. Mas à medida que aumentas a geração para as cem mil, a Uniqueness cai drasticamente. O modelo começa a repetir-se. Se ordenares diferentes modelos generativos com base na Uniqueness a uma pequena escala, as diferenças entre eles parecem pequenas. Aumenta a escala, e o gap entre os modelos alarga-se dramaticamente. O ranking relativo dos teus modelos vai mesmo inverter-se dependendo do tamanho da library que usares para os medir. Para corrigir isto, tens de tratar o tamanho da library como uma variável de controlo estrita no teu pipeline. Nunca podes comparar de forma fiável FCD, FDD ou Uniqueness entre libraries de tamanhos diferentes. Para garantir uma avaliação robusta, deves avaliar libraries que contenham pelo menos cem mil designs, para que as métricas distribucionais converjam completamente. Se as tuas métricas de avaliação mudam simplesmente porque deixaste o sampling loop correr por mais tempo, estás a medir o tamanho da sample, não a inteligência do modelo. É tudo por este episódio. Obrigado por ouvires, e continua a construir!
20

Navegar pelas Alucinações De Novo

3m 54s

Classifique as moléculas geradas por IA de forma inteligente. Exploramos o tradeoff de exploration-exploitation das probabilidades do modelo e como filtrar 'alucinações químicas' frequentes e de baixa qualidade.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 20 de 22. Só porque uma IA generativa cospe uma molécula específica dez mil vezes, não significa que seja um fármaco viável. Podes presumir que a frequência de geração indica qualidade ou relevância química. Mas não indica. Esses outputs altamente frequentes são, muitas vezes, o equivalente químico de um large language model a alucinar. O mecanismo para resolver isto é navegar pelas alucinações de novo usando a likelihood do modelo. Quando geras uma biblioteca massiva de um milhão de strings SMILES a partir de um chemical language model fine-tuned, tens de decidir quais as moléculas a priorizar para estudos prospetivos. Uma abordagem standard, mas falível, é simplesmente selecionar os designs que o modelo gera com mais frequência. Isto cria uma count trap. Em vez de descobrires candidatos a fármacos robustos, acabas por extrair subestruturas básicas e repetitivas, como anéis de benzeno isolados, aminas simples e éteres básicos. Estas são alucinações estruturais recorrentes. O modelo gera-as constantemente não por serem de alta qualidade, mas porque são sintaticamente simples de construir. Para expor e filtrar estas alucinações, avalias a tua biblioteca usando a likelihood do modelo. A likelihood é uma métrica que captura o quão bem uma sequência gerada se alinha com a distribuição de probabilidade que o modelo aprendeu durante o training. Para um modelo autorregressivo, calculas isto multiplicando a sampling probability de cada token individual na string SMILES gerada. Primeiro, calculas o likelihood score para todos os um milhão de designs gerados. A seguir, ordenas toda a biblioteca com base nestes scores. Finalmente, divides a biblioteca ordenada em dez grupos iguais, ou decis, que vão da likelihood mais baixa até à mais alta. É aqui que a coisa fica interessante. Analisar estes decis revela um tradeoff estrito de exploration-exploitation. O décimo decil contém as gerações com maior likelihood. Estes designs representam exploitation. Têm uma validade química extremamente alta, e os seus scaffolds genéricos de Bemis-Murcko correspondem de perto às moléculas ativas conhecidas dos teus dados de training. O modelo está a explorar fortemente o que já sabe que funciona. A desvantagem é que estes designs de topo carecem de novidade. Contêm muito poucas subestruturas novas porque o modelo está a jogar pelo seguro. Descendo para os decis intermédios, encontras um equilíbrio. A novidade e as subestruturas únicas atingem o pico nesta faixa intermédia, enquanto a validade permanece aceitável. Mas quando desces para o primeiro decil — os dez por cento de moléculas com os likelihood scores mais baixos em absoluto — cais na count trap. Se isolares os designs que o modelo gerou mais de dez vezes em toda a run de um milhão de moléculas, eles agrupam-se quase todos neste decil inferior. Têm likelihoods de modelo incrivelmente baixas, mas aparecem com uma frequência enorme. A sua similaridade estrutural com o teu training set é péssima, e a sua validade química geral afunda. Ao fazeres o binning da tua biblioteca desta forma, provas matematicamente que a frequência é um falso sinal de qualidade. Podes descartar sistematicamente os bins de baixa likelihood e alta frequência, e focar o teu screening computacional nos decis intermédios, onde acontece a verdadeira exploração química. Os outputs mais frequentes de um modelo químico generativo costumam ser os piores, mas filtrar a tua biblioteca por decis de likelihood transforma esse ruído num mapa preciso de onde o modelo está a explorar e onde está apenas a alucinar. É tudo por este episódio. Obrigado por ouvires, e continua a construir!
21

Restrições de Sampling de Moléculas

4m 29s

Compreenda por que razão as técnicas de NLP falham na química. Comparamos o Temperature sampling com o Top-k e o Top-p, e por que razão o vocabulário químico restrito muda tudo.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Python Cheminformatics & AI, episódio 21 de 22. No processamento de linguagem natural, o Top-p sampling produz textos incrivelmente criativos. Mas aplica essa mesma lógica à geração de moléculas, e a tua IA vai simplesmente imprimir anéis de carbono idênticos para sempre. A razão resume-se às restrições de sampling de moléculas. Quando um modelo de linguagem química gera uma string SMILES, constrói a molécula um token de cada vez. O modelo prevê uma distribuição de probabilidade para o próximo token, e tu tens de extrair uma escolha específica dessa distribuição. Na geração de texto, os profissionais dependem muito do Top-k e Top-p sampling para fazer essa escolha. O Top-k restringe o modelo aos k tokens absolutamente mais prováveis. O Top-p restringe a seleção ao grupo mais pequeno de tokens cujas probabilidades combinadas excedem uma percentagem alvo p. Se aplicares estes métodos a um modelo de linguagem química, eles falham catastroficamente. Se usares o Top-k sampling com k definido como 3 numa LSTM treinada em alvos de fármacos, o teu modelo vai sofrer um mode collapse severo. Vai produzir moléculas quimicamente válidas, mas serão completamente repetitivas. Aqui está o ponto-chave. A falha deriva do tamanho do vocabulário químico. Um modelo de texto seleciona entre centenas de milhares de palavras. Um modelo de linguagem química usa um alfabeto altamente restrito. Tem apenas uma mão-cheia de elementos como carbono, oxigénio e nitrogénio, além de tokens de sintaxe para ramificações e fechos de anéis. Como o alfabeto químico é minúsculo, e porque a química válida exige regras de sintaxe rígidas, como fechar todos os anéis abertos, um subconjunto muito pequeno de tokens domina absolutamente a distribuição de probabilidade. O carbono e os tokens estruturais básicos são quase sempre altamente prováveis. Quando aplicas o Top-k ou Top-p sampling, cortas a cauda longa da distribuição de probabilidade. O modelo é forçado a escolher exclusivamente dessa faixa estreita de tokens dominantes. Fica preso numa armadilha de filtragem, repetindo exatamente as mesmas estruturas básicas infinitamente. Para escapares desta armadilha, tens de usar o Temperature sampling. Em vez de filtrar tokens, o Temperature sampling aplica um parâmetro de suavização aos scores brutos da rede neural antes de calcular as probabilidades finais. Isto altera a forma de toda a distribuição. Considera um cenário em que estás a correr um modelo LSTM com fine-tuning para gerar novos candidatos a fármacos. Ajustas o parâmetro de Temperature, T, para afinar o tradeoff entre validade e diversidade. Se definires o T baixo, por volta de 0.5, a distribuição de probabilidade apresenta um pico acentuado. O modelo explora intensamente os tokens mais prováveis. O teu output vai apresentar uma validade química extremamente alta, mas as estruturas não terão novidade. Vão imitar de perto o training set. Se aumentares o T para 1.5 ou 2.0, achatas a distribuição de probabilidade. Agora, os tokens menos prováveis têm uma hipótese matemática de serem amostrados. O teu modelo começa a explorar um novo espaço químico. O número de subestruturas únicas na tua biblioteca gerada dispara. Encontras moléculas altamente inovadoras. O tradeoff é que temperaturas mais altas aumentam a aleatoriedade, levando o modelo a cometer mais erros de sintaxe, o que reduz a percentagem geral de strings SMILES válidas. Não podes simplesmente transpor estratégias de geração de texto para o design molecular. Como o vocabulário químico é inerentemente limitado, o Temperature scaling continua a ser a alavanca mais eficaz para equilibrar a estrita validade química com a exploração de novas estruturas. Obrigado por estares aí. Espero que tenhas aprendido algo novo.
22

Fazer o Deploy de Quimioinformática na Cloud

4m 12s

Leve a sua pipeline de IA para produção. Discutimos o empacotamento do RDKit e de modelos de machine learning em contentores Docker e o escalonamento de cargas de trabalho em infraestruturas cloud.

Download
Olá, daqui é o Alex da DEV STORIES DOT EU. Quimioinformática e IA em Python, episódio 22 de 22. Construíste um pipeline de descoberta de fármacos com IA de última geração no teu portátil, mas como é que analisas mil milhões de moléculas durante o fim de semana? A resposta é fazer o deploy de Quimioinformática na Cloud. Mover um modelo de um ambiente local para uma arquitetura de cloud distribuída geralmente falha na camada de dependências. O RDKit não é uma library puramente Python. É uma grande codebase em C++ que requer dependências ao nível do sistema, principalmente as libraries Boost C++. Se provisionares servidores de cloud genéricos e correres scripts de instalação standard, frequentemente deparas-te com erros de compilador ou ficheiros shared object em falta. A documentação oficial do RDKit destaca que fazer a build a partir do source requer uma toolchain de C++ específica. Embora existam pip wheels pré-compiladas, a maneira mais robusta de garantir que todas as dependências subjacentes estão alinhadas é usar o Conda. No entanto, instalar o Conda dinamicamente em milhares de cloud workers temporários demora muito tempo e introduz instabilidade na rede durante o scale-up. Aqui está o insight principal. Tu contornas completamente o problema das dependências ao envolveres o teu pipeline num container Docker. Escreves um ficheiro de configuração que especifica um sistema operativo base. Dentro desse container, instalas um ambiente Conda leve, fazes pull dos binários compilados do RDKit e adicionas as tuas frameworks de machine learning, como o PyTorch ou o XGBoost. Finalmente, copias os weights do teu modelo pré-treinado para a imagem. Fazer a build desta imagem congela toda a stack num único artefacto imutável. O cloud provider só precisa de saber como correr um container Docker standard. As dependências complexas de C++ ficam trancadas em segurança lá dentro. Para processar milhões de moléculas, separas o teu data flow dos teus compute workers usando uma message queue na cloud. Particionas o teu enorme dataset de strings SMILES em chunks mais pequenos e fáceis de gerir. Colocas estes chunks num object storage na cloud e envias uma mensagem com a localização do chunk para a queue. A seguir, apontas um serviço de cloud compute escalável para esta queue. Para workloads pesados e acelerados por GPU, fazes o deploy do teu container usando um serviço como o AWS Batch. Para inferência mais leve, baseada em CPU, plataformas de containers serverless, como o Google Cloud Run ou o AWS Lambda, lidam com isto perfeitamente. Configuras o serviço de compute para fazer scale automaticamente com base na profundidade da queue. Se houver cinquenta mil mensagens à espera, o cloud controller faz spin up de milhares de containers Docker idênticos em simultâneo. Cada container liga-se à queue e reserva uma mensagem. Faz o download do chunk correspondente de strings SMILES. O RDKit converte os SMILES em grafos moleculares, calcula os descritores necessários e passa-os para o teu modelo de machine learning para inferência. O container escreve as moléculas com maior pontuação diretamente numa managed cloud database. Assim que o chunk é processado, o worker apaga a mensagem da queue e agarra na próxima. Quando a queue está vazia, a infraestrutura de cloud termina os containers automaticamente. Só pagas pelos segundos exatos de compute que o teu código realmente consumiu. Escalar quimioinformática raramente tem a ver com escrever estruturas de loop mais rápidas em Python; tem a ver com empacotar o teu ambiente de forma fiável e usar uma arquitetura de cloud decoupled para processar dados em paralelo. Isto conclui a nossa série sobre Quimioinformática e IA em Python. Encorajo-te a ler a documentação oficial do RDKit sobre a instalação, a experimentares containerizar um script simples hands-on, ou a visitares devstories dot eu para sugerires tópicos para séries futuras. É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!