| import torch |
| import numpy as np |
| from torch import nn |
| from scipy import stats |
| from collections import OrderedDict |
| import torch.nn.functional as F |
| from sklearn.metrics import roc_auc_score, r2_score |
| from torch.nn.modules import activation |
| from torch.nn.modules.dropout import Dropout |
|
|
| class Conf_CNN(nn.Module): |
| r""" |
| Convolution hidden representative learning for DNA motifs detection by Peter Koo et al |
| https://doi.org/10.1371/journal.pcbi.1007560 |
| |
| The model forces the motifs to be detected in the first CNN layer |
| The certain receptive field set by different max pooling size |
| |
| Parmas: |
| -------------------- |
| conv_args |
| - channel_ls |
| list [4, x, x] , Koo_net only support 2 layer CNN |
| - kernel_size |
| list, defualt [8,5] |
| - stride |
| list [1, 1s] |
| |
| pool_size |
| list [10,5] |
| """ |
| def __init__(self, conv_args, pool_size=[10,5]): |
| super().__init__() |
| channel_ls,kernel_size,stride,_,_,pad_to = conv_args |
|
|
| self.channel_ls =channel_ls |
| CNN_dims = list(zip(channel_ls[:-1], channel_ls[1:])) |
| self.CNN_dims = CNN_dims |
|
|
| self.kernel_size = kernel_size |
| self.stride = stride |
| self.pool_size = pool_size |
|
|
| |
| nns = [] |
| i = 1 |
| for in_out , ks, strid, ps in zip(CNN_dims, kernel_size, stride, pool_size): |
| layer = nn.Sequential( |
| nn.Conv1d(*in_out, ks, strid), |
| nn.BatchNorm1d(in_out[1]), |
| nn.Mish() |
| ) |
| nns.append((f'Conv_{i}', layer)) |
| nns.append((f'MaxPool_{i}', nn.MaxPool1d(ps))) |
| i += 1 |
| |
| |
| fcs = [ |
| ("fc_3", nn.Linear(channel_ls[-1], 512)), |
| ("BN_3", nn.BatchNorm1d(512)), |
| ("Act_3", nn.ReLU()), |
| ("fc_out", nn.Linear(512, 1)) |
|
|
| ] |
|
|
| self.network = nn.ModuleDict( |
| {"Conv":nn.Sequential(OrderedDict(nns)), "fc":nn.Sequential(OrderedDict(fcs))} |
| ) |
| self.loss_fn = nn.MSELoss() |
| |
| def __check_receptive_field(self): |
| assert len(self.channel_ls) == 3 |
| k_len = len(self.kernel_size) |
| st_len = len(self.stride) |
| p_len = len(self.pool_size) |
| |
|
|
| def forward(self,X): |
| """ |
| 2 stage forward |
| """ |
| if X.shape[1] != 4: |
| X = X.transpose(1,2) |
| Conv_out = self.network['Conv'](X) |
| assert Conv_out.shape[-1] == 1, "the maxpooling is not restricting values to 1" |
|
|
| out = self.network['fc'](Conv_out.squeeze(dim=-1)) |
| return out |
| |
| def compute_loss(self, out,X,Y,popen): |
| |
| if len(Y.shape) == 2: |
| Y = Y.squeeze(1) |
| if len(out.shape) == 2: |
| out = out.squeeze(1) |
|
|
| return {"Total":self.loss_fn(out, Y)} |
| |
| def squeeze_out_Y(self,out,Y): |
| |
| if len(Y.shape) == 2: |
| Y = Y.squeeze(1) |
| if len(out.shape) == 2: |
| out = out.squeeze(1) |
| |
| assert Y.shape == out.shape |
| return out,Y |
| |
| def compute_acc(self,out,X,Y,popen=None): |
| try: |
| epsilon = popen.epsilon |
| except: |
| epsilon = 0.3 |
| |
| out,Y = self.squeeze_out_Y(out,Y) |
| |
| with torch.no_grad(): |
| y_ay = Y.cpu().numpy() |
| out_ay = out.cpu().numpy() |
| |
| acc = stats.spearmanr(y_ay,out_ay)[0] |
| |
| return {"Acc":acc} |