Projetando uma rede neural convolucional para aprendizado de máquina de cannabis, parte 1
Uma bela e brilhante manhã de domingo para projetar Redes Neurais Convolucionais. Uma CNN é uma rede neural treinada no uso de imagens e passada por uma série de filtros para determinar recursos. Como um químico orgânico, usamos nossos olhos para projetar estruturas, então talvez esta seja uma abordagem intuitiva de aprendizado de máquina e fragmente uma molécula usando nossos próprios filtros internos. Parece natural experimentá-lo.

Nosso objetivo para esta rede é saber se uma molécula se comportará como cannabis com base em sua constante de ligação (quão forte um ligante se liga) em um receptor endocanabinóide comum, CB1, um alvo principal para o THC. A estrutura cristalina foi derivada por Hua et al.
A estrutura é uma série de hélices alfa em forma de sapato com o bolso de ligação muito profundo dentro do receptor.

O de THC para um receptor CB1 pode ser quantificado com uma constante de inibição, Ki, que é uma indicação de quão potente é um inibidor. Valores pequenos de Ki de 100 micromolares são considerados potentes.
Se pegarmos uma lista de inibidores para CB1 e suas constantes de inibição conforme registradas em nM deste artigo:
Podemos prever se um novo composto canabinóide se comportaria de maneira semelhante a um terpeno como o THC com base em seu valor constante de inibição. Aqui estão alguns dos dados extraídos do papel. Sinta-se livre para pegar mais.
compounds = {
'CCCCC1=CC(=C2C3C=C(CCC3C(OC2=C1)(C)C)C)O': 36,
'CCCC1=CC(=C2C3C=C(CCC3C(OC2=C1)(C)C)C)O': 22,
'CCCCCC1=CC2=C(C3C=C(CCC3C(O2)(C)C)C)C(=C1C(=O)O)O': 620,
'CCCCCC1=CC(=C(C(=C1)O)C/C=C(\C)/CCC=C(C)C)O': 1045,
'CCCC1=CC(=C(C(=C1)O)C/C=C(\C)/CCC=C(C)C)O': 2865,
'CCCCCC1=CC(=C(C(=C1C(=O)O)O)C/C=C(\C)/CCC=C(C)C)O': 13116,
'COC1=C(C/C=C(CC/C=C(C)\C)\C)C(O)=CC(CCCCC)=C1': 10000,
'CCCCCC1=CC(=C(C(=C1)O)C2C=C(CCC2C(=C)C)C)O': 1690,
'CCCC1=CC(=C(C(=C1)O)C2C=C(CCC2C(=C)C)C)O': 14445,
'CCCCCC1=CC(=C(C(=C1C(=O)O)O)C2C=C(CCC2C(=C)C)C)O': 626,
}

Vamos começar nossas importações:
import rdkit
import numpy as np
import pandas as pd
from rdkit import Chem
from rdkit.Chem import AllChem
from matplotlib import pyplot as plt
df = pd.DataFrame()
df['smiles'] = list(compounds.keys())
df['ki'] = list(compounds.values())
df["mol"] = df["smiles"].apply(Chem.MolFromSmiles)

O efeito de uma resolução na imagem pode ser onde o espaço ocupado por diferentes informações pode dominar.

A incorporação e a resolução da sua imagem são muito importantes porque permitem que a rede neural abstraia os recursos com mais eficiência. Assim, calculamos as dimensões e as coordenadas 2D e configuramos 4 zeros vazios que atuarão como metaarmazenamento de informações como número atômico.
def chemcepterize_mol(mol, embed=10.0, res=0.2):
dimensions = int(embed*2/res)
chempcepterized_molecule = Chem.Mol(mol.ToBinary())
chempcepterized_molecule.ComputeGasteigerCharges()
AllChem.Compute2DCoords(chempcepterized_molecule)
coords = chempcepterized_molecule.GetConformer(0).GetPositions()
vector = np.zeros((dims,dims,4))
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
for i,bond in enumerate(mol.GetBonds()):
bond_order = bond.GetBondTypeAsDouble()
start_atom_index = bond.GetBeginAtomIdx()
end_atom_index = bond.GetEndAtomIdx()
start_coordinates = coords[start_atom_index]
end_coordinates = coords[end_atom_index]
fractional_space = np.linspace(0,1,int(1/res*2))
for fraction in fractional_space:
coordinates = (fraction*start_coordinates + (1-fraction)*end_coordinates)
x = int(round((coordinates[0] + embed)/res))
y = int(round((coordinates[1]+ embed)/res))
vector[ x, y, 0] = bond_order
for i,atom in enumerate(cmol.GetAtoms()):
x = int(round((coords[i][0] + embed)/res))
y = int(round((coords[i][1]+ embed)/res))
vector[ x , y, 1] = atom.GetAtomicNum()
hyptype = atom.GetHybridization().real
vector[ x , y, 2] = hyptype
charge = atom.GetProp("_GasteigerCharge")
vector[ x , y, 3] = charge
return vect
def chemcepterize_mol(mol, embed=10.0, res=0.2):
dimensions = int(embed*2/res)
chempcepterized_molecule = Chem.Mol(mol.ToBinary())
chempcepterized_molecule.ComputeGasteigerCharges()
AllChem.Compute2DCoords(chempcepterized_molecule)
coords = chempcepterized_molecule.GetConformer(0).GetPositions()
vector = np.zeros((dims,dims,4))
# Bonds
for i,bond in enumerate(mol.GetBonds()):
bond_order = bond.GetBondTypeAsDouble()
start_atom_index = bond.GetBeginAtomIdx()
end_atom_index = bond.GetEndAtomIdx()
start_coordinates = coords[start_atom_index]
end_coordinates = coords[end_atom_index]
# Draw Bond A long Vector
fractional_space = np.linspace(0,1,int(1/res*2))
for fraction in fractional_space:
coordinates = (fraction*start_coordinates + (1-fraction)*end_coordinates)
x = int(round((coordinates[0] + embed)/res))
y = int(round((coordinates[1]+ embed)/res))
vector[ x, y, 0] = bond_order
# Atoms
for i,atom in enumerate(cmol.GetAtoms()):
x = int(round((coords[i][0] + embed)/res))
y = int(round((coords[i][1]+ embed)/res))
vector[ x , y, 1] = atom.GetAtomicNum()
hyptype = atom.GetHybridization().real
vector[ x , y, 2] = hyptype
charge = atom.GetProp("_GasteigerCharge")
vector[ x , y, 3] = charge
return vect
def vectorize(mol):
return chemcepterize_mol(mol, embed=12)
df["mol_image"] = df["mol"].apply(vectorize)