├── figure_1.png ├── src ├── gpu_1.sh ├── args.py ├── utils.py ├── utils_vamp.py ├── train.py ├── model.py └── layers.py ├── README.md └── Example_TrpCage_2dEmbedding.ipynb /figure_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghorbanimahdi73/GraphVampNet/HEAD/figure_1.png -------------------------------------------------------------------------------- /src/gpu_1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##SBATCH --ntasks=28 3 | #SBATCH --job-name=trp_1 4 | #SBATCH --time=24:0:0 5 | #SBATCH -N 1 6 | #SBATCH --partition=v100 7 | #SBATCH --gres=gpu:v100:1 8 | #SBATCH --ntasks-per-core=1 9 | ##SBATCH --mem=200g 10 | # load necessary module 11 | 12 | #module load cuDNN/7.6.5/CUDA-10.1 13 | module laod cuda/10.2 14 | 15 | pwd=$PWD 16 | source ~/.bashrc 17 | cd $pwd 18 | 19 | conda activate koopnet 20 | 21 | for i in {1..10};do 22 | python train.py --epochs 100 --batch-size 1000 --num-atoms 20 --num-classes 5 --save-folder logs_$i --h_a 16 --num_neighbors 7 --n_conv 4 --h_g 2 --conv_type SchNet --dmin 0. --dmax 8. --step 0.5 --tau 5 --train --dist-data ../dists_trpcage_ca_7nbrs_1ns.npz --nbr-data ../inds_trpcage_ca_7nbrs_1ns.npz --residual 23 | done 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphVampNet 2 | 3 | ![figure](figure_1.png) 4 | 5 | This repo contains the code for **GraphVAMPNet** 6 | 7 | 8 | ## GraphVAMPNet code 9 | 10 | ## Usage 11 | 12 | ### training 13 | ``` 14 | python train.py --epochs 100 --batch-size 1000 --lr 0.0005 --hidden 16 15 | --num-atoms 20 --num-classes 5 --num_neighbors 7 --conv_type SchNet --dmin 0 16 | --dmax 8. --step 0.5 --dist-data dists.dat --nbr-data nbrs.dat --residual --train 17 | ``` 18 | ### testing 19 | 20 | ``` 21 | python train.py --epochs 100 --batch-size 1000 --lr 0.0005 --hidden 16 22 | --num-atoms 20 --num-classes 5 --num-neighbors 7 --conv_type SchNet --dmin 0 23 | --dmax 8. --step 0.5 --dist-data dists.dat --nbr-data nbrs.dat --residual --trained-model 24 | logs/logs_99.pt 25 | ``` 26 | 27 | ## Requirements 28 | - pytorch 29 | - deeptime 30 | - torch_scatter 31 | 32 | 33 | 34 | ## Sources: 35 | - VAMPNet code is based on deeptime package [deeptime](https://deeptime-ml.github.io/latest/index.html) 36 | - SchNet code is based on the [cgnet](https://github.com/brookehus/cgnet) 37 | 38 | 39 | ## Cite 40 | If you use this code please cite the following paper: 41 | 42 | ``` 43 | ``` 44 | -------------------------------------------------------------------------------- /src/args.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | def buildParser(): 4 | 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument('--no-cuda', action='store_true', default=False, help='Disables CUDA training') 7 | parser.add_argument('--seed', type=int, default=42, help='random seed') 8 | parser.add_argument('--epochs', type=int, default=10, help='number of training epochs') 9 | parser.add_argument('--batch-size', type=int, default=5000, help='batch-size for training') 10 | parser.add_argument('--lr', type=float, default=0.0005, help='Initial learning rate') 11 | parser.add_argument('--hidden', type=int, default=16, help='number of hidden neurons') 12 | parser.add_argument('--num-atoms', type=int, default=10, help='Number of atoms') 13 | parser.add_argument('--num-classes', type=int, default=6, help='number of coarse-grained classes') 14 | parser.add_argument('--save-folder', type=str, default='logs', help='Where to save the trained model') 15 | parser.add_argument('--dropout', type=float, default=0.4, help='Dropout rate') 16 | parser.add_argument('--atom_init', type=str, default=None, help='inital embedding for atoms file') 17 | parser.add_argument('--h_a', type=int, default=16, help='Atom hidden embedding dimension') 18 | parser.add_argument('--num_neighbors', type=int, default=5, help='Number of neighbors for each atom in the graph') 19 | parser.add_argument('--n_conv', type=int, default=4, help='Number of convolution layers') 20 | parser.add_argument('--save_checkpoints', default=True, action='store_true', help='If True, stores checkpoints') 21 | parser.add_argument('--conv_type', default='', type=str, help='the type of convolution layer, one of \ 22 | [GraphConvLayer, NeighborMultiHeadAttention, SchNet]') 23 | parser.add_argument('--dmin', default=0., type=float, help='Minimum distance for the gaussian filter') 24 | parser.add_argument('--dmax', default=3., type=float, help='maximum distance for the gaussian filter') 25 | parser.add_argument('--step', default=0.2, type=float, help='step for the gaussian filter') 26 | parser.add_argument('--tau', default=1, type=int, help='lag time for the model') 27 | parser.add_argument('--val-frac', default=0.3, type=float, help='fraction of dataset for validation') 28 | parser.add_argument('--num_heads', default=2, type=int, help='number of heads in multihead attention') 29 | parser.add_argument('--trained-model', default=None, type=str, help='path to the trained model for loading') 30 | parser.add_argument('--train', default=False, action='store_true', help='Whether to train the model or not') 31 | parser.add_argument('--use_backbone_atoms', default=False, action='store_true', help='Whether to use all the back bone atoms for training') 32 | parser.add_argument('--dont-pool-backbone', default=False, action='store_true', help='Whether not to pool backbone atoms') 33 | parser.add_argument('--h_g', type=int, default=8, help='Number of embedding dimension after backbone pooling') 34 | parser.add_argument('--seq_file', type=str, default=None, help='Sequence file to initialize a one-hot encoding based on amino types') 35 | parser.add_argument('--dist-data', type=str, default='dists_BBA_7nbrs_1ns.npz', help='the distnace data file') 36 | parser.add_argument('--nbr-data', type=str, default='inds_BBA_7nbrs_1ns.npz', help='the neighbors data file') 37 | parser.add_argument('--score-method', type=str, default='VAMP2', help='the scoring method of VAMPNet') 38 | parser.add_argument('--residual', action='store_true', default=False, help='Whether to use residual connections') 39 | parser.add_argument('--attention-pool', action='store_true', default=False, help= 'Whether to perform attention before global pooling') 40 | parser.add_argument('--return-emb', action='store_true', default=False, help='Whether return the learned graph embeddings') 41 | parser.add_argument('--return-attn', action='store_true', default=False, help='Whether to return the attention probs (only for NeighborMultiHeadAttention)') 42 | return parser 43 | 44 | -------------------------------------------------------------------------------- /src/utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import deeptime 4 | from tqdm import tqdm 5 | import matplotlib.pyplot as plt 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | import mdshare 9 | from torch.utils.data import DataLoader 10 | import json 11 | from sklearn.neighbors import BallTree 12 | import mdtraj as md 13 | import argparse 14 | import sys 15 | 16 | from deeptime.decomposition._koopman import KoopmanChapmanKolmogorovValidator 17 | 18 | 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('--num-neighbors', type=int, default=5, help='number of neighbors') 21 | parser.add_argument('--traj-folder', type=str, default=None, help='the path to the trajectory folder') 22 | parser.add_argument('--stride', type=int, default=5, help='stride for trajectory') 23 | #parser.add_argument('--use-backbone', action='store_true', default=False, help='Whether to use produce the data for backbone atoms') 24 | 25 | args = parser.parse_args() 26 | ########## for loading the BBA trajectory #################################### 27 | 28 | 29 | traj_1 = ['../2JOF-0-protein/2JOF-0-protein-'+str(i).zfill(3)+'.dcd' for i in range(105)] 30 | 31 | crys = md.load_pdb('2jof.pdb') 32 | top = crys.topology 33 | inds = top.select('backbone') 34 | 35 | t1 = md.load_dcd(traj_1[0], top=top, stride=args.stride, atom_indices=inds) 36 | coor_t1 = t1.xyz 37 | for i in range(1,len(traj_1)): 38 | t1 = md.load_dcd(traj_1[i], top=top, stride=args.stride, atom_indices=inds) 39 | coor_t1 = np.concatenate((coor_t1, t1.xyz), axis=0) 40 | 41 | print(coor_t1.shape) 42 | 43 | data = list([coor_t1]) 44 | np.savez('pos_trpcage_bb.npz', data[0]) 45 | 46 | 47 | if torch.cuda.is_available(): 48 | device = torch.device('cpu') 49 | print('cuda is is available') 50 | else: 51 | print('Using CPU') 52 | device = torch.device('cpu') 53 | 54 | #ala_coords_file = mdshare.fetch( 55 | # "alanine-dipeptide-3x250ns-heavy-atom-positions.npz", working_directory="data" 56 | #) 57 | #with np.load(ala_coords_file) as fh: 58 | # data = [fh[f"arr_{i}"].astype(np.float32) for i in range(3)] 59 | # 60 | #dihedral_file = mdshare.fetch( 61 | # "alanine-dipeptide-3x250ns-backbone-dihedrals.npz", working_directory="data" 62 | #) 63 | # 64 | #with np.load(dihedral_file) as fh: 65 | # dihedral = [fh[f"arr_{i}"] for i in range(3)] 66 | 67 | 68 | 69 | # reshape the data to be in share list of [N,num_atoms,3] 70 | #data_reshaped = [] 71 | #for i in range(len(data)): 72 | # temp = data[i].reshape(data[0].shape[0], 3, 10).swapaxes(1,2) 73 | # data_reshaped.append(temp) 74 | #----------------------------------------------------- 75 | 76 | def get_nbrs(all_coords, num_neighbors=args.num_neighbors): 77 | ''' 78 | inputs: a trajectory or list of trajectories with shape [T, num_atoms, dim] 79 | T: number of steps 80 | dim: number of dimensions (3 coordinates) 81 | 82 | Returns: 83 | if all_coords is a list: 84 | list of trajectories of ditances and indices 85 | else: 86 | trajectory of distances and indices 87 | 88 | [N, num_atoms, num_neighbors] 89 | ''' 90 | k_nbr=num_neighbors+1 91 | if type(all_coords) == list: 92 | all_dists = [] 93 | all_inds = [] 94 | for i in range(len(all_coords)): 95 | dists = [] 96 | inds = [] 97 | tmp_coords = all_coords[i] 98 | for j in tqdm(range(len(tmp_coords))): 99 | tree = BallTree(tmp_coords[j], leaf_size=3) 100 | dist, ind = tree.query(tmp_coords[j], k=k_nbr) 101 | dists.append(dist[:,1:]) 102 | inds.append(ind[:,1:]) 103 | 104 | dists = np.array(dists) 105 | inds = np.array(inds) 106 | all_dists.append(dists) 107 | all_inds.append(inds) 108 | else: 109 | all_inds = [] 110 | all_dists = [] 111 | for i in range(len(all_coords)): 112 | tree = BallTree(all_coords[i], leaf_size=3) 113 | dist , ind = tree.query(all_coords[i], k=k_nbr) 114 | dists.append(dist[:,1:]) 115 | inds.append(ind[:,1:]) 116 | all_dists = np.array(dists) 117 | all_inds = np.array(inds) 118 | 119 | return all_dists, all_inds 120 | 121 | ns = int(args.stride*0.2) # 0.2 ns is the timestep of trajectories 122 | dists, inds = get_nbrs(data, args.num_neighbors) 123 | np.savez('dists_trpcage_bb_'+str(args.num_neighbors)+'nbrs_'+ str(ns)+'ns'+'.npz', dists[0]) 124 | np.savez('inds_trpcage_bb_'+str(args.num_neighbors)+'nbrs_'+ str(ns)+'ns'+'.npz', inds[0]) 125 | 126 | 127 | def chunks(data, chunk_size=5000): 128 | ''' 129 | splitting the trajectory into chunks for passing into analysis part 130 | data: list of trajectories 131 | chunk_size: the size of each chunk 132 | ''' 133 | if type(data) == list: 134 | 135 | for data_tmp in data: 136 | for j in range(0, len(data_tmp),chunk_size): 137 | print(data_tmp[j:j+chunk_size,...].shape) 138 | yield data_tmp[j:j+chunk_size,...] 139 | 140 | else: 141 | 142 | for j in range(0, len(data), chunk_size): 143 | yield data[j:j+chunk_size,...] 144 | -------------------------------------------------------------------------------- /src/utils_vamp.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import deeptime 4 | from tqdm import tqdm 5 | import matplotlib.pyplot as plt 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | from torch.utils.data import DataLoader 9 | import json 10 | from deeptime.decomposition.deep import VAMPNet 11 | from deeptime.decomposition import VAMP 12 | import os 13 | import pickle 14 | 15 | 16 | plt.set_cmap('jet') 17 | 18 | def estimate_koopman_op(trajs, tau): 19 | if type(trajs) == list: 20 | traj = np.concatenate([t[:-tau] for t in trajs], axis=0) 21 | traj_lag = np.concatenate([t[tau:] for t in trajs], axis=0) 22 | else: 23 | traj = trajs[:-tau] 24 | traj_lag = trajs[tau:] 25 | c_0 = np.transpose(traj)@traj 26 | c_tau = np.transpose(traj)@traj_lag 27 | 28 | eigv, eigvec = np.linalg.eig(c_0) 29 | include = eigv > 1e-7 30 | eigv = eigv[include] 31 | eigvec = eigvec[:, include] 32 | c0_inv = eigvec @ np.diag(1/eigv)@np.transpose(eigvec) 33 | 34 | koopman_op = c0_inv @ c_tau 35 | return koopman_op 36 | 37 | def get_ck_test(traj, steps, tau): 38 | if type(traj) == list: 39 | n_states = traj[0].shape[1] 40 | else: 41 | n_states = traj.shape[1] 42 | 43 | predicted = np.zeros((n_states, n_states, steps)) 44 | estimated = np.zeros((n_states, n_states, steps)) 45 | 46 | predicted[:, :, 0] = np.identity(n_states) 47 | estimated[:, :, 0] = np.identity(n_states) 48 | 49 | for vector, i in zip(np.identity(n_states), range(n_states)): 50 | for n in range(1, steps): 51 | koop = estimate_koopman_op(traj, tau) 52 | koop_pred = np.linalg.matrix_power(koop, n) 53 | koop_est = estimate_koopman_op(traj, tau*n) 54 | 55 | predicted[i,:,n] = vector@koop_pred 56 | estimated[i,:,n] = vector@koop_est 57 | 58 | return [predicted, estimated] 59 | 60 | def plot_ck_test(pred, est, n_states, steps, tau, save_folder): 61 | fig, ax = plt.subplots(n_states, n_states, sharex=True, sharey=True) 62 | for index_i in range(n_states): 63 | for index_j in range(n_states): 64 | 65 | ax[index_i][index_j].plot(range(0, steps*tau, tau), pred[index_i, index_j], color='b') 66 | ax[index_i][index_j].plot(range(0, steps*tau, tau), est[index_i, index_j], color='r', linestyle='--') 67 | ax[index_i][index_j].set_title(str(index_i+1)+'->'+str(index_j+1), fontsize='small') 68 | 69 | ax[0][0].set_ylim((-0.1, 1.1)) 70 | ax[0][0].set_xlim((0, steps*tau)) 71 | ax[0][0].axes.get_xaxis().set_ticks(np.round(np.linspace(0, steps*tau, 3))) 72 | plt.tight_layout() 73 | plt.show() 74 | plt.savefig(save_folder+'/ck_test.png') 75 | 76 | def get_its(traj, lags): 77 | ''' 78 | implied timescales from a trajectory estiamted at a series of lag times 79 | 80 | parameters: 81 | --------------------- 82 | traj: numpy array [traj_timesteps, traj_dimension] traj or list of trajs 83 | lags: numpy array with size [lagtimes] series of lag times at which the implied timescales are estimated 84 | 85 | Returns: 86 | --------------------- 87 | its: numpy array with size [traj_dimensions-1, lag_times] implied timescales estimated for the trajectory 88 | ''' 89 | 90 | if type(traj) == list: 91 | outputsize = traj[0].shape[1] 92 | else: 93 | outputsize = traj.shape[1] 94 | its = np.zeros((outputsize-1, len(lags))) 95 | 96 | for t, tau_lag in enumerate(lags): 97 | koopman_op = estimate_koopman_op(traj, tau_lag) 98 | k_eigvals, k_eigvec = np.linalg.eig(np.real(koopman_op)) 99 | k_eigvals = np.sort(np.absolute(k_eigvals)) 100 | k_eigvals = k_eigvals[:-1] 101 | its[:, t] = (-tau_lag/np.log(k_eigvals)) 102 | 103 | return its 104 | 105 | def plot_its(its, lag, save_folder,ylog=False): 106 | ''' 107 | plots the implied timescales calculated by the function 108 | 109 | get_its: 110 | parameters: 111 | ------------------------ 112 | its: numpy array 113 | the its array returned by the function get_its 114 | lag: numpy array 115 | lag times array used to estimated the implied timescales 116 | ylog: Boolean, optional, default=False 117 | if true, the plot will be a logarithmic plot, otherwize it 118 | will be a semilogy plot 119 | ''' 120 | 121 | if ylog: 122 | plt.loglog(lag, its.T[:,::-1]) 123 | plt.loglog(lag, lag, 'k') 124 | plt.fill_between(lag, lag, 0.99, alpha=0.2, color='k') 125 | else: 126 | plt.semilogy(lag, its.T[:,::-1]) 127 | plt.semilogy(lag,lag, 'k') 128 | plt.fill_between(lag, lag, 0.99, alpha=0.2, color='k') 129 | plt.show() 130 | plt.savefig(save_folder+'/its.png') 131 | 132 | 133 | def plot_scores(train_scores, validation_scores, save_folder): 134 | plt.loglog(train_scores, label='training') 135 | plt.loglog(validation_scores, label='validation') 136 | plt.xlabel('step') 137 | plt.ylabel('score') 138 | plt.legend() 139 | plt.savefig(save_folder+'/scores.png') 140 | 141 | 142 | 143 | def chapman_kolmogorov_validator(model, mlags, n_observables=None, 144 | observables='phi', statistics='psi'): 145 | ''' returns a chapman-kolmogrov validator based on this estimator and a test model 146 | 147 | parameters: 148 | ----------------- 149 | model: VAMP model 150 | mlags: int or int-array 151 | multiple of lagtimes of the test_model to test against 152 | test_model: CovarianceKoopmanModel, optional, default=None, 153 | The model that is tested, if not provided uses this estimator's encapsulated model. 154 | n_observables: int, optional, default=None, 155 | limit the number of default observables to this number. only used if 'observables' are Nonr or 'statistics' are None. 156 | observables: (input_dimension, n_observables) ndarray 157 | coefficents that express one or multiple observables in the basis of the input features 158 | statistics: (input_dim, n_statistics) ndarray 159 | coefficents that express one or more statistics in the basis of the input features 160 | 161 | Returns: 162 | ------------------ 163 | validator: KoopmanChapmanKolmogrovValidator 164 | the validator 165 | ''' 166 | test_model = model.fetch_model() 167 | assert test_model is not None, 'We need a test model via argument or an estimator which was already fit to data' 168 | 169 | lagtime = model.lagtime 170 | if n_observables is not None: 171 | if n_observables > test_model.dim: 172 | import warnings 173 | warnings.warn('selected singular functgions as observables but dimension is lower thanthe requested number of observables') 174 | n_observables = test_model.dim 175 | 176 | else: 177 | n_observables = test_model.dim 178 | 179 | if isinstance(observables, str) and observables == 'phi': 180 | observables = test_model.singular_vectors_right[:, :n_observables] 181 | observables_mean_free = True 182 | else: 183 | observables_mean_free = False 184 | 185 | if isinstance(statistics, str) and statistics == 'psi': 186 | statistics = test_model.singular_vectors_left[:, :n_observables] 187 | statistics_mean_free = True 188 | else: 189 | statistics_mean_free = False 190 | 191 | return VAMPKoopmanCKValidator(test_model, model, lagtime, mlags, observables, statistics, 192 | observables_mean_free, statistics_mean_free) 193 | 194 | def _vamp_estimate_model_for_lag(estimator: VAMP, model, data, lagtime): 195 | est = VAMP(lagtime=lagtime, dim=estimator.dim, var_cutoff=estimator.var_cutoff, scaling=estimator.scaling, 196 | epsilon=estimator.epsilon, observable_transform=estimator.observable_transform) 197 | 198 | whole_dataset = TrajectoryDataset.from_trajectories(lagtime=lagtime, data=data) 199 | whole_dataloder = DataLoader(whole_dataset, batch_size=10000, shuffle=False) 200 | for batch_0, batch_t in whole_dataloder: 201 | est.partial_fit((batch_0.numpy(), batch_t.numpy())) 202 | 203 | return est.fetch_model() -------------------------------------------------------------------------------- /src/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import deeptime 4 | from tqdm import tqdm 5 | import matplotlib.pyplot as plt 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | import mdshare 9 | from torch.utils.data import DataLoader 10 | import json 11 | from args import buildParser 12 | from layers import GaussianDistance, NeighborMultiHeadAttention, InteractionBlock, GraphConvLayer 13 | from model import GraphVampNet 14 | from deeptime.util.data import TrajectoryDataset 15 | from deeptime.decomposition.deep import VAMPNet 16 | from deeptime.decomposition import VAMP 17 | from copy import deepcopy 18 | import os 19 | import pickle 20 | import warnings 21 | from deeptime.decomposition._koopman import KoopmanChapmanKolmogorovValidator 22 | from utils_vamp import * 23 | 24 | if torch.cuda.is_available(): 25 | device = torch.device('cuda') 26 | print('cuda is available') 27 | else: 28 | print('Using CPU') 29 | device = torch.device('cpu') 30 | 31 | # ignore deprecation warnings 32 | warnings.filterwarnings('ignore',category=DeprecationWarning) 33 | 34 | args = buildParser().parse_args() 35 | 36 | if not os.path.exists(args.save_folder): 37 | print('making the folder for saving checkpoints') 38 | os.makedirs(args.save_folder) 39 | 40 | with open(args.save_folder+'/args.txt','w') as f: 41 | f.write(str(args)) 42 | 43 | meta_file = os.path.join(args.save_folder, 'metadata.pkl') 44 | pickle.dump({'args': args}, open(meta_file, 'wb')) 45 | 46 | #------------------- data as a list of trajectories --------------------------- 47 | 48 | dists1, inds1 = np.load(args.dist_data)['arr_0'], np.load(args.nbr_data)['arr_0'] 49 | 50 | mydists1 = torch.from_numpy(dists1).to(device) 51 | myinds1 = torch.from_numpy(inds1).to(device) 52 | 53 | data = [] 54 | data.append(torch.cat((mydists1,myinds1), axis=-1)) 55 | 56 | dataset = TrajectoryDataset.from_trajectories(lagtime=args.tau, data=data) 57 | 58 | 59 | n_val = int(len(dataset)*args.val_frac) 60 | train_data, val_data = torch.utils.data.random_split(dataset, [len(dataset)-n_val, n_val]) 61 | 62 | loader_train = DataLoader(train_data, batch_size=args.batch_size, shuffle=True) 63 | loader_val = DataLoader(val_data, batch_size=args.batch_size, shuffle=False) 64 | 65 | # data is a list of trajectories [T,N,M+M] 66 | #--------------------------------------------------------------------------------- 67 | 68 | lobe = GraphVampNet() 69 | lobe_timelagged = deepcopy(lobe).to(device=device) 70 | lobe = lobe.to(device) 71 | 72 | vampnet = VAMPNet(lobe=lobe, lobe_timelagged=lobe_timelagged, learning_rate=args.lr, device=device, optimizer='Adam', score_method=args.score_method) 73 | 74 | def count_parameters(model): 75 | ''' 76 | count the number of parameters in the model 77 | ''' 78 | return sum(p.numel() for p in model.parameters() if p.requires_grad) 79 | 80 | print('number of parameters', count_parameters(lobe)) 81 | 82 | def train(train_loader , n_epochs, validation_loader=None): 83 | ''' 84 | Parameters: 85 | ----------------- 86 | train_loader: torch.utils.data.DataLoader 87 | The data to use for training, should yield a tuple of batches representing instantaneous and time-lagged samples 88 | n_epochs: int, the number of epochs for training 89 | validation_loader: torch.utils.data.DataLoader: 90 | The validation data should also be yielded as a two-element tuple. 91 | 92 | Returns: 93 | ----------------- 94 | model: VAMPNet 95 | ''' 96 | 97 | for epoch in tqdm(range(n_epochs)): 98 | ''' 99 | perform batches of data here 100 | ''' 101 | for batch_0, batch_t in train_loader: 102 | vampnet.partial_fit((batch_0.to(device),batch_t.to(device))) 103 | 104 | if validation_loader is not None: 105 | with torch.no_grad(): 106 | scores = [] 107 | for val_batch in validation_loader: 108 | scores.append(vampnet.validate((val_batch[0].to(device), val_batch[1].to(device)))) 109 | 110 | mean_score = torch.mean(torch.stack(scores)) 111 | vampnet._validation_scores.append((vampnet._step, mean_score.item())) 112 | 113 | if args.save_checkpoints: 114 | torch.save({ 115 | 'epoch' : epoch, 116 | 'state_dict': lobe.state_dict(), 117 | }, args.save_folder+'/logs_'+str(epoch)+'.pt') 118 | 119 | return vampnet.fetch_model() 120 | 121 | 122 | plt.set_cmap('jet') 123 | 124 | if not args.train and os.path.isfile(args.trained_model): 125 | print('Loading model') 126 | checkpoint = torch.load(args.trained_model) 127 | lobe.load_state_dict(checkpoint['state_dict']) 128 | lobe_timelagged = deepcopy(lobe).to(device=device) 129 | lobe = lobe.to(device) 130 | lobe.eval() 131 | lobe_timelagged.eval() 132 | vampnet = VAMPNet(lobe=lobe, lobe_timelagged=lobe_timelagged, learning_rate=args.lr, device=device) 133 | model = vampnet.fetch_model() 134 | 135 | 136 | elif args.train: 137 | model = train(train_loader=loader_train, n_epochs=args.epochs, validation_loader=loader_val) 138 | 139 | # save the training and validation scores 140 | with open(args.save_folder+'/train_scores.npy','wb') as f: 141 | np.save(f, vampnet.train_scores) 142 | 143 | with open(args.save_folder+'/validation_scores.npy','wb') as f: 144 | np.save(f, vampnet.validation_scores) 145 | 146 | # plotting the training and validation scores of the model 147 | plt.loglog(*vampnet.train_scores.T, label='training') 148 | plt.loglog(*vampnet.validation_scores.T, label='validation') 149 | plt.xlabel('step') 150 | plt.ylabel('score') 151 | plt.legend() 152 | plt.savefig(args.save_folder+'/scores.png') 153 | 154 | # making a numpy array of data for analysis 155 | data_np = [] 156 | for i in range(len(data)): 157 | data_np.append(data[i].cpu().numpy()) 158 | 159 | 160 | # for the analysis part create an iterator for the whole dataset to feed in batches 161 | whole_dataset = TrajectoryDataset.from_trajectories(lagtime=args.tau, data=data_np) 162 | whole_dataloder = DataLoader(whole_dataset, batch_size=args.batch_size, shuffle=False) 163 | 164 | 165 | 166 | # for plotting the implied timescales 167 | lagtimes = np.arange(1,201,2, dtype=np.int32)timescales = [] 168 | for lag in tqdm(lagtimes): 169 | vamp = VAMP(lagtime=lag, observable_transform=model) 170 | whole_dataset = TrajectoryDataset.from_trajectories(lagtime=lag, data=data_np) 171 | whole_dataloder = DataLoader(whole_dataset, batch_size=10000, shuffle=False) 172 | for batch_0, batch_t in whole_dataloder: 173 | vamp.partial_fit((batch_0.numpy(), batch_t.numpy())) 174 | # 175 | covariances = vamp._covariance_estimator.fetch_model() 176 | ts = vamp.fit_from_covariances(covariances).fetch_model().timescales(k=5) 177 | timescales.append(ts) 178 | 179 | 180 | 181 | 182 | f, ax = plt.subplots(1, 1) 183 | ax.semilogy(lagtimes, timescales) 184 | ax.set_xlabel('lagtime') 185 | ax.set_ylabel('timescale / step') 186 | ax.fill_between(lagtimes, ax.get_ylim()[0]*np.ones(len(lagtimes)), lagtimes, alpha=0.5, color='grey'); 187 | f.savefig(args.save_folder+'/ITS.png') 188 | 189 | 190 | 191 | def chunks(data, chunk_size=5000): 192 | ''' 193 | splitting the trajectory into chunks for passing into analysis part 194 | data: list of trajectories 195 | chunk_size: the size of each chunk 196 | ''' 197 | if type(data) == list: 198 | 199 | for data_tmp in data: 200 | for j in range(0, len(data_tmp),chunk_size): 201 | print(data_tmp[j:j+chunk_size,...].shape) 202 | yield data_tmp[j:j+chunk_size,...] 203 | 204 | else: 205 | 206 | for j in range(0, len(data), chunk_size): 207 | yield data[j:j+chunk_size,...] 208 | 209 | n_classes = int(args.num_classes) 210 | 211 | probs = [] 212 | total_emb= [] 213 | total_attn = [] 214 | for data_tmp in data_np: 215 | # transforming the data into the vampnet for modeling the dynamics 216 | mydata = chunks(data_tmp, chunk_size=5000) 217 | state_probs = np.zeros((data_tmp.shape[0], n_classes)) 218 | emb_tmp = np.zeros((data_tmp.shape[0], args.h_a)) 219 | attn_tmp = np.zeros((data_tmp.shape[0], args.num_atoms, args.num_neighbors)) 220 | 221 | n_iter = 0 222 | for i,batch in enumerate(mydata): 223 | batch_size = len(batch) 224 | state_probs[n_iter:n_iter+batch_size] = model.transform(batch) 225 | if args.return_emb and not args.return_attn: 226 | emb_1 = model.lobe(torch.tensor(batch), return_emb=True, return_attn=False) 227 | emb_tmp[n_iter:n_iter+batch_size] = emb_1.cpu().detach().numpy() 228 | elif args.return_emb and args.return_attn: 229 | emb_1, attn_1 = model.lobe(torch.tensor(batch), return_emb=True, return_attn=True) 230 | emb_tmp[n_iter:n_iter+batch_size], attn_tmp[n_iter:n_iter+batch_size] = emb_1.cpu().detach().numpy(),attn_1.cpu().detach().numpy() 231 | n_iter = n_iter + batch_size 232 | probs.append(state_probs) 233 | if args.return_emb: 234 | total_emb.append(emb_tmp) 235 | if args.return_attn: 236 | total_attn.append(attn_tmp) 237 | 238 | # problem here 239 | np.savez(args.save_folder+'/transformed.npz', probs[0]) 240 | 241 | if args.return_emb: 242 | np.savez(args.save_folder+'/embeddings.npz', total_emb[0]) 243 | if args.return_attn: 244 | np.savez(args.save_folder+'/total_attn.npz', total_attn[0]) 245 | 246 | quit() 247 | 248 | max_tau = 200 249 | lags = np.arange(1, max_tau, 1) 250 | 251 | #its = get_its(probs, lags) 252 | #plot_its(its, lags, ylog=False, save_folder=args.save_folder) 253 | 254 | steps = 6 255 | tau_msm = 200 256 | predicted, estimated = get_ck_test(probs, steps, tau_msm) 257 | 258 | plot_ck_test(predicted, estimated, n_classes, steps, tau_msm, args.save_folder) 259 | 260 | np.save(args.save_folder+'/ITS.npy', np.array(timescales)) 261 | np.savez(args.save_folder+'/ck.npz', list((predicted, estimated))) 262 | 263 | 264 | quit() 265 | 266 | # for plotting the CK test 267 | vamp = VAMP(lagtime=lag, observable_transform=model) 268 | whole_dataset = TrajectoryDataset.from_trajectories(lagtime=200, data=data_np) 269 | whole_dataloder = DataLoader(whole_dataset, batch_size=10000, shuffle=False) 270 | for batch_0, batch_t in whole_dataloder: 271 | vamp.partial_fit((batch_0.numpy(), batch_t.numpy())) 272 | 273 | validator = chapman_kolmogorov_validator(model=vamp, mlags=10) 274 | 275 | #validator = vamp.chapman_kolmogorov_validator(mlags=5) 276 | 277 | cktest = validator.fit(data_np, n_jobs=1, progress=tqdm).fetch_model() 278 | n_states = args.num_classes - 1 279 | 280 | tau = cktest.lagtimes[1] 281 | steps = len(cktest.lagtimes) 282 | fig, ax = plt.subplots(n_states, n_states, sharex=True, sharey=True, constrained_layout=True) 283 | for i in range(n_states): 284 | for j in range(n_states): 285 | pred = ax[i][j].plot(cktest.lagtimes, cktest.predictions[:, i, j], color='b') 286 | est = ax[i][j].plot(cktest.lagtimes, cktest.estimates[:, i, j], color='r', linestyle='--') 287 | ax[i][j].set_title(str(i+1)+ '->' +str(j+1), 288 | fontsize='small') 289 | ax[0][0].set_ylim((-0.1,1.1)); 290 | ax[0][0].set_xlim((0, steps*tau)); 291 | ax[0][0].axes.get_xaxis().set_ticks(np.round(np.linspace(0, steps*tau, 3))); 292 | fig.legend([pred[0], est[0]], ["Predictions", "Estimates"], 'lower center', ncol=2, 293 | bbox_to_anchor=(0.5, -0.1)); 294 | 295 | fig.savefig(args.save_folder+'/cktest.png') 296 | -------------------------------------------------------------------------------- /src/model.py: -------------------------------------------------------------------------------- 1 | # Author: Mahdi Ghorbani 2 | 3 | import torch 4 | import numpy as np 5 | import deeptime 6 | from tqdm import tqdm 7 | import matplotlib.pyplot as plt 8 | import torch.nn as nn 9 | import torch.nn.functional as F 10 | from torch.utils.data import DataLoader 11 | import json 12 | from sklearn.neighbors import BallTree 13 | from args import buildParser 14 | from layers import GaussianDistance, GraphConvLayer, NeighborMultiHeadAttention, LinearLayer, ContinuousFilterConv, InteractionBlock 15 | from layers import GATLayer 16 | from layers import GraphAttentionLayer 17 | #from torch_scatter import scatter_mean 18 | import time 19 | 20 | args = buildParser().parse_args() 21 | 22 | if torch.cuda.is_available(): 23 | device = torch.device('cuda') 24 | print('cuda is is available') 25 | else: 26 | print('Using CPU') 27 | device = torch.device('cpu') 28 | 29 | 30 | class GraphVampNet(nn.Module): 31 | ''' wrapper class for different types of graph convolutions: ['GraphConvLayer', 'NeighborMultiHeadAttention', 'SchNets'] 32 | 33 | parameters: 34 | ----------------- 35 | seq_file: text file, 36 | the sequence file for initializing a one-hot encoding for embedding of different atoms 37 | If not provided, a random initilizer will be used for atom embeddings 38 | num_atoms: int, 39 | number of atoms 40 | num_neighbors: int, 41 | number of neighbors of each atom to be considered. 42 | tau: int, 43 | lagtime to be considered for the model 44 | n_classes: int, 45 | number of classes to cluster the output graphs 46 | n_conv: int, 47 | number of convlutional layers on graphs 48 | dmin: float, 49 | the minimum distance for performing the gaussian basis expansion 50 | dmax: float, 51 | the maximum distance for performing the gaussian basis expansion 52 | step: float, 53 | the step for gaussian basis expansion 54 | h_a: int, 55 | number of dimensions for atom embeddings 56 | h_g: int, 57 | number of dimension for after pooling 58 | atom_embedding_init: str, 59 | the type of initialization for the atom embedding 60 | use_pre_trained: boolean, 61 | Whether to use a pretrained embedding for atoms 62 | activation: 63 | the non-linear activation function to be used in the model 64 | pre_trained_weights_file: str, 65 | the filename for pretrained embedding 66 | conv_type: the type of convlutional layer for graphs ['GraphConvLayer', 'NeighborMultiHeadAttention', 'SchNets'] 67 | num_heads: int, 68 | the number of heads for multi-head attention in NeighborMultiHeadAttention convlution type 69 | residual: boolean, 70 | Whether to add a residual connection between different convolutions 71 | use_backbone_atoms: boolean, 72 | Whether to use backbone atoms for the protein graph model (if False will use the Ca atoms only) 73 | 74 | attention_pool: bool 75 | Whether to add Graph Attention layer between embedding learned before performing graph pooling 76 | ''' 77 | def __init__(self, seq_file=args.seq_file, num_atoms=args.num_atoms, num_neighbors=args.num_neighbors, 78 | n_classes=args.num_classes, n_conv=args.n_conv, dmin=args.dmin, dmax=args.dmax, step=args.step, 79 | h_a=args.h_a, h_g=args.h_g, atom_embedding_init='normal', use_pre_trained=False, activation=nn.ReLU(), 80 | pre_trained_weights_file=None, conv_type=args.conv_type, num_heads=args.num_heads, residual=args.residual, 81 | use_backbone_atoms=args.use_backbone_atoms, dont_pool_backbone=args.dont_pool_backbone, 82 | attention_pool=args.attention_pool): 83 | 84 | super(GraphVampNet, self).__init__() 85 | self.seq_file = seq_file 86 | self.num_atoms = num_atoms 87 | self.num_neighbors = num_neighbors 88 | self.n_classes= n_classes 89 | self.n_conv = n_conv 90 | self.dmin = dmin 91 | self.dmax = dmax 92 | self.step = step 93 | self.h_a = h_a 94 | self.h_g = h_g 95 | self.gauss = GaussianDistance(dmin, dmax, step) 96 | self.h_b = self.gauss.num_features # number of gaussians 97 | self.num_heads = num_heads 98 | self.activation = nn.ReLU() 99 | self.use_backbone_atoms = use_backbone_atoms 100 | self.residual = residual 101 | #self.atom_emb = nn.Embedding(num_embeddings=self.num_atoms, embedding_dim=self.h_a) 102 | #self.atom_emb.weight.data.normal_() 103 | self.conv_type = conv_type 104 | if self.conv_type == 'GraphConvLayer': 105 | self.convs = nn.ModuleList([GraphConvLayer(self.h_a, 106 | self.h_b) for _ in range(self.n_conv)]) 107 | 108 | elif self.conv_type == 'NeighborMultiHeadAttention': 109 | self.convs = nn.ModuleList([NeighborMultiHeadAttention(self.h_a, 110 | self.h_b, 111 | self.num_heads) for _ in range(self.n_conv)]) 112 | 113 | elif self.conv_type == 'SchNet': 114 | self.convs = nn.ModuleList([InteractionBlock(n_inputs=self.h_a, 115 | n_gaussians=self.h_b, 116 | n_filters=self.h_a, 117 | activation=nn.Tanh()) for _ in range(self.n_conv)]) 118 | 119 | self.conv_activation = nn.ReLU() 120 | if self.h_g is not None: 121 | self.fc_classes = nn.Linear(self.h_g, n_classes) 122 | else: 123 | self.fc_classes = nn.Linear(self.h_a, n_classes) 124 | self.init = atom_embedding_init 125 | self.use_pre_trained = use_pre_trained 126 | self.dont_pool_backbone = dont_pool_backbone 127 | self.attention_pool = attention_pool 128 | 129 | #elf.weight = nn.Parameter(torch.Tensor(self.h_a, 1)) 130 | 131 | #if args.use_backbone_atoms: 132 | if args.h_g is not None: 133 | self.amino_emb = nn.Linear(self.h_a, self.h_g) 134 | 135 | if use_pre_trained: 136 | self.pre_trained_emb(pre_trained_weights_file) 137 | 138 | elif seq_file is not None: 139 | atom_emb = self.onehot_encode_amino(seq_file) 140 | self.atom_embeddings = torch.tensor(atom_emb, dtype=torch.float32).to(device) 141 | self.h_init = atom_emb.shape[-1] # dimension of atom embedding [20] 142 | emb = nn.Embedding.from_pretrained(self.atom_embeddings, freeze=False) 143 | self.atom_emb = nn.Linear(self.h_init, self.h_a) # linear layer for atom features 144 | 145 | else: 146 | # initialize the atom embeddings randomly 147 | self.atom_emb = nn.Embedding(num_embeddings=self.num_atoms, embedding_dim=self.h_a) 148 | self.init_emb() 149 | 150 | if self.attention_pool: 151 | self.attn_pool_model = GATLayer(self.h_a, self.h_a, concat_heads=True, alpha=0.2) 152 | 153 | def pre_trained_emb(self, file): 154 | ''' 155 | loads the pre-trained node embedings from a file 156 | For now we are not freezing the pre-trained embeddings since 157 | we are going to update it in the graph convolution 158 | ''' 159 | 160 | with open(self.pre_trained_weights_file) as f: 161 | loaded_emb = json.load(f) 162 | 163 | embed_list = [torch.tensor(value, dtype=torch.float32) for value in loaded_emb.values()] 164 | self.atom_embeddings = torch.stack(embed_list, dim=0) 165 | self.h_init = self.atom_embeddings.shape[-1] # dimension atom embedding init 166 | self.atom_emb = nn.Embedding.from_pretrained(self, atom_embeddings, freeze=False) 167 | self.embedding = nn.Linear(self.h_init, self.h_a) 168 | 169 | def init_emb(self): 170 | ''' 171 | Initialize random embedding for the atoms 172 | ''' 173 | #--------------initialization for the embedding-------------- 174 | if self.init == 'normal': 175 | self.atom_emb.weight.data.normal_() 176 | 177 | elif self.init == 'xavier_normal': 178 | self.atom_emb.weight.data._xavier_normal() 179 | 180 | elif self.init == 'uniform': 181 | self.atom_emb.weight.data._uniform() 182 | 183 | 184 | def onehot_encode_amino(self, seq_file): 185 | ''' 186 | one-hot encoding of amino types for initializing the embedding 187 | ''' 188 | with open(seq_file, 'r') as f: 189 | sequence = open(seq_file) 190 | seq = sequence.readlines()[0].strip() 191 | 192 | amino_dict = {'A':0, 193 | 'R':1, 194 | 'N':2, 195 | 'D':3, 196 | 'C':4, 197 | 'Q':5, 198 | 'E':6, 199 | 'G':7, 200 | 'H':8, 201 | 'I':9, 202 | 'L':10, 203 | 'K':11, 204 | 'M':12, 205 | 'F':13, 206 | 'P':14, 207 | 'S':15, 208 | 'T':16, 209 | 'W':17, 210 | 'Y':18, 211 | 'Z':19} 212 | 213 | if args.use_backbone_atoms: 214 | s_encoded = np.zeros((20, 3*len(seq))) 215 | for i, n in enumerate(s): 216 | s_encoded[amino_dict[n],i*3:i*3+3] = 1 217 | 218 | else: 219 | s_encoded = np.zeros((20, len(seq))) 220 | for i, n in enumerate(s): 221 | s_encoded[amino_dict[n],i] = 1 222 | 223 | return s_encoded.T 224 | 225 | #------------------------------------------------------------ 226 | 227 | @staticmethod 228 | def convert_adj(mat): 229 | # convert the nbr_adj_list matrix to an adjacency matrix 230 | mat = mat.to(torch.long) 231 | adj = torch.zeros((mat.shape[0], mat.shape[1], mat.shape[1])) 232 | for i in range(mat.shape[0]): 233 | adj[i][torch.arange(adj.shape[1])[:,None],mat[i]] = 1 234 | adj[i] += torch.eye(mat.shape[1]) 235 | return adj.to(device) 236 | 237 | def pooling(self, atom_emb): 238 | # global pooling layer by averaging the embedding of nodes to get embedding of graph 239 | 240 | summed = torch.sum(atom_emb, dim=1) 241 | return summed / self.num_atoms 242 | 243 | 244 | def pool_amino(self, atom_emb): 245 | ''' 246 | pooling the features of atoms in each amino acid to get a feature vector for each residue 247 | parameters: 248 | -------------------------- 249 | atom_emb: embedding of atoms [B,N,h_a] 250 | residue_atom_idx: mapping between every atom and every residue in the protein 251 | size: [N] example [0,0,0,1,1,1,2,2,2] for N=6 and NA=3 252 | 253 | Returns: 254 | -------------------------- 255 | pooled features of amino acids in the graph 256 | [B, Na, h_a] 257 | ''' 258 | 259 | B = atom_emb.shape[0] 260 | N = atom_emb.shape[1] 261 | h_a = atom_emb.shape[2] 262 | 263 | residue_atom_idx = torch.arange(N).repeat(1,3) 264 | residue_atom_idx = residue_atom_idx.view(3,N).T.reshape(-1,1).squeeze(-1) 265 | Na = torch.max(residue_atom_idx)+1 # number of residues 266 | pooled = scatter_mean(atom_emb, residue_atom_idx, out=atom_emb.new_zeros(B,Na,h_a), dim=1) 267 | return pooled 268 | 269 | def return_emb(self): 270 | ''' 271 | returns the embedding learned for each amino acid (or Ca atom) after training the model 272 | ''' 273 | return self.emb 274 | 275 | 276 | 277 | def forward(self, data, return_emb=False, return_attn=False): 278 | ''' Graph neural net computation to get features of protein at each timestep of simulation 279 | 280 | data: has shape [batch-size, num_atoms, num_neighbors*2] 281 | the first half of last index contains the nbr_adj_dist -> distance between every two atoms 282 | the second half of data contains the the nbr_adj_list -> the index of neighbors of each atom 283 | 284 | This model: 285 | 1. expands the nbr_adj_dist into gaussian basis function [batch-size, num-atoms, num-neighbors, n_gaussians] 286 | 2. initalize the embedding and get the initial embedding of each atom 287 | 3. perform graph convolution to propagate messages along nodes and edges multiple times 288 | 4. pooling to get the features for the graph from node features 289 | 5. Linear layer to get coarse grain for number of classes 290 | 6. Apply a softmax activation for getting the class assignment probabilities 291 | 292 | ''' 293 | M = data.shape[-1] # num_neighbors*2 294 | nbr_adj_dist = data[:,:,:M//2] # [batch-size, num_atoms, num_neighbors] 295 | nbr_adj_list = data[:,:,M//2:] # [batch-size, num_atoms, num_neighbors] 296 | N = nbr_adj_list.shape[1] 297 | B = nbr_adj_list.shape[0] 298 | 299 | nbr_emb = self.gauss.expand(nbr_adj_dist) # [batch-size, num_atoms, num_neighbors, n_gaussians] 300 | # this is the edge embedding 301 | 302 | atom_emb_idx = torch.arange(N).repeat(B,1).to(device) 303 | atom_emb = self.atom_emb(atom_emb_idx) 304 | # atom_emb [B,N,h_a] 305 | 306 | if args.conv_type == 'GraphConvLayer': 307 | for idx in range(self.n_conv): 308 | tmp_conv = self.convs[idx](atom_emb=atom_emb, 309 | nbr_emb=nbr_emb, 310 | nbr_adj_list=nbr_adj_list) 311 | if self.residual: 312 | atom_emb = atom_emb + tmp_conv 313 | else: 314 | atom_emb = tmp_conv 315 | 316 | elif args.conv_type == 'NeighborMultiHeadAttention': 317 | for idx in range(self.n_conv): 318 | tmp_conv = self.convs[idx](h_V=atom_emb, 319 | h_E=nbr_emb, 320 | mask_attend=nbr_adj_list) 321 | if self.residual: 322 | atom_emb = atom_emb + tmp_conv 323 | else: 324 | atom_emb = tmp_conv 325 | 326 | elif args.conv_type == 'SchNet': 327 | for idx in range(self.n_conv): 328 | tmp_conv, attn_probs = self.convs[idx](features=atom_emb, 329 | rbf_expansion=nbr_emb, 330 | neighbor_list=nbr_adj_list) 331 | 332 | if self.residual: 333 | atom_emb = atom_emb + tmp_conv 334 | else: 335 | atom_emb = tmp_conv 336 | 337 | emb = self.conv_activation(atom_emb) 338 | # [batch-size, num-atoms, h_a] 339 | 340 | 341 | if args.use_backbone_atoms: 342 | # apply a pooling layer for backbone atoms to amino acid features 343 | emb = self.pool_amino(emb) 344 | 345 | #t1 = time.time() 346 | #adj = self.convert_adj(nbr_adj_list) # convert nbr_adj_list to an adjacency matrix 347 | #t2 = time.time() 348 | #print('time: ' + str(t2-t1)) 349 | #if self.attention_pool: 350 | # emb, attn_probs = self.attn_pool_model(emb, adj) 351 | 352 | 353 | #print(attn_probs.shape) 354 | 355 | # embedding for each atom or amino acid learned after training 356 | #print(emb.shape) 357 | self.emb = emb # [batch, N, h_a] 358 | 359 | 360 | # the last pooling layer for getting graph features 361 | #attn_logits = torch.matmul(self.emb, self.weight).reshape(B,N) 362 | #attn_probs = F.softmax(attn_logits, dim=-1) 363 | 364 | #h_a = self.emb.shape[2] 365 | #self.emb = self.emb.reshape((B,h_a,N)) 366 | #self.prot_emb = torch.bmm(self.emb, attn_probs.unsqueeze(-1)).squeeze(-1) 367 | 368 | self.prot_emb = self.pooling(self.emb) 369 | if self.h_g is not None: 370 | self.prot_emb = self.amino_emb(self.prot_emb) 371 | # [B, h_a] or [B, h_g] 372 | #print(self.prot_emb.shape) 373 | self.class_logits = self.fc_classes(self.prot_emb) 374 | # [B, n_classes] 375 | self.class_probs = F.softmax(self.class_logits, dim=-1) 376 | if return_emb: 377 | return self.prot_emb, attn_probs 378 | else: 379 | return self.class_probs 380 | -------------------------------------------------------------------------------- /src/layers.py: -------------------------------------------------------------------------------- 1 | # Author: Mahdi Ghorbani 2 | 3 | from __future__ import print_function 4 | 5 | import numpy as np 6 | import torch 7 | import torch.nn as nn 8 | import torch.nn.functional as F 9 | 10 | if torch.cuda.is_available(): 11 | device = torch.device('cuda') 12 | print('cuda is is available') 13 | else: 14 | print('Using CPU') 15 | device = torch.device('cpu') 16 | 17 | def LinearLayer(d_in, d_out, bias=True, activation=None, dropout=0, weight_init='xavier'): 18 | ''' 19 | Linear layer function 20 | 21 | Parameters: 22 | --------------------- 23 | d_in: int, input dimension 24 | d_out: int, output dimension 25 | bias: bool, (default=True) Whether or not to add bias 26 | activation: torch.nn.Module() (default=None) 27 | activation function of the layer 28 | dropout: float (default=0) 29 | the dropout to be added 30 | weight_init: str,, float, or nn.init function (default='xavier') 31 | specifies the initialization of the layer weights. If float or int is passed a constant initialization 32 | is used. 33 | 34 | Returns: 35 | ---------------------- 36 | seq: list of torch.nn.Module instances 37 | the full linear layer including activations and optional dropout 38 | ''' 39 | seq = [nn.Linear(d_in, d_out, bias=bias)] 40 | if activation is not None: 41 | if isinstance(activation, nn.Module): 42 | seq += [activation] 43 | else: 44 | raise TypeError('Activation {} is not a valid torch.nn.Module'.format(str(activation))) 45 | 46 | if dropout is not None: 47 | seq += [nn.Dropout(dropout)] 48 | 49 | with torch.no_grad(): 50 | if weight_init == 'xavier': 51 | torch.nn.init.xavier_uniform_(seq[0].weight) 52 | if weight_init == 'identity': 53 | torch.nn.init.eye_(seq[0].weight) 54 | if weight_init not in ['xavier', 'identity', None]: 55 | if isinstance(weight_init, int) or isinstance(weight_init, float): 56 | torch.nn.init.constant_(seq[0].weight, weight_init) 57 | 58 | return seq 59 | 60 | class NeighborNormLayer(nn.Module): 61 | ''' Normalization layer that divides the output of a preceding layer by the number of neighbor features. 62 | ''' 63 | def __init__(self): 64 | super(NeighborNormLayer, self).__init__() 65 | 66 | def forward(self, input_features, n_neighbors): 67 | ''' Computes normalized output 68 | 69 | Parameters: 70 | ---------------- 71 | input_features: torch.tensor 72 | input tensor of features [n_frames, n_atoms, n_feats] 73 | n_neighbors: int, number of neighbors 74 | 75 | Returns: 76 | ---------------- 77 | normalized_features: torch.tensor, normalized input features 78 | ''' 79 | return input_features / n_neighbors 80 | 81 | 82 | def gather_nodes(nodes, neighbor_idx): 83 | ''' 84 | given node-features [batch-size, num-atoms, num-features] and neighbor_dix [batch-size, num-atoms, num-neighbors] 85 | this find the neighbors of each node and concatentates their features together: 86 | 87 | Returns: 88 | [batch-szie, num-atoms, num-neighbors, num-features] 89 | ''' 90 | neighbors_flat = neighbor_idx.view((neighbor_idx.shape[0], -1)) 91 | # [batch-size, num_nodes*num_neighbors] 92 | neighbors_flat = neighbors_flat.unsqueeze(-1).expand(-1,-1,nodes.size(2)) 93 | # [batch-size, num_nodes*num_neighbors, num_features] 94 | 95 | neighbor_features = torch.gather(nodes, 1, neighbors_flat) 96 | neighbor_features = neighbor_features.view(list(neighbor_idx.shape)[:3]+[-1]) 97 | return neighbor_features 98 | 99 | def cat_neighbor_nodes(h_nodes, h_neighbors, E_idx): 100 | ''' 101 | given node embeddings [h_nodes] and neighbor embeddings [h_neighbors] and indexes this concatentates the features 102 | params: 103 | h_nodes: [B,N,h_nodes] 104 | h_neighbors: [B,N,M,h_edges] 105 | E_idx: [B,N,M] 106 | returns: 107 | concatenated features [B,N,M,h_nodes+h_edges] 108 | ''' 109 | h_nodes = gather_nodes(h_nodes, E_idx) 110 | h_nn = torch.cat([h_neighbors, h_nodes], -1) 111 | return h_nn 112 | 113 | 114 | 115 | class GraphAttentionLayer(nn.Module): 116 | def __init__(self, in_features, out_features, alpha, concat=True,): 117 | super(GraphAttentionLayer, self).__init__() 118 | self.in_features = in_features 119 | self.out_features = out_features 120 | self.alpha = alpha 121 | 122 | self.W = nn.Parameter(torch.empty(size=(in_features, out_features))) 123 | nn.init.xavier_uniform_(self.W.data, gain=1.414) 124 | self.a = nn.Parameter(torch.empty(size=(2*out_features, 1))) 125 | nn.init.xavier_uniform_(self.a.data, gain=1.414) 126 | 127 | self.leakyrelu = nn.LeakyReLU(self.alpha) 128 | 129 | def forward(self, h, adj): 130 | Wh = torch.mm(h, self.W) 131 | Wh1 = torch.matmul(Wh, self.a[:self.out_features, :]) 132 | Wh2 = torch.matmul(Wh, self.a[:,self.out_features:,:]) 133 | # broadcast add 134 | e = Wh1 + Wh2 135 | e = self.leakyrelu(e) 136 | zero_vec = -9e15 * torch.ones_like(e) 137 | attention = torch.where(adj>0, e, zero_vec) 138 | attention = F.softmax(attention, dim=1) 139 | h_prime = torch.matmul(attention, Wh) 140 | 141 | return h_prime, attention 142 | 143 | 144 | class GATLayer(nn.Module): 145 | def __init__(self, c_in, c_out, num_heads=1, concat_heads=True, alpha=0.2): 146 | ''' 147 | inputs: 148 | c_in: dim of input features 149 | c_out: dim of output features 150 | num_head: number of attention heads. here we only use 1 151 | concat_heads: Whether to concat attention heads 152 | alpha: negative slope of LeakyRelu activation 153 | ''' 154 | super().__init__() 155 | self.num_heads = num_heads 156 | self.concat_heads = concat_heads 157 | if self.concat_heads: 158 | assert c_out % num_heads == 0, 'Number of outupt features must be multiple of the count of heads' 159 | c_out = c_out // num_heads 160 | 161 | self.projection = nn.Linear(c_in, c_out*num_heads) 162 | self.a = nn.Parameter(torch.Tensor(num_heads, 2*c_out)) # one per head 163 | self.leakyrelu = nn.LeakyReLU(alpha) 164 | 165 | # parameter initialization 166 | nn.init.xavier_uniform_(self.projection.weight.data, gain=1.414) 167 | nn.init.xavier_uniform_(self.a.data, gain=1.414) 168 | 169 | def forward(self, node_feats, adj_matrix, return_attn_probs=True): 170 | ''' 171 | Inputs: 172 | node_feats: input features of nodes [batch-size, num_nodes, c_in] 173 | adj_matrix: adjacency matrix [batch-size, num_nodes, num_nodes] with self connections 174 | return_attn_probs: If True, attention weights will be returned 175 | ''' 176 | batch_size, num_nodes = node_feats.size(0), node_feats.size(1) 177 | 178 | node_feats = self.projection(node_feats) 179 | node_feats = node_feats.view(batch_size, num_nodes, self.num_heads, -1) 180 | 181 | # concatenate the node feature of all the nodes that are connected 182 | edges = adj_matrix.nonzero(as_tuple=False) # return edges 183 | node_feats_flat = node_feats.view(batch_size*num_nodes, self.num_heads, -1) 184 | 185 | edge_indices_row = edges[:,0] * num_nodes + edges[:,1] 186 | edge_indices_col = edges[:,0] * num_nodes + edges[:,2] 187 | a_input = torch.cat([ 188 | torch.index_select(input=node_feats_flat, index=edge_indices_row, dim=0), 189 | torch.index_select(input=node_feats_flat, index=edge_indices_col, dim=0)], dim=-1) 190 | 191 | # calculate attention MLP output (independent for each head) 192 | attn_logits = torch.einsum('bhc,hc->bh', a_input, self.a) 193 | attn_logits = self.leakyrelu(attn_logits) 194 | 195 | # map list of attention values back into a matrix 196 | attn_matrix = attn_logits.new_zeros(adj_matrix.shape+(self.num_heads,)).fill_(-9e15) 197 | attn_matrix[adj_matrix[...,None].repeat(1,1,1,self.num_heads)==1] =attn_logits.reshape(-1) 198 | 199 | # Weighted average of attention 200 | attn_probs = F.softmax(attn_matrix, dim=2) 201 | 202 | node_feats = torch.einsum('bijh,bjhc->bihc', attn_probs, node_feats) 203 | 204 | # If heads should be concatenated : 205 | if self.concat_heads: 206 | node_feats = node_feats.reshape(batch_size, num_nodes, -1) 207 | else: 208 | node_feats = node_feats.mean(dim=2) 209 | 210 | if return_attn_probs: 211 | return node_feats, attn_probs 212 | else: 213 | return node_feats 214 | 215 | 216 | class NeighborMultiHeadAttention(nn.Module): 217 | ''' MultiHeadAttention class for neighbors of every node in the graph representation 218 | 219 | multihead attention is defined on the edges between node in the neighborhood of every node 220 | 221 | quries: current node embedding 222 | keys: relational information r(i,j)=(h_j, e_ij) j from N(i,k) 223 | values: relational information same as keys 224 | 225 | 226 | parameters: 227 | ------------------ 228 | num_hidden: int, number of features of atoms 229 | num_int: int, number of gaussians for edge 230 | num_heads: int, number of heads for multi-head attention 231 | 232 | Returns: 233 | ------------------ 234 | updated node embedding after multihead attention of neighbors 235 | ''' 236 | def __init__(self, num_hidden, num_in, num_heads=4): 237 | super(NeighborMultiHeadAttention, self).__init__() 238 | self.num_heads = num_heads 239 | self.num_hidden = num_hidden 240 | 241 | # self-attention layers: {queries, keys, values, output} 242 | self.W_Q = nn.Linear(num_hidden, num_hidden, bias=False) 243 | self.W_K = nn.Linear(num_in, num_hidden, bias=False) # make the edges the same size as node embedding size 244 | self.W_V = nn.Linear(num_in, num_hidden, bias=False) # make the edges the same size as node embedding size 245 | self.W_O = nn.Linear(num_hidden, num_hidden, bias=False) # linear layer for the output 246 | return 247 | 248 | def _masked_softmax(self, attend_logits, mask_attend, dim=-1): 249 | ''' numercially stable masked softmax ''' 250 | # attend_logits: [batch-size, num_nodes, num_heads, num_neighbors] 251 | # mask_attend: [batch-size, num_nodes, num_heads, num_neighbors] 252 | negative_inf = np.finfo(np.float32).min 253 | attend_logits = torch.where(mask_attend, attend_logits, torch.tensor(negative_inf).to(device)) 254 | attend = F.softmax(attend_logits, dim) 255 | attend = mask_attend * attend 256 | return attend 257 | 258 | def forward(self, h_V, h_E, mask_attend=None, return_attn_probs=True): 259 | ''' self attention graph structure O(NK) 260 | 261 | parameters: 262 | h_V: node features [batch_size, num_nodes, n_features] 263 | h_E: neighbor featues [batch_size, num_nodes, num_neighbors, n_gaussians] 264 | mask_attend: mask for attention [batch_size, num_nodes, num_neighbors] 265 | Returns: 266 | h_V_t: node update after neighbor attention [batch-size, num_nodes, n_features] 267 | ''' 268 | # dimensions 269 | n_batch, n_nodes, n_neighbors = h_E.shape[:3] 270 | n_heads = self.num_heads 271 | d = int(self.num_hidden/n_heads) 272 | 273 | Q = self.W_Q(h_V.to(torch.float32)).view([n_batch, n_nodes, 1, n_heads, 1, d]) # [B,N,1,n_heads,1,d] 274 | # [batch-size, num-nodes, 1, num_heads, 1, d] 275 | K = self.W_K(h_E.to(torch.float32)).view([n_batch, n_nodes, n_neighbors, n_heads, d, 1]) 276 | # [batch-size, num-nodes, num_neighbors, num_heads, d, 1] 277 | V = self.W_V(h_E.to(torch.float32)).view([n_batch, n_nodes, n_neighbors, n_heads, d]) 278 | # [batch-size, num-nodes, num_neighbors, num_heads, d] 279 | 280 | # attention with scaled inner product between keys and queries 281 | attend_logits = torch.matmul(Q,K).view([n_batch, n_nodes, n_neighbors, n_heads]).transpose(-2,-1) 282 | # [batch-size, num-nodes, n_heads, num_nbrs] 283 | attend_logits = attend_logits / np.sqrt(d) # normalize 284 | #if mask_attend is not None: 285 | # masked softmax 286 | # mask = mask_attend.unsqueeze(2).expand(-1, -1, n_heads, -1).to(device) 287 | # [batch-size, num_nodes, num_heads, num_neighbors] 288 | # attend = self._masked_softmax(attend_logits, mask) 289 | #else: 290 | attend = F.softmax(attend_logits, -1).to(device) 291 | # [batch-size, num-nodes, num-heads, num-neighbors] 292 | 293 | h_V_update = torch.matmul(attend.unsqueeze(-2).to(torch.float32), V.transpose(2,3)) 294 | # multiply attention scores with the values 295 | h_V_update = h_V_update.view([n_batch, n_nodes, self.num_hidden]) 296 | h_V_update = self.W_O(h_V_update) 297 | if return_attn_probs: 298 | return h_V_update, attend.mean(dim=2) 299 | else: 300 | return h_V_update 301 | 302 | class GraphConvLayer(nn.Module): 303 | r''' Graph convolutional layer as introduced by Tian et al in 2019 for materrials and reformultated for protines. 304 | 305 | 306 | formulation: 307 | v_{i}^{k+1} = v_{i}{k} + \sim_{j} w_{i,j}^k \circ g(z_{i,j}^k W_{c}^k + b_{c}^k) 308 | where: 309 | w_{i,j}^k = sigmoid(z_{i,j}^k W_{g}^k + b_{g}^k) and z_{i,j}^k = concat([v_{i}^k, v_{j}^k, u_{i,j}^k]) 310 | 311 | v_{i}^k is the node embedding of atom i at layer k, z_{i,j}^k is the concatentation of neighboring atoms and their bond features. 312 | g() denote a non-linear activation function, w_{i,j}^k is an edge-gating mechanism to incorporate different interaction strength 313 | among neighbors of a node. 314 | 315 | 316 | Parameters: 317 | --------------------- 318 | atom_emb_dim : int, atom embedding dimension 319 | bond_emb_dim: int, bond embedding dimension (number of gaussians) 320 | 321 | 322 | References: 323 | ---------------------- 324 | {Sanyal2020.04.06.028266, 325 | author = {Sanyal, Soumya and Anishchenko, Ivan and Dagar, Anirudh and Baker, David and Talukdar, Partha}, 326 | title = {ProteinGCN: Protein model quality assessment using Graph Convolutional Networks}, 327 | year = {2020}, 328 | doi = {10.1101/2020.04.06.028266}, 329 | publisher = {Cold Spring Harbor Laboratory}, 330 | URL = {https://www.biorxiv.org/content/early/2020/04/07/2020.04.06.028266}, 331 | journal = {bioRxiv} 332 | ''' 333 | def __init__(self, atom_emb_dim, bond_emb_dim): 334 | super(GraphConvLayer, self).__init__() 335 | self.h_a = atom_emb_dim 336 | self.h_b = bond_emb_dim 337 | self.fc_full = nn.Linear(2*self.h_a+self.h_b, 2*self.h_a) 338 | self.sigmoid = nn.Sigmoid() 339 | self.activation_hidden =nn.ReLU() 340 | self.bn_hidden = nn.BatchNorm1d(2*self.h_a) 341 | self.bn_output = nn.BatchNorm1d(self.h_a) 342 | self.activation_output = nn.ReLU() 343 | 344 | def forward(self, atom_emb, nbr_emb, nbr_adj_list): 345 | ''' Compute the GraphConvLayer 346 | 347 | Parameters: 348 | ------------------ 349 | atom_emb: torch.tensor, atom embeddings [batch-size, num_atoms, num_features] 350 | nbr_emb: torch.tensor, bond embedding of atom neighbors [batch-size, num_atom, num_neighbor, n_gaussians] 351 | nbr_adj_list: torch.tensor, indices for neighbors of a node [batch-size, num_atoms, num_neighbors] 352 | 353 | Returns: 354 | ------------------- 355 | out: atom embeddings after applying GraphConvLayer [batch-size, num_atom, num_features] 356 | ''' 357 | N, M = nbr_adj_list.shape[1:] 358 | # N is number of atoms and M is number of neighbors 359 | B = atom_emb.shape[0] # batch-size 360 | 361 | # gather the feature of neighbors into size [batch-size, num_atoms, num_neighbors, num_features] 362 | atom_nbr_emb = atom_emb[torch.arange(B).unsqueeze(-1), nbr_adj_list.to(torch.long).view(B,-1)].view(B,N,M,self.h_a).to(device) 363 | # concatenate the embedding of neighboring atoms with the bond embedding connecting the two 364 | # shape [batch-size, num-atoms, num_neighbors, 2*num_features + num_gaussians] 365 | total_nbr_emb = torch.cat([atom_emb.unsqueeze(2).expand(B,N,M,self.h_a), atom_nbr_emb, nbr_emb],dim=-1).to(torch.float32) 366 | 367 | # apply a linear layer 368 | total_gated_emb = self.fc_full(total_nbr_emb) 369 | total_gated_emb = self.bn_hidden(total_gated_emb.view(-1,self.h_a*2)).view(B,N,M,self.h_a*2) 370 | nbr_filter, nbr_core = total_gated_emb.chunk(2, dim=3) 371 | # Sigmoid function for edge-gating mechanism 372 | nbr_filter = self.sigmoid(nbr_filter) 373 | nbr_core = self.activation_hidden(nbr_core) 374 | # element-wise multiplication and aggregation of neighbors 375 | nbr_sumed = torch.sum(nbr_filter*nbr_core, dim=2) 376 | # apply batch-norm to output 377 | nbr_sumed = self.bn_output(nbr_sumed.view(-1, self.h_a)).view(B,N,self.h_a) 378 | # apply non-linear activation to output 379 | out = self.activation_output(atom_emb+nbr_sumed) 380 | return out 381 | 382 | class GaussianDistance(object): 383 | def __init__(self, dmin, dmax, step, var=None): 384 | 385 | ''' Expands ditsnces by gaussian basis functions 386 | parameters: 387 | ------------------- 388 | dmin: float, minimum distance between atoms to be considered for gaussian basis 389 | dmax: float, maximum distance between atoms to be considered for gaussian basis 390 | step: float, step size for the gaussian filter 391 | ''' 392 | assert dmin < dmax 393 | assert dmax - dmin > step 394 | self.filter = torch.arange(dmin, dmax+step, step) 395 | self.num_features = len(self.filter) 396 | if var is None: 397 | var = step 398 | self.var = var 399 | 400 | def expand(self, distance): 401 | ''' 402 | apply gaussian distance filter to a numpy array distance 403 | parameters: 404 | ----------------- 405 | N: number of atoms 406 | M: number of neighbors 407 | B: batch-size 408 | distance: shape [B, N, M] 409 | 410 | returns: 411 | expanded distance with shape [B, N, M, bond_fea_len] 412 | ''' 413 | return torch.exp(-(torch.unsqueeze(distance,-1).to(device)-self.filter.to(device))**2/self.var**2) 414 | 415 | 416 | class ContinuousFilterConv(nn.Module): 417 | ''' 418 | Continuous filter convolution layer for SchNet as described by Schütt et al.(2018) 419 | A continuous-filter convolutional layer uses continuous radial basis functions for discrete data. (Schütt et al. (2018)) 420 | Continuous-filter convolution block consists of a filter generating network as follows: 421 | 422 | Filter generator: 423 | 1. get distances betwee nodes. 424 | 2. atom-wise/Linear layer with non-linear activation 425 | 3. atom-wise/Linear layer with non-linear activation 426 | 427 | The filter generator output is then multiplied element-wise with the continuous convolution filter as part of the interaction block. 428 | 429 | Parameters: 430 | ----------------- 431 | n_gaussians: int 432 | number of gaussian used in hte radial basis function. needed to determine input feature size of first dense layer 433 | n_filters: int 434 | number of filters that will be created. Also determines the output size. Needs to be the same size as the features of residual 435 | connection in the interaction block. 436 | activation: nn.Module 437 | Activation function for the filter generating network. 438 | 439 | Notes: 440 | ------------------ 441 | Following current implementation in SchNetPack, the last linear layer of the filter generator does not contain an activation 442 | function. This allows the filter generator to contain negative values. 443 | 444 | References: 445 | 446 | ''' 447 | def __init__(self, n_gaussians, n_filters, activation=nn.Tanh(), normalization_layer=None): 448 | 449 | super(ContinuousFilterConv, self).__init__() 450 | filter_layers = LinearLayer(n_gaussians, n_filters, bias=True, activation=activation) 451 | filter_layers += LinearLayer(n_filters, n_filters, bias=True) # no activation here 452 | self.filter_generator = nn.Sequential(*filter_layers) 453 | 454 | self.nbr_filter = nn.Parameter(torch.Tensor(n_filters, 1)) 455 | nn.init.xavier_uniform_(self.nbr_filter.data, gain=1.414) 456 | 457 | if normalization_layer is not None: 458 | self.normalization_layer = normalization_layer 459 | else: 460 | self.normalization_layer = None 461 | 462 | def forward(self, features, rbf_expansion, neighbor_list): 463 | ''' Compute convolutional block 464 | Parameters: 465 | ------------- 466 | features: torch.Tensor 467 | Feature vector of size [n_frames, n_atoms, n_features] 468 | rbf_expansion: torch.Tensor 469 | Gaussian expansion of bead distances of size, [n_frames, n_atoms, n_neighbors, n_gaussians] 470 | neighbor_list: torch.Tensor 471 | indices of all neighbors of each bead size [n_frames, n_atoms, n_neighbors] 472 | 473 | Returns: 474 | ------------- 475 | aggregated features: torch.Tensor 476 | Residual features of shape [n_frames, n_atoms, n_features] 477 | ''' 478 | 479 | # generate convolutional filter of size [n_frames, n_atoms, n_neighbors, n_features] 480 | 481 | conv_filter = self.filter_generator(rbf_expansion.to(torch.float32)) 482 | 483 | # Feature tensor needs to also be transformed from [n_frames, n_atoms, n_features] 484 | # to [n_frames, n_atoms, n_neighbors, n_features] 485 | n_batch, n_atoms, n_neighbors = neighbor_list.size() 486 | 487 | # size [n_frames, n_atoms*n_neighbors, 1] 488 | neighbor_list = neighbor_list.reshape(-1, n_atoms*n_neighbors, 1) 489 | 490 | # size [n_frames, natoms*n_neighbors, n_features] 491 | neighbor_list = neighbor_list.expand(-1, -1, features.size(2)) 492 | 493 | # Gather the features into the respective places in the neighbor list 494 | neighbor_features = torch.gather(features, 1, neighbor_list.to(torch.int64)) 495 | # Reshape back to [n_frames, n_atoms, n_neighbors, n_features] for element-wise multiplication 496 | 497 | neighbor_features = neighbor_features.reshape(n_batch, n_atoms, n_neighbors, -1) 498 | 499 | # element-wise multiplication of the features with the convolutional filter 500 | conv_features = neighbor_features * conv_filter 501 | # [B, N, M, n_features] 502 | #nbr_filter = self.nbr_filter(conv_features).view([n_batch, n_atoms, 1, n_neighbors]) 503 | nbr_filter = torch.matmul(conv_features, self.nbr_filter).view([n_batch, n_atoms, n_neighbors]) 504 | # [B, N, 1, M] 505 | nbr_filter = F.softmax(nbr_filter, -1).to(device) 506 | nbr_filter = nbr_filter.view([n_batch, n_atoms, n_neighbors]) 507 | # [B, N, M] 508 | aggregated_features = torch.einsum('bij,bijc->bic',nbr_filter, conv_features) 509 | 510 | 511 | # attention for pooling 512 | 513 | # aggregate/pool the features from [n_frames, n_atoms, n_neighbors, n_features] to [n_frames, n_atoms, n_features] 514 | #aggregated_features = torch.sum(conv_features, dim=2) 515 | 516 | ####### later using attention on the connectivities so we need this now ######### 517 | #aggregated_features = conv_features 518 | 519 | if self.normalization_layer is not None: 520 | if isinstance(self.normalization_layer, NeighborNormLayer): 521 | return self.normalization_layer(aggregated_features, n_neighbors) 522 | else: 523 | return self.normalization_layer(aggregated_features) 524 | else: 525 | return aggregated_features, nbr_filter 526 | 527 | 528 | class InteractionBlock(nn.Module): 529 | ''' 530 | SchNet interaction block as described by Schütt et al. (2018). 531 | 532 | An interaction block consists of : 533 | 1. Atom-wise/Linear layer without activation function 534 | 2. Continuous filter convolution, which is a filter-generator multiplied element-wise with the output of previous layer 535 | 3. Atom-wise/Linear layer with the activation 536 | 4. Atom-wise/Linear layer without activation 537 | 538 | The output of an interaction block will then be used to form an additive residual connection with the original input features, 539 | [x'1, ..., x'n] 540 | 541 | Parameters: 542 | --------------- 543 | n_inputs: int, number of input features, determines input size for the initial linear layer 544 | n_gaussians: int, number of gaussians that has been used in the radial basis function. needed to determine the input size of the continuous 545 | filter convolution. 546 | n_filters: int, number of filters that will be created in the continuous filter convolution. The same feature size will be used for the output 547 | linear layers of the interaction block. 548 | activation: nn.Module activation function for the atom-wise layers. 549 | normalization_layer: nn.Module (default=None) 550 | normalization layer to be applied to the output of the ContinuousFilterConvolution 551 | 552 | The residul connection will be added later in model module between the interaction blocks 553 | 554 | References: 555 | ---------------- 556 | K.T. Schütt. P.-J. Kindermans, H. E. Sauceda, S. Chmiela, 557 | A. Tkatchenko, K.-R. Müller. (2018) 558 | SchNet - a deep learning architecture for molecules and materials. 559 | The Journal of Chemical Physics. 560 | https://doi.org/10.1063/1.5019779 561 | ''' 562 | 563 | def __init__(self, n_inputs, n_gaussians, n_filters, activation=nn.Tanh(), normalization_layer=None): 564 | super(InteractionBlock, self).__init__() 565 | 566 | self.initial_dense = nn.Sequential(*LinearLayer(n_inputs, n_filters, bias=False, activation=None)) 567 | 568 | self.cfconv = ContinuousFilterConv(n_gaussians=n_gaussians, 569 | n_filters=n_filters, 570 | activation=activation, 571 | normalization_layer=normalization_layer) 572 | 573 | #self.attn = AttnBlock(n_filters, n_filters) 574 | 575 | 576 | # look here if adding layers here will give any problems 577 | output_layers = LinearLayer(n_filters, n_filters, bias=True, activation=activation) 578 | output_layers += LinearLayer(n_filters, n_filters, bias=True) 579 | self.output_dense = nn.Sequential(*output_layers) 580 | 581 | @staticmethod 582 | def convert_adj(mat): 583 | # convert the nbr_adj_list matrix to an adjacency matrix 584 | mat = mat.to(torch.long) 585 | adj = torch.zeros((mat.shape[0], mat.shape[1], mat.shape[1])) 586 | for i in range(mat.shape[0]): 587 | adj[i][torch.arange(adj.shape[1])[:,None],mat[i]] = 1 588 | adj[i] += torch.eye(mat.shape[1]) 589 | return adj.to(device) 590 | 591 | 592 | def forward(self, features, rbf_expansion, neighbor_list): 593 | ''' Compute interaction block 594 | 595 | Parameters: 596 | ----------------- 597 | features: torch.Tensor 598 | Input features from an embedding or ineteraction layer. [n_frames, n_atom, n_features] 599 | rbf_expansion: torch.Tensor, 600 | Radial basis function expansion of distances [n_frames, n_atoms, n_neighbors, n_gaussians] 601 | neighbor_list: torch.Tensor 602 | Indices of all neighbors of each atom [n_frames, n_atoms, n_neighbors] 603 | 604 | Returns: 605 | ----------------- 606 | output_features: torch.Tensor 607 | Output of an interaction block. This output can be used to form a residual connection with the output of 608 | a prior embedding/interaction layer. [n_frames, n_atoms, n_filters] 609 | ''' 610 | init_feature_output = self.initial_dense(features) 611 | conv_output, attn = self.cfconv(init_feature_output.to(torch.float32), rbf_expansion.to(torch.float32), neighbor_list) 612 | #adj = self.convert_adj(neighbor_list) 613 | #conv_output_t, attn = self.attn(conv_output, neighbor_list) 614 | output_features = self.output_dense(conv_output).to(torch.float32) 615 | return output_features, attn 616 | -------------------------------------------------------------------------------- /Example_TrpCage_2dEmbedding.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "b513f3f0", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import numpy as np\n", 11 | "import matplotlib.pyplot as plt\n", 12 | "import pyemma" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "id": "8c27e196", 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "embd = np.load('embeddings.npz')['arr_0']" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 3, 28 | "id": "70b72457", 29 | "metadata": {}, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "image/png": "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\n", 34 | "text/plain": [ 35 | "
" 36 | ] 37 | }, 38 | "metadata": { 39 | "needs_background": "light" 40 | }, 41 | "output_type": "display_data" 42 | } 43 | ], 44 | "source": [ 45 | "from pylab import *\n", 46 | "rc('axes', linewidth=2)\n", 47 | "f, ax = plt.subplots(1,1, figsize=(8,5), dpi=100)\n", 48 | "pyemma.plots.plot_free_energy(embd[:,0], embd[:,1],ax=ax)\n", 49 | "\n", 50 | "fontsize = 10\n", 51 | "for tick in ax.xaxis.get_major_ticks():\n", 52 | " tick.label1.set_fontsize(fontsize)\n", 53 | " tick.label1.set_fontweight('bold')\n", 54 | "for tick in ax.yaxis.get_major_ticks():\n", 55 | " tick.label1.set_fontsize(fontsize)\n", 56 | " tick.label1.set_fontweight('bold')\n", 57 | " \n", 58 | "plt.savefig('trpcage_free_energy.png')" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 4, 64 | "id": "18b7134a", 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "transformed = []\n", 69 | "for i in range(1,2):\n", 70 | " trans_temp = []\n", 71 | " trans_temp.append(np.load('trans_'+str(i)+'.npz')['arr_0'])\n", 72 | " transformed.append(trans_temp) " 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 5, 78 | "id": "feb034fc", 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "y_m_t = []\n", 83 | "inds = []\n", 84 | "thresh = 0.95\n", 85 | "exp = 0\n", 86 | "for i in range(1):\n", 87 | " tmp = []\n", 88 | " tmp_ind = []\n", 89 | " for j in range(len(transformed[exp][i])):\n", 90 | " if transformed[exp][i][j].max()>thresh:\n", 91 | " tmp.append(np.argmax(transformed[exp][i][j]))\n", 92 | " tmp_ind.append(j)\n", 93 | " tmp = np.array(tmp)\n", 94 | " tmp_ind = np.array(tmp_ind)\n", 95 | " \n", 96 | " y_m_t.append(tmp)\n", 97 | " inds.append(tmp_ind)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 6, 103 | "id": "d686d6a3", 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "data": { 108 | "text/plain": [ 109 | "[array([ 0, 1, 2, ..., 208797, 208798, 208799])]" 110 | ] 111 | }, 112 | "execution_count": 6, 113 | "metadata": {}, 114 | "output_type": "execute_result" 115 | } 116 | ], 117 | "source": [ 118 | "inds" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 7, 124 | "id": "88d8402e", 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "my_dict = {0:0, 1:2, 2:1, 3:3, 4:4}" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 8, 134 | "id": "2d85b2b0", 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "y_m_t_t = np.vectorize(my_dict.get)(y_m_t[0])" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 10, 144 | "id": "5b0a6528", 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "data": { 149 | "text/plain": [ 150 | "
" 151 | ] 152 | }, 153 | "metadata": {}, 154 | "output_type": "display_data" 155 | }, 156 | { 157 | "data": { 158 | "image/png": "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\n", 159 | "text/plain": [ 160 | "
" 161 | ] 162 | }, 163 | "metadata": { 164 | "needs_background": "light" 165 | }, 166 | "output_type": "display_data" 167 | } 168 | ], 169 | "source": [ 170 | "from pylab import *\n", 171 | "plt.set_cmap('jet')\n", 172 | "rc('axes', linewidth=2)\n", 173 | "f, ax = plt.subplots(1,1, figsize=(8,5))\n", 174 | "pyemma.plots.plot_state_map(embd[inds[0],0], embd[inds[0],1], y_m_t_t, ax=ax, ncontours=100)\n", 175 | "\n", 176 | "fontsize = 10\n", 177 | "for tick in ax.xaxis.get_major_ticks():\n", 178 | " tick.label1.set_fontsize(fontsize)\n", 179 | " tick.label1.set_fontweight('bold')\n", 180 | "for tick in ax.yaxis.get_major_ticks():\n", 181 | " tick.label1.set_fontsize(fontsize)\n", 182 | " tick.label1.set_fontweight('bold')\n", 183 | " \n", 184 | "\n", 185 | "pyemma.plots.plot_state_map(embd[:,0], embd[:,1], np.zeros(embd[:,0].shape[0]), ax=ax, alpha=0.1, mask=True, cbar=False,cmap='Greys')\n", 186 | "plt.savefig('trpcage_states.png')" 187 | ] 188 | } 189 | ], 190 | "metadata": { 191 | "kernelspec": { 192 | "display_name": "Python 3 (ipykernel)", 193 | "language": "python", 194 | "name": "python3" 195 | }, 196 | "language_info": { 197 | "codemirror_mode": { 198 | "name": "ipython", 199 | "version": 3 200 | }, 201 | "file_extension": ".py", 202 | "mimetype": "text/x-python", 203 | "name": "python", 204 | "nbconvert_exporter": "python", 205 | "pygments_lexer": "ipython3", 206 | "version": "3.8.12" 207 | } 208 | }, 209 | "nbformat": 4, 210 | "nbformat_minor": 5 211 | } 212 | --------------------------------------------------------------------------------