Diseño de una red neuronal convolucional para el aprendizaje automático de cannabis Parte 1

May 01 2023
Una bonita y brillante mañana de domingo para diseñar Redes Neuronales Convolucionales. Una CNN es una red neuronal entrenada en el uso de imágenes y pasa a través de una serie de filtros para determinar las características.

Una bonita y brillante mañana de domingo para diseñar Redes Neuronales Convolucionales. Una CNN es una red neuronal entrenada en el uso de imágenes y pasa a través de una serie de filtros para determinar las características. Como químico orgánico, usamos nuestros ojos para diseñar estructuras, por lo que quizás este sea un enfoque de aprendizaje automático intuitivo y fragmentemos una molécula usando nuestros propios filtros internos. Parece natural probarlo.

Nuestro objetivo para esta red es saber si una molécula se comportará como el cannabis en función de su constante de unión (qué tan fuerte se une un ligando) en un receptor endocannabinoide común, CB1, un objetivo principal para el THC. La estructura cristalina fue derivada por Hua et al.

La estructura es una serie de hélices alfa en forma de zapato con el bolsillo de unión muy profundo dentro del receptor.

El THC a un receptor CB1 se puede cuantificar con una constante de inhibición, Ki, que es una indicación de cuán potente es un inhibidor. Los valores pequeños de Ki de 100 micromolar se consideran potentes.

Si tomamos una lista de inhibidores para CB1 y sus constantes de inhibición registradas en nM de este documento:

¿Podemos predecir si un nuevo compuesto cannabinoide se comportaría de manera similar a un terpeno como el THC en función de su valor constante de inhibición? Estos son algunos de los datos extraídos del artículo. Siéntete libre de agarrar más.

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 a poner en marcha nuestras importaciones:


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)

El efecto de una resolución en la imagen puede ser donde puede dominar el espacio ocupado por diferente información.

La incrustación y resolución de su imagen es muy importante porque permite que la red neuronal abstraiga características de manera más eficiente. Así que calculamos las dimensiones y las coordenadas 2D y configuramos 4 ceros vacíos que actuarán como un almacén meta para información como el 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)