Commit 4121879c authored by Florian RICHOUX's avatar Florian RICHOUX

Remove unecessary files and update Readme

parent 52447dd5
This project aims at discovering unmet descriptions of Protein-Protein Interactions using a large-scale approach.
\ No newline at end of file
# What is DeepPPI?
DeepPPI is a deep learning project to predict protein-protein interactions based on protein sequence only.
It is declined into PyTorch models (deprecated) and Keras models.
# How to use our Keras models?
In the 'keras' folder, run the with Python. For instance, to print helps, type
`python -h`
To train a model, you must give both a training set and a validation set. For instance
`python -train ../data/small_1166_train.txt -val ../data/small_1166_val.txt`
In our IEEE/ACM Transactions on Computational Biology and Bioinformatics / arXiv paper, our datasets can be found in:
..* text files in `data/mirror` for our regular dataset
..* text files in `data/mirror/double` for our strict dataset
The two models from these papers can be found at `keras/models/` and `keras/models/`. Trained weights of these models are in `keras/weights/`.
To load weights and test a model on a test set, the command is the following:
`python -load <weights_file> -test <test_file>`
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
# Utilisation de Bio.PDB
from Bio.PDB import *
### Specify path for aaindex init othwerwise python cmd is called...
import aaindex as aaindex
# TODO FR : normaliser les données pour les coordonnées 3D
# TODO FR : piste 1 -> normaliser en fonction de la taille de la maille cristallo : difficile car on doit tenir compte du nmbre de structures dans la maille
# TODO FR : piste 2 -> normalisation magique avec numpy ->
# TODO ST : retourner un vecteur par acide aminé (entier de 0 à 19)
# TODO ST : retourner un vecteur par type d'atome (0 à 4 (ou 5 ?))
# TODO ST : vecteur interaction séparé du vecteur data
# TODO ST : meilleur méthode de séparation des acides aminés à l'interface
# voir l'option NeighborSearch ou
# TODO ST : mieux séparer les chaines pour être sûr d'avoir deux protéines différentes, en interaction 1:1
one_letter ={'VAL':'V', 'ILE':'I', 'LEU':'L', 'GLU':'E', 'GLN':'Q',
'ASP':'D', 'ASN':'N', 'HIS':'H', 'TRP':'W', 'PHE':'F', 'TYR':'Y',
'ARG':'R', 'LYS':'K', 'SER':'S', 'THR':'T', 'MET':'M', 'ALA':'A',
'GLY':'G', 'PRO':'P', 'CYS':'C'}
def get_residues_in_contact(model, aa):
for c in model:
if c != aa.get_parent():
for residue in c:
distance = ca2-ca1
if distance < 10:
# print ("La distance entre {} et {} est : {}".format(c, ca2name, distance))
return ca2name, 1
return ca2name, 0
def get_amino_acid_parameters(AA):
# TODO : sélection arbitraire des sources
# bien entendu, à raffiner ...
parameters['JOND750101']='Hydrophobicity (Jones, 1975)'
parameters['KRIW790103']='Side chain volume (Krigbaum-Komoriya, 1979)'
parameters['CHOP780201']='Normalized frequency of alpha-helix (Chou-Fasman, 1978b)'
parameters['CHOP780202']='Normalized frequency of beta-sheet (Chou-Fasman, 1978b)'
parameters['DAYM780101']='Amino acid composition (Dayhoff et al., 1978b)'
parameters['CHAM820101']='Polarizability parameter (Charton-Charton, 1982)'
for p in parameters.keys():
except Exception as e:
# print ("Le vecteur trouvé est {}".format(l))
return v
def output_old_version(structure):
for model in structure:
for chain in model:
for residue in chain:
r = residue.get_resname()
# if r != 'HOH' and r != ' MG':
if r in one_letter.keys():
s,interaction=get_residues_in_contact(model, residue)
# Phase 2 : uniquement AA1 AA2 contact ou pas
# vect_tout=[r,s,interaction]
# output_vecteurs(vect_tout)
except Exception as e:
# print ("L'erreur est %s" % e)
for atom in residue:
print r , atom.get_name(), atom.get_coord()
# Ne garder que le type d'atome ou son nom ?
# print ("%d %s %s %5.2f %5.2f %5.2f" % (interaction, r, atom.get_name()[0], coords[0],coords[1], coords[2]))
# Phase 3
# vect_coords=[interaction, r, atom.get_name()[0], coords[0],coords[1], coords[2]]
# vect_tout=vect_coords+vect_aa
# output_vecteurs(vect_tout)
def output_vecteurs(mon_vecteur):
print (mon_vecteur)
def main():
# p = MMCIFParser()
# structure = p.get_structure('demo', '1a2y.cif')
structure = p.get_structure('demo', '1wq1.pdb')
# Structures à considérer pour le jeu de données initial
# - 1tv6
# - 1e27
# - 1pys
# - 1tnu (mais A,B)
# - 2cc1 (mais A,B)
# - 1m2t
# - 1wq1 (ras-GAP)
# print ("Le contenu du dictionnaire est %s" % structure.header)
# for h in structure.header:
# print ("L'entrée est %s" % h)
for c in structure.get_chains():
print("Il y a {} chaines dans le pdb, la première chaine est {}".format(len(chain_list),chain_list[0].get_id()))
# TODO : faire un vecteur qui donne non seulement l'interaction, mais aussi les deux atomes en interaction
# TODO : indiquer l'hybridation chimique de l'atome
# TODO : typer les atomes avec un champ de force à définir
if __name__ == "__main__":
for file in $pdbdir/*/*.gz;
nbuniprot=$( zgrep DBREF $file |awk '{print $7'}|sort|uniq|wc -l )
if [ $nbuniprot -eq 2 ]; then
pdb=$( basename $file )
echo $pdb
# echo "$pdb : $nbuniprot entries"
#! /usr/bin/python
# Copyright (c) 2003 Robert L. Campbell
from cctbx import uctbx, sgtbx
from pymol.cgo import *
from pymol import cmd
from pymol.vfont import plain
def set_to_zero(a):
if abs(a) < 1e-10:
return a
def draw_cell(obj,radius=0.2,name="cell"):
From pymol issue the "run" command to load the script,
then issue the "draw_cell(object,<optional radius>)" command
to actually run it and create the cgo object showing the unit cell
border for the space group specified by molecular object 'object'.
e.g. load 1avv.pdb
draw_cell 1avv 0.5 (or draw_cell('1avv',.5))
see also help(draw_cell_param) to draw the cell border for
user-defined cell dimensions (i.e. not loaded from a pdb file)
See also "help(draw_cell_param) to draw the cell border by
specifying the unit cell parameters directly (i.e. not loaded from
a pdb file).
def draw_cell_param(cell_param_list,radius=0.2,name="cell"):
If you wish to draw the unit cell border for any cell without the
need to load a pdb file, then do this:
e.g. run
to generate the cell border for this trigonal space group "p 31 2 1"
with a radius of 0.5A. Labels for the origin, and A, B and C axes
will appear as well. The perimeter of the cell is colored with the
RGB components corresponding to the A,B,C components.
size = radius*15.
origin_offset = radius * -25.
vert_000 = map(set_to_zero,U.orthogonalize((0.,0.,0)))
vert_100 = map(set_to_zero,U.orthogonalize((1.,0.,0)))
vert_010 = map(set_to_zero,U.orthogonalize((0.,1.,0)))
vert_001 = map(set_to_zero,U.orthogonalize((0.,0.,1)))
vert_110 = map(set_to_zero,U.orthogonalize((1.,1.,0)))
vert_011 = map(set_to_zero,U.orthogonalize((0.,1.,1)))
vert_101 = map(set_to_zero,U.orthogonalize((1.,0.,1)))
vert_111 = map(set_to_zero,U.orthogonalize((1.,1.,1)))
# vert_000 = map(None,U.orthogonalize((0.,0.,0)))
# vert_100 = map(None,U.orthogonalize((1.,0.,0)))
# vert_010 = map(None,U.orthogonalize((0.,1.,0)))
# vert_001 = map(None,U.orthogonalize((0.,0.,1)))
# vert_110 = map(None,U.orthogonalize((1.,1.,0)))
# vert_011 = map(None,U.orthogonalize((0.,1.,1)))
# vert_101 = map(None,U.orthogonalize((1.,0.,1)))
# vert_111 = map(None,U.orthogonalize((1.,1.,1)))
#print vert_000
#radius = [0.2]
#print radius
cell = []
cell = cell + vert_000 + vert_100 + [radius] + [0,0,0] + [1,0,0]
cell = cell + vert_000 + vert_010 + [radius] + [0,0,0] + [0,1,0]
cell = cell + vert_000 + vert_001 + [radius] + [0,0,0] + [0,0,1]
cell = cell + vert_100 + vert_110 + [radius] + [1,0,0] + [1,1,0]
cell = cell + vert_100 + vert_101 + [radius] + [1,0,0] + [1,0,1]
cell = cell + vert_010 + vert_110 + [radius] + [0,1,0] + [1,1,0]
cell = cell + vert_010 + vert_011 + [radius] + [0,1,0] + [0,1,1]
cell = cell + vert_001 + vert_101 + [radius] + [0,0,1] + [1,0,1]
cell = cell + vert_001 + vert_011 + [radius] + [0,0,1] + [0,1,1]
cell = cell + vert_110 + vert_111 + [radius] + [1,1,0] + [1,1,1]
cell = cell + vert_101 + vert_111 + [radius] + [1,0,1] + [1,1,1]
cell = cell + vert_011 + vert_111 + [radius] + [0,1,1] + [1,1,1]
#return cell
text = [COLOR, 1.0, 0.0, 1.0,]
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import random
import requests
import time
import sys
from xml.etree import ElementTree as ET
from Bio import SeqIO
# Utilisation de Bio.PDB
#from Bio.PDB import *
def download_uniprot_file(uniprot_id):
if not os.path.exists(unp_file) or os.path.getsize(unp_file) == 15614:
print("Downloading ... {}".format(uniprot_id), file=sys.stderr)
unp_url = ''+unp_file
unp = requests.get(unp_url)
with open(unp_file,'w') as f:
if os.path.getsize(unp_file) == 15614:
print("Uniprot me blackliste ...", file=sys.stderr)
def get_uniprot(uniprot_id):
return o
def get_uniprot_object(uniprot_id):
records=SeqIO.parse('../uniprot/'+uniprot_id+'.xml', 'uniprot-xml')
return r
def get_partners(uniprot_id):
Biopython does not record the binding partners from Intact keeped by Uniprot,
so we need to parse the file using ElementTree
for n in ur[0]:
for m in n.iter('{}interactant'):
for i in m.iter('{}id'):
return partners
def main():
print("TODO : réfléchir au cas des homodimères ...", file=sys.stderr)
# i=0
for u in targets:
for p in partners:
print("{} {} {} {} {}".format(u, p, u_obj.seq, p_obj.seq, 1))
# Create dummy dataset for negative interactions
# Guess up to 10 interactions from the db, according to average stats on the genome
putative_interactions=random.randint(0, 20)
for y in xrange(0, putative_interactions):
# print("Le nombre de partenaires à tester est {} et le nombre réduit est {}".format(len(putative_partners), len(set(putative_partners))))
# set est utile car le "tirage au sort" contient souvent des doublons ...
for i in set(putative_partners):
if dummy in partners:
print("{} {} {} {} {}".format(u, dummy, u_obj.seq, t_obj.seq, 1))
print("{} {} {} {} {}".format(u, dummy, u_obj.seq, t_obj.seq, 0))
# except Exception as e:
# print("Erreur: {}".format(e))
# # in this case no identifier is found in the targets list, do nothing
# pass
# i=i+1
if __name__ == "__main__":
import torch
from torch.autograd import Variable
# From
def one_hot(size, index):
mask = torch.LongTensor(*size).fill_(0)
ones = 1
if isinstance(index, Variable):
ones = Variable(torch.LongTensor(index.size()).fill_(1))
mask = Variable(mask, volatile=index.volatile)
ret = mask.scatter_(1, index, ones)
return ret
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import random
import sys
from xml.etree import ElementTree as ET
from Bio import SeqIO
class UniprotEntry(object):
uniprotID = ""
sequence = ""
partners = ""
# The class "constructor" - It's actually an initializer
def __init__(self, uniprotID, sequence, partners):
self.uniprotID = uniprotID
self.sequence = sequence = partners
def main():
et = ET.parse('uniprot-human.xml')
for n in etr.iter('{}entry'):
# Only consider the first uniprot identifier, other ones are duplicate
sequence=n.find('{}sequence').text.strip().replace('\r', '').replace('\n', '')
for m in n.iter('{}interactant'):
for i in m.iter('{}id'):
# Get new object for this entry
e=UniprotEntry(accession, sequence, partners)
# e.uniprotID=accession
uniprotList=[l for l in uniprotEntries.keys()]
print("La liste est composée de {} membres".format(len(uniprotList)),file=sys.stderr)
for k in uniprotEntries.keys():
for b in uniprotEntries[k].partners:
print("{} {} {} {} 1".format(k, uniprotEntries[b].uniprotID, uniprotEntries[k].sequence, uniprotEntries[b].sequence))
except Exception as e:
print("{} -> {} no info: {}".format(k, b, e), file=sys.stderr)
# Create dummy dataset for negative interactions
# Guess up to 5 interactions from the db, according to average stats on the genome
putative_interactions=random.randint(0, 5)
for y in xrange(0, putative_interactions):
# print("Le nombre de partenaires à tester est {} et le nombre réduit est {}".format(len(putative_partners), len(set(putative_partners))))
# set est utile car le "tirage au sort" contient souvent des doublons ...
for i in set(putative_partners):
if not uid in uniprotEntries[k].partners:
print("{} {} {} {} {}".format(uniprotEntries[k].uniprotID, uid, uniprotEntries[k].sequence, uniprotEntries[uid].sequence, 0))
except Exception as e:
print("Pour {}, l'erreur est {}".format(i,e),file=sys.stderr)
if __name__ == "__main__":
title={Deep Learning},
author={Ian Goodfellow and Yoshua Bengio and Aaron Courville},
publisher={MIT Press},
\ No newline at end of file
This diff is collapsed.
\section{Etape 3}
Informations sur les structures de protéine 3d :
\ No newline at end of file
\section{Réseaux de neurones}
Un réseau de neurones est un système dont les composants, des neurones, qui reçoivent une entrée, et y associent une sortie grâce à une fonction d'activation.
Le réseau est formé car certaines sorties de neurones sont reliées aux entrées d'autres neurones, formant un graphe orienté pondéré par des poids associés aux arêtes du graphe.
Les poids peuvent être modifiés à travers l'apprentissage.
%TODO: add a schéma + better explanation
\subsection{Fonction d'activation}
Une fonction d'activation est une fonction mathématique appliquée au signal en sortie du neurone, qui reprend l'idée du potentiel d'action présent en biologie.
Il en existe de plusieurs types, qui ont des caractéristiques et des utilisations variées.
\subsubsection*{Fonction sigmoïde}
%TODO: add schéma sigmoïde
%TODO: reword
La fonction sigmoïde présente l'intérêt d'avoir une dérivable de sa fonction inverse facile à calculer ce qui intervient dans les performances des algorithmes l'utilisant.
f(x)=\frac{1}{1 + e^{- x}}
%TODO: add schéma ReLU
La fonction d'activation ReLU (pour Rectified Linear Units) est une fonction qui est toujours positive (ou nulle).
f(x) = x^+ = \max(0, x)
Elle est très populaire dans le cadre des réseaux de neurones profonds\footnote{}
\footnote{Papier sur la ReLU \url{}}
%TODO:put links of articles in bibliographie not footnotes
Il y a trois types principaux d'apprentissage pour un réseau de neurones, l'apprentissage supervisé, l'apprentissage non supervisé et l'apprentissage par renforcement.
Dans le cadre de ce stage, l'apprentissage sera exclusivement supervisé.
\subsubsection*{Apprentissage supervisé}
En apprentissage supervisé, on cherche à faire converger le modèle pour relier les entrées à des sorties dans un domaine dont on fournit les données au réseau lors de l'apprentissage.
Les données en entrée utilisées pour l'apprentissage sont ainsi annotées avec un label donnant le résultat attendu pour cette entrée.
On utilise souvent l'apprentissage supervisé pour les problèmes de classification et de régression.
Un problème de régression est un problème où les sorties sont des valeurs dans un ensemble continu de réels, tandis qu'un problème de classification cherche à classer les entrées dans différentes catégories.
%TODO: préciser ?
\subsubsection*{Rétropropagation du gradient}
Le but du modèle à travers son apprentissage est d'arriver à la configuration idéale des poids des différentes connexions entre ses couches/neurones.
Pour ce faire, à la fin du traitement d'un exemple par la chaîne de neurones, on calcule l'erreur par rapport à la bonne réponse en sortie, et on propage ensuite l'information en arrière dans le réseau, grâce à l'algorithme de rétropropagation du gradient (stochastique). Ca permet d'avoir une fonction de coût qu'on cherche à minimiser pour que le réseau soit plus efficace.
Comme il faut avoir connaissance de la sortie désirée pour une entrée, il faut pour utiliser la rétropropagation du gradient être dans un système d'apprentissage supervisé\footnote{A l'exception des auto-encodeurs. \url{lien}}.
%add lien + infos?
Cet algorithme cherche à atteindre le minimum de la fonction et donc calcule le gradient permettant de faire décroître la fonction de coût le plus efficacement pour pouvoir ensuite propager cette information aux couches précédentes et avoir ainsi une mise à jour des poids du modèle.
On effectue cette rétropropagation plusieurs fois pour arriver à un minimum de la fonction de coût, mais comme il peut arriver qu'on atteigne un minimum local et non global, on ajoute souvent une inertie\footnote{ou momentum} pour éviter d'être coincé par un minimum local.
L'objectif d'un réseau de neurones est d'obtenir des résultats corrects sur des entrées inconnues, ce qu'on appelle la généralisation.
Lorsqu'on entraîne un réseau, on commence par chercher à minimiser le taux d'erreur sur les données d'entraînement, mais on cherche au final à minimiser le taux d'erreur sur des données inconnues.
Pour vérifier la qualité de l'entraînement du réseau, on va donc mesure le taux d'erreur de test sur des données que le réseau n'aura jamais rencontré lors de son entraînement.
En faisant celà, on cherche à éviter deux choses : le sur-apprentissage et le sous-apprentissage.
Le sur-apprentissage arrive lorsque le modèle contient énormément de paramètres et est trop proche des données d'apprentissage, ce qui entraîne un grand taux d'erreur de test lorsqu'on lui présente des données inconnus.
Le sous-apprentissage quand a lui intervient lorsque le modèle n'arrive pas à extrapoler suffisamment pour correspondre aux données d'entraînement.
%TODO: add schema (
Pour mesurer ces valeurs, on peut utiliser par exemple l'erreur quadratique moyenne et on souhaite qu'elle soit la plus petite possible de manière à garantir un apprentissage correct.
\subsection{Deep Learning}
Le Deep Learning, ou apprentissage profond est une méthode de machine learning cherchant à obtenir un haut niveau d'abstraction par rapport aux données.
Les différentes couches permettent à chaque fois d'augmenter un peu l'abstraction du modèle.
Ce type d'apprentissage tient son nom de la présence de plusieurs couches de neurones entre l'entrée et la sortie du modèle qui sont donc cachées au plus profond du modèle.
\subsection{Pourquoi utiliser du deep learning}
En ce qui concerne les interaction entre protéines, les biologistes ont choisi des critères sans être forcément sûrs que ce soient les bons critères qu'ils prennent en compte.
Un réseau de neurones profonds va déterminer des 'features'\footnote{ou critères} sans qu'il y ait de choix arbitraire d'un opérateur, ce qui permet de se détacher du possible biais du choix des biologistes mais qui permettrait également de peut-être obtenir de nouvelles informations sur ces critères.
%TODO: speak of Random Forests
\subsection{Réseau à convolutions}
Les réseaux à convolution comprennent des couches de convolution, parfois du pooling ainsi que des couches full-connected de neurones.
La partie Convolution et Pooling fait de l'extraction de feature, tandis que les couches full-connected font plutôt de l'abstraction des informations.
Les couches de convolution prennent en entrée une petite partie de l'entrée (par exemple un carré de 5x5 pixels sur une image) et y appliquent une opération de convolution ce qui crée des 'feature map'.
%TODO: better explain
Le pooling a lieu en général après une convolution, et sort par exemple le maximum des valeurs sur une certaine quantité d'entrées données (pour du max pooling).
Les couches full-connected signifient que tous les neurones d'entrée sont reliés à tous les neurones de sortie.
%TODO: do better
\section{Travaux précédents}
\subsection{DeepPPI: Boosting Prediction of Protein-Protein Interactions with Deep Neural Networks}
L'objectif des auteurs de ce papier est la prédiction d'interactions protéine-protéine, et ils expliquent bien leur démarche mais le jeu de données est uniquement sur le nom des protéines sans prendre en compte la séquence et donc on peut considérer que leur réseau a plutôt mémorisé les noms de protéines interagissant ensemble plus qu'un réel apprentissage sur une interaction au niveau de la chaîne polypeptidique.
%TODO: Extend + write better
%add that it's nice that they gave the code?
\subsection{Continuous Distributed Representation of Biological Sequences for Deep Proteomics and Genomics}
L'objectif de ce papier est de faire une classification des familles de protéine et également de proposer une nouvelle représentation des séquences d'acides aminés en utilisant des n-grams de trois acides aminés.
Un n-gram est une sous-séquence de n éléments construite à partir d'une séquence donnée.
Les n-grams sont souvent utilisés en traitement automatique de la langue pour garder un historique sur une séquence de mots.
%TODO: expand
%say they don't give code (CHECK)
Les premiers travaux sur ce projet ont été effectués sur une machine équipée de deux GPUs.
L'utilisation de GPU est importante car elle permet d'avoir de meilleures performances, les GPUs étant mieux équipés pour du calcul matriciel.
%TODO: ask if more details needed ? (probably yes)
Pytorch\footnote{\url{}} est un framework Python de deep learning qui permet d'utiliser les GPUs (uniquement Nvidia, car se reposant sur la technologie CUDA) pour optimiser les temps de calculs des réseaux de neurones.
L'intérêt principal d'utiliser un framework tel que Pytorch, c'est d'avoir un outil qui fait les calculs de gradients automatiquement (avec autograd dans Pytorch), de manière à minimiser les erreurs humaines.
On profite également de la possibilité de gérer les données en entrée de manière optimale. %quand c'est bien fait. hum
%TODO:better intro
L'objectif de ce stage est d'entraîner un réseau de neurones à prédire l'interaction entre deux protéines ainsi que la localisation de cette interaction sur la structure des deux protéines.
La compréhension des interactions entre protéines sont très importantes dans de nombreux domaines,
%TODO: add examples
Ce stage a été encadré par Florian Richoux du Laboratoire des Sciences du Numérique de Nantes et effectué en collaboration avec Stéphane Télétchéa du Laboratoire UFIP.
L'idée est d'effectuer le travail en trois étapes.
La première ayant pour objectif de créer un réseau de neurones prenant en entrée deux chaînes polypeptidiques de protéine et ressortant une classification simple : il y a une interaction ou il n'y en a pas.
La deuxième étape aura pour objectif de déterminer la localisation sur la chaîne polypeptidique de l'interaction entre les protéines.
La troisième étape prendra en entrée la structure en 3D des protéines pour essayer de déterminer la localisation de l'interaction, car les structures 3D ont une grande importance dans les interactions entre protéines.
Ce rapport commence par une présentation des réseaux de neurones ainsi que du Deep Learning. On y trouvera ensuite des notes sur des travaux précédents dans le domaine qui se rapportent à l'objectif du stage. Les différentes étapes du travail seront présentées après.
%TODO: réecrire proprement le plan quand tout sera la
Deep Learning by Ian Goodfellow, Yoshua Bengio and Aaron Courville.
\ No newline at end of file