Upload folder using huggingface_hub (part 2)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- model/src/mrl_te_optimization/models/Modules/__pycache__/Backbone.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/Backbone.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/GP_net.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/GP_net.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/Koo_net.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/Koo_net.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/__init__.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/__init__.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/_operator.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/__pycache__/_operator.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/Modules/_operator.py +246 -0
- model/src/mrl_te_optimization/models/Modules/nonDeep.py +69 -0
- model/src/mrl_te_optimization/models/ScheduleOptimizer.py +105 -0
- model/src/mrl_te_optimization/models/Self_attention.py +102 -0
- model/src/mrl_te_optimization/models/__pycache__/Backbone.cpython-310.pyc +0 -0
- model/src/mrl_te_optimization/models/__pycache__/Backbone.cpython-311.pyc +0 -0
- model/src/mrl_te_optimization/models/bucket_sampler.py +99 -0
- model/src/mrl_te_optimization/models/log_and_save.py +271 -0
- model/src/mrl_te_optimization/models/loss.py +86 -0
- model/src/mrl_te_optimization/models/max_activation_patch.py +795 -0
- model/src/mrl_te_optimization/models/popen.py +150 -0
- model/src/mrl_te_optimization/models/reader.py +512 -0
- model/src/mrl_te_optimization/models/train_val.py +337 -0
- model/src/mrl_te_optimization/popen.py +150 -0
- model/src/mrl_te_optimization/script/Nupack_MFE_prediction.py +48 -0
- model/src/mrl_te_optimization/script/PATH.py +3 -0
- model/src/mrl_te_optimization/script/covar_test.py +203 -0
- model/src/mrl_te_optimization/script/covar_train.py +243 -0
- model/src/mrl_te_optimization/script/data_prepocessing.sh +2 -0
- model/src/mrl_te_optimization/script/detect_changepoint_featmap.py +146 -0
- model/src/mrl_te_optimization/script/download_training_data.sh +40 -0
- model/src/mrl_te_optimization/script/evaluate_channel_effect.py +112 -0
- model/src/mrl_te_optimization/script/fix_test_for_RP.py +32 -0
- model/src/mrl_te_optimization/script/generate_config_js.sh +13 -0
- model/src/mrl_te_optimization/script/iter_test.py +219 -0
- model/src/mrl_te_optimization/script/iter_train.py +251 -0
- model/src/mrl_te_optimization/script/main_train.py +201 -0
- model/src/mrl_te_optimization/script/preprocessing_MPA.py +115 -0
- model/src/mrl_te_optimization/script/preprocessing_RP.py +65 -0
- model/src/mrl_te_optimization/script/run-TF-modisco.py +99 -0
- model/src/mrl_te_optimization/script/train_kmer_classifer.py +239 -0
- model/src/mrl_te_optimization/script/train_kmer_models.py +167 -0
- model/src/mrl_te_optimization/script/train_oneLayer_CNN.py +114 -0
- model/src/mrl_te_optimization/util.py +384 -0
- model/src/mrl_te_optimization/utils.py +209 -0
- model/src/mrl_te_optimization/xpresso_input.json +0 -0
- requirements.txt +62 -0
- scripts/optimize_te_mrl.py +424 -0
- scripts/predict.py +213 -0
- scripts/train.py +398 -0
model/src/mrl_te_optimization/models/Modules/__pycache__/Backbone.cpython-310.pyc
ADDED
|
Binary file (23.6 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/Backbone.cpython-311.pyc
ADDED
|
Binary file (43.8 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/GP_net.cpython-310.pyc
ADDED
|
Binary file (5.89 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/GP_net.cpython-311.pyc
ADDED
|
Binary file (10.5 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/Koo_net.cpython-310.pyc
ADDED
|
Binary file (3.76 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/Koo_net.cpython-311.pyc
ADDED
|
Binary file (6.74 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (287 Bytes). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (292 Bytes). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/_operator.cpython-310.pyc
ADDED
|
Binary file (9.88 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/__pycache__/_operator.cpython-311.pyc
ADDED
|
Binary file (16.9 kB). View file
|
|
|
model/src/mrl_te_optimization/models/Modules/_operator.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import math
|
| 3 |
+
import numpy as np
|
| 4 |
+
from torch import nn
|
| 5 |
+
from scipy import stats
|
| 6 |
+
import torch.nn.functional as F
|
| 7 |
+
from einops import rearrange
|
| 8 |
+
from sklearn.metrics import roc_auc_score, r2_score
|
| 9 |
+
from torch.nn.modules import activation
|
| 10 |
+
from torch.nn.modules.dropout import Dropout
|
| 11 |
+
|
| 12 |
+
class Conv1d_block(nn.Module):
|
| 13 |
+
"""
|
| 14 |
+
the Convolution backbone define by a list of convolution block
|
| 15 |
+
"""
|
| 16 |
+
def __init__(self,channel_ls,kernel_size,stride, padding_ls=None,diliation_ls=None,pad_to=None, activation='ReLU'):
|
| 17 |
+
"""
|
| 18 |
+
Argument
|
| 19 |
+
channel_ls : list, [int] , channel for each conv layer
|
| 20 |
+
kernel_size : int
|
| 21 |
+
stride : list , [int]
|
| 22 |
+
padding_ls : list , [int]
|
| 23 |
+
diliation_ls : list , [int]
|
| 24 |
+
"""
|
| 25 |
+
super(Conv1d_block,self).__init__()
|
| 26 |
+
### property
|
| 27 |
+
self.activation = activation
|
| 28 |
+
self.channel_ls = channel_ls
|
| 29 |
+
self.kernel_size = kernel_size
|
| 30 |
+
self.stride = stride
|
| 31 |
+
if padding_ls is None:
|
| 32 |
+
self.padding_ls = [0] * (len(channel_ls) - 1)
|
| 33 |
+
else:
|
| 34 |
+
assert len(padding_ls) == len(channel_ls) - 1
|
| 35 |
+
self.padding_ls = padding_ls
|
| 36 |
+
if diliation_ls is None:
|
| 37 |
+
self.diliation_ls = [1] * (len(channel_ls) - 1)
|
| 38 |
+
else:
|
| 39 |
+
assert len(diliation_ls) == len(channel_ls) - 1
|
| 40 |
+
self.diliation_ls = diliation_ls
|
| 41 |
+
|
| 42 |
+
self.encoder = nn.ModuleList(
|
| 43 |
+
# in_C out_C padding diliation
|
| 44 |
+
[self.Conv_block(channel_ls[i],channel_ls[i+1],self.padding_ls[i],self.diliation_ls[i],self.stride[i]) for i in range(len(self.padding_ls))]
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
def Conv_block(self,in_Chan,out_Chan,padding,dilation,stride):
|
| 48 |
+
|
| 49 |
+
activation_layer = eval(f"nn.{self.activation}")
|
| 50 |
+
|
| 51 |
+
block = nn.Sequential(
|
| 52 |
+
nn.Conv1d(in_Chan,out_Chan,self.kernel_size,stride,padding,dilation),
|
| 53 |
+
nn.BatchNorm1d(out_Chan),
|
| 54 |
+
activation_layer())
|
| 55 |
+
|
| 56 |
+
return block
|
| 57 |
+
|
| 58 |
+
def forward(self,x):
|
| 59 |
+
if x.shape[2] == 4:
|
| 60 |
+
out = x.transpose(1,2)
|
| 61 |
+
else:
|
| 62 |
+
out = x
|
| 63 |
+
for block in self.encoder:
|
| 64 |
+
out = block(out)
|
| 65 |
+
return out
|
| 66 |
+
|
| 67 |
+
def forward_stage(self,x,stage):
|
| 68 |
+
"""
|
| 69 |
+
return the activation of each stage for exchanging information
|
| 70 |
+
"""
|
| 71 |
+
assert stage < len(self.encoder)
|
| 72 |
+
|
| 73 |
+
out = self.encoder[stage](x)
|
| 74 |
+
return out
|
| 75 |
+
|
| 76 |
+
def cal_out_shape(self,L_in=100,padding=0,diliation=1,stride=2):
|
| 77 |
+
"""
|
| 78 |
+
For convolution 1D encoding , compute the final length
|
| 79 |
+
"""
|
| 80 |
+
L_out = 1+ (L_in + 2*padding -diliation*(self.kernel_size-1) -1)/stride
|
| 81 |
+
return L_out
|
| 82 |
+
|
| 83 |
+
def last_out_len(self,L_in=100):
|
| 84 |
+
for i in range(len(self.padding_ls)):
|
| 85 |
+
padding = self.padding_ls[i]
|
| 86 |
+
diliation = self.diliation_ls[i]
|
| 87 |
+
stride = self.stride[i]
|
| 88 |
+
L_in = self.cal_out_shape(L_in,padding,diliation,stride)
|
| 89 |
+
# assert int(L_in) == L_in , "convolution out shape is not int"
|
| 90 |
+
|
| 91 |
+
return int(L_in) if L_in >=0 else 1
|
| 92 |
+
|
| 93 |
+
class ConvTranspose1d_block(Conv1d_block):
|
| 94 |
+
"""
|
| 95 |
+
the Convolution transpose backbone define by a list of convolution block
|
| 96 |
+
"""
|
| 97 |
+
def __init__(self,channel_ls,kernel_size,stride,padding_ls=None,diliation_ls=None,pad_to=None):
|
| 98 |
+
channel_ls = channel_ls[::-1]
|
| 99 |
+
stride = stride[::-1]
|
| 100 |
+
padding_ls = padding_ls[::-1] if padding_ls is not None else [0] * (len(channel_ls) - 1)
|
| 101 |
+
diliation_ls = diliation_ls[::-1] if diliation_ls is not None else [1] * (len(channel_ls) - 1)
|
| 102 |
+
super(ConvTranspose1d_block,self).__init__(channel_ls,kernel_size,stride,padding_ls,diliation_ls,pad_to)
|
| 103 |
+
|
| 104 |
+
def Conv_block(self,in_Chan,out_Chan,padding,dilation,stride):
|
| 105 |
+
"""
|
| 106 |
+
replace `Conv1d` with `ConvTranspose1d`
|
| 107 |
+
"""
|
| 108 |
+
block = nn.Sequential(
|
| 109 |
+
nn.ConvTranspose1d(in_Chan,out_Chan,self.kernel_size,stride,padding,dilation=dilation),
|
| 110 |
+
nn.BatchNorm1d(out_Chan),
|
| 111 |
+
nn.ReLU())
|
| 112 |
+
|
| 113 |
+
return block
|
| 114 |
+
|
| 115 |
+
def cal_out_shape(self,L_in,padding=0,diliation=1,stride=1,out_padding=0):
|
| 116 |
+
# L_in=100,padding=0,diliation=1,stride=2
|
| 117 |
+
"""
|
| 118 |
+
For convolution Transpose 1D decoding , compute the final length
|
| 119 |
+
"""
|
| 120 |
+
L_out = (L_in -1 )*stride + diliation*(self.kernel_size -1 )+1-2*padding + out_padding
|
| 121 |
+
return L_out
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
class linear_block(nn.Module):
|
| 125 |
+
def __init__(self,in_Chan,out_Chan,dropout_rate=0.2):
|
| 126 |
+
"""
|
| 127 |
+
building block func to define dose network
|
| 128 |
+
"""
|
| 129 |
+
super(linear_block,self).__init__()
|
| 130 |
+
self.block = nn.Sequential(
|
| 131 |
+
nn.Linear(in_Chan,out_Chan),
|
| 132 |
+
nn.Dropout(dropout_rate),
|
| 133 |
+
nn.BatchNorm1d(out_Chan),
|
| 134 |
+
nn.ReLU()
|
| 135 |
+
)
|
| 136 |
+
def forward(self,x):
|
| 137 |
+
return self.block(x)
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class Self_Attention(nn.Module):
|
| 141 |
+
"""
|
| 142 |
+
self attention operator for Conv1d sequences output
|
| 143 |
+
"""
|
| 144 |
+
def __init__(self, in_dim:int, out_dim:int, qk_dim:int, n_head:int):
|
| 145 |
+
super().__init__()
|
| 146 |
+
|
| 147 |
+
self.n_head = n_head
|
| 148 |
+
self.total_qk_dim = qk_dim * n_head
|
| 149 |
+
self.transform = nn.ModuleDict({
|
| 150 |
+
k : nn.Linear(in_dim, self.total_qk_dim) for k in ['k', 'q', 'v']
|
| 151 |
+
})
|
| 152 |
+
|
| 153 |
+
self.fc_out = nn.Linear(self.total_qk_dim, out_dim)
|
| 154 |
+
|
| 155 |
+
def dim_rerrange(self, x):
|
| 156 |
+
|
| 157 |
+
# first break down total qk dimension
|
| 158 |
+
# then transpose length with heads
|
| 159 |
+
x1 = rearrange(x, "b l (n c) -> b n c l", n=self.n_head)
|
| 160 |
+
return x1
|
| 161 |
+
|
| 162 |
+
def _get_attention_map(self,X):
|
| 163 |
+
"""
|
| 164 |
+
break the forward function to access attention mat
|
| 165 |
+
"""
|
| 166 |
+
# assume we have a 3 dimension input X (b, len, in_dim)
|
| 167 |
+
# each out in qkv is also 3 dimension (b, len , qk_dim)
|
| 168 |
+
qkv = [self.transform[key](X) for key in ['k', 'q', 'v']]
|
| 169 |
+
q, k, v = map(self.dim_rerrange, qkv)
|
| 170 |
+
|
| 171 |
+
# here i and j is the channel
|
| 172 |
+
sim = torch.einsum("b n c i, b n c j -> b n i j", q, k)
|
| 173 |
+
sim = sim - sim.amax(dim=-1, keepdim=True).detach()
|
| 174 |
+
attn = sim.softmax(dim=-1)
|
| 175 |
+
return attn, v
|
| 176 |
+
|
| 177 |
+
def forward(self, X):
|
| 178 |
+
|
| 179 |
+
attn, v = self._get_attention_map(X)
|
| 180 |
+
|
| 181 |
+
out = torch.einsum("b n i j, b n c j -> b n i c", attn, v)
|
| 182 |
+
out = rearrange(out, "b n i c -> b i (n c)")
|
| 183 |
+
return self.fc_out(out)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
class Self_Attention_for_GP(Self_Attention):
|
| 187 |
+
"""
|
| 188 |
+
self attention operator for Conv1d sequences Global Pooling output
|
| 189 |
+
The input has 2 dimension (no length dim),
|
| 190 |
+
"""
|
| 191 |
+
def __init__(self, in_dim:int, out_dim:int, qk_dim:int, n_head:int):
|
| 192 |
+
super().__init__(in_dim, out_dim, qk_dim, n_head)
|
| 193 |
+
|
| 194 |
+
def _get_attention_map(self,X):
|
| 195 |
+
# assume we have a 3 dimension input X (b, len, in_dim)
|
| 196 |
+
# each out in qkv is also 3 dimension (b, len , qk_dim)
|
| 197 |
+
qkv = [self.transform[key](X) for key in ['k', 'q', 'v']]
|
| 198 |
+
q, k, v = map(
|
| 199 |
+
lambda x : rearrange(x, "b (n c)-> b n c"), qkv
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
# here i and j is the channel
|
| 203 |
+
sim = torch.einsum("b n i, b n j -> b n i j", q, k).softmax(dim=-2, keepdim=True)
|
| 204 |
+
sim = sim - attn.amax(dim=-1, keepdim=True).detach()
|
| 205 |
+
attn = sim.softmax(dim=-1)
|
| 206 |
+
return attn, v
|
| 207 |
+
|
| 208 |
+
def forward(self, X):
|
| 209 |
+
#
|
| 210 |
+
attn, v = self._get_attention_map(X)
|
| 211 |
+
|
| 212 |
+
out = torch.einsum("b n i j, b n j -> b n i", attn, v)
|
| 213 |
+
out = rearrange(out, "b n i -> b (n i)")
|
| 214 |
+
return self.fc_out(out)
|
| 215 |
+
|
| 216 |
+
class Residual(nn.Module):
|
| 217 |
+
def __init__(self, fn):
|
| 218 |
+
super().__init__()
|
| 219 |
+
self.fn = fn
|
| 220 |
+
|
| 221 |
+
def forward(self, x, *args, **kwargs):
|
| 222 |
+
return self.fn(x, *args, **kwargs) + x
|
| 223 |
+
|
| 224 |
+
class PreNorm(nn.Module):
|
| 225 |
+
def __init__(self, dim, fn):
|
| 226 |
+
super().__init__()
|
| 227 |
+
self.fn = fn
|
| 228 |
+
self.norm = nn.GroupNorm(1, dim)
|
| 229 |
+
|
| 230 |
+
def forward(self, x):
|
| 231 |
+
x = self.norm(x.transpose(1,2))
|
| 232 |
+
return self.fn(x.transpose(1,2))
|
| 233 |
+
|
| 234 |
+
class SinusoidalPositionEmbeddings(nn.Module):
|
| 235 |
+
def __init__(self, dim):
|
| 236 |
+
super().__init__()
|
| 237 |
+
self.dim = dim
|
| 238 |
+
|
| 239 |
+
def forward(self, time):
|
| 240 |
+
device = time.device
|
| 241 |
+
half_dim = self.dim // 2
|
| 242 |
+
embeddings = math.log(10000) / (half_dim -1) # why do we minus 1 ?
|
| 243 |
+
embeddings = torch.exp(torch.arange(half_dim, device=device)* -embeddings)
|
| 244 |
+
embeddings = time[:, None] * embeddings[None, :] # expand to 2 dimension
|
| 245 |
+
embeddings = torch.cat((embeddings.sin(), embeddings.cos()), dim=-1)
|
| 246 |
+
return embeddings
|
model/src/mrl_te_optimization/models/Modules/nonDeep.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
sys.path.append(os.path.abspath("../"))
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import torch
|
| 7 |
+
from torch import nn
|
| 8 |
+
import reader
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class Kmer_LinReg(nn.Module):
|
| 12 |
+
"""
|
| 13 |
+
simple kmer model detect motifs
|
| 14 |
+
"""
|
| 15 |
+
def __init__(self, kmer_size, pad_to):
|
| 16 |
+
super().__init__()
|
| 17 |
+
self.k = kmer_size
|
| 18 |
+
self.input_length = pad_to
|
| 19 |
+
|
| 20 |
+
# define Conv then replace the parameters
|
| 21 |
+
channel_size = 4**kmer_size
|
| 22 |
+
self.kmer_conv = nn.Conv1d(4, 1, kmer_size)
|
| 23 |
+
self.custom_conv()
|
| 24 |
+
|
| 25 |
+
self.kmer_binarizer = nn.ReLU()
|
| 26 |
+
|
| 27 |
+
out_length = self.compute_kmer_outshape()
|
| 28 |
+
self.fc_out = nn.Linear(channel_size * out_length, 1)
|
| 29 |
+
|
| 30 |
+
def compute_kmer_outshape(self):
|
| 31 |
+
"""
|
| 32 |
+
default stride = 1, pad = 0
|
| 33 |
+
"""
|
| 34 |
+
dilation = 1
|
| 35 |
+
padding = 0
|
| 36 |
+
stride = 1
|
| 37 |
+
L_in = self.input_length
|
| 38 |
+
L_out = 1 + L_in + 2 * padding - dilation * (self.k - 1) - 1
|
| 39 |
+
return L_out
|
| 40 |
+
|
| 41 |
+
def create_kmer(self):
|
| 42 |
+
all_kmer = {0:['']}
|
| 43 |
+
k = 1
|
| 44 |
+
while k <= self.k:
|
| 45 |
+
k_mer = [] # 1 ; 4 ; 2: 4**2 ...
|
| 46 |
+
for source in all_kmer[k-1]:
|
| 47 |
+
k_mer += [source + base for base in ['A','C','G','T']]
|
| 48 |
+
|
| 49 |
+
assert len(k_mer) == 4**k, f"new kmers {len(k_mer)}, not equal to {4**k}"
|
| 50 |
+
all_kmer[k] = k_mer
|
| 51 |
+
k += 1
|
| 52 |
+
|
| 53 |
+
all_kmer.pop(0)
|
| 54 |
+
return all_kmer
|
| 55 |
+
|
| 56 |
+
def custom_conv(self):
|
| 57 |
+
|
| 58 |
+
# only detect 5-mer is kmersize is 5
|
| 59 |
+
# Zhang et al includes shorter kmers in their features
|
| 60 |
+
kmers = self.create_kmer()[self.k]
|
| 61 |
+
|
| 62 |
+
matrix = [reader.one_hot(kmer).T for kmer in kmers]
|
| 63 |
+
kernels = np.stack(matrix)
|
| 64 |
+
|
| 65 |
+
kernels = matrix[0].reshape(1, 4, 3)
|
| 66 |
+
|
| 67 |
+
self.kmer_conv.weight = nn.Parameter(torch.from_numpy(kernels).long(), requires_grad=False)
|
| 68 |
+
|
| 69 |
+
|
model/src/mrl_te_optimization/models/ScheduleOptimizer.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
from torch import nn
|
| 7 |
+
from matplotlib import pyplot as plt
|
| 8 |
+
from matplotlib import cm
|
| 9 |
+
|
| 10 |
+
global scheduleoptim_text
|
| 11 |
+
scheduleoptim_text="ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), betas=(0.9, 0.98), eps=1e-09, weight_decay=1e-4, amsgrad=True),n_warmup_steps=20)"
|
| 12 |
+
|
| 13 |
+
scheduleoptim_dict_str="""ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 14 |
+
betas=(0.9, 0.98),
|
| 15 |
+
eps=1e-09,
|
| 16 |
+
weight_decay={weight_decay},
|
| 17 |
+
amsgrad={amsgrad}),
|
| 18 |
+
n_warmup_steps={n_warmup_steps})"""
|
| 19 |
+
|
| 20 |
+
class ScheduledOptim(object):
|
| 21 |
+
"""A simple wrapper class for learning rate scheduling"""
|
| 22 |
+
|
| 23 |
+
def __init__(self, optimizer, n_warmup_steps):
|
| 24 |
+
self.optimizer = optimizer
|
| 25 |
+
self.d_model = 128
|
| 26 |
+
self.n_warmup_steps = n_warmup_steps
|
| 27 |
+
self.n_current_steps = 0
|
| 28 |
+
self.delta = 1
|
| 29 |
+
|
| 30 |
+
def state_dict(self):
|
| 31 |
+
return self.optimizer.state_dict()
|
| 32 |
+
|
| 33 |
+
def load_state_dict(self,state):
|
| 34 |
+
self.optimizer.load_state_dict(state)
|
| 35 |
+
|
| 36 |
+
def step(self):
|
| 37 |
+
"""Step by the inner optimizer"""
|
| 38 |
+
self.optimizer.step()
|
| 39 |
+
|
| 40 |
+
def zero_grad(self):
|
| 41 |
+
"""Zero out the gradients by the inner optimizer"""
|
| 42 |
+
self.optimizer.zero_grad()
|
| 43 |
+
|
| 44 |
+
def increase_delta(self):
|
| 45 |
+
self.delta *= 2
|
| 46 |
+
self.delta = min(1024,self.delta)
|
| 47 |
+
|
| 48 |
+
def update_learning_rate(self):
|
| 49 |
+
"""Learning rate scheduling per step"""
|
| 50 |
+
|
| 51 |
+
self.n_current_steps += self.delta
|
| 52 |
+
new_lr = np.power(self.d_model, -0.5) * np.min([
|
| 53 |
+
np.power(self.n_current_steps, -0.5),
|
| 54 |
+
np.power(self.n_warmup_steps, -1.5) * self.n_current_steps])
|
| 55 |
+
# -1.5
|
| 56 |
+
for param_group in self.optimizer.param_groups:
|
| 57 |
+
param_group['lr'] = new_lr
|
| 58 |
+
return new_lr
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def find_lr(net,train_data,Variable):
|
| 62 |
+
criterion = torch.nn.CrossEntropyLoss()
|
| 63 |
+
|
| 64 |
+
net.fc = nn.Linear(2048, 120)
|
| 65 |
+
|
| 66 |
+
with torch.cuda.device(0):
|
| 67 |
+
net = net.cuda()
|
| 68 |
+
|
| 69 |
+
basic_optim = torch.optim.SGD(net.parameters(), lr=1e-5)
|
| 70 |
+
optimizer = ScheduledOptim(basic_optim)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
lr_mult = (1 / 1e-5) ** (1 / 100)
|
| 74 |
+
lr = []
|
| 75 |
+
losses = []
|
| 76 |
+
best_loss = 1e9
|
| 77 |
+
for data, label in train_data:
|
| 78 |
+
with torch.cuda.device(0):
|
| 79 |
+
data = Variable(data.cuda())
|
| 80 |
+
label = Variable(label.cuda())
|
| 81 |
+
# forward
|
| 82 |
+
out = net(data)
|
| 83 |
+
loss = criterion(out, label)
|
| 84 |
+
# backward
|
| 85 |
+
optimizer.zero_grad()
|
| 86 |
+
loss.backward()
|
| 87 |
+
optimizer.step()
|
| 88 |
+
lr.append(optimizer.learning_rate)
|
| 89 |
+
losses.append(loss.data[0])
|
| 90 |
+
optimizer.set_learning_rate(optimizer.learning_rate * lr_mult)
|
| 91 |
+
if loss.data[0] < best_loss:
|
| 92 |
+
best_loss = loss.data[0]
|
| 93 |
+
if loss.data[0] > 4 * best_loss or optimizer.learning_rate > 1.:
|
| 94 |
+
break
|
| 95 |
+
|
| 96 |
+
plt.figure()
|
| 97 |
+
plt.xticks(np.log([1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1]), (1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1))
|
| 98 |
+
plt.xlabel('learning rate')
|
| 99 |
+
plt.ylabel('loss')
|
| 100 |
+
plt.plot(np.log(lr), losses)
|
| 101 |
+
plt.show()
|
| 102 |
+
plt.figure()
|
| 103 |
+
plt.xlabel('num iterations')
|
| 104 |
+
plt.ylabel('learning rate')
|
| 105 |
+
plt.plot(lr)
|
model/src/mrl_te_optimization/models/Self_attention.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import torch
|
| 4 |
+
from torch import nn
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
class self_attention(nn.Module):
|
| 8 |
+
|
| 9 |
+
def __init__(self,in_channel,n_head,d_k,d_v):
|
| 10 |
+
super(self_attention,self).__init__()
|
| 11 |
+
self.n_head=n_head
|
| 12 |
+
self.d_k = d_k
|
| 13 |
+
self.d_v = d_v
|
| 14 |
+
self.W_dict = nn.ModuleDict({"Wq" : nn.Linear(in_channel,n_head*d_k),
|
| 15 |
+
"Wk" : nn.Linear(in_channel,n_head*d_k),
|
| 16 |
+
"Wv" : nn.Linear(in_channel,n_head*d_v)})
|
| 17 |
+
|
| 18 |
+
def forward(self,X):
|
| 19 |
+
|
| 20 |
+
# some dimension
|
| 21 |
+
dk_sqrt = int(np.sqrt(self.d_k))
|
| 22 |
+
|
| 23 |
+
querys = self.W_dict['Wq'](X) # B*X_dim*dk
|
| 24 |
+
keys = self.W_dict['Wk'](X) # B* hs_out -> B*64
|
| 25 |
+
values = self.W_dict['Wv'](X) # B* hs_out -> B*128
|
| 26 |
+
|
| 27 |
+
sim_M = torch.bmm(querys,keys.transpose(1,2))/8 # B* X_dim * X_dim
|
| 28 |
+
attention = torch.softmax(sim_M,dim=-1)
|
| 29 |
+
# result
|
| 30 |
+
result = torch.bmm(attention,values).squeeze(2) # B*X_dim*1 -> B*X_dim
|
| 31 |
+
|
| 32 |
+
return result
|
| 33 |
+
|
| 34 |
+
class task_attention(nn.Module):
|
| 35 |
+
"""
|
| 36 |
+
Task Attention Layer, it contains a task specific mask `Wq` as the Query. Key is computed from the input
|
| 37 |
+
|
| 38 |
+
Arguments:
|
| 39 |
+
|
| 40 |
+
d_v : int , dimension of the network width input , i.e : (Batch_size, d_v)
|
| 41 |
+
d_k : int , dimension of the Query and Key.
|
| 42 |
+
"""
|
| 43 |
+
def __init__(self,d_v:int,d_k=64):
|
| 44 |
+
super(task_attention,self).__init__()
|
| 45 |
+
|
| 46 |
+
self.d_k = d_k
|
| 47 |
+
self.d_v = d_v
|
| 48 |
+
self.W_dict = nn.ModuleDict({"Wq" : nn.Linear(d_k,d_v),
|
| 49 |
+
"Wk" : nn.Linear(d_v,d_k)})
|
| 50 |
+
|
| 51 |
+
def forward(self,X):
|
| 52 |
+
# i.e X : (B ,128)
|
| 53 |
+
# if len(X.shape) == 2:
|
| 54 |
+
# X = X
|
| 55 |
+
|
| 56 |
+
# some dimension
|
| 57 |
+
dk_sqrt = int(np.sqrt(self.d_k))
|
| 58 |
+
|
| 59 |
+
keys = self.W_dict['Wk'](X).squeeze(2) # (B, 128) -> (B ,64)
|
| 60 |
+
|
| 61 |
+
# dot product similarity is used here , which is implemented by `nn.Linear`
|
| 62 |
+
sim_M =self.W_dict['Wq'](keys) /dk_sqrt # (B,128,64) * (B,64,128) -> (B, 128, 128)
|
| 63 |
+
attention = torch.softmax(sim_M,dim=-1)
|
| 64 |
+
# result
|
| 65 |
+
result = torch.mul(attention,X) # (B, 128) * (B, 128) -> B*128
|
| 66 |
+
|
| 67 |
+
return result
|
| 68 |
+
|
| 69 |
+
class task_attention(nn.Module):
|
| 70 |
+
"""
|
| 71 |
+
Task Attention Layer, it contains a task specific mask `Wq` as the Query. Key is computed from the input
|
| 72 |
+
|
| 73 |
+
Arguments:
|
| 74 |
+
|
| 75 |
+
d_v : int , dimension of the network width input , i.e : (Batch_size, d_v)
|
| 76 |
+
d_k : int , dimension of the Query and Key.
|
| 77 |
+
"""
|
| 78 |
+
def __init__(self,d_v:int,d_k=64):
|
| 79 |
+
super(task_attention,self).__init__()
|
| 80 |
+
|
| 81 |
+
self.d_k = d_k
|
| 82 |
+
self.d_v = d_v
|
| 83 |
+
self.W_dict = nn.ModuleDict({"Wq" : nn.Linear(d_v,d_k),
|
| 84 |
+
"Wk" : nn.Linear(d_v,d_k)})
|
| 85 |
+
|
| 86 |
+
def forward(self,X):
|
| 87 |
+
# i.e X : (B ,128)
|
| 88 |
+
# if len(X.shape) == 2:
|
| 89 |
+
# X = X
|
| 90 |
+
|
| 91 |
+
# some dimension
|
| 92 |
+
dk_sqrt = int(np.sqrt(self.d_k))
|
| 93 |
+
query = self.W_dict['Wq'](X).squeeze(2)
|
| 94 |
+
keys = self.W_dict['Wk'](X).squeeze(2) # (B, 128) -> (B ,64)
|
| 95 |
+
|
| 96 |
+
# dot product similarity is used here , which is implemented by `nn.Linear`
|
| 97 |
+
sim_M =self.W_dict['Wq'](keys) /dk_sqrt # (B,128,64) * (B,64,128) -> (B, 128, 128)
|
| 98 |
+
attention = torch.softmax(sim_M,dim=-1)
|
| 99 |
+
# result
|
| 100 |
+
result = torch.mul(attention,X) # (B, 128) * (B, 128) -> B*128
|
| 101 |
+
|
| 102 |
+
return result
|
model/src/mrl_te_optimization/models/__pycache__/Backbone.cpython-310.pyc
ADDED
|
Binary file (23.7 kB). View file
|
|
|
model/src/mrl_te_optimization/models/__pycache__/Backbone.cpython-311.pyc
ADDED
|
Binary file (44.1 kB). View file
|
|
|
model/src/mrl_te_optimization/models/bucket_sampler.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import numpy as np
|
| 3 |
+
import pandas as pd
|
| 4 |
+
from torch.utils.data.sampler import Sampler,BatchSampler,SubsetRandomSampler
|
| 5 |
+
|
| 6 |
+
class Basic_sampler(Sampler):
|
| 7 |
+
def __init__(self, data):
|
| 8 |
+
super().__init__(data)
|
| 9 |
+
self.data= data
|
| 10 |
+
|
| 11 |
+
def __len__(self):
|
| 12 |
+
return self.data.shape[0]
|
| 13 |
+
|
| 14 |
+
def __iter__(self):
|
| 15 |
+
return (i for i in range(self.data.shape[0]))
|
| 16 |
+
|
| 17 |
+
class sort_sampler(Sampler):
|
| 18 |
+
def __init__(self, data, sort_key="utr_len"):
|
| 19 |
+
super().__init__(data)
|
| 20 |
+
self.data = data
|
| 21 |
+
self.sort_key = sort_key
|
| 22 |
+
zip_ = [(i, seq_len) for i, seq_len in enumerate(data[sort_key].values)]
|
| 23 |
+
zip_ = sorted(zip_, key=lambda r: r[1])
|
| 24 |
+
self.sorted_indexes = [item[0] for item in zip_]
|
| 25 |
+
|
| 26 |
+
def __iter__(self):
|
| 27 |
+
return iter(self.sorted_indexes)
|
| 28 |
+
|
| 29 |
+
def __len__(self):
|
| 30 |
+
return len(self.data)
|
| 31 |
+
|
| 32 |
+
class Bucket_Sampler(BatchSampler):
|
| 33 |
+
""" `BucketBatchSampler` toggles between `sampler` batches and sorted batches.
|
| 34 |
+
|
| 35 |
+
Typically, the `sampler` will be a `RandomSampler` allowing the user to toggle between
|
| 36 |
+
random batches and sorted batches. A larger `bucket_size_multiplier` is more sorted and vice
|
| 37 |
+
versa.
|
| 38 |
+
|
| 39 |
+
Background:
|
| 40 |
+
``BucketBatchSampler`` is similar to a ``BucketIterator`` found in popular libraries like
|
| 41 |
+
``AllenNLP`` and ``torchtext``. A ``BucketIterator`` pools together examples with a similar
|
| 42 |
+
size length to reduce the padding required for each batch while maintaining some noise
|
| 43 |
+
through bucketing.
|
| 44 |
+
|
| 45 |
+
**AllenNLP Implementation:**
|
| 46 |
+
https://github.com/allenai/allennlp/blob/master/allennlp/data/iterators/bucket_iterator.py
|
| 47 |
+
|
| 48 |
+
**torchtext Implementation:**
|
| 49 |
+
https://github.com/pytorch/text/blob/master/torchtext/data/iterator.py#L225
|
| 50 |
+
|
| 51 |
+
Args:
|
| 52 |
+
sampler (torch.data.utils.sampler.Sampler):
|
| 53 |
+
batch_size (int): Size of mini-batch.
|
| 54 |
+
drop_last (bool): If `True` the sampler will drop the last batch if its size would be less
|
| 55 |
+
than `batch_size`.
|
| 56 |
+
sort_key (callable, optional): Callable to specify a comparison key for sorting.
|
| 57 |
+
bucket_size_multiplier (int, optional): Buckets are of size
|
| 58 |
+
`batch_size * bucket_size_multiplier`.
|
| 59 |
+
|
| 60 |
+
Example:
|
| 61 |
+
>>> from torchnlp.random import set_seed
|
| 62 |
+
>>> set_seed(123)
|
| 63 |
+
>>>
|
| 64 |
+
>>> from torch.utils.data.sampler import SequentialSampler
|
| 65 |
+
>>> sampler = SequentialSampler(list(range(10)))
|
| 66 |
+
>>> list(BucketBatchSampler(sampler, batch_size=3, drop_last=False))
|
| 67 |
+
[[6, 7, 8], [0, 1, 2], [3, 4, 5], [9]]
|
| 68 |
+
>>> list(BucketBatchSampler(sampler, batch_size=3, drop_last=True))
|
| 69 |
+
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
|
| 70 |
+
"""
|
| 71 |
+
def __init__(self,
|
| 72 |
+
data,
|
| 73 |
+
batch_size,
|
| 74 |
+
drop_last=False,
|
| 75 |
+
sort_key='utr_len',
|
| 76 |
+
bucket_size_multiplier=100):
|
| 77 |
+
self.data = data
|
| 78 |
+
self.sampler = Basic_sampler(data)
|
| 79 |
+
super().__init__(self.sampler, batch_size, drop_last)
|
| 80 |
+
self.sort_key = sort_key
|
| 81 |
+
_bucket_size = batch_size * bucket_size_multiplier
|
| 82 |
+
if hasattr(self.sampler, "__len__"):
|
| 83 |
+
_bucket_size = min(_bucket_size, len(self.sampler))
|
| 84 |
+
self.bucket_sampler = BatchSampler(self.sampler, _bucket_size, False)
|
| 85 |
+
|
| 86 |
+
def __iter__(self):
|
| 87 |
+
for bucket in self.bucket_sampler:
|
| 88 |
+
sorted_sampler = sort_sampler(self.data.iloc[bucket], self.sort_key)
|
| 89 |
+
for batch in SubsetRandomSampler(
|
| 90 |
+
list(BatchSampler(sorted_sampler, self.batch_size, self.drop_last))):
|
| 91 |
+
yield [bucket[i] for i in batch]
|
| 92 |
+
|
| 93 |
+
def __len__(self):
|
| 94 |
+
if self.drop_last:
|
| 95 |
+
return len(self.sampler) // self.batch_size
|
| 96 |
+
else:
|
| 97 |
+
return np.ceil(len(self.sampler) / self.batch_size)
|
| 98 |
+
|
| 99 |
+
|
model/src/mrl_te_optimization/models/log_and_save.py
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
import logging
|
| 4 |
+
import re
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import numpy as np
|
| 7 |
+
from matplotlib import pyplot as plt
|
| 8 |
+
import copy
|
| 9 |
+
|
| 10 |
+
def snapshot(dir_path, run_name, state,logger):
|
| 11 |
+
snapshot_file = os.path.join(dir_path,
|
| 12 |
+
run_name + '-model_best.pth')
|
| 13 |
+
# torch.save can save any object
|
| 14 |
+
# dict type object in our cases
|
| 15 |
+
torch.save(state, snapshot_file)
|
| 16 |
+
logger.info("Snapshot saved to {}\n".format(snapshot_file))
|
| 17 |
+
|
| 18 |
+
class Log_parser(object):
|
| 19 |
+
def __init__(self,log_path,val_split_line=False,use_line_as_valtest=1):
|
| 20 |
+
# -------- read --------
|
| 21 |
+
self.val_split_line = val_split_line
|
| 22 |
+
self.use_line_as_valtest = use_line_as_valtest
|
| 23 |
+
if os.path.exists(log_path):
|
| 24 |
+
with open(log_path,'r') as f:
|
| 25 |
+
log_file = f.readlines()
|
| 26 |
+
f.close()
|
| 27 |
+
# stripping
|
| 28 |
+
log_file = np.array([line.strip() for line in log_file])
|
| 29 |
+
else:
|
| 30 |
+
print('log path error !')
|
| 31 |
+
self.log_file = log_file
|
| 32 |
+
|
| 33 |
+
# self.possible_metric = ['LOSS','lr','Avg_ACC','teaching_rate','TOTAL','KLD','MSE','M_N','CrossEntropy','chimerla_weight','Total','TE','Loop','Match','MAE','RMSE','RL_loss','Recons_loss','Motif_loss','RL_Acc','Recons_Acc','Motif_Acc','Acc','Mean_Total', 'DTP_wt_RL','DTP_wt_Recons','DTP_wt_Motif']
|
| 34 |
+
|
| 35 |
+
# -------- basic matcher --------
|
| 36 |
+
self.epoch_line_matcher = r"\s.* epoch (\d{1,4}).*"
|
| 37 |
+
self.start_val_line_matcher = r"\s*.* start validation .*\s*"
|
| 38 |
+
self.match_logging_time = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} -"
|
| 39 |
+
self.match_percentage = r"\s*\d{1,6} /\s*\d{1,6}\s*\((\d|\.){,6}%\):"
|
| 40 |
+
|
| 41 |
+
self.match_sub_verbose = lambda x : r"\s*%s:\s*(?P<%s>(-|\d|\.|e|){,40})"%(x,x)
|
| 42 |
+
|
| 43 |
+
# -------- high level matcher --------
|
| 44 |
+
self.train_verbose_finder = self.match_logging_time + self.match_percentage
|
| 45 |
+
|
| 46 |
+
# --------- get output DF ---------
|
| 47 |
+
self.extract_training_verbose_data()
|
| 48 |
+
self.extract_val_verbose_data()
|
| 49 |
+
|
| 50 |
+
def lines_to_json(self, line, sett):
|
| 51 |
+
remove_time = line.split('%):')[1].split() if sett=='train' else line.split(' - \t ')[1].split()
|
| 52 |
+
line_json = {metrics.split(':')[0]:metrics.split(':')[1] for metrics in remove_time}
|
| 53 |
+
return line_json
|
| 54 |
+
|
| 55 |
+
def lines_matching(self,matcher):
|
| 56 |
+
"""
|
| 57 |
+
return lines that can match certain syntax
|
| 58 |
+
"""
|
| 59 |
+
return [line for line in self.log_file if re.match(matcher,line) is not None]
|
| 60 |
+
|
| 61 |
+
def position_matching(self,matcher):
|
| 62 |
+
"""
|
| 63 |
+
return position of the line that can match certain syntax
|
| 64 |
+
"""
|
| 65 |
+
return [i for i,line in enumerate(self.log_file) if re.match(matcher,line) is not None]
|
| 66 |
+
|
| 67 |
+
# def get_metrics_order(self):
|
| 68 |
+
# """
|
| 69 |
+
# get train verbose line and define train_verbose_matcher automatically
|
| 70 |
+
# """
|
| 71 |
+
# # find all the train verbose lines
|
| 72 |
+
|
| 73 |
+
# test_t_v = self.train_verbose_lines[0] # a testing train verbose
|
| 74 |
+
|
| 75 |
+
# # using the esting trainverbose to determine metric order
|
| 76 |
+
# # train_metric = np.array([metric for metric in self.possible_metric if metric in test_t_v])
|
| 77 |
+
# # train_metric = self.check_dup_metric(train_metric,test_t_v)
|
| 78 |
+
|
| 79 |
+
# # train_metric_posi = np.array([test_t_v.index(metric) for metric in train_metric])
|
| 80 |
+
|
| 81 |
+
# # order = train_metric_posi.argsort()
|
| 82 |
+
# # self.train_metric = train_metric[order]
|
| 83 |
+
|
| 84 |
+
# # # ----|| automatically determine train verbose matcher ||----
|
| 85 |
+
# # self.train_verbose_matcher = self.train_verbose_finder
|
| 86 |
+
# # for metric in self.train_metric:
|
| 87 |
+
# # self.train_verbose_matcher += self.match_sub_verbose(metric)
|
| 88 |
+
|
| 89 |
+
# # def check_dup_metric(self,train_metric,test_t_v):
|
| 90 |
+
# # """
|
| 91 |
+
# # to deal with the problem of `MSE` and `RMSE`
|
| 92 |
+
# # """
|
| 93 |
+
# # train_metric = list(train_metric)
|
| 94 |
+
# # if ("MSE" in train_metric) & ("RMSE" in train_metric):
|
| 95 |
+
# # if test_t_v.index('MSE') == test_t_v.index('RMSE')+1:
|
| 96 |
+
# # train_metric.remove('MSE')
|
| 97 |
+
# # return np.array(train_metric)
|
| 98 |
+
|
| 99 |
+
def extract_training_verbose_data(self):
|
| 100 |
+
"""
|
| 101 |
+
regular expression to match the printed metric during training and save to pd.DataFrame
|
| 102 |
+
"""
|
| 103 |
+
self.train_verbose_lines = self.lines_matching(self.train_verbose_finder)
|
| 104 |
+
|
| 105 |
+
self.train_verbose_dict = [self.lines_to_json(line,'train') for line in self.train_verbose_lines]
|
| 106 |
+
|
| 107 |
+
self.train_metric = list(self.train_verbose_dict[0].keys())
|
| 108 |
+
|
| 109 |
+
self.train_verbose_DF = pd.json_normalize(self.train_verbose_dict).astype(float)
|
| 110 |
+
|
| 111 |
+
# return self.train_verbose_DF
|
| 112 |
+
|
| 113 |
+
def extract_val_verbose_data(self):
|
| 114 |
+
"""
|
| 115 |
+
regular expression to match the printed metric during training and save to pd.DataFrame
|
| 116 |
+
"""
|
| 117 |
+
self.start_val_posi = self.position_matching(self.start_val_line_matcher)
|
| 118 |
+
val_verbose_posi = np.array(self.start_val_posi) +1 # observe from log
|
| 119 |
+
self.val_verbose_posi = val_verbose_posi[val_verbose_posi < len(self.log_file)]
|
| 120 |
+
self.val_verbose_lines = self.log_file[self.val_verbose_posi]
|
| 121 |
+
if self.val_split_line:
|
| 122 |
+
self.val_verbose_lines = ["\t".join(self.log_file[[posi,posi+1,posi+2,posi+3,posi+4]]) for posi in self.val_verbose_posi]
|
| 123 |
+
|
| 124 |
+
# test_v_v = self.val_verbose_lines[self.use_line_as_valtest]
|
| 125 |
+
|
| 126 |
+
# using the esting trainverbose to determine metric order
|
| 127 |
+
# val_metric = np.array([metric for metric in self.possible_metric if metric in test_v_v])
|
| 128 |
+
# val_metric = self.check_dup_metric(val_metric,test_v_v)
|
| 129 |
+
# val_metric_posi = np.array([test_v_v.index(metric) for metric in val_metric])
|
| 130 |
+
# order = val_metric_posi.argsort() # sort
|
| 131 |
+
# self.val_metric = val_metric[order]
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
# # ----|| automatically determine val verbose matcher ||----
|
| 135 |
+
# self.val_verbose_matcher = self.match_logging_time
|
| 136 |
+
|
| 137 |
+
# if re.match(self.match_logging_time + self.match_percentage,test_v_v) is not None:
|
| 138 |
+
# self.val_verbose_matcher += self.match_percentage # detect whether validation set also get percentage info
|
| 139 |
+
|
| 140 |
+
# for metric in self.val_metric:
|
| 141 |
+
# self.val_verbose_matcher += self.match_sub_verbose(metric)
|
| 142 |
+
|
| 143 |
+
self.val_verbose_dict = [self.lines_to_json(line, 'val') for line in self.val_verbose_lines]
|
| 144 |
+
self.val_metric = list(self.val_verbose_dict[0].keys())
|
| 145 |
+
# np.array(
|
| 146 |
+
# [list(
|
| 147 |
+
# re.match(self.val_verbose_matcher,line).groupdict().values()
|
| 148 |
+
# ) for line in self.val_verbose_lines]
|
| 149 |
+
# ).astype(np.float64)
|
| 150 |
+
|
| 151 |
+
self.val_verbose_DF = pd.json_normalize(self.val_verbose_dict).astype(float)
|
| 152 |
+
|
| 153 |
+
# return self.val_verbose_DF
|
| 154 |
+
|
| 155 |
+
def plot_val_metric(self,fig=None,dataset='val'):
|
| 156 |
+
DF = self.val_verbose_DF if dataset == 'val' else self.train_verbose_DF
|
| 157 |
+
metrics = self.val_metric if dataset == 'val' else self.train_metric
|
| 158 |
+
n = len(metrics)
|
| 159 |
+
|
| 160 |
+
if fig is None:
|
| 161 |
+
fig = plt.figure(figsize=(18,5*np.ceil(n/3)))
|
| 162 |
+
if n <=3:
|
| 163 |
+
axs = fig.subplots(1,n)
|
| 164 |
+
for i in range(n):
|
| 165 |
+
axs[i].plot(DF[metrics[i]].values)
|
| 166 |
+
axs[i].set_title(dataset.capitalize()+" "+metrics[i]) # TRAIN or VAL
|
| 167 |
+
else:
|
| 168 |
+
axs = fig.add_subplot(n//3+1,n,1+i)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def plot_a_exp_set(log_list,log_name_ls,dataset='val',fig=None,layout=None,check_time=10,start_from=0,mean_of_train=None,define_order=None,esubset=None, cycle_train=False,**kwargs):
|
| 172 |
+
all_metric = [logg.__getattribute__(dataset+"_metric") for logg in log_list]
|
| 173 |
+
share_metric = [all_metric[0]]
|
| 174 |
+
for logg_metric in all_metric[1:]:
|
| 175 |
+
share_metric = np.intersect1d(share_metric,logg_metric)
|
| 176 |
+
if define_order is not None:
|
| 177 |
+
assert set(define_order) == set(share_metric)
|
| 178 |
+
|
| 179 |
+
n = len(share_metric) + 1 # val or train
|
| 180 |
+
fig = plt.figure(figsize=(20,5)) if fig is None else fig
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
if layout is None:
|
| 184 |
+
axs = fig.subplots(1,n);
|
| 185 |
+
else:
|
| 186 |
+
row,column = layout
|
| 187 |
+
axs = fig.subplots(row,column).flatten()
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
for i,metric in enumerate(share_metric):
|
| 191 |
+
# layout
|
| 192 |
+
|
| 193 |
+
ax = axs[i]
|
| 194 |
+
for st,log in enumerate(log_list):
|
| 195 |
+
DF = log.__getattribute__(dataset+"_verbose_DF")
|
| 196 |
+
|
| 197 |
+
if (dataset == 'train') & (type(mean_of_train)==int):
|
| 198 |
+
DF = mean_of(mean_of_train,DF)
|
| 199 |
+
elif (dataset == 'train') & (type(esubset)==slice):
|
| 200 |
+
DF = subset_of(esubset,DF)
|
| 201 |
+
X = np.arange(DF.shape[0])*check_time if dataset == 'val' else np.arange(DF.shape[0])
|
| 202 |
+
ax.plot(X[start_from:],DF[metric].values[start_from:],**kwargs)
|
| 203 |
+
ax.set_title(" ".join([dataset.capitalize(),metric]))
|
| 204 |
+
for st,log in enumerate(log_list):
|
| 205 |
+
axs[-1].plot(0,0,label=log_name_ls[st])
|
| 206 |
+
axs[-1].axis('off')
|
| 207 |
+
axs[-1].legend()
|
| 208 |
+
|
| 209 |
+
def plot_cycle_exp_set(log_ls,log_name,dataset='val',**kwargs):
|
| 210 |
+
interval = 2 if dataset=='val' else 6
|
| 211 |
+
new_log_ls = []
|
| 212 |
+
new_log_name = []
|
| 213 |
+
for i in range(len(log_ls)):
|
| 214 |
+
log = log_ls[i]
|
| 215 |
+
DF = log.__getattribute__(dataset+"_verbose_DF")
|
| 216 |
+
ds1_index = [i for i in range(DF.shape[0]) if i//interval%2 ==0]
|
| 217 |
+
ds2_index = [i for i in range(DF.shape[0]) if i//interval%2 ==1]
|
| 218 |
+
DF1 = DF.iloc[ds1_index]
|
| 219 |
+
DF2 = DF.iloc[ds2_index]
|
| 220 |
+
log1 = copy.deepcopy(log)
|
| 221 |
+
log2 = copy.deepcopy(log)
|
| 222 |
+
|
| 223 |
+
log1.__setattr__(dataset+'_verbose_DF', DF1)
|
| 224 |
+
log2.__setattr__(dataset+'_verbose_DF', DF2)
|
| 225 |
+
|
| 226 |
+
new_log_ls.append(log1)
|
| 227 |
+
new_log_ls.append(log2)
|
| 228 |
+
|
| 229 |
+
new_log_name.append(log_name[i]+"_ds1")
|
| 230 |
+
new_log_name.append(log_name[i]+"_ds2")
|
| 231 |
+
|
| 232 |
+
plot_a_exp_set(new_log_ls, new_log_name, **kwargs)
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
def subset_of(x,DF):
|
| 236 |
+
|
| 237 |
+
values = DF.values
|
| 238 |
+
mean_ls = []
|
| 239 |
+
|
| 240 |
+
for i in range(0,values.shape[0],x.stop):
|
| 241 |
+
# x : slice , x.stop , the slice window of the
|
| 242 |
+
mean_ls.append(values[i:i+x.stop][x])
|
| 243 |
+
|
| 244 |
+
mean_ls = np.concatenate(mean_ls,axis=0)
|
| 245 |
+
mean_DF = pd.DataFrame(mean_ls,columns=DF.columns)
|
| 246 |
+
|
| 247 |
+
return mean_DF
|
| 248 |
+
|
| 249 |
+
def mean_of(x,DF):
|
| 250 |
+
|
| 251 |
+
values = DF.values
|
| 252 |
+
mean_ls = []
|
| 253 |
+
|
| 254 |
+
for i in range(0,values.shape[0],x):
|
| 255 |
+
|
| 256 |
+
mean_ls.append(np.mean(values[i:i+x,:],axis=0))
|
| 257 |
+
|
| 258 |
+
mean_ls = np.stack(mean_ls)
|
| 259 |
+
mean_DF = pd.DataFrame(mean_ls,columns=DF.columns)
|
| 260 |
+
|
| 261 |
+
return mean_DF
|
| 262 |
+
|
| 263 |
+
def read_log_of_a_dir(log_dir):
|
| 264 |
+
"""
|
| 265 |
+
...log_dir : abs path of log dir
|
| 266 |
+
"""
|
| 267 |
+
file_ls = [file for file in os.listdir(log_dir) if ".log" in file]
|
| 268 |
+
log_path = [os.path.join(log_dir,file) for file in file_ls]
|
| 269 |
+
log_name = [file.replace('.log','') for file in file_ls]
|
| 270 |
+
log_ls = [Log_parser(file) for file in log_path]
|
| 271 |
+
return log_ls,log_name
|
model/src/mrl_te_optimization/models/loss.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
from torch import nn
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def softmax(x):
|
| 8 |
+
"""
|
| 9 |
+
one dimensional softmax designed for numpy array
|
| 10 |
+
"""
|
| 11 |
+
e_x = np.exp(x)
|
| 12 |
+
out = e_x / e_x.sum()
|
| 13 |
+
return out
|
| 14 |
+
|
| 15 |
+
class Dynamic_Weight_Averaging():
|
| 16 |
+
def __init__(self,tasks,tau,init_weight):
|
| 17 |
+
"""
|
| 18 |
+
Dynamic Weight Averaging implementation
|
| 19 |
+
"""
|
| 20 |
+
# number of tasks
|
| 21 |
+
self.N = len(tasks)
|
| 22 |
+
# self.loss_list = np.array([loss_dict[t+'_loss'].detach().cpu().item() for t in tasks])
|
| 23 |
+
self.step = 0
|
| 24 |
+
self.omega = np.array([init_weight]*self.N ) # the weight , \omega_i(t)
|
| 25 |
+
self.tau = tau # † : a value to adjust the soft-max
|
| 26 |
+
|
| 27 |
+
def _magnitude_adjust(self):
|
| 28 |
+
"""
|
| 29 |
+
automatic adjustment of loss magnitude
|
| 30 |
+
"""
|
| 31 |
+
self.relative_magnitude = self.loss_list.min() / self.loss_list
|
| 32 |
+
|
| 33 |
+
def _update(self,loss_dict):
|
| 34 |
+
# update r with L_i(t-1)
|
| 35 |
+
self.step += 1
|
| 36 |
+
if self.step < 2:
|
| 37 |
+
self.loss_list = np.array([loss_dict[t+'_loss'].detach().cpu().item() for t in self.tasks])
|
| 38 |
+
return self.init_weight
|
| 39 |
+
else:
|
| 40 |
+
self._magnitude_adjust()
|
| 41 |
+
last_loss = self.loss_list
|
| 42 |
+
self.loss_list = np.array([loss_dict[t+'_loss'].detach().cpu().item() for t in self.tasks])
|
| 43 |
+
# computing DWA
|
| 44 |
+
r_t = np.divide(self.loss_list,last_loss) / self.tau
|
| 45 |
+
self.omega = self.N * softmax(r_t)
|
| 46 |
+
weight_t = np.multiply(self.relative_magnitude,self.omega)
|
| 47 |
+
return {self.tasks[i]:weight_t[i] for i in range(len(self.tasks))}
|
| 48 |
+
|
| 49 |
+
class Dynamic_Task_Priority(object):
|
| 50 |
+
def __init__(self,tasks,gamma,init_weight):
|
| 51 |
+
"""
|
| 52 |
+
Dynamic Task Priority (DTP) wish to weight more on tasks with lower KPI
|
| 53 |
+
In our cases, we take accuracy as the KPI
|
| 54 |
+
"""
|
| 55 |
+
self.gamma = np.array([gamma[t] for t in tasks]) if type(gamma) == dict else gamma # an adjustment param
|
| 56 |
+
self.tasks = tasks
|
| 57 |
+
# self.kappa = [loss_dict[t+'_Acc'] for t in tasks]
|
| 58 |
+
self.omega = init_weight
|
| 59 |
+
self.init_weight = init_weight
|
| 60 |
+
self.step = 0
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def _magnitude_adjust(self):
|
| 64 |
+
"""
|
| 65 |
+
automatic adjustment of loss magnitude
|
| 66 |
+
"""
|
| 67 |
+
# TODO : test this effectiveness
|
| 68 |
+
self.relative_magnitude = self.kappa.min() / (self.kappa+1e-8)
|
| 69 |
+
if np.any(self.kappa==1):
|
| 70 |
+
self.kappa[np.where(self.kappa==1)[0]] -= 1e-8
|
| 71 |
+
|
| 72 |
+
def _update(self,loss_dict):
|
| 73 |
+
"""
|
| 74 |
+
weight is updated like belowing
|
| 75 |
+
`math` : w_i(t) = -(1-\kappa_i(t))^{\gamma_i} log \kappa_i(t)
|
| 76 |
+
"""
|
| 77 |
+
self.step += 1
|
| 78 |
+
self.kappa = np.array([loss_dict[t+'_Acc'] for t in self.tasks])
|
| 79 |
+
self._magnitude_adjust()
|
| 80 |
+
self.omega = -1 * np.multiply(np.power(1 - self.kappa,self.gamma),np.log(self.kappa+1e-8))
|
| 81 |
+
|
| 82 |
+
if self.step < 2:
|
| 83 |
+
return self.init_weight
|
| 84 |
+
else:
|
| 85 |
+
weight_t = np.multiply(self.relative_magnitude,self.omega)
|
| 86 |
+
return {self.tasks[i]:weight_t[i] for i in range(len(self.tasks))}
|
model/src/mrl_te_optimization/models/max_activation_patch.py
ADDED
|
@@ -0,0 +1,795 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import re
|
| 4 |
+
sys.path.append(os.path.dirname(__file__))
|
| 5 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 6 |
+
import utils
|
| 7 |
+
import copy
|
| 8 |
+
import torch
|
| 9 |
+
import train_val
|
| 10 |
+
import reader
|
| 11 |
+
import logomaker
|
| 12 |
+
from torch import nn
|
| 13 |
+
import numpy as np
|
| 14 |
+
import pandas as pd
|
| 15 |
+
import seaborn as sns
|
| 16 |
+
from tqdm.auto import tqdm
|
| 17 |
+
from importlib import reload
|
| 18 |
+
from scipy import stats
|
| 19 |
+
from matplotlib import pyplot as plt
|
| 20 |
+
from sklearn import cluster
|
| 21 |
+
from sklearn.manifold import TSNE
|
| 22 |
+
import ruptures as rpt
|
| 23 |
+
from popen import Auto_popen
|
| 24 |
+
|
| 25 |
+
tensor_2_numpy = lambda x: x.detach().cpu().numpy()
|
| 26 |
+
|
| 27 |
+
class Maximum_activation_patch(object):
|
| 28 |
+
def __init__(self, popen, which_layer, n_patch=9, kfold_index=None, device_string='cpu'):
|
| 29 |
+
self.popen = popen
|
| 30 |
+
self.layer = which_layer
|
| 31 |
+
self.popen.cuda_id = torch.device("cuda:%s"%device_string) if device_string.isdigit() else torch.device('cpu')
|
| 32 |
+
self.n_patch = n_patch
|
| 33 |
+
self.kfold_index = kfold_index
|
| 34 |
+
self.total_stride = np.product(popen.stride[:self.layer])
|
| 35 |
+
self.compute_reception_field()
|
| 36 |
+
self.compute_virtual_pad()
|
| 37 |
+
|
| 38 |
+
def load_indexed_dataloader(self,task):
|
| 39 |
+
# True or 'train_val'
|
| 40 |
+
assert (self.popen.kfold_cv!=False) == (self.kfold_index != None), \
|
| 41 |
+
"kfold CV should match with kfold index"
|
| 42 |
+
|
| 43 |
+
self.popen.kfold_index = self.kfold_index
|
| 44 |
+
self.popen.shuffle = False
|
| 45 |
+
self.popen.pad_to = 57 if self.popen.cycle_set==None else 105
|
| 46 |
+
|
| 47 |
+
tmp_popen = copy.copy(self.popen)
|
| 48 |
+
if self.popen.cycle_set != None:
|
| 49 |
+
base_path = copy.copy(self.popen.split_like)
|
| 50 |
+
base_csv = copy.copy(self.popen.csv_path)
|
| 51 |
+
# base_csv = "/mnt/sina/run/ml/gan/motif/MTtrans/test.csv"
|
| 52 |
+
|
| 53 |
+
if base_path is not None:
|
| 54 |
+
assert task != None , "task is not defined !"
|
| 55 |
+
tmp_popen.split_like = [path.replace('cycle', task) for path in base_path]
|
| 56 |
+
else:
|
| 57 |
+
tmp_popen.csv_path = base_csv.replace('cycle', task)
|
| 58 |
+
# tmp_popen.csv_path = "/mnt/sina/run/ml/gan/motif/MTtrans/test.csv"
|
| 59 |
+
|
| 60 |
+
# tmp_popen.csv_path = "/mnt/sina/run/ml/gan/motif/MTtrans/test.csv"
|
| 61 |
+
# base_csv = "/mnt/sina/run/ml/gan/motif/MTtrans/test.csv"
|
| 62 |
+
|
| 63 |
+
return reader.get_dataloader(tmp_popen)
|
| 64 |
+
|
| 65 |
+
def load_model(self):
|
| 66 |
+
if self.kfold_index is not None:
|
| 67 |
+
base_pth = self.popen.vae_log_path
|
| 68 |
+
self.popen.vae_log_path = base_pth.replace(".pth","_cv%s.pth"%self.kfold_index)
|
| 69 |
+
|
| 70 |
+
model = utils.load_model(self.popen, None)
|
| 71 |
+
if self.kfold_index is not None:
|
| 72 |
+
self.popen.vae_log_path = base_pth
|
| 73 |
+
return model
|
| 74 |
+
|
| 75 |
+
def get_filter_param(self, model):
|
| 76 |
+
Conv_layer = model.soft_share.encoder[self.layer-1]
|
| 77 |
+
|
| 78 |
+
return tensor_2_numpy( next(Conv_layer[0][0].parameters()) )
|
| 79 |
+
|
| 80 |
+
def loading(self,task, which_set):
|
| 81 |
+
model = self.load_model().to(self.popen.cuda_id)
|
| 82 |
+
dataloader = self.load_indexed_dataloader(task)[which_set]
|
| 83 |
+
self.df = dataloader.dataset.df
|
| 84 |
+
return model, dataloader
|
| 85 |
+
|
| 86 |
+
@torch.no_grad()
|
| 87 |
+
def cumulative_rl_decision(self, task=None,which_set=0, extra_loader=None):
|
| 88 |
+
"""
|
| 89 |
+
take out the memory h_i of each position and pass to output layer
|
| 90 |
+
Arg:
|
| 91 |
+
task : str
|
| 92 |
+
which_set : int, 0 : training set, 1 : val set, 2 : test set
|
| 93 |
+
"""
|
| 94 |
+
model, dataloader= self.loading(task, which_set)
|
| 95 |
+
model.eval()
|
| 96 |
+
|
| 97 |
+
Y_ls = []
|
| 98 |
+
for Data in tqdm(dataloader):
|
| 99 |
+
# iter each batch
|
| 100 |
+
x,y = train_val.put_data_to_cuda(Data,self.popen,False)
|
| 101 |
+
x = torch.transpose(x, 1, 2)
|
| 102 |
+
y_pred = model.predict_each_position(x)
|
| 103 |
+
Y_ls.append( tensor_2_numpy(y_pred) )
|
| 104 |
+
Y_ay = np.concatenate(Y_ls, axis=0)
|
| 105 |
+
|
| 106 |
+
# release some cache
|
| 107 |
+
torch.cuda.empty_cache()
|
| 108 |
+
del model
|
| 109 |
+
return Y_ay.reshape(Y_ay.shape[0],-1)
|
| 110 |
+
|
| 111 |
+
def extract_feature_map(self, task=None, which_set=0, extra_loader=None):
|
| 112 |
+
"""
|
| 113 |
+
load trained model and unshuffled dataloader, make model forwarded
|
| 114 |
+
Arg:
|
| 115 |
+
task : str
|
| 116 |
+
which_set : int, 0 : training set, 1 : val set, 2 : test set
|
| 117 |
+
"""
|
| 118 |
+
model, dataloader= self.loading(task, which_set)
|
| 119 |
+
if extra_loader is not None:
|
| 120 |
+
dataloader = extra_loader
|
| 121 |
+
self.df = extra_loader.dataset.df
|
| 122 |
+
|
| 123 |
+
feature_map = []
|
| 124 |
+
X_ls = []
|
| 125 |
+
Y_ls = []
|
| 126 |
+
# print(type(dataloader))
|
| 127 |
+
model.eval()
|
| 128 |
+
with torch.no_grad():
|
| 129 |
+
print(len(dataloader))
|
| 130 |
+
for Data in tqdm(dataloader):
|
| 131 |
+
# print(Data)
|
| 132 |
+
# print(Data[0].shape)
|
| 133 |
+
# print(Data[1].shape)
|
| 134 |
+
# iter each batch
|
| 135 |
+
x,y = train_val.put_data_to_cuda(Data,self.popen,False)
|
| 136 |
+
# print(x)
|
| 137 |
+
# print(np.shape(Data[0].numpy()))
|
| 138 |
+
shape = np.shape(Data[0].numpy()[0])
|
| 139 |
+
xt = torch.tensor(np.reshape(Data[0].numpy()[0],(1,shape[0],shape[1])),dtype=torch.float64)
|
| 140 |
+
# print(type(xt))
|
| 141 |
+
# print(type(x))
|
| 142 |
+
xt = xt.float()
|
| 143 |
+
# xt = torch.transpose(xt, 1, 2)
|
| 144 |
+
# print(model.forward(xt))
|
| 145 |
+
# print(model.predict_each_position(x))
|
| 146 |
+
|
| 147 |
+
# print(type(y))
|
| 148 |
+
# print(x.shape)
|
| 149 |
+
x = torch.transpose(x, 1, 2)
|
| 150 |
+
# X_ls.append(x.numpy())
|
| 151 |
+
Y_ls.append( tensor_2_numpy(y))
|
| 152 |
+
|
| 153 |
+
for layer in model.soft_share.encoder[:self.layer]:
|
| 154 |
+
out = layer(x)
|
| 155 |
+
x = out
|
| 156 |
+
feature_map.append( tensor_2_numpy(out))
|
| 157 |
+
|
| 158 |
+
torch.cuda.empty_cache()
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
feature_map_l = np.concatenate( feature_map, axis=0)
|
| 162 |
+
|
| 163 |
+
# self.X_ls = np.concatenate(X_ls, axis=0)
|
| 164 |
+
self.Y_ls = np.concatenate(Y_ls, axis=0)
|
| 165 |
+
|
| 166 |
+
print("activation map of layer |%d|"%self.layer,feature_map_l.shape)
|
| 167 |
+
# print(self.X_ls.shape)
|
| 168 |
+
print("Y : ",self.Y_ls.shape)
|
| 169 |
+
self.feature_map = feature_map_l
|
| 170 |
+
|
| 171 |
+
self.filters = self.get_filter_param(model)
|
| 172 |
+
|
| 173 |
+
del model
|
| 174 |
+
|
| 175 |
+
return feature_map_l
|
| 176 |
+
|
| 177 |
+
def compute_reception_field(self):
|
| 178 |
+
r = 1
|
| 179 |
+
strides = self.popen.stride[:self.layer][::-1]
|
| 180 |
+
|
| 181 |
+
for i,s in enumerate(strides):
|
| 182 |
+
r = s*(r-1) + self.popen.kernel_size
|
| 183 |
+
|
| 184 |
+
self.r = r
|
| 185 |
+
self.strides = strides
|
| 186 |
+
print('the reception filed is ', r)
|
| 187 |
+
|
| 188 |
+
def compute_virtual_pad(self):
|
| 189 |
+
v = []
|
| 190 |
+
pd = self.popen.padding_ls[:self.layer]
|
| 191 |
+
|
| 192 |
+
for i,p in enumerate(pd):
|
| 193 |
+
v.append(p*np.product(self.popen.stride[:len(pd)-i-1]))
|
| 194 |
+
|
| 195 |
+
self.virtual_pad = np.sum(v)
|
| 196 |
+
print('the virtual pad is', self.virtual_pad)
|
| 197 |
+
|
| 198 |
+
def retrieve_input_site(self, high_layer_site):
|
| 199 |
+
"""pad ?"""
|
| 200 |
+
|
| 201 |
+
virtual_start = high_layer_site*self.total_stride - self.virtual_pad
|
| 202 |
+
start = max(0, virtual_start)
|
| 203 |
+
|
| 204 |
+
end = virtual_start + self.r
|
| 205 |
+
return max(0,int(start)), int(end)
|
| 206 |
+
|
| 207 |
+
def detect_changepoint(self,time_series):
|
| 208 |
+
bkpt = rpt.KernelCPD(kernel="linear", min_size=1).fit_predict(time_series, n_bkps=1)[0]
|
| 209 |
+
return bkpt - 1
|
| 210 |
+
|
| 211 |
+
def retrieve_featmap_at_changepoint(self, featmap, rl_chain, threshold=1, direction='less', detect_region=None):
|
| 212 |
+
"""
|
| 213 |
+
Using the change point of rl series, to retrieve feature map at the same position
|
| 214 |
+
e.g. : to find negative change point threshold=-1, direction='less'
|
| 215 |
+
e.g. : to find positive change point threshold=0.5, direction='greater'
|
| 216 |
+
|
| 217 |
+
featmap : np.ndarray, (n_sample, n_channel, n_position)
|
| 218 |
+
rl_chain : np.ndarray, (n_sample, n_position)
|
| 219 |
+
|
| 220 |
+
threshold : the threshold define the rl after change point minus that ahead the point that are considered
|
| 221 |
+
direction : the direction of changes
|
| 222 |
+
detect_region : list of slice [], which region of the rl chain is used to detect change point, default None (full sequence is considered)
|
| 223 |
+
"""
|
| 224 |
+
# take out the negative break point
|
| 225 |
+
|
| 226 |
+
if direction == 'less':
|
| 227 |
+
condition = lambda x1, x2 : x1 - x2 < threshold
|
| 228 |
+
elif direction == 'greater':
|
| 229 |
+
condition = lambda x1, x2 : x1 - x2 > threshold
|
| 230 |
+
|
| 231 |
+
if detect_region is None:
|
| 232 |
+
detect_region = [slice(0, None)] * rl_chain.shape[0]
|
| 233 |
+
|
| 234 |
+
change_point_act = []
|
| 235 |
+
for i, trend in enumerate(rl_chain):
|
| 236 |
+
region = detect_region[i]
|
| 237 |
+
bkpt= self.detect_changepoint(trend[region]) + region.start
|
| 238 |
+
|
| 239 |
+
if condition(trend[bkpt+1] , trend[bkpt]):
|
| 240 |
+
activation_vec = featmap[i, :, bkpt+1]
|
| 241 |
+
change_point_act.append(activation_vec)
|
| 242 |
+
|
| 243 |
+
chagnepoint_map = np.asarray(change_point_act)
|
| 244 |
+
return chagnepoint_map
|
| 245 |
+
|
| 246 |
+
def locate_MA_seq(self, channel, feature_map=None):
|
| 247 |
+
"""
|
| 248 |
+
|
| 249 |
+
"""
|
| 250 |
+
if feature_map is None:
|
| 251 |
+
feature_map = self.feature_map
|
| 252 |
+
|
| 253 |
+
channel_feature = feature_map[:, channel,:]
|
| 254 |
+
F0_ay = channel_feature.max(axis=-1)
|
| 255 |
+
|
| 256 |
+
max_n_index = np.argpartition(F0_ay, -1*self.n_patch, axis=0)[-1*self.n_patch:]
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
# a patch of sequences
|
| 260 |
+
max_patch = self.df[self.popen.seq_col].values[max_n_index]
|
| 261 |
+
|
| 262 |
+
# find the location of maximally acitvated
|
| 263 |
+
Conv4_sites = np.argmax(channel_feature[max_n_index],axis=1)
|
| 264 |
+
|
| 265 |
+
mapped_input_sites = [self.retrieve_input_site(site) for site in Conv4_sites]
|
| 266 |
+
|
| 267 |
+
# the mapped region of the sequences
|
| 268 |
+
max_act_region = []
|
| 269 |
+
for utr, (start, end) in zip(max_patch, mapped_input_sites):
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
pad_gap = self.popen.pad_to - len(utr)
|
| 273 |
+
field = utr[max(0, start-pad_gap): end-pad_gap]
|
| 274 |
+
|
| 275 |
+
max_act_region.append(field)
|
| 276 |
+
|
| 277 |
+
# print(mapped_input_sites)
|
| 278 |
+
|
| 279 |
+
full_field = [len(field)==self.r for field in max_act_region]
|
| 280 |
+
|
| 281 |
+
return np.array(max_act_region)[full_field], max_n_index[full_field], np.array(mapped_input_sites)[full_field]
|
| 282 |
+
|
| 283 |
+
def sequence_to_matrix(self, max_act_region, weight=None, transformation='counts'):
|
| 284 |
+
|
| 285 |
+
assert np.all([seq != "" for seq in max_act_region])
|
| 286 |
+
|
| 287 |
+
max_len = max([len(seq) for seq in max_act_region])
|
| 288 |
+
|
| 289 |
+
M = np.zeros((max_len,4))
|
| 290 |
+
if weight is None:
|
| 291 |
+
weight = np.ones((self.n_patch,))
|
| 292 |
+
for seq, w in zip(max_act_region, weight):
|
| 293 |
+
oh_M = reader.one_hot(seq)*w
|
| 294 |
+
M += np.concatenate([np.zeros((max_len - len(seq),4)), oh_M],axis=0)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
seq_logo_df = pd.DataFrame(M, columns=['A', 'C', 'G', 'U'])
|
| 298 |
+
if transformation!='counts':
|
| 299 |
+
seq_logo_df = logomaker.transform_matrix(seq_logo_df, from_type='counts', to_type=transformation)
|
| 300 |
+
|
| 301 |
+
return seq_logo_df
|
| 302 |
+
|
| 303 |
+
def plot_sequence_logo(self, seq_logo_df, save_fig_path=None, ax=None):
|
| 304 |
+
"""
|
| 305 |
+
input : max_act_region ; list of str
|
| 306 |
+
"""
|
| 307 |
+
# plot
|
| 308 |
+
if ax is None:
|
| 309 |
+
fig = plt.figure(dpi=300)
|
| 310 |
+
ax = fig.gca()
|
| 311 |
+
MA_C = logomaker.Logo(seq_logo_df,ax=ax)
|
| 312 |
+
|
| 313 |
+
ax.spines['right'].set_visible(False)
|
| 314 |
+
ax.spines['top'].set_visible(False)
|
| 315 |
+
ax.spines['bottom'].set_visible(False)
|
| 316 |
+
|
| 317 |
+
# save
|
| 318 |
+
if save_fig_path is not None:
|
| 319 |
+
MA_C.fig.savefig(save_fig_path,transparent=True,dpi=600)
|
| 320 |
+
save_dir = os.path.dirname(save_fig_path)
|
| 321 |
+
|
| 322 |
+
try:
|
| 323 |
+
self.save_dir
|
| 324 |
+
except:
|
| 325 |
+
# which is the first time we save
|
| 326 |
+
self.save_dir = save_dir
|
| 327 |
+
print('fig saved to',self.save_dir)
|
| 328 |
+
plt.close(MA_C.fig)
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
def fast_logo(self, channel, feature_map=None, n_patch=None, transformation='information', save_fig_path=None, title=None,ax=None):
|
| 335 |
+
|
| 336 |
+
if n_patch is not None:
|
| 337 |
+
self.n_patch = n_patch
|
| 338 |
+
max_act_region, _, _ = self.locate_MA_seq(channel, feature_map)
|
| 339 |
+
M = self.sequence_to_matrix(max_act_region, transformation=transformation)
|
| 340 |
+
|
| 341 |
+
# print(max_act_region)
|
| 342 |
+
|
| 343 |
+
F0_ay, (spr,pr) = self.activation_density(channel, feature_map=feature_map, to_print=False, to_plot=False)
|
| 344 |
+
# print(np.shape(F0_ay))
|
| 345 |
+
# print(type(F0_ay))
|
| 346 |
+
|
| 347 |
+
self.plot_sequence_logo(M, save_fig_path=save_fig_path, ax=ax)
|
| 348 |
+
if ax is None:
|
| 349 |
+
ax=plt.gca()
|
| 350 |
+
if title is None:
|
| 351 |
+
title = "filter {} : $r =$ {}".format(channel, spr)
|
| 352 |
+
|
| 353 |
+
ax.set_title(title, fontsize=35)
|
| 354 |
+
return M, spr
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
def activation_density(self, channel, to_print=True, to_plot=True, feature_map=None, **kwargs):
|
| 358 |
+
if feature_map is None:
|
| 359 |
+
feature_map = self.feature_map
|
| 360 |
+
|
| 361 |
+
channel_feature = feature_map[:, channel,:]
|
| 362 |
+
F0_ay = channel_feature.max(axis=-1)
|
| 363 |
+
if to_plot:
|
| 364 |
+
sns.kdeplot(F0_ay, **kwargs);
|
| 365 |
+
if to_print:
|
| 366 |
+
print("num of max acti: %s"%np.sum(F0_ay==F0_ay.max()))
|
| 367 |
+
|
| 368 |
+
n_gtr = [np.sum(F0_ay > q) for q in np.quantile(F0_ay,[0.5,0.8,0.95])]
|
| 369 |
+
print("quantiles: 50% {} 80% {} 95% {}".format(*n_gtr))
|
| 370 |
+
|
| 371 |
+
spr = stats.spearmanr(F0_ay, self.Y_ls.flatten())
|
| 372 |
+
pr = stats.pearsonr(F0_ay, self.Y_ls.flatten())
|
| 373 |
+
return F0_ay, (round(spr[0],3),round(pr[0],3))
|
| 374 |
+
|
| 375 |
+
def within_patch_clustering(self, channel, n_clusters, n_patch=None , to_plot=True,**kwargs):
|
| 376 |
+
"""
|
| 377 |
+
return:
|
| 378 |
+
subclusters : list, list of patch (alignments)
|
| 379 |
+
"""
|
| 380 |
+
self.n_patch = n_patch
|
| 381 |
+
act_patch, _, _ = self.locate_MA_seq(channel)
|
| 382 |
+
flatten_seq = np.stack([reader.one_hot(seq).flatten() for seq in act_patch])
|
| 383 |
+
print("the shape of sequence matrix {}".format(flatten_seq.shape))
|
| 384 |
+
|
| 385 |
+
# clsutering
|
| 386 |
+
cluster_index = cluster.KMeans(n_clusters=n_clusters).fit_predict(flatten_seq)
|
| 387 |
+
# down
|
| 388 |
+
if to_plot:
|
| 389 |
+
tsne = TSNE(metric='cosine').fit(flatten_seq)
|
| 390 |
+
self.tsne=tsne
|
| 391 |
+
plt.figure(figsize=(6,5),dpi=150)
|
| 392 |
+
# sns.set_theme(style='ticks', palette='viridis')
|
| 393 |
+
scatter_args = {"palette":'viridis'}
|
| 394 |
+
scatter_args.update(kwargs)
|
| 395 |
+
sns.scatterplot(x=tsne.embedding_[:,0], y=tsne.embedding_[:,1],
|
| 396 |
+
hue=cluster_index, **scatter_args);
|
| 397 |
+
|
| 398 |
+
return act_patch, flatten_seq, cluster_index
|
| 399 |
+
|
| 400 |
+
def activation_overview(self, **kwargs):
|
| 401 |
+
channel_spearman = []
|
| 402 |
+
|
| 403 |
+
fig, ax = plt.subplots(1,1, figsize=(10,5), dpi=300)
|
| 404 |
+
ax.spines['top'].set_visible(False)
|
| 405 |
+
ax.spines['right'].set_visible(False)
|
| 406 |
+
|
| 407 |
+
n_channel = self.popen.channel_ls[self.layer]
|
| 408 |
+
for i in tqdm(range(n_channel)):
|
| 409 |
+
act, (spr, pr) = self.activation_density(i, to_print=False, feature_map=None, **kwargs);
|
| 410 |
+
channel_spearman.append(spr[0])
|
| 411 |
+
return fig, ax, np.array(channel_spearman)
|
| 412 |
+
|
| 413 |
+
def matrix_to_seq(self, matrix):
|
| 414 |
+
"""
|
| 415 |
+
return the sequence with maximum weight at each site
|
| 416 |
+
"""
|
| 417 |
+
max_act_seq = ''
|
| 418 |
+
assert matrix.shape[1] == 4
|
| 419 |
+
for i in matrix.argmax(axis=1):
|
| 420 |
+
max_act_seq += ['A', 'C', 'G', 'T'][i]
|
| 421 |
+
|
| 422 |
+
return max_act_seq
|
| 423 |
+
|
| 424 |
+
def save_as_meme_format(self,channels:list, save_path, filter_prefix='filter', transformation='probability'):
|
| 425 |
+
motifs = []
|
| 426 |
+
success_channel = []
|
| 427 |
+
for cc in channels:
|
| 428 |
+
try:
|
| 429 |
+
region, index, patches = self.locate_MA_seq(channel=cc)
|
| 430 |
+
M = self.sequence_to_matrix(region, transformation=transformation);
|
| 431 |
+
motifs.append(M)
|
| 432 |
+
success_channel.append(cc)
|
| 433 |
+
except ValueError:
|
| 434 |
+
continue
|
| 435 |
+
|
| 436 |
+
write_meme(success_channel, motifs ,save_path, filter_prefix)
|
| 437 |
+
|
| 438 |
+
def gradience_scaler(self,array):
|
| 439 |
+
"""
|
| 440 |
+
a scaling function to
|
| 441 |
+
"""
|
| 442 |
+
meann = np.mean(array)
|
| 443 |
+
ranges = array.max() - array.min()
|
| 444 |
+
return (array-meann)/ranges
|
| 445 |
+
|
| 446 |
+
def get_input_grad(self, task, focus=True, fm=None, starting_layer=None):
|
| 447 |
+
"""
|
| 448 |
+
compute the gradience of Y over feature_map
|
| 449 |
+
fm : specify feature map
|
| 450 |
+
starting_layer: or None [0,3]
|
| 451 |
+
"""
|
| 452 |
+
All_grad = []
|
| 453 |
+
current_layer = self.layer if starting_layer is None else starting_layer
|
| 454 |
+
model = self.load_model().to(self.popen.cuda_id)
|
| 455 |
+
model.train()
|
| 456 |
+
if fm is None:
|
| 457 |
+
fm = self.feature_map
|
| 458 |
+
|
| 459 |
+
for start in tqdm(range(0, fm.shape[0], 64)):
|
| 460 |
+
# prepare input
|
| 461 |
+
minibatch = fm[start:start+64]
|
| 462 |
+
X = torch.as_tensor(minibatch, device=self.popen.cuda_id).float()
|
| 463 |
+
X.requires_grad=True
|
| 464 |
+
|
| 465 |
+
# forward
|
| 466 |
+
# x = model.soft_share.encoder[3](X)
|
| 467 |
+
out=X
|
| 468 |
+
for layer in model.soft_share.encoder[current_layer:]:
|
| 469 |
+
out = layer(out)
|
| 470 |
+
Z_t = torch.transpose(out, 1, 2)
|
| 471 |
+
h_prim,(c1,c2) = model.tower[task][0](Z_t)
|
| 472 |
+
out = model.tower[task][1](c2)
|
| 473 |
+
|
| 474 |
+
# auto grad
|
| 475 |
+
external_grad = torch.ones_like(out)
|
| 476 |
+
out.backward(gradient=external_grad,retain_graph=True)
|
| 477 |
+
grad = X.grad
|
| 478 |
+
|
| 479 |
+
if focus:
|
| 480 |
+
indices = self.argmax_to_indeces(np.argmax(minibatch, axis=2))
|
| 481 |
+
grad = grad[indices].reshape(-1,256)
|
| 482 |
+
|
| 483 |
+
All_grad.append( tensor_2_numpy(grad) )
|
| 484 |
+
|
| 485 |
+
# concate each channel and average over input sequences
|
| 486 |
+
grad_ay = np.concatenate(All_grad, axis=0)#.mean(axis=0)
|
| 487 |
+
|
| 488 |
+
# return self.gradience_scaler(grad_ay)
|
| 489 |
+
return grad_ay
|
| 490 |
+
|
| 491 |
+
def argmax_to_indeces(self,index):
|
| 492 |
+
"index : of shape [batch, 256] , the result of "
|
| 493 |
+
s_index = []
|
| 494 |
+
ch_index = []
|
| 495 |
+
loc_index = []
|
| 496 |
+
for sample in range(index.shape[0]):
|
| 497 |
+
sam_loc = index[sample]
|
| 498 |
+
for ch, pos in enumerate(sam_loc):
|
| 499 |
+
s_index.append(sample)
|
| 500 |
+
ch_index.append(ch)
|
| 501 |
+
loc_index.append(pos)
|
| 502 |
+
|
| 503 |
+
return (s_index, ch_index, loc_index)
|
| 504 |
+
|
| 505 |
+
def extract_max_seq_pattern(self, condition, n_clusters=6, n_patch=3000):
|
| 506 |
+
pattern = []
|
| 507 |
+
channel_source = []
|
| 508 |
+
for channel in np.where(condition)[0]:
|
| 509 |
+
|
| 510 |
+
try:
|
| 511 |
+
act_patch, flatten_seq, cluster_index = self.within_patch_clustering(channel, n_clusters=n_clusters, to_plot=False,n_patch=n_patch)
|
| 512 |
+
except ValueError:
|
| 513 |
+
continue
|
| 514 |
+
|
| 515 |
+
for i in range(n_clusters):
|
| 516 |
+
sub_cluster = act_patch[cluster_index==i]
|
| 517 |
+
if len(sub_cluster) > 0:
|
| 518 |
+
matrix = self.sequence_to_matrix(sub_cluster)
|
| 519 |
+
pattern.append(self.matrix_to_seq(matrix))
|
| 520 |
+
channel_source.append(channel)
|
| 521 |
+
return pattern, channel_source
|
| 522 |
+
|
| 523 |
+
def sum_occurrance(df, pattern):
|
| 524 |
+
pattern_occurance = []
|
| 525 |
+
for p in pattern:
|
| 526 |
+
pattern_occurance.append(np.sum([(p in utr) for utr in df.seq.values]))
|
| 527 |
+
return np.array(pattern_occurance)
|
| 528 |
+
|
| 529 |
+
def generate_scramble_index(size , N_1):
|
| 530 |
+
scramble_index=np.zeros((size,))
|
| 531 |
+
|
| 532 |
+
while scramble_index.sum() < N_1:
|
| 533 |
+
num_ = int(N_1 - scramble_index.sum())
|
| 534 |
+
randindex = np.random.randint(0, size, size=(num_,))
|
| 535 |
+
|
| 536 |
+
for i in randindex:
|
| 537 |
+
scramble_index[i]
|
| 538 |
+
return scramble_index
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
class merge_task_map(Maximum_activation_patch):
|
| 542 |
+
def __init__(self, popen, which_layer, n_patch , kfold_index=None, device_string='cpu'):
|
| 543 |
+
"""merging all tasksa"""
|
| 544 |
+
super().__init__(popen, which_layer, n_patch , kfold_index, device_string)
|
| 545 |
+
self.old_popen = copy.copy(popen)
|
| 546 |
+
self.df_dict = {}
|
| 547 |
+
self.Y_2_task = {}
|
| 548 |
+
self.patches_ls = None
|
| 549 |
+
|
| 550 |
+
def load_indexed_dataloader(self,task):
|
| 551 |
+
|
| 552 |
+
if task in ['Andrev2015','muscle','pc3']:
|
| 553 |
+
self.popen.seq_col = 'utr'
|
| 554 |
+
self.popen.aux_task_columns = ['log_te']
|
| 555 |
+
self.popen.split_like = None
|
| 556 |
+
self.popen.kfold_cv = True
|
| 557 |
+
|
| 558 |
+
loader_ls = super().load_indexed_dataloader(task)
|
| 559 |
+
self.popen = copy.copy(self.old_popen)
|
| 560 |
+
return loader_ls
|
| 561 |
+
|
| 562 |
+
def extract_feature_map(self, which_set=0):
|
| 563 |
+
feature_map = {}
|
| 564 |
+
for task in self.popen.cycle_set:
|
| 565 |
+
feature_map[task] = super().extract_feature_map(task=task, which_set=which_set)
|
| 566 |
+
self.Y_2_task[task] = self.Y_ls
|
| 567 |
+
self.feature_map = feature_map
|
| 568 |
+
return feature_map
|
| 569 |
+
|
| 570 |
+
def loading(self,task, which_set):
|
| 571 |
+
model = self.load_model().to(self.popen.cuda_id)
|
| 572 |
+
dataloader = self.load_indexed_dataloader(task)[which_set]
|
| 573 |
+
self.df_dict[task] = dataloader.dataset.df
|
| 574 |
+
return model, dataloader
|
| 575 |
+
|
| 576 |
+
def locate_MA_seq(self, channel, feature_map=None, patches_ls=None):
|
| 577 |
+
"""A multi-task version of MA region retrieve"""
|
| 578 |
+
regions = []
|
| 579 |
+
indeces = {}
|
| 580 |
+
patches = []
|
| 581 |
+
|
| 582 |
+
if patches_ls is None:
|
| 583 |
+
patches_ls = self.patches_ls
|
| 584 |
+
|
| 585 |
+
for i, task in enumerate(self.popen.cycle_set):
|
| 586 |
+
# task out : region, index, patches
|
| 587 |
+
if patches_ls is not None:
|
| 588 |
+
self.n_patch = patches_ls[i]
|
| 589 |
+
# print(f"{task} n_patch: {self.n_patch}")
|
| 590 |
+
self.df = self.df_dict[task]
|
| 591 |
+
# _region , index , patches
|
| 592 |
+
r, i, p = super().locate_MA_seq(channel, feature_map=self.feature_map[task])
|
| 593 |
+
regions.append(r)
|
| 594 |
+
indeces[task] = i
|
| 595 |
+
patches.append(p)
|
| 596 |
+
|
| 597 |
+
return np.concatenate(regions) , indeces , np.concatenate(patches)
|
| 598 |
+
|
| 599 |
+
def activation_density(self, channel, to_print=True, to_plot=True, feature_map=None, **kwargs):
|
| 600 |
+
all_F0 = []
|
| 601 |
+
all_spr = []
|
| 602 |
+
all_pr = []
|
| 603 |
+
for i, task in enumerate(self.popen.cycle_set):
|
| 604 |
+
# task out : region, index, patches
|
| 605 |
+
task_featmap = self.feature_map[task]
|
| 606 |
+
self.Y_ls = self.Y_2_task[task]
|
| 607 |
+
|
| 608 |
+
if to_print:
|
| 609 |
+
print(task)
|
| 610 |
+
F0, (spr,pr) = super().activation_density(channel, to_print=to_print,
|
| 611 |
+
to_plot=False,
|
| 612 |
+
feature_map = task_featmap)
|
| 613 |
+
all_F0.append(F0)
|
| 614 |
+
all_spr.append(spr)
|
| 615 |
+
all_pr.append(pr)
|
| 616 |
+
|
| 617 |
+
# merge all activateion
|
| 618 |
+
|
| 619 |
+
if to_plot:
|
| 620 |
+
for F0_ay in all_F0:
|
| 621 |
+
sns.kdeplot(F0_ay, **kwargs)
|
| 622 |
+
|
| 623 |
+
return all_F0 , (all_spr, all_pr)
|
| 624 |
+
|
| 625 |
+
def flexible_n_patch(self,channel, qtl=0.95):
|
| 626 |
+
"""
|
| 627 |
+
call this function before the all other functions will enable a flexible task-wise n_patch
|
| 628 |
+
|
| 629 |
+
"""
|
| 630 |
+
all_F0 , (all_spr, all_pr) = self.activation_density(channel,False, False,None)
|
| 631 |
+
thres = np.max([np.quantile(f0, qtl) for f0 in all_F0])
|
| 632 |
+
self.patches_ls = [np.sum(f0 > thres) for f0 in all_F0]
|
| 633 |
+
return self.patches_ls
|
| 634 |
+
|
| 635 |
+
def activation_overview(self):
|
| 636 |
+
pr_ay=[]
|
| 637 |
+
spr_ay=[]
|
| 638 |
+
|
| 639 |
+
# the number of convolution filters in layer 3
|
| 640 |
+
# the index is also 3 because input channel = 4 for layer 0
|
| 641 |
+
for i in tqdm(range(self.popen.channel_ls[self.layer])):
|
| 642 |
+
#
|
| 643 |
+
_,(spr,pr) = self.activation_density(i,False,False)
|
| 644 |
+
pr_ay.append(pr)
|
| 645 |
+
spr_ay.append(spr)
|
| 646 |
+
|
| 647 |
+
# convert to ndarray
|
| 648 |
+
pr_ay = np.stack(pr_ay)
|
| 649 |
+
spr_ay = np.stack(spr_ay)
|
| 650 |
+
return pr_ay, spr_ay
|
| 651 |
+
|
| 652 |
+
def save_as_meme_format(self,channels:list, save_path, filter_prefix='filter', transformation='probability', qtl=0.95, fix_patches_ls=None):
|
| 653 |
+
"""
|
| 654 |
+
Save the position weight matrix as the meme-suite acceptale minimal motif format
|
| 655 |
+
"""
|
| 656 |
+
|
| 657 |
+
with open(save_path, 'w') as f:
|
| 658 |
+
f.write("MEME version 5.3.0\n\n")
|
| 659 |
+
f.write("ALPHABET= ACGT\n\n")
|
| 660 |
+
f.write("strands: + -\n\n")
|
| 661 |
+
f.write("Background letter frequencies\n")
|
| 662 |
+
f.write("A 0.25 C 0.25 G 0.25 T 0.25\n")
|
| 663 |
+
|
| 664 |
+
for cc in channels:
|
| 665 |
+
if fix_patches_ls is None:
|
| 666 |
+
n_patches_ls = self.flexible_n_patch(cc, qtl=qtl)
|
| 667 |
+
else:
|
| 668 |
+
n_patches_ls = fix_patches_ls
|
| 669 |
+
try:
|
| 670 |
+
region, index, patches = self.locate_MA_seq(channel=cc, patches_ls=n_patches_ls)
|
| 671 |
+
M = self.sequence_to_matrix(region, transformation=transformation);
|
| 672 |
+
f.write('\n')
|
| 673 |
+
f.write(f"MOTIF {filter_prefix}_{cc}\n")
|
| 674 |
+
seq_len = len(region[0])
|
| 675 |
+
f.write(f"letter-probability matrix: alength= 4 w= {seq_len} \n")
|
| 676 |
+
for line in M.values:
|
| 677 |
+
f.write(" "+line.__str__()[1:-1]+'\n')
|
| 678 |
+
except ValueError:
|
| 679 |
+
continue
|
| 680 |
+
|
| 681 |
+
f.close()
|
| 682 |
+
print('writed')
|
| 683 |
+
|
| 684 |
+
def get_input_grad(self, focus=True):
|
| 685 |
+
grads = {}
|
| 686 |
+
for task in self.popen.cycle_set:
|
| 687 |
+
grads[task] = super().get_input_grad(focus=True, task=task, fm=self.feature_map[task])
|
| 688 |
+
return grads
|
| 689 |
+
|
| 690 |
+
class Maximum_activation_kmer(Maximum_activation_patch):
|
| 691 |
+
def __init__(self,popen, which_layer, n_patch, kfold_index):
|
| 692 |
+
super().__init__(popen, which_layer, n_patch, kfold_index)
|
| 693 |
+
self.virtual_pad = 0
|
| 694 |
+
|
| 695 |
+
def compute_virtual_pad(self):
|
| 696 |
+
self.virtual_pad = 0
|
| 697 |
+
print('the virtual pad is', self.virtual_pad)
|
| 698 |
+
|
| 699 |
+
def load_indexed_dataloader(self, task='kmer'):
|
| 700 |
+
self.csv_path = f"<DATA_DIR>/all_{self.r}mer.csv"
|
| 701 |
+
self.popen.split_like = [self.csv_path,self.csv_path]
|
| 702 |
+
self.popen.csv_path = None
|
| 703 |
+
self.popen.kfold_cv = False
|
| 704 |
+
self.popen.kfold_index = self.kfold_index
|
| 705 |
+
self.popen.pad_to = self.r
|
| 706 |
+
self.popen.seq_col = 'utr'
|
| 707 |
+
self.popen.aux_task_columns = ['rl']
|
| 708 |
+
return reader.get_dataloader(self.popen)
|
| 709 |
+
|
| 710 |
+
def extract_feature_map(self):
|
| 711 |
+
|
| 712 |
+
model, dataloader= self.loading('kmer', 1)
|
| 713 |
+
|
| 714 |
+
for l in range(self.layer):
|
| 715 |
+
# remove padding to precisely locate
|
| 716 |
+
model.soft_share.encoder[l][0][0].padding = (0,)
|
| 717 |
+
|
| 718 |
+
feature_map = []
|
| 719 |
+
X_ls = []
|
| 720 |
+
Y_ls = []
|
| 721 |
+
|
| 722 |
+
model.eval()
|
| 723 |
+
with torch.no_grad():
|
| 724 |
+
for Data in tqdm(dataloader):
|
| 725 |
+
# iter each batch
|
| 726 |
+
x,y = train_val.put_data_to_cuda(Data,self.popen,False)
|
| 727 |
+
x = torch.transpose(x, 1, 2)
|
| 728 |
+
# X_ls.append(x.numpy())
|
| 729 |
+
Y_ls.append( tensor_2_numpy(y) )
|
| 730 |
+
|
| 731 |
+
for layer in model.soft_share.encoder[:self.layer]:
|
| 732 |
+
out = layer(x)
|
| 733 |
+
x = out
|
| 734 |
+
feature_map.append( tensor_2_numpy(out) )
|
| 735 |
+
|
| 736 |
+
torch.cuda.empty_cache()
|
| 737 |
+
|
| 738 |
+
|
| 739 |
+
feature_map_l = np.concatenate( feature_map, axis=0)
|
| 740 |
+
|
| 741 |
+
# self.X_ls = np.concatenate(X_ls, axis=0)
|
| 742 |
+
self.Y_ls = np.concatenate(Y_ls, axis=0)
|
| 743 |
+
|
| 744 |
+
print("activation map of layer |%d|"%self.layer,feature_map_l.shape)
|
| 745 |
+
# print(self.X_ls.shape)
|
| 746 |
+
print("Y : ",self.Y_ls.shape)
|
| 747 |
+
self.feature_map = feature_map_l
|
| 748 |
+
|
| 749 |
+
self.filters = self.get_filter_param(model)
|
| 750 |
+
|
| 751 |
+
del model
|
| 752 |
+
self.df = pd.read_csv(self.csv_path)
|
| 753 |
+
return feature_map_l
|
| 754 |
+
|
| 755 |
+
def write_meme(channels:list, PWMs:list ,save_path, filter_prefix='filter'):
|
| 756 |
+
"""
|
| 757 |
+
Save the position weight matrix as the meme-suite acceptale minimal motif format
|
| 758 |
+
"""
|
| 759 |
+
assert len(channels)==len(PWMs)
|
| 760 |
+
with open(save_path, 'w') as f:
|
| 761 |
+
f.write("MEME version 5.4.1\n\n")
|
| 762 |
+
f.write("ALPHABET= ACGT\n\n")
|
| 763 |
+
f.write("strands: + -\n\n")
|
| 764 |
+
f.write("Background letter frequencies\n")
|
| 765 |
+
f.write("A 0.25 C 0.25 G 0.25 T 0.25\n")
|
| 766 |
+
|
| 767 |
+
for cc,M in zip(channels, PWMs):
|
| 768 |
+
f.write('\n')
|
| 769 |
+
f.write(f"MOTIF {filter_prefix}_{cc}\n")
|
| 770 |
+
seq_len = M.shape[0]
|
| 771 |
+
f.write(f"letter-probability matrix: alength= 4 w= {seq_len} \n")
|
| 772 |
+
for line in M.values:
|
| 773 |
+
f.write(" "+line.__str__()[1:-1]+'\n')
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
f.close()
|
| 777 |
+
print('writed to', save_path)
|
| 778 |
+
|
| 779 |
+
def extract_meme(memepath):
|
| 780 |
+
"""
|
| 781 |
+
read the meme file and extract motifs to rewrite
|
| 782 |
+
"""
|
| 783 |
+
with open(memepath,'r') as f:
|
| 784 |
+
all_lines = f.readlines()[9:]
|
| 785 |
+
|
| 786 |
+
all_blocks = []
|
| 787 |
+
for i, line in enumerate(all_lines):
|
| 788 |
+
if line.startswith("MOTIF"):
|
| 789 |
+
width = re.match(r"letter-probability matrix: alength= 4 w= (\d)*",all_lines[i+1]).groups(1)
|
| 790 |
+
width = int(width[0])
|
| 791 |
+
|
| 792 |
+
all_blocks.append( all_lines[i:i+3+width])
|
| 793 |
+
|
| 794 |
+
return all_blocks
|
| 795 |
+
|
model/src/mrl_te_optimization/models/popen.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import numpy as np
|
| 4 |
+
import utils
|
| 5 |
+
import json
|
| 6 |
+
from models import Modules
|
| 7 |
+
import configparser
|
| 8 |
+
import logging
|
| 9 |
+
|
| 10 |
+
class Auto_popen(object):
|
| 11 |
+
def __init__(self,config_file):
|
| 12 |
+
"""
|
| 13 |
+
read the config_fiel
|
| 14 |
+
"""
|
| 15 |
+
# machine config path
|
| 16 |
+
self.shuffle = True
|
| 17 |
+
self.script_dir = utils.script_dir
|
| 18 |
+
self.data_dir = utils.data_dir
|
| 19 |
+
self.data_dir = '/mnt/sina/run/ml/gan/motif/MTtrans/test.csv'
|
| 20 |
+
self.log_dir = utils.log_dir
|
| 21 |
+
self.pth_dir = utils.pth_dir
|
| 22 |
+
self.set_attr_as_none(['te_net_l2','loss_fn','modual_to_fix','other_input_columns','pretrain_pth','kfold_index'])
|
| 23 |
+
self.split_like = False
|
| 24 |
+
self.loss_schema = 'constant'
|
| 25 |
+
|
| 26 |
+
# transform to dict and convert to specific data type
|
| 27 |
+
self.config = configparser.ConfigParser()
|
| 28 |
+
self.config.read(config_file)
|
| 29 |
+
self.config_file = config_file
|
| 30 |
+
self.config_dict = {item[0]: eval(item[1]) for item in self.config.items('DEFAULT')}
|
| 31 |
+
print(self.config_dict)
|
| 32 |
+
# assign some attr from config_dict
|
| 33 |
+
self.set_attr_from_dict(self.config_dict.keys())
|
| 34 |
+
self.check_run_and_setting_name() # check run name
|
| 35 |
+
self._dataset = "_" + self.dataset if self.dataset != '' else self.dataset
|
| 36 |
+
# the saving direction
|
| 37 |
+
self.path_category = self.config_file.split('/')[-4]
|
| 38 |
+
self.vae_log_path = config_file.replace('.ini','.log')
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
self.Resumable = False
|
| 42 |
+
|
| 43 |
+
# covariates for other input
|
| 44 |
+
self.n_covar = len(self.other_input_columns) if self.other_input_columns is not None else 0
|
| 45 |
+
|
| 46 |
+
# generate self.model_args
|
| 47 |
+
self.get_model_config()
|
| 48 |
+
|
| 49 |
+
@property
|
| 50 |
+
def vae_pth_path(self):
|
| 51 |
+
save_to = os.path.join(self.pth_dir,self.model_type+self._dataset,self.setting_name)
|
| 52 |
+
if self.kfold_index is None:
|
| 53 |
+
pth = os.path.join(save_to, self.run_name + '-model_best.pth')
|
| 54 |
+
elif type(self.kfold_index) == int:
|
| 55 |
+
k = self.kfold_index
|
| 56 |
+
pth = os.path.join(save_to, self.run_name + f'-model_best_cv{k}.pth')
|
| 57 |
+
return pth
|
| 58 |
+
|
| 59 |
+
@vae_pth_path.setter
|
| 60 |
+
def vae_pth_path(self, path):
|
| 61 |
+
self._vae_pth_path = path
|
| 62 |
+
|
| 63 |
+
def set_attr_from_dict(self,attr_ls):
|
| 64 |
+
for attr in attr_ls:
|
| 65 |
+
self.__setattr__(attr,self.config_dict[attr])
|
| 66 |
+
|
| 67 |
+
def set_attr_as_none(self,attr_ls):
|
| 68 |
+
for attr in attr_ls:
|
| 69 |
+
self.__setattr__(attr,None)
|
| 70 |
+
|
| 71 |
+
def check_run_and_setting_name(self):
|
| 72 |
+
file_name = self.config_file.split("/")[-1]
|
| 73 |
+
dir_name = self.config_file.split("/")[-2]
|
| 74 |
+
self.setting_name = dir_name
|
| 75 |
+
assert self.run_name == file_name.split(".")[0]
|
| 76 |
+
|
| 77 |
+
def get_model_config(self):
|
| 78 |
+
"""
|
| 79 |
+
assert we type in the correct model type and group them into model_args
|
| 80 |
+
"""
|
| 81 |
+
|
| 82 |
+
if self.model_type in dir(Modules):
|
| 83 |
+
self.Model_Class = eval("Modules.{}".format(self.model_type))
|
| 84 |
+
else:
|
| 85 |
+
raise NameError("not such model type")
|
| 86 |
+
|
| 87 |
+
# conv_args define the soft-sharing part
|
| 88 |
+
conv_args = ["channel_ls","kernel_size","stride","padding_ls","diliation_ls","pad_to"]
|
| 89 |
+
self.conv_args = tuple([self.__getattribute__(arg) for arg in conv_args])
|
| 90 |
+
|
| 91 |
+
# left args dfine the tower part in which the arguments are different among tasks
|
| 92 |
+
left_args={# Backbone models
|
| 93 |
+
'RL_regressor':["tower_width","dropout_rate"],
|
| 94 |
+
'RL_clf':["n_class","tower_width","dropout_rate"],
|
| 95 |
+
'RL_gru':["tower_width","dropout_rate"],
|
| 96 |
+
'RL_FACS': ["tower_width","dropout_rate"],
|
| 97 |
+
'RL_hard_share':["tower_width","dropout_rate", "activation","cycle_set" ],
|
| 98 |
+
'RL_covar_reg':["tower_width","dropout_rate", "activation", "n_covar", "cycle_set" ],
|
| 99 |
+
'RL_covar_intercept':["tower_width","dropout_rate", "activation", "n_covar", "cycle_set" ],
|
| 100 |
+
'RL_mish_gru':["tower_width","dropout_rate"],
|
| 101 |
+
# GP models
|
| 102 |
+
'GP_net': ['tower_width', 'dropout_rate', 'global_pooling', 'activation', 'cycle_set'],
|
| 103 |
+
'Frame_GP': ['tower_width', 'dropout_rate', 'activation', 'cycle_set'],
|
| 104 |
+
'RL_Atten': ['qk_dim', 'n_head', 'n_atten_layer', 'tower_width', 'dropout_rate', 'activation', 'cycle_set'],
|
| 105 |
+
# Koo net
|
| 106 |
+
'Conf_CNN' : ['pool_size'],
|
| 107 |
+
}[self.model_type]
|
| 108 |
+
|
| 109 |
+
self.model_args = [self.conv_args] + [self.__getattribute__(arg) for arg in left_args]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def check_experiment(self,logger):
|
| 113 |
+
"""
|
| 114 |
+
check any unfinished experiment ?
|
| 115 |
+
"""
|
| 116 |
+
log_save_dir = os.path.dirname(self.vae_log_path)
|
| 117 |
+
pth_save_dir = os.path.join(self.pth_dir,self.model_type+self._dataset,self.setting_name)
|
| 118 |
+
# make dirs
|
| 119 |
+
if not os.path.exists(log_save_dir):
|
| 120 |
+
os.makedirs(log_save_dir)
|
| 121 |
+
if not os.path.exists(pth_save_dir):
|
| 122 |
+
os.makedirs(pth_save_dir)
|
| 123 |
+
|
| 124 |
+
# check resume
|
| 125 |
+
if os.path.exists(self.vae_log_path) & os.path.exists(self.vae_pth_path):
|
| 126 |
+
self.Resumable = True
|
| 127 |
+
logger.info(' \t \t ==============<<< Experiment detected >>>============== \t \t \n')
|
| 128 |
+
|
| 129 |
+
def update_ini_file(self,E,logger):
|
| 130 |
+
"""
|
| 131 |
+
E is the dict contain the things to update
|
| 132 |
+
"""
|
| 133 |
+
# update the ini file
|
| 134 |
+
self.config_dict.update(E)
|
| 135 |
+
strconfig = {K: repr(V) for K,V in self.config_dict.items()}
|
| 136 |
+
self.config['DEFAULT'] = strconfig
|
| 137 |
+
|
| 138 |
+
with open(self.config_file,'w') as f:
|
| 139 |
+
self.config.write(f)
|
| 140 |
+
|
| 141 |
+
logger.info(' ini file updated ')
|
| 142 |
+
|
| 143 |
+
def chimera_weight_update(self):
|
| 144 |
+
# TODO : progressively update the loss weight between tasks
|
| 145 |
+
|
| 146 |
+
# TODO : 1. scale the loss into the same magnitude
|
| 147 |
+
|
| 148 |
+
# TODO : 2. update the weight by their own learning progress
|
| 149 |
+
|
| 150 |
+
return None
|
model/src/mrl_te_optimization/models/reader.py
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import copy
|
| 4 |
+
sys.path.append(os.path.dirname(__file__))
|
| 5 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 6 |
+
|
| 7 |
+
import json
|
| 8 |
+
import torch
|
| 9 |
+
import numpy as np
|
| 10 |
+
import pandas as pd
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from Bio import SeqIO
|
| 14 |
+
from Bio.SeqRecord import SeqRecord
|
| 15 |
+
|
| 16 |
+
from torch.utils.data import DataLoader, Dataset ,random_split,IterableDataset
|
| 17 |
+
from sklearn.model_selection import KFold,train_test_split
|
| 18 |
+
from bucket_sampler import Bucket_Sampler
|
| 19 |
+
from utils import Seq_one_hot
|
| 20 |
+
|
| 21 |
+
global script_dir
|
| 22 |
+
global data_dir
|
| 23 |
+
|
| 24 |
+
with open(os.path.join(os.path.dirname(os.path.dirname(__file__)),"machine_configure.json"),'r') as f:
|
| 25 |
+
config = json.load(f)
|
| 26 |
+
|
| 27 |
+
script_dir = config['script_dir']
|
| 28 |
+
data_dir = config['data_dir']
|
| 29 |
+
|
| 30 |
+
def one_hot(seq,complementary=False):
|
| 31 |
+
"""
|
| 32 |
+
one_hot encoding on sequence
|
| 33 |
+
complementary: encode nucleatide into complementary one
|
| 34 |
+
"""
|
| 35 |
+
# setting
|
| 36 |
+
seq = list(seq.replace("U","T"))
|
| 37 |
+
seq_len = len(seq)
|
| 38 |
+
complementary = -1 if complementary else 1
|
| 39 |
+
# compose dict
|
| 40 |
+
keys = ['A', 'C', 'G', 'T'][::complementary]
|
| 41 |
+
oh_dict = {keys[i]:i for i in range(4)}
|
| 42 |
+
# array
|
| 43 |
+
oh_array = np.zeros((seq_len,4))
|
| 44 |
+
for i,C in enumerate(seq):
|
| 45 |
+
try:
|
| 46 |
+
oh_array[i,oh_dict[C]]=1
|
| 47 |
+
except:
|
| 48 |
+
continue # for nucleotide that are not in A C G T
|
| 49 |
+
return oh_array
|
| 50 |
+
|
| 51 |
+
def read_bpseq(test_bpseq_path):
|
| 52 |
+
"""
|
| 53 |
+
read bpseq file, extract sequence and ptable
|
| 54 |
+
"""
|
| 55 |
+
with open(test_bpseq_path,'r') as f:
|
| 56 |
+
test_bpseq = f.readlines()
|
| 57 |
+
f.close()
|
| 58 |
+
|
| 59 |
+
for i in range(8):
|
| 60 |
+
if test_bpseq[i].startswith('1'):
|
| 61 |
+
start_index = i
|
| 62 |
+
|
| 63 |
+
bp_seq = test_bpseq[start_index:]
|
| 64 |
+
|
| 65 |
+
seq = ''.join([line.strip().split(" ")[1] for line in bp_seq])
|
| 66 |
+
ptable = [int(line.strip().split(" ")[2]) for line in bp_seq]
|
| 67 |
+
|
| 68 |
+
assert len(ptable) == int(bp_seq[-1].split(" ")[0])
|
| 69 |
+
|
| 70 |
+
return seq,ptable
|
| 71 |
+
|
| 72 |
+
def pad_zeros(X,pad_to):
|
| 73 |
+
"""
|
| 74 |
+
zero padding at the right end of the sequence
|
| 75 |
+
"""
|
| 76 |
+
if pad_to == 0:
|
| 77 |
+
# pad_to = 8*(X.shape[0]//8 + 1) + 1
|
| 78 |
+
try:
|
| 79 |
+
seq_len = X.shape[0]
|
| 80 |
+
except:
|
| 81 |
+
seq_len = X[0].shape[0]
|
| 82 |
+
pad_to = 3*(seq_len//3 + 1) + 1
|
| 83 |
+
|
| 84 |
+
seq_len = X.shape[0] if isinstance(X, np.ndarray) else X[0].shape[0]
|
| 85 |
+
gap = pad_to - seq_len
|
| 86 |
+
|
| 87 |
+
# here we change to padding ahead , previously nn.ZeroPad2d([0,0,0,gap])
|
| 88 |
+
pad_fn = nn.ZeroPad2d([0,0,gap,0]) # (padding_left , padding_right , padding_top , padding_bottom )
|
| 89 |
+
# gap_array = np.zeros()
|
| 90 |
+
if isinstance(X, list): # additional input
|
| 91 |
+
X_padded = [pad_fn(torch.tensor(X[0])), X[1]]
|
| 92 |
+
elif isinstance(X, np.ndarray):
|
| 93 |
+
X_padded = pad_fn(torch.tensor(X))
|
| 94 |
+
return X_padded
|
| 95 |
+
|
| 96 |
+
def pack_seq(ds_zls:list,pad_to:int):
|
| 97 |
+
X_ts = [X for X,Y in ds_zls]
|
| 98 |
+
if pad_to == 0:
|
| 99 |
+
try:
|
| 100 |
+
max_len = np.max([X.shape[0] for X in X_ts])
|
| 101 |
+
except:
|
| 102 |
+
max_len = np.max([X[0].shape[0] for X in X_ts])
|
| 103 |
+
|
| 104 |
+
pad_to = 3*(max_len//3 + 1) + 1
|
| 105 |
+
|
| 106 |
+
if isinstance(X_ts[0],np.ndarray):
|
| 107 |
+
X_packed = torch.stack([pad_zeros(X=x,pad_to=pad_to) for x in X_ts])
|
| 108 |
+
else:
|
| 109 |
+
X_packed = [torch.stack([pad_zeros(X=x[0],pad_to=pad_to) for x in X_ts]), torch.tensor([x[1] for x in X_ts])]
|
| 110 |
+
Y_packed = torch.tensor(np.array([Y for X,Y in ds_zls]))
|
| 111 |
+
|
| 112 |
+
return X_packed , Y_packed
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
class mask_reader(Dataset):
|
| 117 |
+
def __init__(self,npy_path):
|
| 118 |
+
"""
|
| 119 |
+
read the mask A549 sequence and with real sequence
|
| 120 |
+
"""
|
| 121 |
+
self.data_set = np.load(npy_path)
|
| 122 |
+
self.X = self.data_set[:,0]
|
| 123 |
+
self.Y = self.data_set[:,1]
|
| 124 |
+
|
| 125 |
+
def __len__(self):
|
| 126 |
+
return self.X.shape[0]
|
| 127 |
+
|
| 128 |
+
def __getitem__(self,index):
|
| 129 |
+
return (self.X[index,:,:],self.Y[index,:,:])
|
| 130 |
+
|
| 131 |
+
class mix_dataset(Dataset):
|
| 132 |
+
def __init__(self):
|
| 133 |
+
# dataset_ls = [mask_reader(os.path.join(data_dir,'mix_data',"mix_%s.npy"%set)) for set in ['train','val','test']]
|
| 134 |
+
raise ValueError("the dataset is not defined")
|
| 135 |
+
|
| 136 |
+
class mask_dataset(Dataset):
|
| 137 |
+
def __init__(self):
|
| 138 |
+
raise ValueError("the dataset is not defined")
|
| 139 |
+
|
| 140 |
+
class ribo_dataset(Dataset):
|
| 141 |
+
|
| 142 |
+
def __init__(self,DF, pad_to, trunc_len=50, seq_col='utr',
|
| 143 |
+
aux_columns='TE_count', other_input_columns=None):
|
| 144 |
+
"""
|
| 145 |
+
Dataset to trancate sequence and return in one-hot encoding way
|
| 146 |
+
`dataset(DF,pad_to,trunc_len=50,seq_col='utr')`
|
| 147 |
+
...DF: the dataframe contain sequence and its meta-info
|
| 148 |
+
...pad_to: final size of the output tensor
|
| 149 |
+
...trunc_len: maximum sequence to retain. number of nt preceding AUG
|
| 150 |
+
...seq_col : which col of the DF contain sequence to convert
|
| 151 |
+
"""
|
| 152 |
+
DF[seq_col] = DF[seq_col].astype(str)
|
| 153 |
+
self.df = DF
|
| 154 |
+
self.pad_to = pad_to
|
| 155 |
+
self.trunc_len = 0 if trunc_len is None else trunc_len
|
| 156 |
+
|
| 157 |
+
# X and Y
|
| 158 |
+
self.seqs = self.df.loc[:,seq_col].values
|
| 159 |
+
self.other_input_columns = other_input_columns
|
| 160 |
+
self.Y = self.df.loc[:,aux_columns].values
|
| 161 |
+
|
| 162 |
+
def __len__(self):
|
| 163 |
+
return self.df.shape[0]
|
| 164 |
+
|
| 165 |
+
def __getitem__(self,i):
|
| 166 |
+
seq = self.seqs[i]
|
| 167 |
+
x_padded = self.seq_chunk_N_oh(seq)
|
| 168 |
+
input = x_padded
|
| 169 |
+
if self.other_input_columns is not None:
|
| 170 |
+
input = [x_padded]
|
| 171 |
+
for col in self.other_input_columns:
|
| 172 |
+
input.append(self.df.loc[:,col].values[i])
|
| 173 |
+
y = self.Y[i]
|
| 174 |
+
return input,y
|
| 175 |
+
|
| 176 |
+
def seq_chunk_N_oh(self,seq):
|
| 177 |
+
"""
|
| 178 |
+
truncate the sequence and encode in one hot
|
| 179 |
+
"""
|
| 180 |
+
if (len(seq) > self.trunc_len)&(self.trunc_len >0):
|
| 181 |
+
seq = seq[-1* self.trunc_len:]
|
| 182 |
+
|
| 183 |
+
X = one_hot(seq)
|
| 184 |
+
X = torch.tensor(X)
|
| 185 |
+
|
| 186 |
+
# X_padded = pad_zeros(X, self.pad_to)
|
| 187 |
+
|
| 188 |
+
return X.float()
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class MTL_dataset(Dataset):
|
| 192 |
+
def __init__(self, DF, pad_to=100, seq_col='utr', aux_columns=None,
|
| 193 |
+
other_input_columns=None, trunc_len=None):
|
| 194 |
+
"""
|
| 195 |
+
the dataset for Multi-task learning, will return sequence in one-hot encoded version, together with some auxilary task label
|
| 196 |
+
arguments:
|
| 197 |
+
...csv_path: abs path of csv file, column `utr` should be in the csv
|
| 198 |
+
...pad_to : maximum length of the sequences
|
| 199 |
+
...columns : list contains what axuslary task label will be
|
| 200 |
+
"""
|
| 201 |
+
self.pad_to = pad_to
|
| 202 |
+
self.trunc_len = trunc_len
|
| 203 |
+
DF[seq_col] = DF[seq_col].astype(str)
|
| 204 |
+
self.df = DF # read Df
|
| 205 |
+
self.seqs = self.df[seq_col].values # take out all the sequence in DF
|
| 206 |
+
self.columns = aux_columns
|
| 207 |
+
self.other_input_columns = other_input_columns
|
| 208 |
+
|
| 209 |
+
assert trunc_len == None, "MTL dataset does not support argument trunc len"
|
| 210 |
+
|
| 211 |
+
def __len__(self):
|
| 212 |
+
return self.df.shape[0]
|
| 213 |
+
|
| 214 |
+
def __getitem__(self,index):
|
| 215 |
+
seq = self.seqs[index] # sequence: str of len 25~100
|
| 216 |
+
|
| 217 |
+
X = one_hot(seq).astype(float) # seq_oh : np array, one hot encoding sequence
|
| 218 |
+
# X = pad_zeros(X) # X : torch.tensor , zero padded to 100
|
| 219 |
+
|
| 220 |
+
if self.columns == None:
|
| 221 |
+
# which means no auxilary label is needed
|
| 222 |
+
item = X ,X
|
| 223 |
+
elif (type(self.columns) == list) & (len(self.columns)!=0):
|
| 224 |
+
# return what's in columns
|
| 225 |
+
aux_labels = self.df.loc[:,self.columns].values[index]
|
| 226 |
+
# if len(self.columns) == 1:
|
| 227 |
+
# aux_labels = aux_labels.reshape(-1,1)
|
| 228 |
+
item = X ,aux_labels
|
| 229 |
+
|
| 230 |
+
if self.other_input_columns is not None:
|
| 231 |
+
input = []
|
| 232 |
+
for col in self.other_input_columns:
|
| 233 |
+
input.append(self.df.loc[:,col].values[index])
|
| 234 |
+
item = (X, input),aux_labels
|
| 235 |
+
|
| 236 |
+
return item
|
| 237 |
+
|
| 238 |
+
class kmer_scan_dataset(Dataset):
|
| 239 |
+
def __init__(self, DF, seq_col, kmer_size, aux_columns=None, *args):
|
| 240 |
+
super().__init__()
|
| 241 |
+
self.df = DF
|
| 242 |
+
self.seqs = DF[seq_col].values
|
| 243 |
+
self.rls = DF[aux_columns].values
|
| 244 |
+
self.k = kmer_size
|
| 245 |
+
self.kmer_sets = self.create_kmer()
|
| 246 |
+
self.kmer_lookup = { kmer : i for i, kmer in enumerate(self.kmer_sets) }
|
| 247 |
+
|
| 248 |
+
def __len__(self):
|
| 249 |
+
return self.df.shape[0]
|
| 250 |
+
|
| 251 |
+
def __getitem__(self, index):
|
| 252 |
+
seq = self.seqs[index]
|
| 253 |
+
y = self.rls[index]
|
| 254 |
+
|
| 255 |
+
x = self.scan_kmer(seq)
|
| 256 |
+
return torch.tensor(x.astype(float)), torch.tensor(y)
|
| 257 |
+
|
| 258 |
+
def scan_kmer(self, seq):
|
| 259 |
+
|
| 260 |
+
mat = np.zeros((len(self.kmer_lookup), len(seq)-self.k))
|
| 261 |
+
for i in range(0, len(seq)-self.k):
|
| 262 |
+
seq_let = seq[i:i+self.k]
|
| 263 |
+
mat[self.kmer_lookup[seq_let], i] = 1
|
| 264 |
+
|
| 265 |
+
return mat
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def create_kmer(self):
|
| 269 |
+
all_kmer = {0:['']}
|
| 270 |
+
k = 1
|
| 271 |
+
while k <= self.k:
|
| 272 |
+
k_mer = [] # 1 ; 4 ; 2: 4**2 ...
|
| 273 |
+
for source in all_kmer[k-1]:
|
| 274 |
+
k_mer += [source + base for base in ['A','C','G','T']]
|
| 275 |
+
|
| 276 |
+
assert len(k_mer) == 4**k, f"new kmers {len(k_mer)}, not equal to {4**k}"
|
| 277 |
+
all_kmer[k] = k_mer
|
| 278 |
+
k += 1
|
| 279 |
+
|
| 280 |
+
all_kmer.pop(0)
|
| 281 |
+
return all_kmer[self.k]
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
class FASTA_dataset(MTL_dataset):
|
| 287 |
+
def __init__(self,DF, pad_to,trunc_len, seq_col, aux_columns, other_input_columns):
|
| 288 |
+
super().__init__(DF=DF, pad_to=pad_to, trunc_len=trunc_len, seq_col=seq_col,
|
| 289 |
+
aux_columns=aux_columns, other_input_columns=other_input_columns)
|
| 290 |
+
|
| 291 |
+
def get_splited_dataloader(dataset_func, df_ls, ratio:list, batch_size, shuffle, pad_to, seed=42,return_dataset=False):
|
| 292 |
+
"""
|
| 293 |
+
split the total dataset into train val test, and return in a DataLoader (train_loader,val_loader,test_loader)
|
| 294 |
+
dataset : the defined <UTR_dataset>
|
| 295 |
+
ratio : the ratio of train : val : test
|
| 296 |
+
batch_size : int
|
| 297 |
+
"""
|
| 298 |
+
|
| 299 |
+
# determined set-ls
|
| 300 |
+
|
| 301 |
+
set_ls = [dataset_func(df) for df in df_ls]
|
| 302 |
+
if return_dataset:
|
| 303 |
+
return set_ls
|
| 304 |
+
|
| 305 |
+
if pad_to == 0 :
|
| 306 |
+
# automatic padding to `8x -1`
|
| 307 |
+
# and we will pad the sequence of similar length with bucket sampler
|
| 308 |
+
col_fn = lambda x: pack_seq(x,0)
|
| 309 |
+
sampler_ls = [{"batch_sampler":Bucket_Sampler(df,batch_size=batch_size,drop_last=True),
|
| 310 |
+
"num_workers":4,
|
| 311 |
+
"drop_last":False,
|
| 312 |
+
"collate_fn":col_fn} for df in df_ls]
|
| 313 |
+
# wrap dataset to dataloader
|
| 314 |
+
loader_ls = [DataLoader(subset,**kwargs) for subset,kwargs in zip(set_ls,sampler_ls)]
|
| 315 |
+
else:
|
| 316 |
+
col_fn = lambda x: pack_seq(x,pad_to)
|
| 317 |
+
loaderargs = {"batch_size": batch_size,
|
| 318 |
+
"generator":torch.Generator().manual_seed(42),
|
| 319 |
+
"drop_last":False ,
|
| 320 |
+
"num_workers":4,
|
| 321 |
+
"shuffle":shuffle,
|
| 322 |
+
"collate_fn":col_fn}
|
| 323 |
+
# wrap dataset to dataloader
|
| 324 |
+
loader_ls = [DataLoader(subset,**loaderargs) for subset in set_ls]
|
| 325 |
+
|
| 326 |
+
if len(loader_ls) == 2:
|
| 327 |
+
# a complement of empty test set
|
| 328 |
+
loader_ls.append(None)
|
| 329 |
+
|
| 330 |
+
return loader_ls
|
| 331 |
+
|
| 332 |
+
def split_DF(data_path,split_like,ratio, kfold_cv, kfold_index=None,seed=42):
|
| 333 |
+
|
| 334 |
+
class _cf_data(object):
|
| 335 |
+
def __init__(self,data_path):
|
| 336 |
+
self.path = data_path
|
| 337 |
+
self.is_fasta = data_path.endswith('.fasta')
|
| 338 |
+
self.__read__()
|
| 339 |
+
|
| 340 |
+
def __read__(self):
|
| 341 |
+
if self.is_fasta:
|
| 342 |
+
self.data = list(SeqIO.parse(self.path,'fasta'))
|
| 343 |
+
else:
|
| 344 |
+
self.data = pd.read_csv(os.path.join(data_dir,self.path),low_memory=False)
|
| 345 |
+
|
| 346 |
+
def __len__(self):
|
| 347 |
+
return len(self.data)
|
| 348 |
+
|
| 349 |
+
def _slice_(self, indices):
|
| 350 |
+
if isinstance(self.data, list) & self.is_fasta:
|
| 351 |
+
return np.array(self.data)[indices]
|
| 352 |
+
elif isinstance(self.data, pd.DataFrame):
|
| 353 |
+
return self.data.iloc[indices]
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
if kfold_cv == True:
|
| 357 |
+
full_df = pd.read_csv(os.path.join(data_dir,data_path),low_memory=False)
|
| 358 |
+
# K-fold CV : 8:1:1 for each partition
|
| 359 |
+
df_ls = KFold_df_split(full_df,kfold_index)
|
| 360 |
+
|
| 361 |
+
if kfold_cv == 'train_val':
|
| 362 |
+
train_val, test = [_cf_data(data_path).data for data_path in split_like]
|
| 363 |
+
# K-fold CV : 8:1:1 for each partition
|
| 364 |
+
train, val = KFold_1_split(train_val,kfold_index)
|
| 365 |
+
df_ls = [train, val , test]
|
| 366 |
+
|
| 367 |
+
elif type(split_like) == list:
|
| 368 |
+
df_ls = [_cf_data(data_path).data for data_path in split_like]
|
| 369 |
+
|
| 370 |
+
elif type(kfold_cv) == str:
|
| 371 |
+
full_df = pd.read_csv(os.path.join(data_dir,data_path),low_memory=False)
|
| 372 |
+
if kfold_cv in full_df.columns:
|
| 373 |
+
kfold_index = str(kfold_index)
|
| 374 |
+
test = full_df.query(f"`{kfold_cv}` == @kfold_index")
|
| 375 |
+
train_val = full_df.query(f"`{kfold_cv}` != @kfold_index")
|
| 376 |
+
train, val = train_test_split(train_val, test_size=0.05)
|
| 377 |
+
df_ls = [train, val, test]
|
| 378 |
+
|
| 379 |
+
else:
|
| 380 |
+
full_df = _cf_data(data_path)
|
| 381 |
+
# POPEN.ratio will determine train :val :test ratio
|
| 382 |
+
total_len = len(full_df)
|
| 383 |
+
lengths = [int(total_len*sub_ratio) for sub_ratio in ratio[:-1]]
|
| 384 |
+
lengths.append(total_len-sum(lengths)) # make sure the sum of length is the total len
|
| 385 |
+
|
| 386 |
+
set_ls = random_split(full_df,lengths,generator=torch.Generator().manual_seed(seed))
|
| 387 |
+
df_ls = [full_df._slice_(subset.indices) for subset in set_ls] # df.iloc [ idx ]
|
| 388 |
+
|
| 389 |
+
return df_ls
|
| 390 |
+
|
| 391 |
+
def split_DF_call(data_path,split_like,ratio, kfold_cv, kfold_index=None,seed=42):
|
| 392 |
+
|
| 393 |
+
class _cf_data(object):
|
| 394 |
+
def __init__(self,data_path):
|
| 395 |
+
self.path = data_path
|
| 396 |
+
self.is_fasta = data_path.endswith('.fasta')
|
| 397 |
+
self.__read__()
|
| 398 |
+
|
| 399 |
+
def __read__(self):
|
| 400 |
+
if self.is_fasta:
|
| 401 |
+
self.data = list(SeqIO.parse(self.path,'fasta'))
|
| 402 |
+
else:
|
| 403 |
+
self.data = pd.read_csv(os.path.join(data_dir,self.path),low_memory=False)
|
| 404 |
+
|
| 405 |
+
def __len__(self):
|
| 406 |
+
return len(self.data)
|
| 407 |
+
|
| 408 |
+
def _slice_(self, indices):
|
| 409 |
+
if isinstance(self.data, list) & self.is_fasta:
|
| 410 |
+
return np.array(self.data)[indices]
|
| 411 |
+
elif isinstance(self.data, pd.DataFrame):
|
| 412 |
+
return self.data.iloc[indices]
|
| 413 |
+
|
| 414 |
+
|
| 415 |
+
if kfold_cv == True:
|
| 416 |
+
full_df = pd.read_csv(os.path.join(data_dir,data_path),low_memory=False)
|
| 417 |
+
# K-fold CV : 8:1:1 for each partition
|
| 418 |
+
df_ls = KFold_df_split(full_df,kfold_index)
|
| 419 |
+
|
| 420 |
+
if kfold_cv == 'train_val':
|
| 421 |
+
train_val, test = [_cf_data(data_path).data for data_path in split_like]
|
| 422 |
+
# K-fold CV : 8:1:1 for each partition
|
| 423 |
+
train, val = KFold_1_split(train_val,kfold_index)
|
| 424 |
+
df_ls = [train, val , test]
|
| 425 |
+
|
| 426 |
+
elif type(split_like) == list:
|
| 427 |
+
df_ls = [_cf_data(data_path).data for data_path in split_like]
|
| 428 |
+
|
| 429 |
+
elif type(kfold_cv) == str:
|
| 430 |
+
full_df = pd.read_csv(os.path.join(data_dir,data_path),low_memory=False)
|
| 431 |
+
if kfold_cv in full_df.columns:
|
| 432 |
+
kfold_index = str(kfold_index)
|
| 433 |
+
test = full_df.query(f"`{kfold_cv}` == @kfold_index")
|
| 434 |
+
train_val = full_df.query(f"`{kfold_cv}` != @kfold_index")
|
| 435 |
+
train, val = train_test_split(train_val, test_size=0.05)
|
| 436 |
+
df_ls = [train, val, test]
|
| 437 |
+
|
| 438 |
+
else:
|
| 439 |
+
full_df = _cf_data(data_path)
|
| 440 |
+
# POPEN.ratio will determine train :val :test ratio
|
| 441 |
+
total_len = len(full_df)
|
| 442 |
+
lengths = [int(total_len*sub_ratio) for sub_ratio in ratio[:-1]]
|
| 443 |
+
lengths.append(total_len-sum(lengths)) # make sure the sum of length is the total len
|
| 444 |
+
|
| 445 |
+
set_ls = random_split(full_df,lengths,generator=torch.Generator().manual_seed(seed))
|
| 446 |
+
df_ls = [full_df._slice_(subset.indices) for subset in set_ls] # df.iloc [ idx ]
|
| 447 |
+
|
| 448 |
+
return df_ls
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
def KFold_df_split(df,K,**kfoldargs):
|
| 452 |
+
"""
|
| 453 |
+
split the dataset DF in a ratio of 8:1:1 , train:val:test in the framework of K-fold CV
|
| 454 |
+
set random seed = 43
|
| 455 |
+
arguments:
|
| 456 |
+
df : the `pd.DataFrame` object containing all data info
|
| 457 |
+
K : [0,4] , the index of subfold
|
| 458 |
+
"""
|
| 459 |
+
|
| 460 |
+
# K-fold partition : n_splits=5
|
| 461 |
+
fold_index = list(KFold(10,shuffle=True,random_state=42).split(df))
|
| 462 |
+
train_val_index, test_index = fold_index[K]
|
| 463 |
+
# the first 4/5 part of it is train set
|
| 464 |
+
|
| 465 |
+
# index the df
|
| 466 |
+
train_val_df = df.iloc[train_val_index]
|
| 467 |
+
test_df = df.iloc[test_index]
|
| 468 |
+
|
| 469 |
+
# the remaining 1/5 data will further break into val and test
|
| 470 |
+
train_df, val_df = train_test_split(train_val_df,test_size=0.05,random_state=42)
|
| 471 |
+
|
| 472 |
+
return [train_df,val_df,test_df]
|
| 473 |
+
|
| 474 |
+
def KFold_1_split(df,K,**kfoldargs):
|
| 475 |
+
"""
|
| 476 |
+
for dataset with standard test set, where only train_val can be splited
|
| 477 |
+
"""
|
| 478 |
+
fold_index = list(KFold(10,shuffle=True,random_state=42).split(df))
|
| 479 |
+
train_index, val_index = fold_index[K]
|
| 480 |
+
# the first 4/5 part of it is train set
|
| 481 |
+
|
| 482 |
+
# index the df
|
| 483 |
+
train = df.iloc[train_index]
|
| 484 |
+
val = df.iloc[val_index]
|
| 485 |
+
|
| 486 |
+
return train , val
|
| 487 |
+
|
| 488 |
+
def get_dataloader(POPEN):
|
| 489 |
+
"""
|
| 490 |
+
wrapper
|
| 491 |
+
"""
|
| 492 |
+
|
| 493 |
+
# POPEN.csv_path = "/mnt/sina/run/ml/gan/motif/MTtrans/test.csv"
|
| 494 |
+
# print(POPEN.csv_path)
|
| 495 |
+
# print(POPEN.split_like)
|
| 496 |
+
# print(POPEN.train_test_ratio)
|
| 497 |
+
# print(POPEN.kfold_cv)
|
| 498 |
+
# print(POPEN.kfold_index)
|
| 499 |
+
df_ls = split_DF(POPEN.csv_path,POPEN.split_like,POPEN.train_test_ratio,POPEN.kfold_cv,POPEN.kfold_index,seed=42)
|
| 500 |
+
|
| 501 |
+
|
| 502 |
+
DS_Class = eval(POPEN.dataset+"_dataset")
|
| 503 |
+
|
| 504 |
+
dataset_func = lambda x : DS_Class(x,pad_to=POPEN.pad_to,trunc_len=POPEN.trunc_len,
|
| 505 |
+
seq_col=POPEN.seq_col, aux_columns=POPEN.aux_task_columns,
|
| 506 |
+
other_input_columns=POPEN.other_input_columns)
|
| 507 |
+
|
| 508 |
+
loader_ls = get_splited_dataloader(dataset_func, df_ls,ratio=POPEN.train_test_ratio,
|
| 509 |
+
batch_size=POPEN.batch_size, shuffle=POPEN.shuffle,
|
| 510 |
+
pad_to=POPEN.pad_to, seed=42) # new function
|
| 511 |
+
|
| 512 |
+
return loader_ls
|
model/src/mrl_te_optimization/models/train_val.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import time
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import logging
|
| 7 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 8 |
+
import utils
|
| 9 |
+
import torch
|
| 10 |
+
from scipy.stats import pearsonr
|
| 11 |
+
from torch import optim
|
| 12 |
+
from sklearn.metrics import r2_score, f1_score, roc_auc_score
|
| 13 |
+
from models.ScheduleOptimizer import ScheduledOptim , find_lr
|
| 14 |
+
from models.loss import Dynamic_Task_Priority as DTP
|
| 15 |
+
|
| 16 |
+
def train(dataloader,model,optimizer,popen,epoch,lr=None, verbose=True):
|
| 17 |
+
|
| 18 |
+
logger = logging.getLogger("VAE")
|
| 19 |
+
loader_len = len(dataloader) # number of iteration
|
| 20 |
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 21 |
+
|
| 22 |
+
model = model.to(device)
|
| 23 |
+
|
| 24 |
+
model.train()
|
| 25 |
+
verbose_list=[]
|
| 26 |
+
verbose_df = pd.DataFrame()
|
| 27 |
+
for idx,data in enumerate(dataloader):
|
| 28 |
+
|
| 29 |
+
X,Y = put_data_to_cuda(data,popen,require_grad=True)
|
| 30 |
+
optimizer.zero_grad()
|
| 31 |
+
|
| 32 |
+
out = model(X)
|
| 33 |
+
|
| 34 |
+
loss_dict = model.compute_loss(out,X,Y,popen)
|
| 35 |
+
loss = loss_dict['Total']
|
| 36 |
+
acc_dict = model.compute_acc(out,X,Y,popen)
|
| 37 |
+
loss_dict.update(acc_dict) # adding the acc ditc into loss dict
|
| 38 |
+
|
| 39 |
+
loss.backward()
|
| 40 |
+
optimizer.step()
|
| 41 |
+
|
| 42 |
+
# ====== update lr =======
|
| 43 |
+
if type(optimizer) == ScheduledOptim:
|
| 44 |
+
lr = optimizer.update_learning_rate() # see model.optim.py
|
| 45 |
+
loss_dict["lr"]=lr
|
| 46 |
+
elif popen.optimizer == 'Adam':
|
| 47 |
+
lr = optimizer.param_groups[0]['lr']
|
| 48 |
+
if popen.loss_schema != 'constant':
|
| 49 |
+
popen.chimerla_weight = popen.loss_schedualer._update(loss_dict)
|
| 50 |
+
for t in popen.tasks:
|
| 51 |
+
loss_dict[popen.loss_schema+"_wt_"+t] = popen.chimerla_weight[t]
|
| 52 |
+
|
| 53 |
+
with torch.no_grad():
|
| 54 |
+
loss_dict= utils.clean_value_dict(loss_dict)
|
| 55 |
+
verbose_list.append(loss_dict)
|
| 56 |
+
|
| 57 |
+
# ======== verbose ========
|
| 58 |
+
# record result 5 times for a epoch
|
| 59 |
+
if verbose:
|
| 60 |
+
if idx % int(loader_len/5) == 0:
|
| 61 |
+
|
| 62 |
+
# plot that in loss dict
|
| 63 |
+
loss_dict_keys = list(loss_dict.keys())
|
| 64 |
+
|
| 65 |
+
train_verbose = "{:5d} / {:5d} ({:s}%):"
|
| 66 |
+
verbose_args = [idx,loader_len,str(int(idx/loader_len*100)).zfill(3)]
|
| 67 |
+
for key in loss_dict_keys:
|
| 68 |
+
train_verbose += "\t %s:{:.7f}"%key
|
| 69 |
+
verbose_args.append(loss_dict[key])
|
| 70 |
+
|
| 71 |
+
# plot the cumulative mean total loss
|
| 72 |
+
short_batch_df = pd.json_normalize(verbose_list) # this will be cumulative
|
| 73 |
+
mean_total = short_batch_df.loc[:,'Total'].mean()
|
| 74 |
+
train_verbose += "\t %s:{:.7f}"%"Mean_Total"
|
| 75 |
+
verbose_args.append(mean_total)
|
| 76 |
+
|
| 77 |
+
train_verbose = train_verbose.format(*verbose_args)
|
| 78 |
+
|
| 79 |
+
logger.info(train_verbose)
|
| 80 |
+
if popen.cuda_id != torch.device('cpu'):
|
| 81 |
+
with torch.cuda.device(popen.cuda_id):
|
| 82 |
+
torch.cuda.empty_cache()
|
| 83 |
+
|
| 84 |
+
def validate(dataloader,model,popen,epoch):
|
| 85 |
+
|
| 86 |
+
logger = logging.getLogger("VAE")
|
| 87 |
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 88 |
+
|
| 89 |
+
model = model.to(device)
|
| 90 |
+
model.teacher_forcing = False # turn off teacher_forcing
|
| 91 |
+
|
| 92 |
+
# ====== set up empty =====
|
| 93 |
+
verbose_list=[]
|
| 94 |
+
Y_ls = []
|
| 95 |
+
pred_ls = []
|
| 96 |
+
metric_dict = {}
|
| 97 |
+
# ======== evaluate =======
|
| 98 |
+
model.eval()
|
| 99 |
+
with torch.no_grad():
|
| 100 |
+
for idx,data in enumerate(dataloader):
|
| 101 |
+
X,Y = put_data_to_cuda(data,popen,require_grad=False)
|
| 102 |
+
Y_ls.append(Y.cpu().numpy())
|
| 103 |
+
out = model(X)
|
| 104 |
+
pred_ls.append(out.cpu().numpy())
|
| 105 |
+
loss_dict = model.compute_loss(out,X,Y,popen)
|
| 106 |
+
loss = loss_dict['Total']
|
| 107 |
+
acc_dict = model.compute_acc(out,X,Y,popen)
|
| 108 |
+
loss_dict.update(acc_dict)
|
| 109 |
+
|
| 110 |
+
loss_dict = utils.clean_value_dict(loss_dict) # convert possible torch to single item
|
| 111 |
+
verbose_list.append(loss_dict)
|
| 112 |
+
|
| 113 |
+
if popen.cuda_id != torch.device('cpu'):
|
| 114 |
+
with torch.cuda.device(popen.cuda_id):
|
| 115 |
+
torch.cuda.empty_cache()
|
| 116 |
+
|
| 117 |
+
# # average among batch
|
| 118 |
+
|
| 119 |
+
# ======== verbose ========
|
| 120 |
+
Y_ay = np.concatenate(Y_ls,axis=0).flatten()
|
| 121 |
+
pred_ay = np.concatenate(pred_ls,axis=0).flatten()
|
| 122 |
+
|
| 123 |
+
if popen.model_type == 'RL_clf':
|
| 124 |
+
metric_dict["F1"] = f1_score(Y_ay, pred_ay>0.5, average='binary')
|
| 125 |
+
metric_dict["AUROC"] = roc_auc_score(Y_ay, pred_ay)
|
| 126 |
+
else:
|
| 127 |
+
metric_dict[f"r2"] = r2_score(Y_ay, pred_ay)
|
| 128 |
+
metric_dict[f"pr"] = pearsonr(Y_ay, pred_ay)[0]
|
| 129 |
+
|
| 130 |
+
verbose_df = pd.json_normalize(verbose_list)
|
| 131 |
+
|
| 132 |
+
val_verbose = ""
|
| 133 |
+
verbose_args = []
|
| 134 |
+
verbose_dict = {key:verbose_df[key].mean() for key in verbose_df.columns}
|
| 135 |
+
verbose_dict.update(metric_dict)
|
| 136 |
+
|
| 137 |
+
for key,values in verbose_dict.items():
|
| 138 |
+
val_verbose += "\t %s:{:.7f}"%key
|
| 139 |
+
verbose_args.append(values)
|
| 140 |
+
|
| 141 |
+
val_verbose = val_verbose.format(*verbose_args)
|
| 142 |
+
|
| 143 |
+
logger.info(val_verbose)
|
| 144 |
+
|
| 145 |
+
# what avg acc return : mean of RL_Acc , Recons_Acc, Motif_Acc
|
| 146 |
+
acc_col = list(acc_dict.keys())
|
| 147 |
+
Avg_acc = np.mean(verbose_df.loc[:,acc_col].mean(axis=0))
|
| 148 |
+
|
| 149 |
+
# return these to save current performance
|
| 150 |
+
return (verbose_df['Total'].mean(),Avg_acc) if 'RL_loss' not in verbose_df.keys() else (verbose_df['RL_loss'].mean(),verbose_df['RL_Acc'].mean())
|
| 151 |
+
|
| 152 |
+
def iter_train(loader_dict, model, optimizer, popen, epoch, verbose=True):
|
| 153 |
+
|
| 154 |
+
logger = logging.getLogger("VAE")
|
| 155 |
+
# loader_len = len(dataloader) # number of iteration
|
| 156 |
+
all_len = [len(loader[0]) for loader in loader_dict.values()]
|
| 157 |
+
max_len = np.max(all_len)
|
| 158 |
+
n_task = len(popen.cycle_set)
|
| 159 |
+
total_len = max_len*n_task
|
| 160 |
+
|
| 161 |
+
all_train = {task : iter(loader[0]) for task,loader in loader_dict.items()}
|
| 162 |
+
def try_next(all_train, task):
|
| 163 |
+
try:
|
| 164 |
+
data = next(all_train[task])
|
| 165 |
+
return data
|
| 166 |
+
except StopIteration:
|
| 167 |
+
all_train[task] = iter(loader_dict[task][0])
|
| 168 |
+
data = next(all_train[task])
|
| 169 |
+
return data
|
| 170 |
+
|
| 171 |
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 172 |
+
model = model.to(device)
|
| 173 |
+
model.train()
|
| 174 |
+
|
| 175 |
+
verbose_list=[]
|
| 176 |
+
for idx in range(total_len):
|
| 177 |
+
task = popen.cycle_set[idx%n_task]
|
| 178 |
+
model.task = task
|
| 179 |
+
|
| 180 |
+
data = try_next(all_train, task)
|
| 181 |
+
|
| 182 |
+
X,Y = put_data_to_cuda(data,popen,require_grad=True)
|
| 183 |
+
optimizer.zero_grad()
|
| 184 |
+
|
| 185 |
+
out = model(X)
|
| 186 |
+
loss_dict = model.compute_loss(out,X,Y,popen)
|
| 187 |
+
loss = loss_dict['Total']
|
| 188 |
+
acc_dict = model.compute_acc(out,X,Y,popen)
|
| 189 |
+
loss_dict.update(acc_dict) # adding the acc ditc into loss dict
|
| 190 |
+
|
| 191 |
+
loss.backward()
|
| 192 |
+
optimizer.step()
|
| 193 |
+
|
| 194 |
+
# ====== update lr =======
|
| 195 |
+
if type(optimizer) == ScheduledOptim:
|
| 196 |
+
lr = optimizer.update_learning_rate() # see model.optim.py
|
| 197 |
+
loss_dict["lr"]=lr
|
| 198 |
+
elif popen.optimizer == 'Adam':
|
| 199 |
+
lr = optimizer.param_groups[0]['lr']
|
| 200 |
+
if popen.loss_schema != 'constant':
|
| 201 |
+
popen.chimerla_weight = popen.loss_schedualer._update(loss_dict)
|
| 202 |
+
for t in popen.tasks:
|
| 203 |
+
loss_dict[popen.loss_schema+"_wt_"+t] = popen.chimerla_weight[t]
|
| 204 |
+
|
| 205 |
+
with torch.no_grad():
|
| 206 |
+
loss_dict= utils.clean_value_dict(loss_dict)
|
| 207 |
+
verbose_list.append(loss_dict)
|
| 208 |
+
|
| 209 |
+
# ======== verbose ========
|
| 210 |
+
# record result 5 times for a epoch
|
| 211 |
+
if verbose:
|
| 212 |
+
if idx % int(total_len/5) == 0:
|
| 213 |
+
|
| 214 |
+
# plot that in loss dict
|
| 215 |
+
loss_dict_keys = list(loss_dict.keys())
|
| 216 |
+
|
| 217 |
+
train_verbose = "{:5d} / {:5d} ({:s}%):"
|
| 218 |
+
verbose_args = [idx,total_len,str(int(idx/total_len*100)).zfill(3)]
|
| 219 |
+
for key in loss_dict_keys:
|
| 220 |
+
train_verbose += "\t %s:{:.7f}"%key
|
| 221 |
+
verbose_args.append(loss_dict[key])
|
| 222 |
+
|
| 223 |
+
# plot the cumulative mean total loss
|
| 224 |
+
short_batch_df = pd.json_normalize(verbose_list) # this will be cumulative
|
| 225 |
+
mean_total = short_batch_df.loc[:,'Total'].mean()
|
| 226 |
+
train_verbose += "\t %s:{:.7f}"%"Mean_Total"
|
| 227 |
+
verbose_args.append(mean_total)
|
| 228 |
+
|
| 229 |
+
train_verbose = train_verbose.format(*verbose_args)
|
| 230 |
+
|
| 231 |
+
logger.info(train_verbose)
|
| 232 |
+
|
| 233 |
+
if popen.cuda_id != torch.device('cpu'):
|
| 234 |
+
with torch.cuda.device(popen.cuda_id):
|
| 235 |
+
torch.cuda.empty_cache()
|
| 236 |
+
|
| 237 |
+
def cycle_validate(loader_dict, model, optimizer, popen, epoch , which_set=1, return_=False):
|
| 238 |
+
|
| 239 |
+
logger = logging.getLogger("VAE")
|
| 240 |
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
| 241 |
+
|
| 242 |
+
model = model.to(device)
|
| 243 |
+
|
| 244 |
+
# ====== set up empty =====
|
| 245 |
+
# model.loss_dict_keys = ['RL_loss', 'Recons_loss', 'Motif_loss', 'Total', 'RL_Acc', 'Recons_Acc', 'Motif_Acc']
|
| 246 |
+
verbose_list=[]
|
| 247 |
+
r2_dict = {}
|
| 248 |
+
Y_n_pred = {}
|
| 249 |
+
# ======== evaluate =======
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
for subset, dataloader in loader_dict.items():
|
| 253 |
+
|
| 254 |
+
# fix
|
| 255 |
+
model.task = subset
|
| 256 |
+
# # logger.info(" =======================| fix |======================= ")
|
| 257 |
+
# model = utils.fix_parameter(model, popen.modual_to_fix[0])
|
| 258 |
+
# train(dataloader[0], model, optimizer, popen, epoch, verbose=True)
|
| 259 |
+
Y_ls = []
|
| 260 |
+
pred_ls = []
|
| 261 |
+
with torch.no_grad():
|
| 262 |
+
model.eval()
|
| 263 |
+
for idx,data in enumerate(dataloader[which_set]):
|
| 264 |
+
X,Y = put_data_to_cuda(data,popen,require_grad=False)
|
| 265 |
+
out = model(X)
|
| 266 |
+
|
| 267 |
+
Y_ls.append(Y.detach().cpu().numpy())
|
| 268 |
+
pred_ls.append(out.detach().cpu().numpy())
|
| 269 |
+
|
| 270 |
+
loss_dict = model.compute_loss(out,X,Y,popen)
|
| 271 |
+
loss_dict['%s_loss'%subset] = loss_dict['Total']
|
| 272 |
+
acc_dict = model.compute_acc(out,X,Y,popen)
|
| 273 |
+
loss_dict.update(acc_dict)
|
| 274 |
+
|
| 275 |
+
loss_dict = utils.clean_value_dict(loss_dict) # convert possible torch to single item
|
| 276 |
+
verbose_list.append(loss_dict)
|
| 277 |
+
|
| 278 |
+
if popen.cuda_id != torch.device('cpu'):
|
| 279 |
+
with torch.cuda.device(popen.cuda_id):
|
| 280 |
+
torch.cuda.empty_cache()
|
| 281 |
+
|
| 282 |
+
Y_ay = np.concatenate(Y_ls,axis=0).flatten()
|
| 283 |
+
pred_ay = np.concatenate(pred_ls,axis=0).flatten()
|
| 284 |
+
if return_:
|
| 285 |
+
Y_n_pred[subset] = (Y_ay, pred_ay)
|
| 286 |
+
r2_dict[f"{subset}_r2"] = r2_score(Y_ay, pred_ay)
|
| 287 |
+
r2_dict[f"{subset}_pr"] = pearsonr(Y_ay, pred_ay)[0]
|
| 288 |
+
|
| 289 |
+
# # average among batch
|
| 290 |
+
|
| 291 |
+
# ======== verbose ========
|
| 292 |
+
|
| 293 |
+
verbose_df = pd.json_normalize(verbose_list)
|
| 294 |
+
|
| 295 |
+
val_verbose = ""
|
| 296 |
+
verbose_args = []
|
| 297 |
+
verbose_dict = {key:verbose_df[key].mean() for key in verbose_df.columns}
|
| 298 |
+
verbose_dict.update(r2_dict)
|
| 299 |
+
for key,values in verbose_dict.items():
|
| 300 |
+
val_verbose += "\t %s:{:.7f}"%key
|
| 301 |
+
verbose_args.append(values)
|
| 302 |
+
|
| 303 |
+
val_verbose = val_verbose.format(*verbose_args)
|
| 304 |
+
|
| 305 |
+
logger.info(val_verbose)
|
| 306 |
+
|
| 307 |
+
# what avg acc return : mean of RL_Acc , Recons_Acc, Motif_Acc
|
| 308 |
+
acc_col = list(acc_dict.keys())
|
| 309 |
+
Avg_acc = np.mean(verbose_df.loc[:,acc_col].mean(axis=0))
|
| 310 |
+
|
| 311 |
+
if return_:
|
| 312 |
+
return verbose_dict, Y_n_pred
|
| 313 |
+
else:
|
| 314 |
+
return verbose_dict
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def put_data_to_cuda(data,popen,require_grad=True):
|
| 318 |
+
|
| 319 |
+
X,y = data
|
| 320 |
+
device = popen.cuda_id
|
| 321 |
+
# for X is a list [seq, uAUG ....]
|
| 322 |
+
if popen.other_input_columns is not None:
|
| 323 |
+
X = [x_i.float().to(device) for x_i in X]
|
| 324 |
+
if require_grad:
|
| 325 |
+
for x_i in X:
|
| 326 |
+
x_i.required_grad = True
|
| 327 |
+
|
| 328 |
+
# X is not a list : seq
|
| 329 |
+
else:
|
| 330 |
+
X = X.float().to(device)
|
| 331 |
+
if require_grad:
|
| 332 |
+
X.required_grad = True # check !!!
|
| 333 |
+
|
| 334 |
+
Y = y.float().to(device)
|
| 335 |
+
|
| 336 |
+
# Y = Y if X.shape == Y.shape else None # for mask data
|
| 337 |
+
return X,Y
|
model/src/mrl_te_optimization/popen.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import numpy as np
|
| 4 |
+
import utils
|
| 5 |
+
import json
|
| 6 |
+
from models import Modules
|
| 7 |
+
import configparser
|
| 8 |
+
import logging
|
| 9 |
+
|
| 10 |
+
class Auto_popen(object):
|
| 11 |
+
def __init__(self,config_file):
|
| 12 |
+
"""
|
| 13 |
+
read the config_fiel
|
| 14 |
+
"""
|
| 15 |
+
# machine config path
|
| 16 |
+
self.shuffle = True
|
| 17 |
+
self.script_dir = utils.script_dir
|
| 18 |
+
self.data_dir = utils.data_dir
|
| 19 |
+
self.log_dir = utils.log_dir
|
| 20 |
+
self.pth_dir = utils.pth_dir
|
| 21 |
+
self.set_attr_as_none(['te_net_l2','loss_fn','modual_to_fix','other_input_columns','pretrain_pth','kfold_index'])
|
| 22 |
+
self.split_like = False
|
| 23 |
+
self.loss_schema = 'constant'
|
| 24 |
+
|
| 25 |
+
# transform to dict and convert to specific data type
|
| 26 |
+
self.config = configparser.ConfigParser()
|
| 27 |
+
self.config.read(config_file)
|
| 28 |
+
self.config_file = config_file
|
| 29 |
+
self.config_dict = {item[0]: eval(item[1]) for item in self.config.items('DEFAULT')}
|
| 30 |
+
|
| 31 |
+
# assign some attr from config_dict
|
| 32 |
+
self.set_attr_from_dict(self.config_dict.keys())
|
| 33 |
+
self.check_run_and_setting_name() # check run name
|
| 34 |
+
self._dataset = "_" + self.dataset if self.dataset != '' else self.dataset
|
| 35 |
+
# the saving direction
|
| 36 |
+
self.path_category = self.config_file.split('/')[-4]
|
| 37 |
+
self.vae_log_path = config_file.replace('.ini','.log')
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
self.Resumable = False
|
| 41 |
+
|
| 42 |
+
# covariates for other input
|
| 43 |
+
self.n_covar = len(self.other_input_columns) if self.other_input_columns is not None else 0
|
| 44 |
+
|
| 45 |
+
# generate self.model_args
|
| 46 |
+
self.get_model_config()
|
| 47 |
+
|
| 48 |
+
@property
|
| 49 |
+
def vae_pth_path(self):
|
| 50 |
+
save_to = os.path.join(self.pth_dir,self.model_type+self._dataset,self.setting_name)
|
| 51 |
+
if self.kfold_index is None:
|
| 52 |
+
pth = os.path.join(save_to, self.run_name + '-model_best.pth')
|
| 53 |
+
elif type(self.kfold_index) == int:
|
| 54 |
+
k = self.kfold_index
|
| 55 |
+
pth = os.path.join(save_to, self.run_name + f'-model_best_cv{k}.pth')
|
| 56 |
+
return pth
|
| 57 |
+
|
| 58 |
+
@vae_pth_path.setter
|
| 59 |
+
def vae_pth_path(self, path):
|
| 60 |
+
self._vae_pth_path = path
|
| 61 |
+
|
| 62 |
+
def set_attr_from_dict(self,attr_ls):
|
| 63 |
+
for attr in attr_ls:
|
| 64 |
+
self.__setattr__(attr,self.config_dict[attr])
|
| 65 |
+
|
| 66 |
+
def set_attr_as_none(self,attr_ls):
|
| 67 |
+
for attr in attr_ls:
|
| 68 |
+
self.__setattr__(attr,None)
|
| 69 |
+
|
| 70 |
+
def check_run_and_setting_name(self):
|
| 71 |
+
file_name = self.config_file.split("/")[-1]
|
| 72 |
+
dir_name = self.config_file.split("/")[-2]
|
| 73 |
+
self.setting_name = dir_name
|
| 74 |
+
assert self.run_name == file_name.split(".")[0]
|
| 75 |
+
# assert self.run_name == file_name.split(".")[0]
|
| 76 |
+
|
| 77 |
+
def get_model_config(self):
|
| 78 |
+
"""
|
| 79 |
+
assert we type in the correct model type and group them into model_args
|
| 80 |
+
"""
|
| 81 |
+
self.model_type = 'RL_hard_share'
|
| 82 |
+
if self.model_type in dir(Modules):
|
| 83 |
+
self.Model_Class = eval("Modules.{}".format(self.model_type))
|
| 84 |
+
else:
|
| 85 |
+
raise NameError("not such model type")
|
| 86 |
+
|
| 87 |
+
# conv_args define the soft-sharing part
|
| 88 |
+
conv_args = ["channel_ls","kernel_size","stride","padding_ls","diliation_ls","pad_to"]
|
| 89 |
+
self.conv_args = tuple([self.__getattribute__(arg) for arg in conv_args])
|
| 90 |
+
|
| 91 |
+
# left args dfine the tower part in which the arguments are different among tasks
|
| 92 |
+
left_args={# Backbone models
|
| 93 |
+
'RL_regressor':["tower_width","dropout_rate"],
|
| 94 |
+
'RL_clf':["n_class","tower_width","dropout_rate"],
|
| 95 |
+
'RL_gru':["tower_width","dropout_rate"],
|
| 96 |
+
'RL_FACS': ["tower_width","dropout_rate"],
|
| 97 |
+
'RL_hard_share':["tower_width","dropout_rate", "activation","cycle_set" ],
|
| 98 |
+
'RL_covar_reg':["tower_width","dropout_rate", "activation", "n_covar", "cycle_set" ],
|
| 99 |
+
'RL_covar_intercept':["tower_width","dropout_rate", "activation", "n_covar", "cycle_set" ],
|
| 100 |
+
'RL_mish_gru':["tower_width","dropout_rate"],
|
| 101 |
+
# GP models
|
| 102 |
+
'GP_net': ['tower_width', 'dropout_rate', 'global_pooling', 'activation', 'cycle_set'],
|
| 103 |
+
'Frame_GP': ['tower_width', 'dropout_rate', 'activation', 'cycle_set'],
|
| 104 |
+
'RL_Atten': ['qk_dim', 'n_head', 'n_atten_layer', 'tower_width', 'dropout_rate', 'activation', 'cycle_set'],
|
| 105 |
+
# Koo net
|
| 106 |
+
'Conf_CNN' : ['pool_size'],
|
| 107 |
+
}[self.model_type]
|
| 108 |
+
|
| 109 |
+
self.model_args = [self.conv_args] + [self.__getattribute__(arg) for arg in left_args]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def check_experiment(self,logger):
|
| 113 |
+
"""
|
| 114 |
+
check any unfinished experiment ?
|
| 115 |
+
"""
|
| 116 |
+
log_save_dir = os.path.dirname(self.vae_log_path)
|
| 117 |
+
pth_save_dir = os.path.join(self.pth_dir,self.model_type+self._dataset,self.setting_name)
|
| 118 |
+
# make dirs
|
| 119 |
+
if not os.path.exists(log_save_dir):
|
| 120 |
+
os.makedirs(log_save_dir)
|
| 121 |
+
if not os.path.exists(pth_save_dir):
|
| 122 |
+
os.makedirs(pth_save_dir)
|
| 123 |
+
|
| 124 |
+
# check resume
|
| 125 |
+
if os.path.exists(self.vae_log_path) & os.path.exists(self.vae_pth_path):
|
| 126 |
+
self.Resumable = True
|
| 127 |
+
logger.info(' \t \t ==============<<< Experiment detected >>>============== \t \t \n')
|
| 128 |
+
|
| 129 |
+
def update_ini_file(self,E,logger):
|
| 130 |
+
"""
|
| 131 |
+
E is the dict contain the things to update
|
| 132 |
+
"""
|
| 133 |
+
# update the ini file
|
| 134 |
+
self.config_dict.update(E)
|
| 135 |
+
strconfig = {K: repr(V) for K,V in self.config_dict.items()}
|
| 136 |
+
self.config['DEFAULT'] = strconfig
|
| 137 |
+
|
| 138 |
+
with open(self.config_file,'w') as f:
|
| 139 |
+
self.config.write(f)
|
| 140 |
+
|
| 141 |
+
logger.info(' ini file updated ')
|
| 142 |
+
|
| 143 |
+
def chimera_weight_update(self):
|
| 144 |
+
# TODO : progressively update the loss weight between tasks
|
| 145 |
+
|
| 146 |
+
# TODO : 1. scale the loss into the same magnitude
|
| 147 |
+
|
| 148 |
+
# TODO : 2. update the weight by their own learning progress
|
| 149 |
+
|
| 150 |
+
return None
|
model/src/mrl_te_optimization/script/Nupack_MFE_prediction.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/ssd/users/wergillius/.conda/envs/pytorch/bin/python
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import nupack
|
| 7 |
+
import PATH
|
| 8 |
+
import utils
|
| 9 |
+
import scipy
|
| 10 |
+
from tqdm import tqdm
|
| 11 |
+
tqdm.pandas()
|
| 12 |
+
|
| 13 |
+
my_model=nupack.Model(material='RNA')
|
| 14 |
+
eGFP_seq = utils.eGFP_seq
|
| 15 |
+
|
| 16 |
+
data_dir= utils.data_dir
|
| 17 |
+
csv_name = sys.argv[1]
|
| 18 |
+
csv_path = csv_name if os.path.exists(csv_name) else os.path.join(data_dir, csv_name)
|
| 19 |
+
|
| 20 |
+
assert os.path.exists(csv_path), "csv not found"
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
df = pd.read_csv(csv_path)
|
| 24 |
+
seq_col = 'seq' if 'seq' in df.columns else 'utr'
|
| 25 |
+
tr_col = 'rl' if 'rl' in df.columns else 'log_te'
|
| 26 |
+
|
| 27 |
+
def cor_fun(col):
|
| 28 |
+
pearson_r = scipy.stats.pearsonr(df[col].values,
|
| 29 |
+
df[tr_col].values)[0]
|
| 30 |
+
return pearson_r
|
| 31 |
+
|
| 32 |
+
nupck_engery_fn = lambda x: nupack.mfe(strands=[x], model=my_model)[0].energy
|
| 33 |
+
df['nupack_MFE'] = df[seq_col].progress_apply(nupck_engery_fn)
|
| 34 |
+
|
| 35 |
+
print("nupack_MFE : {}".format(cor_fun('nupack_MFE')))
|
| 36 |
+
|
| 37 |
+
# nupck_engery_fn = lambda x: nupack.mfe(strands=[x + eGFP_seq[:10]], model=my_model)[0].energy
|
| 38 |
+
# df['eGFP10_nupMFE'] = df[seq_col].progress_apply(nupck_engery_fn)
|
| 39 |
+
|
| 40 |
+
# print("eGFP10_nupMFE : {}".format(cor_fun('eGFP10_nupMFE')))
|
| 41 |
+
|
| 42 |
+
# nupck_engery_fn = lambda x: nupack.mfe(strands=[x + eGFP_seq[:50]], model=my_model)[0].energy
|
| 43 |
+
# df['eGFP50_nupMFE'] = df[seq_col].progress_apply(nupck_engery_fn)
|
| 44 |
+
|
| 45 |
+
# print("eGFP50_nupMFE : {}".format(cor_fun('eGFP50_nupMFE')))
|
| 46 |
+
|
| 47 |
+
df.to_csv(csv_path, index=False)
|
| 48 |
+
print(f"saved to {csv_path}")
|
model/src/mrl_te_optimization/script/PATH.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
from utils import *
|
model/src/mrl_te_optimization/script/covar_test.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser('the main to train model')
|
| 6 |
+
parser.add_argument('--config_file',type=str,required=True)
|
| 7 |
+
parser.add_argument('--cuda',type=str,default=0,required=False)
|
| 8 |
+
parser.add_argument("--kfold_index",type=int,default=1,required=False)
|
| 9 |
+
args = parser.parse_args()
|
| 10 |
+
|
| 11 |
+
cuda_id = args.cuda if args.cuda is not None else utils.get_config_cuda(args.config_file)
|
| 12 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_id)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
import torch
|
| 17 |
+
import copy
|
| 18 |
+
import utils
|
| 19 |
+
from torch import optim
|
| 20 |
+
import numpy as np
|
| 21 |
+
from models import reader,train_val
|
| 22 |
+
from models.ScheduleOptimizer import ScheduledOptim,scheduleoptim_dict_str
|
| 23 |
+
from models.popen import Auto_popen
|
| 24 |
+
from models.loss import Dynamic_Task_Priority,Dynamic_Weight_Averaging
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
POPEN = Auto_popen(args.config_file)
|
| 28 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 29 |
+
POPEN.cuda_id = device
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
POPEN.kfold_index = args.kfold_index
|
| 33 |
+
if POPEN.kfold_cv:
|
| 34 |
+
if args.kfold_index is None:
|
| 35 |
+
raise NotImplementedError("please specify the kfold index to perform K fold cross validation")
|
| 36 |
+
POPEN.vae_log_path = POPEN.vae_log_path.replace(".log","_cv%d.log"%args.kfold_index)
|
| 37 |
+
#POPEN.vae_pth_path = POPEN.vae_pth_path.replace(".pth","_cv%d.pth"%args.kfold_index)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Run name
|
| 41 |
+
if POPEN.run_name is None:
|
| 42 |
+
run_name = POPEN.model_type + time.strftime("__%Y_%m_%d_%H:%M")
|
| 43 |
+
else:
|
| 44 |
+
run_name = POPEN.run_name
|
| 45 |
+
|
| 46 |
+
# log dir
|
| 47 |
+
logger = utils.setup_logs(POPEN.vae_log_path)
|
| 48 |
+
logger.info(f" ===========================| device {device}{cuda_id} |=========================== ")
|
| 49 |
+
# built model dir or check resume
|
| 50 |
+
POPEN.check_experiment(logger)
|
| 51 |
+
|
| 52 |
+
# |=====================================|
|
| 53 |
+
# |=========== setup part ==========|
|
| 54 |
+
# |=====================================|
|
| 55 |
+
# read data
|
| 56 |
+
loader_set = {}
|
| 57 |
+
n_covar_dict = {}
|
| 58 |
+
base_path = ['cycle_train_val.csv', 'cycle_test.csv']
|
| 59 |
+
base_csv = 'cycle_MTL_transfer.csv'
|
| 60 |
+
for task in POPEN.cycle_set:
|
| 61 |
+
if (task in ['MPA_U', 'MPA_H', 'MPA_V', 'SubMPA_H']):
|
| 62 |
+
datapopen = Auto_popen('log/Backbone/RL_covar_intercept/3M/no_covar.ini')
|
| 63 |
+
datapopen.split_like = [path.replace('cycle', task) for path in base_path]
|
| 64 |
+
datapopen.kfold_index = args.kfold_index
|
| 65 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 66 |
+
|
| 67 |
+
elif (task in ['RP_293T', 'RP_muscle', 'RP_PC3']):
|
| 68 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3R/schedule_MTL.ini')
|
| 69 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 70 |
+
datapopen.kfold_index = args.kfold_index
|
| 71 |
+
datapopen.pad_to = POPEN.pad_to
|
| 72 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 73 |
+
datapopen.n_covar = POPEN.n_covar
|
| 74 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 75 |
+
|
| 76 |
+
elif (task in ['pcr3', '293']):
|
| 77 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/karollus_RPs/rp_cycle.ini')
|
| 78 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 79 |
+
datapopen.kfold_index = args.kfold_index
|
| 80 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 81 |
+
datapopen.pad_to = POPEN.pad_to
|
| 82 |
+
datapopen.n_covar = POPEN.n_covar
|
| 83 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 84 |
+
loader_set[task] = reader.get_dataloader(datapopen)
|
| 85 |
+
|
| 86 |
+
POPEN.n_covar = n_covar_dict
|
| 87 |
+
POPEN.get_model_config() # update model config
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
# =========== setup model ===========
|
| 91 |
+
# train_iter = iter(train_loader)
|
| 92 |
+
# X,Y = next(train_iter)
|
| 93 |
+
# -- pretrain --
|
| 94 |
+
if POPEN.pretrain_pth is not None:
|
| 95 |
+
# load pretran model
|
| 96 |
+
logger.info("===============================| pretrain |===============================")
|
| 97 |
+
logger.info(f" {POPEN.pretrain_pth}")
|
| 98 |
+
pretrain_popen = Auto_popen(os.path.join(utils.script_dir, POPEN.pretrain_pth))
|
| 99 |
+
if not os.path.exists(pretrain_popen.vae_pth_path):
|
| 100 |
+
if type(args.kfold_index) == int:
|
| 101 |
+
pretrain_popen.kfold_index = args.kfold_index
|
| 102 |
+
pretrain_model = torch.load(pretrain_popen.vae_pth_path, map_location=torch.device('cpu'))['state_dict']
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
if POPEN.model_type == pretrain_popen.model_type:
|
| 106 |
+
# if not POPEN.Resumable:
|
| 107 |
+
# # we only load pre-train for the first time
|
| 108 |
+
# # later we can resume
|
| 109 |
+
model = pretrain_model.to(device)
|
| 110 |
+
del pretrain_model
|
| 111 |
+
|
| 112 |
+
if (POPEN.cycle_set != pretrain_popen.cycle_set):
|
| 113 |
+
model.all_tasks = POPEN.cycle_set
|
| 114 |
+
model.tower = torch.nn.ModuleDict(
|
| 115 |
+
{POPEN.cycle_set[i] : model.tower[t] for i, t in enumerate(pretrain_popen.cycle_set)}
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
elif POPEN.modual_to_fix is not None:
|
| 119 |
+
# POPEN.model_type != pretrain_popen.model_type
|
| 120 |
+
|
| 121 |
+
model = POPEN.Model_Class(*POPEN.model_args)
|
| 122 |
+
for modual in POPEN.modual_to_fix:
|
| 123 |
+
if modual in dir(pretrain_model):
|
| 124 |
+
eval(f'model.{modual}').load_state_dict(
|
| 125 |
+
eval(f'model.{modual}').state_dict()
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
state_dict = {'epoch': 0,
|
| 129 |
+
'validation_acc': 0,
|
| 130 |
+
'state_dict': model.to('cpu'),
|
| 131 |
+
'validation_loss': 0}
|
| 132 |
+
shared_pretrain_pth = POPEN.vae_pth_path.replace(f"_cv{args.kfold_index}", '')
|
| 133 |
+
if not os.path.exists(shared_pretrain_pth):
|
| 134 |
+
utils.snapshot(shared_pretrain_pth, state_dict)
|
| 135 |
+
utils.snapshot(POPEN.vae_pth_path, state_dict)
|
| 136 |
+
|
| 137 |
+
model = torch.load(POPEN.vae_pth_path, map_location=torch.device('cpu'))
|
| 138 |
+
model = model.to(device)
|
| 139 |
+
|
| 140 |
+
# -- end2end --
|
| 141 |
+
else:
|
| 142 |
+
Model_Class = POPEN.Model_Class # DL_models.LSTM_AE
|
| 143 |
+
|
| 144 |
+
model = Model_Class(*POPEN.model_args).to(device)
|
| 145 |
+
|
| 146 |
+
if POPEN.Resumable:
|
| 147 |
+
model = utils.load_model(POPEN, model, logger)
|
| 148 |
+
|
| 149 |
+
# =========== fix parameters ===========
|
| 150 |
+
if isinstance(POPEN.modual_to_fix, list):
|
| 151 |
+
for modual in POPEN.modual_to_fix:
|
| 152 |
+
model = utils.fix_parameter(model,modual)
|
| 153 |
+
model = model.to(device)
|
| 154 |
+
logger.info(' \t \t ==============| %s fixed |============== \t \t \n'%POPEN.modual_to_fix)
|
| 155 |
+
# =========== set optimizer ===========
|
| 156 |
+
if POPEN.optimizer == 'Schedule':
|
| 157 |
+
optimizer = ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 158 |
+
betas=(0.9, 0.98),
|
| 159 |
+
eps=1e-09,
|
| 160 |
+
weight_decay=1e-4,
|
| 161 |
+
amsgrad=True),
|
| 162 |
+
n_warmup_steps=20)
|
| 163 |
+
elif type(POPEN.optimizer) == dict:
|
| 164 |
+
optimizer = eval(scheduleoptim_dict_str.format(**POPEN.optimizer))
|
| 165 |
+
else:
|
| 166 |
+
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 167 |
+
lr=POPEN.lr,
|
| 168 |
+
betas=(0.9, 0.98),
|
| 169 |
+
eps=1e-09,
|
| 170 |
+
weight_decay=POPEN.l2)
|
| 171 |
+
if POPEN.loss_schema == 'DTP':
|
| 172 |
+
POPEN.loss_schedualer = Dynamic_Task_Priority(POPEN.tasks,POPEN.gamma,POPEN.chimerla_weight)
|
| 173 |
+
elif POPEN.loss_schema == 'DWA':
|
| 174 |
+
POPEN.loss_schedualer = Dynamic_Weight_Averaging(POPEN.tasks,POPEN.tau,POPEN.chimerla_weight)
|
| 175 |
+
# =========== resume ===========
|
| 176 |
+
best_loss = np.inf
|
| 177 |
+
best_acc = 0
|
| 178 |
+
best_epoch = 0
|
| 179 |
+
previous_epoch = 0
|
| 180 |
+
if POPEN.Resumable:
|
| 181 |
+
previous_epoch,best_loss,best_acc = utils.resume(POPEN, optimizer,logger)
|
| 182 |
+
epoch = previous_epoch
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# |=====================================|
|
| 186 |
+
# |========== test part ==========|
|
| 187 |
+
# |=====================================|
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
logger.info("===============================| testing |===============================")
|
| 192 |
+
verbose_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch, which_set=2)
|
| 193 |
+
# matching task performance influence what to save
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
if np.any(['r2' in key for key in verbose_dict.keys()]):
|
| 198 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'r2' in key])
|
| 199 |
+
acc_dict = {f"cv{args.kfold_index}_{key}":values for key, values in verbose_dict.items() if 'r2' in key}
|
| 200 |
+
else:
|
| 201 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'acc' in key])
|
| 202 |
+
acc_dict = {}
|
| 203 |
+
val_total_loss = verbose_dict['Total']
|
model/src/mrl_te_optimization/script/covar_train.py
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser('the main to train model')
|
| 6 |
+
parser.add_argument('--config_file',type=str,required=True)
|
| 7 |
+
parser.add_argument('--cuda',type=str,default=0,required=False)
|
| 8 |
+
parser.add_argument("--kfold_index",type=int,default=1,required=False)
|
| 9 |
+
args = parser.parse_args()
|
| 10 |
+
|
| 11 |
+
cuda_id = args.cuda if args.cuda is not None else utils.get_config_cuda(args.config_file)
|
| 12 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_id)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
import torch
|
| 17 |
+
import copy
|
| 18 |
+
import utils
|
| 19 |
+
from torch import optim
|
| 20 |
+
import numpy as np
|
| 21 |
+
from models import reader,train_val
|
| 22 |
+
from models.ScheduleOptimizer import ScheduledOptim,scheduleoptim_dict_str
|
| 23 |
+
from models.popen import Auto_popen
|
| 24 |
+
from models.loss import Dynamic_Task_Priority,Dynamic_Weight_Averaging
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
POPEN = Auto_popen(args.config_file)
|
| 28 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 29 |
+
POPEN.cuda_id = device
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
POPEN.kfold_index = args.kfold_index
|
| 33 |
+
if POPEN.kfold_cv:
|
| 34 |
+
if args.kfold_index is None:
|
| 35 |
+
raise NotImplementedError("please specify the kfold index to perform K fold cross validation")
|
| 36 |
+
POPEN.vae_log_path = POPEN.vae_log_path.replace(".log","_cv%d.log"%args.kfold_index)
|
| 37 |
+
#POPEN.vae_pth_path = POPEN.vae_pth_path.replace(".pth","_cv%d.pth"%args.kfold_index)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Run name
|
| 41 |
+
if POPEN.run_name is None:
|
| 42 |
+
run_name = POPEN.model_type + time.strftime("__%Y_%m_%d_%H:%M")
|
| 43 |
+
else:
|
| 44 |
+
run_name = POPEN.run_name
|
| 45 |
+
|
| 46 |
+
# log dir
|
| 47 |
+
logger = utils.setup_logs(POPEN.vae_log_path)
|
| 48 |
+
logger.info(f" ===========================| device {device}{cuda_id} |=========================== ")
|
| 49 |
+
# built model dir or check resume
|
| 50 |
+
POPEN.check_experiment(logger)
|
| 51 |
+
|
| 52 |
+
# |=====================================|
|
| 53 |
+
# |=========== setup part ==========|
|
| 54 |
+
# |=====================================|
|
| 55 |
+
# read data
|
| 56 |
+
loader_set = {}
|
| 57 |
+
n_covar_dict = {}
|
| 58 |
+
base_path = ['cycle_train_val.csv', 'cycle_test.csv']
|
| 59 |
+
base_csv = 'cycle_MTL_transfer.csv'
|
| 60 |
+
for task in POPEN.cycle_set:
|
| 61 |
+
if (task in ['MPA_U', 'MPA_H', 'MPA_V', 'SubMPA_H']):
|
| 62 |
+
datapopen = Auto_popen('log/Backbone/RL_covar_intercept/3M/no_covar.ini')
|
| 63 |
+
datapopen.split_like = [path.replace('cycle', task) for path in base_path]
|
| 64 |
+
datapopen.kfold_index = args.kfold_index
|
| 65 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 66 |
+
|
| 67 |
+
elif (task in ['RP_293T', 'RP_muscle', 'RP_PC3']):
|
| 68 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3R/schedule_MTL.ini')
|
| 69 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 70 |
+
datapopen.kfold_index = args.kfold_index
|
| 71 |
+
datapopen.pad_to = POPEN.pad_to
|
| 72 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 73 |
+
datapopen.n_covar = POPEN.n_covar
|
| 74 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 75 |
+
|
| 76 |
+
elif (task in ['pcr3', '293']):
|
| 77 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/karollus_RPs/rp_cycle.ini')
|
| 78 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 79 |
+
datapopen.kfold_index = args.kfold_index
|
| 80 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 81 |
+
datapopen.pad_to = POPEN.pad_to
|
| 82 |
+
datapopen.n_covar = POPEN.n_covar
|
| 83 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 84 |
+
loader_set[task] = reader.get_dataloader(datapopen)
|
| 85 |
+
|
| 86 |
+
POPEN.n_covar = n_covar_dict
|
| 87 |
+
POPEN.get_model_config() # update model config
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
# =========== setup model ===========
|
| 91 |
+
# train_iter = iter(train_loader)
|
| 92 |
+
# X,Y = next(train_iter)
|
| 93 |
+
# -- pretrain --
|
| 94 |
+
if POPEN.pretrain_pth is not None:
|
| 95 |
+
# load pretran model
|
| 96 |
+
logger.info("===============================| pretrain |===============================")
|
| 97 |
+
logger.info(f" {POPEN.pretrain_pth}")
|
| 98 |
+
pretrain_popen = Auto_popen(os.path.join(utils.script_dir, POPEN.pretrain_pth))
|
| 99 |
+
if not os.path.exists(pretrain_popen.vae_pth_path):
|
| 100 |
+
if type(args.kfold_index) == int:
|
| 101 |
+
pretrain_popen.kfold_index = args.kfold_index
|
| 102 |
+
pretrain_model = torch.load(pretrain_popen.vae_pth_path, map_location=torch.device('cpu'))['state_dict']
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
if POPEN.model_type == pretrain_popen.model_type:
|
| 106 |
+
# if not POPEN.Resumable:
|
| 107 |
+
# # we only load pre-train for the first time
|
| 108 |
+
# # later we can resume
|
| 109 |
+
model = pretrain_model.to(device)
|
| 110 |
+
del pretrain_model
|
| 111 |
+
|
| 112 |
+
if (POPEN.cycle_set != pretrain_popen.cycle_set):
|
| 113 |
+
model.all_tasks = POPEN.cycle_set
|
| 114 |
+
model.tower = torch.nn.ModuleDict(
|
| 115 |
+
{POPEN.cycle_set[i] : model.tower[t] for i, t in enumerate(pretrain_popen.cycle_set)}
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
elif POPEN.modual_to_fix is not None:
|
| 119 |
+
# POPEN.model_type != pretrain_popen.model_type
|
| 120 |
+
|
| 121 |
+
model = POPEN.Model_Class(*POPEN.model_args)
|
| 122 |
+
for modual in POPEN.modual_to_fix:
|
| 123 |
+
if modual in dir(pretrain_model):
|
| 124 |
+
eval(f'model.{modual}').load_state_dict(
|
| 125 |
+
eval(f'model.{modual}').state_dict()
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
state_dict = {'epoch': 0,
|
| 129 |
+
'validation_acc': 0,
|
| 130 |
+
'state_dict': model.to('cpu'),
|
| 131 |
+
'validation_loss': 0}
|
| 132 |
+
shared_pretrain_pth = POPEN.vae_pth_path.replace(f"_cv{args.kfold_index}", '')
|
| 133 |
+
if not os.path.exists(shared_pretrain_pth):
|
| 134 |
+
utils.snapshot(shared_pretrain_pth, state_dict)
|
| 135 |
+
utils.snapshot(POPEN.vae_pth_path, state_dict)
|
| 136 |
+
|
| 137 |
+
model = torch.load(POPEN.vae_pth_path, map_location=torch.device('cpu'))
|
| 138 |
+
model = model.to(device)
|
| 139 |
+
|
| 140 |
+
# -- end2end --
|
| 141 |
+
else:
|
| 142 |
+
Model_Class = POPEN.Model_Class # DL_models.LSTM_AE
|
| 143 |
+
|
| 144 |
+
model = Model_Class(*POPEN.model_args).to(device)
|
| 145 |
+
|
| 146 |
+
if POPEN.Resumable:
|
| 147 |
+
model = utils.load_model(POPEN, model, logger)
|
| 148 |
+
|
| 149 |
+
# =========== fix parameters ===========
|
| 150 |
+
if isinstance(POPEN.modual_to_fix, list):
|
| 151 |
+
for modual in POPEN.modual_to_fix:
|
| 152 |
+
model = utils.fix_parameter(model,modual)
|
| 153 |
+
model = model.to(device)
|
| 154 |
+
logger.info(' \t \t ==============| %s fixed |============== \t \t \n'%POPEN.modual_to_fix)
|
| 155 |
+
# =========== set optimizer ===========
|
| 156 |
+
if POPEN.optimizer == 'Schedule':
|
| 157 |
+
optimizer = ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 158 |
+
betas=(0.9, 0.98),
|
| 159 |
+
eps=1e-09,
|
| 160 |
+
weight_decay=1e-4,
|
| 161 |
+
amsgrad=True),
|
| 162 |
+
n_warmup_steps=20)
|
| 163 |
+
elif type(POPEN.optimizer) == dict:
|
| 164 |
+
optimizer = eval(scheduleoptim_dict_str.format(**POPEN.optimizer))
|
| 165 |
+
else:
|
| 166 |
+
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 167 |
+
lr=POPEN.lr,
|
| 168 |
+
betas=(0.9, 0.98),
|
| 169 |
+
eps=1e-09,
|
| 170 |
+
weight_decay=POPEN.l2)
|
| 171 |
+
if POPEN.loss_schema == 'DTP':
|
| 172 |
+
POPEN.loss_schedualer = Dynamic_Task_Priority(POPEN.tasks,POPEN.gamma,POPEN.chimerla_weight)
|
| 173 |
+
elif POPEN.loss_schema == 'DWA':
|
| 174 |
+
POPEN.loss_schedualer = Dynamic_Weight_Averaging(POPEN.tasks,POPEN.tau,POPEN.chimerla_weight)
|
| 175 |
+
# =========== resume ===========
|
| 176 |
+
best_loss = np.inf
|
| 177 |
+
best_acc = 0
|
| 178 |
+
best_epoch = 0
|
| 179 |
+
previous_epoch = 0
|
| 180 |
+
if POPEN.Resumable:
|
| 181 |
+
previous_epoch,best_loss,best_acc = utils.resume(POPEN, optimizer,logger)
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
# |=====================================|
|
| 185 |
+
# |========== training part ==========|
|
| 186 |
+
# |=====================================|
|
| 187 |
+
for epoch in range(POPEN.max_epoch-previous_epoch+1):
|
| 188 |
+
epoch += previous_epoch
|
| 189 |
+
|
| 190 |
+
#
|
| 191 |
+
logger.info("===============================| epoch {} |===============================".format(epoch))
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
train_val.iter_train(loader_set,model=model,optimizer=optimizer,popen=POPEN,epoch=epoch)
|
| 195 |
+
|
| 196 |
+
# -----------| validate |-----------
|
| 197 |
+
logger.info("===============================| start validation |===============================")
|
| 198 |
+
verbose_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch)
|
| 199 |
+
test_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch, which_set=2)
|
| 200 |
+
|
| 201 |
+
if np.any(['r2' in key for key in verbose_dict.keys()]):
|
| 202 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'r2' in key])
|
| 203 |
+
else:
|
| 204 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'acc' in key])
|
| 205 |
+
val_total_loss = verbose_dict['Total']
|
| 206 |
+
|
| 207 |
+
# matching task performance influence what to save
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
DICT ={"ran_epoch":epoch,"n_current_steps":optimizer.n_current_steps,"delta":optimizer.delta} if type(optimizer) == ScheduledOptim else {"ran_epoch":epoch}
|
| 211 |
+
POPEN.update_ini_file(DICT,logger)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
# -----------| compare the result |-----------
|
| 215 |
+
if (best_loss > val_total_loss) :
|
| 216 |
+
# update best performance
|
| 217 |
+
best_loss = min(best_loss,val_total_loss)
|
| 218 |
+
best_acc = max(best_acc,val_avg_acc)
|
| 219 |
+
best_epoch = epoch
|
| 220 |
+
|
| 221 |
+
# save
|
| 222 |
+
utils.snapshot(POPEN.vae_pth_path, {
|
| 223 |
+
'epoch': epoch + 1,
|
| 224 |
+
'validation_acc': val_avg_acc,
|
| 225 |
+
# 'state_dict': model.state_dict(),
|
| 226 |
+
'state_dict': model,
|
| 227 |
+
'validation_loss': val_total_loss,
|
| 228 |
+
'optimizer': optimizer.state_dict(),
|
| 229 |
+
})
|
| 230 |
+
|
| 231 |
+
# update the popen
|
| 232 |
+
POPEN.update_ini_file({'run_name':run_name,
|
| 233 |
+
"ran_epoch":epoch,
|
| 234 |
+
"best_acc":best_acc},
|
| 235 |
+
logger)
|
| 236 |
+
|
| 237 |
+
elif (epoch - best_epoch >= 30)&((type(optimizer) == ScheduledOptim)):
|
| 238 |
+
optimizer.increase_delta()
|
| 239 |
+
|
| 240 |
+
elif (epoch - best_epoch >= 60)&(epoch > POPEN.max_epoch/2):
|
| 241 |
+
# at the late phase of training
|
| 242 |
+
logger.info("<<<<<<<<<<< Early Stopping >>>>>>>>>>")
|
| 243 |
+
break
|
model/src/mrl_te_optimization/script/data_prepocessing.sh
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
python ./preprocessing_MPA.py
|
| 2 |
+
python ./preprocessing_RP.py
|
model/src/mrl_te_optimization/script/detect_changepoint_featmap.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
import PATH
|
| 6 |
+
import torch
|
| 7 |
+
import argparse
|
| 8 |
+
import seaborn as sns
|
| 9 |
+
#
|
| 10 |
+
from models import reader
|
| 11 |
+
from models import train_val
|
| 12 |
+
from models.popen import Auto_popen
|
| 13 |
+
from models import max_activation_patch as MAP
|
| 14 |
+
#
|
| 15 |
+
from sklearn.linear_model import Lasso, Ridge, ElasticNet, LassoCV, RidgeCV, ElasticNetCV
|
| 16 |
+
import warnings
|
| 17 |
+
from scipy.cluster import hierarchy
|
| 18 |
+
from matplotlib.backends.backend_pdf import PdfPages
|
| 19 |
+
warnings.filterwarnings('ignore')
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
#
|
| 23 |
+
parser = argparse.ArgumentParser('the script to evlauate the effect of ')
|
| 24 |
+
parser.add_argument("-c", "--config", type=str, required=True, help='the model config file: xxx.ini')
|
| 25 |
+
parser.add_argument("-s", "--set", type=int, default=2, help='train - 0 ,val - 1, test - 2 ')
|
| 26 |
+
parser.add_argument("-p", "--n_max_act", type=int, default=500, help='the number of seq')
|
| 27 |
+
parser.add_argument("-k", "--kfold_cv", type=int, default=1, help='the repeat')
|
| 28 |
+
parser.add_argument("-d", "--device", type=str, default='cpu', help='the device to use to extract featmap, digit or cpu')
|
| 29 |
+
args = parser.parse_args()
|
| 30 |
+
|
| 31 |
+
# args = parser.parse_args(["-c","/ssd/users/wergillius/Project/MTtrans/log/Backbone/RL_hard_share/3M/small_repective_filed_strides1113.ini",
|
| 32 |
+
# "-s","2",
|
| 33 |
+
# "-d", "1"])
|
| 34 |
+
|
| 35 |
+
config_path = args.config
|
| 36 |
+
save_path = config_path.replace(".ini", "_coef")
|
| 37 |
+
config = Auto_popen(config_path)
|
| 38 |
+
config.batch_size = 256
|
| 39 |
+
config.shuffle = False
|
| 40 |
+
config.kfold_cv = 'train_val'
|
| 41 |
+
all_task = config.cycle_set
|
| 42 |
+
|
| 43 |
+
task_channel_effect = {}
|
| 44 |
+
task_performance = {}
|
| 45 |
+
|
| 46 |
+
# path check
|
| 47 |
+
if os.path.exists(config_path) and not os.path.exists(save_path):
|
| 48 |
+
os.mkdir(save_path)
|
| 49 |
+
|
| 50 |
+
saved_pdf =os.path.join(save_path, 'changepoint_actmap.pdf')
|
| 51 |
+
pp = PdfPages(saved_pdf)
|
| 52 |
+
channel_cluster_task = {}
|
| 53 |
+
for task in all_task:
|
| 54 |
+
|
| 55 |
+
# .... format featmap as data ....
|
| 56 |
+
print(f"\n\nevaluating for task: {task}")
|
| 57 |
+
# re-instance the map for each task
|
| 58 |
+
map_task = MAP.Maximum_activation_patch(popen=config, which_layer=4,
|
| 59 |
+
n_patch=args.n_max_act,
|
| 60 |
+
kfold_index=args.kfold_cv,
|
| 61 |
+
device_string=args.device)
|
| 62 |
+
|
| 63 |
+
# extract feature map and rl decision chain
|
| 64 |
+
featmap = map_task.extract_feature_map(task=task, which_set=args.set)
|
| 65 |
+
cum_rl_trend = map_task.cumulative_rl_decision(task=task, which_set=args.set)
|
| 66 |
+
|
| 67 |
+
# truncate the featmap and rl trend according to sequence length
|
| 68 |
+
seq_len_ls = map_task.df[config.seq_col].apply(len)
|
| 69 |
+
total_stride = np.product(map_task.strides)
|
| 70 |
+
to_stay = seq_len_ls//total_stride - 4
|
| 71 |
+
trunc_start = featmap.shape[2] - to_stay
|
| 72 |
+
|
| 73 |
+
# if max_seq_len == 50:
|
| 74 |
+
# trunc_start = -12
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
# find the low rl sequences
|
| 78 |
+
rl_pred = cum_rl_trend[:,-1]
|
| 79 |
+
threshold = np.quantile(rl_pred, [0.05, 0.95])
|
| 80 |
+
|
| 81 |
+
low_rl = rl_pred < threshold[0]
|
| 82 |
+
high_rl = rl_pred > threshold[1]
|
| 83 |
+
|
| 84 |
+
# subset find low rl change point feature
|
| 85 |
+
lowrl_rl_chain = cum_rl_trend[low_rl]
|
| 86 |
+
lowrl_ft = featmap[low_rl]
|
| 87 |
+
lowrl_detect_region = [slice(s,None) for s in trunc_start[low_rl]]
|
| 88 |
+
changepoint_map = map_task.retrieve_featmap_at_changepoint(lowrl_ft, lowrl_rl_chain,
|
| 89 |
+
threshold=-1, direction='less', detect_region=lowrl_detect_region)
|
| 90 |
+
print(changepoint_map.shape)
|
| 91 |
+
|
| 92 |
+
# sample high rl feature
|
| 93 |
+
highrl_rl_chain = cum_rl_trend[high_rl]
|
| 94 |
+
highrl_ft = featmap[high_rl]
|
| 95 |
+
highrl_detect_region = [slice(s,None) for s in trunc_start[high_rl]]
|
| 96 |
+
background_map = map_task.retrieve_featmap_at_changepoint(highrl_ft, highrl_rl_chain,
|
| 97 |
+
threshold=0.5, direction='greater', detect_region=highrl_detect_region)
|
| 98 |
+
|
| 99 |
+
# and then subsample
|
| 100 |
+
n_background = background_map.shape[0]
|
| 101 |
+
n_foreground = changepoint_map.shape[0]
|
| 102 |
+
if n_background > n_foreground:
|
| 103 |
+
downsample_seed = np.random.choice(np.arange(0,n_background), size=n_foreground)
|
| 104 |
+
background_map = background_map[downsample_seed]
|
| 105 |
+
n_background = background_map.shape[0]
|
| 106 |
+
|
| 107 |
+
# concate and order two group
|
| 108 |
+
row_colors = ["#E09832"]*n_background + ["#192D48"]*n_foreground
|
| 109 |
+
all_act=np.concatenate([background_map, changepoint_map], axis=0)
|
| 110 |
+
feat_norm_act = (all_act - all_act.min(axis=0)) / (all_act.max(axis=0) - all_act.min(axis=0))
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
# Visualization
|
| 114 |
+
g=sns.clustermap(feat_norm_act, row_colors=row_colors);
|
| 115 |
+
|
| 116 |
+
# 'array', 'axis', 'calculate_dendrogram', 'calculated_linkage', 'data',
|
| 117 |
+
# 'dendrogram', 'dependent_coord', 'independent_coord', 'label', 'linkage',
|
| 118 |
+
# 'method', 'metric', 'plot', 'reordered_ind', 'rotate', 'shape', 'xlabel',
|
| 119 |
+
# 'xticklabels', 'xticks', 'ylabel', 'yticklabels', 'yticks'
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
Z_col=g.dendrogram_col.linkage
|
| 123 |
+
thres = 0.8*max(Z_col[:,2])
|
| 124 |
+
R = hierarchy.dendrogram(Z_col ,color_threshold=thres, truncate_mode=None,
|
| 125 |
+
above_threshold_color='#AAAAAA', p=10, orientation='top',ax=g.ax_col_dendrogram);
|
| 126 |
+
# R['leaves']
|
| 127 |
+
# R['ivl']
|
| 128 |
+
|
| 129 |
+
Z_row=g.dendrogram_row.linkage
|
| 130 |
+
thres = 0.8*max(Z_row[:,2])
|
| 131 |
+
R2 = hierarchy.dendrogram(Z_row ,color_threshold=thres, truncate_mode=None, orientation='left',
|
| 132 |
+
above_threshold_color='#AAAAAA', p=10, ax=g.ax_row_dendrogram);
|
| 133 |
+
g.ax_row_dendrogram.invert_yaxis()
|
| 134 |
+
g.figure.suptitle(task)
|
| 135 |
+
|
| 136 |
+
pp.savefig(g.figure)
|
| 137 |
+
|
| 138 |
+
channel_cluster_task[task] = pd.DataFrame(dict(zip(R['leaves'],R['leaves_color_list'])))
|
| 139 |
+
print("No..")
|
| 140 |
+
pp.close()
|
| 141 |
+
channel_cluster_df = pd.DataFrame(channel_cluster_task)
|
| 142 |
+
saved_csv = os.path.join(save_path, "changepoint_channel_cluster.csv")
|
| 143 |
+
channel_cluster_df.to_csv(saved_csv, index=False)
|
| 144 |
+
print("==DONE==")
|
| 145 |
+
print(f"result save to {saved_pdf}\n \t\t {saved_csv}")
|
| 146 |
+
|
model/src/mrl_te_optimization/script/download_training_data.sh
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DATA_DIR=$(cat machine_configure.json |grep data_dir|awk -F ': "' '{print $2}'|awk -F '",' '{print $1}')
|
| 2 |
+
|
| 3 |
+
if [ ! -d ${DATA_DIR} ]; then
|
| 4 |
+
echo "=============================================================="
|
| 5 |
+
echo " "
|
| 6 |
+
echo ${DATA_DIR} does not exist! Redirect to ./data
|
| 7 |
+
echo " "
|
| 8 |
+
echo "=============================================================="
|
| 9 |
+
DATA_DIR=$(pwd)/data
|
| 10 |
+
fi
|
| 11 |
+
|
| 12 |
+
cd ${DATA_DIR}
|
| 13 |
+
|
| 14 |
+
## download the ribosome profiling datasest
|
| 15 |
+
# RP-muscle
|
| 16 |
+
wget https://raw.githubusercontent.com/zzz2010/5UTR_Optimizer/master/data/df_counts_and_len.TE_sorted.Muscle.with_annot.txt
|
| 17 |
+
# RP-293T
|
| 18 |
+
wget https://raw.githubusercontent.com/zzz2010/5UTR_Optimizer/master/data/df_counts_and_len.TE_sorted.HEK_Andrev2015.with_annot.txt
|
| 19 |
+
# RP-PC3
|
| 20 |
+
wget https://raw.githubusercontent.com/zzz2010/5UTR_Optimizer/master/data/df_counts_and_len.TE_sorted.pc3.with_annot.txt
|
| 21 |
+
# ref
|
| 22 |
+
wget https://raw.githubusercontent.com/zzz2010/5UTR_Optimizer/master/data/gencode_v17_5utr_15bpcds.fa
|
| 23 |
+
|
| 24 |
+
## download the Massively parallel report assay datasets
|
| 25 |
+
# MPA_U
|
| 26 |
+
wget ftp.ncbi.nlm.nih.gov/geo/samples/GSM3130nnn/GSM3130435/suppl/GSM3130435_egfp_unmod_1.csv.gz
|
| 27 |
+
# MPA_H
|
| 28 |
+
wget ftp.ncbi.nlm.nih.gov/geo/samples/GSM3130nnn/GSM3130443/suppl/GSM3130443_designed_library.csv.gz
|
| 29 |
+
# MPA_V
|
| 30 |
+
wget ftp.ncbi.nlm.nih.gov/geo/samples/GSM4084nnn/GSM4084997/suppl/GSM4084997_varying_length_25to100.csv.gz
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
## dowlaod the yeast dataset
|
| 34 |
+
wget ftp.ncbi.nlm.nih.gov/geo/samples/GSM2793nnn/GSM2793752/suppl/GSM2793752_Random_UTRs.csv.gz
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
gzip -d *.gz
|
| 38 |
+
|
| 39 |
+
echo "Finished ! All data ready~"
|
| 40 |
+
echo "Please step to the pre-proccessing"
|
model/src/mrl_te_optimization/script/evaluate_channel_effect.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
import PATH
|
| 6 |
+
import torch
|
| 7 |
+
import argparse
|
| 8 |
+
#
|
| 9 |
+
from models import reader
|
| 10 |
+
from models import train_val
|
| 11 |
+
from models.popen import Auto_popen
|
| 12 |
+
from models import max_activation_patch as MAP
|
| 13 |
+
#
|
| 14 |
+
from sklearn.linear_model import LassoCV, RidgeCV, ElasticNetCV, LogisticRegressionCV
|
| 15 |
+
import warnings
|
| 16 |
+
warnings.filterwarnings('ignore')
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
#
|
| 20 |
+
parser = argparse.ArgumentParser('the script to evlauate the effect of ')
|
| 21 |
+
parser.add_argument("-c", "--config", type=str, required=True, help='the model config file: xxx.ini')
|
| 22 |
+
parser.add_argument("-s", "--set", type=int, default=2, help='train - 0 ,val - 1, test - 2 ')
|
| 23 |
+
parser.add_argument("-p", "--n_max_act", type=int, default=500, help='the number of seq')
|
| 24 |
+
parser.add_argument("-k", "--kfold_cv", type=int, default=1, help='the repeat')
|
| 25 |
+
parser.add_argument("-t", "--task", type=str, default='regression', help='either regression or classification')
|
| 26 |
+
parser.add_argument("-d", "--device", type=str, default='cpu', help='the device to use to extract featmap, digit or cpu')
|
| 27 |
+
args = parser.parse_args()
|
| 28 |
+
|
| 29 |
+
config_path = args.config
|
| 30 |
+
save_path = config_path.replace(".ini", "_coef")
|
| 31 |
+
config = Auto_popen(config_path)
|
| 32 |
+
config.batch_size = 256
|
| 33 |
+
# config.kfold_cv = 'train_val'
|
| 34 |
+
all_task = config.cycle_set
|
| 35 |
+
|
| 36 |
+
task_channel_effect = {}
|
| 37 |
+
task_performance = {}
|
| 38 |
+
|
| 39 |
+
# path check
|
| 40 |
+
if os.path.exists(config_path) and not os.path.exists(save_path):
|
| 41 |
+
os.mkdir(save_path)
|
| 42 |
+
|
| 43 |
+
for task in all_task:
|
| 44 |
+
|
| 45 |
+
# .... format featmap as data ....
|
| 46 |
+
print(f"\n\nevaluating for task: {task}")
|
| 47 |
+
# re-instance the map for each task
|
| 48 |
+
map_task = MAP.Maximum_activation_patch(popen=config, which_layer=4,
|
| 49 |
+
n_patch=args.n_max_act,
|
| 50 |
+
kfold_index=args.kfold_cv,
|
| 51 |
+
device_string=args.device)
|
| 52 |
+
|
| 53 |
+
# extract feature map and rl decision chain
|
| 54 |
+
featmap = map_task.extract_feature_map(task=task, which_set=args.set)
|
| 55 |
+
cum_rl_trend = map_task.cumulative_rl_decision(task=task, which_set=args.set)
|
| 56 |
+
|
| 57 |
+
# truncate the featmap and rl trend according to sequence length
|
| 58 |
+
max_seq_len = map_task.df[config.seq_col].apply(len).max()
|
| 59 |
+
to_stay = max_seq_len // np.product(map_task.strides) +1
|
| 60 |
+
trunc_start = featmap.shape[2] - to_stay
|
| 61 |
+
featmap = featmap[:,:,trunc_start:]
|
| 62 |
+
cum_rl_trend = cum_rl_trend[:,trunc_start:]
|
| 63 |
+
|
| 64 |
+
# construct input for linear regression
|
| 65 |
+
n_sample,n_channel,n_posi = featmap.shape
|
| 66 |
+
|
| 67 |
+
X = featmap.reshape(n_sample,-1)
|
| 68 |
+
Y = map_task.Y_ls.flatten()
|
| 69 |
+
|
| 70 |
+
# .... regression ....
|
| 71 |
+
if args.task == 'regression':
|
| 72 |
+
L1 = LassoCV(alphas=np.linspace(2e-3, 0.1, 49))
|
| 73 |
+
L2 = RidgeCV(alphas=np.linspace(0.001, 0.101, 20))
|
| 74 |
+
elastic = ElasticNetCV(alphas=np.linspace(2e-3, 0.1, 49), n_jobs=10)
|
| 75 |
+
models = [L1, L2, elastic]
|
| 76 |
+
model_names = ['Lasso', 'Ridge', 'Elastic']
|
| 77 |
+
|
| 78 |
+
else:
|
| 79 |
+
LR = LogisticRegressionCV(n_jobs=10)
|
| 80 |
+
# L1 = LogisticRegressionCV(n_jobs=10,penalty='l1', solver='saga')
|
| 81 |
+
# elastic = LogisticRegressionCV(n_jobs=10,penalty='elasticnet', solver='saga', l1_ratios=np.linspace(0.0, 0.5, 10))
|
| 82 |
+
models = [LR]
|
| 83 |
+
model_names = ['Logistic']
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
for model,name in zip(models, model_names):
|
| 87 |
+
print(f"\nregressing {name}..")
|
| 88 |
+
model.fit(X,Y)
|
| 89 |
+
r2 = model.score(X,Y) # will be
|
| 90 |
+
sparsity = np.sum(model.coef_==0) / X.shape[1] *100
|
| 91 |
+
try:
|
| 92 |
+
alpha = model.alpha_
|
| 93 |
+
except:
|
| 94 |
+
alpha = 0.0
|
| 95 |
+
|
| 96 |
+
print(f"{name} with optimal alpha {alpha:.5f}, r2/acc {r2:.3f} , zero coeff {sparsity:.1f}%")
|
| 97 |
+
|
| 98 |
+
# save df
|
| 99 |
+
effect = model.coef_.reshape(n_channel,-1)
|
| 100 |
+
fullcoef_df = pd.DataFrame(effect, columns=[f"{name}_posi_"+str(trunc_start+i) for i in range(to_stay)])
|
| 101 |
+
fullcoef_df.to_csv( os.path.join(save_path , f"{task}_{name}_coef.csv"), index=False)
|
| 102 |
+
task_channel_effect[f"{task}_{name}"] = effect.mean(axis=1)
|
| 103 |
+
|
| 104 |
+
task_performance[f"{task}_{name}"] = [alpha, r2, sparsity, model.coef_.max(), model.coef_.min()]
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
all_effect = pd.DataFrame(task_channel_effect)
|
| 108 |
+
all_effect.to_csv(os.path.join(save_path, "all_task_mean_effect.csv"), index=False)
|
| 109 |
+
|
| 110 |
+
report_df = pd.DataFrame(task_performance)
|
| 111 |
+
report_df.index = ['optim_alpha','r2', 'zero_pctg', 'max_coef', 'min_coef']
|
| 112 |
+
report_df.to_csv(os.path.join(save_path, "regression_report.csv"), index=False)
|
model/src/mrl_te_optimization/script/fix_test_for_RP.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
## generating the hand craft featuress
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
##
|
| 6 |
+
|
| 7 |
+
test_set_tid = []
|
| 8 |
+
trainval_dict = {}
|
| 9 |
+
test_set_dict = {}
|
| 10 |
+
for cell_line in ['muscle',"PC3","293T"]:
|
| 11 |
+
|
| 12 |
+
seed = 41
|
| 13 |
+
|
| 14 |
+
df = processed_dict[cell_line]
|
| 15 |
+
df_to_sample = df.query("`T_id` not in @test_set_tid")
|
| 16 |
+
df_overlap = df.query("(`T_id` in @test_set_tid)")
|
| 17 |
+
|
| 18 |
+
# the number to sample reduce as the list cumulated from previous cell type
|
| 19 |
+
# what to sample
|
| 20 |
+
n_2_sample = int(0.1*df.shape[0]) - df_overlap.shape[0]
|
| 21 |
+
sampled_subset = df_to_sample.sample(n=n_2_sample,random_state=seed)
|
| 22 |
+
|
| 23 |
+
# merge newly sampled with those in the list
|
| 24 |
+
test_set_df = sampled_subset.append(df_overlap)
|
| 25 |
+
trainval_dict[cell_line] = pd.concat([df,test_set_df]).drop_duplicates(keep=False)
|
| 26 |
+
test_set_dict[cell_line] = test_set_df
|
| 27 |
+
# adding new Tids
|
| 28 |
+
test_set_tid += sampled_subset.T_id.values.tolist()
|
| 29 |
+
|
| 30 |
+
for cell_line in ["muscle","PC3","293T"]:
|
| 31 |
+
trainval_dict[cell_line].to_csv(pj(f"RP_{cell_line}_train_val.csv"))
|
| 32 |
+
test_set_dict[cell_line].to_csv(pj(f"RP_{cell_line}_test.csv"))
|
model/src/mrl_te_optimization/script/generate_config_js.sh
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
script_dir=$(pwd)
|
| 3 |
+
echo "{" > machine_configure.json
|
| 4 |
+
echo '"script_dir": "'${script_dir}'",' >> machine_configure.json
|
| 5 |
+
echo '"data_dir": "'${script_dir}'/data",' >> machine_configure.json
|
| 6 |
+
echo '"log_dir": "'${script_dir}'/log",' >> machine_configure.json
|
| 7 |
+
echo '"pth_dir": "'${script_dir}'/checkpoint"' >> machine_configure.json
|
| 8 |
+
echo "}" >> machine_configure.json
|
| 9 |
+
|
| 10 |
+
if [ ! -d ${script_dir}/data ]; then
|
| 11 |
+
mkdir data
|
| 12 |
+
mkdir checkpoint
|
| 13 |
+
fi
|
model/src/mrl_te_optimization/script/iter_test.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser('the main to train model')
|
| 6 |
+
parser.add_argument('--config_file',type=str,required=True)
|
| 7 |
+
parser.add_argument('--cuda',type=str,default=0,required=False)
|
| 8 |
+
parser.add_argument("--kfold_index",type=int,default=1,required=False)
|
| 9 |
+
args = parser.parse_args()
|
| 10 |
+
|
| 11 |
+
cuda_id = args.cuda if args.cuda is not None else utils.get_config_cuda(args.config_file)
|
| 12 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_id)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
import torch
|
| 17 |
+
import copy
|
| 18 |
+
import utils
|
| 19 |
+
from torch import optim
|
| 20 |
+
import numpy as np
|
| 21 |
+
from models import reader,train_val
|
| 22 |
+
from models.ScheduleOptimizer import ScheduledOptim,scheduleoptim_dict_str
|
| 23 |
+
from models.popen import Auto_popen
|
| 24 |
+
from models.loss import Dynamic_Task_Priority,Dynamic_Weight_Averaging
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
POPEN = Auto_popen(args.config_file)
|
| 28 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 29 |
+
POPEN.cuda_id = device
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
POPEN.kfold_index = args.kfold_index
|
| 33 |
+
if POPEN.kfold_cv:
|
| 34 |
+
if args.kfold_index is None:
|
| 35 |
+
raise NotImplementedError("please specify the kfold index to perform K fold cross validation")
|
| 36 |
+
POPEN.vae_log_path = POPEN.vae_log_path.replace(".log","_cv%d.log"%args.kfold_index)
|
| 37 |
+
#POPEN.vae_pth_path = POPEN.vae_pth_path.replace(".pth","_cv%d.pth"%args.kfold_index)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Run name
|
| 41 |
+
if POPEN.run_name is None:
|
| 42 |
+
run_name = POPEN.model_type + time.strftime("__%Y_%m_%d_%H:%M")
|
| 43 |
+
else:
|
| 44 |
+
run_name = POPEN.run_name
|
| 45 |
+
|
| 46 |
+
# log dir
|
| 47 |
+
logger = utils.setup_logs(POPEN.vae_log_path)
|
| 48 |
+
logger.info(f" ===========================| device {device}{cuda_id} |=========================== ")
|
| 49 |
+
# built model dir or check resume
|
| 50 |
+
POPEN.check_experiment(logger)
|
| 51 |
+
|
| 52 |
+
# |=====================================|
|
| 53 |
+
# |=========== setup part ==========|
|
| 54 |
+
# |=====================================|
|
| 55 |
+
# read data
|
| 56 |
+
loader_set = {}
|
| 57 |
+
n_covar_dict = {}
|
| 58 |
+
base_path = ['cycle_train_val.csv', 'cycle_test.csv']
|
| 59 |
+
base_csv = 'cycle_MTL_transfer.csv'
|
| 60 |
+
for task in POPEN.cycle_set:
|
| 61 |
+
if (task in ['MPA_U', 'MPA_H', 'MPA_V', 'SubMPA_H']):
|
| 62 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3M/schedule_lr.ini')
|
| 63 |
+
datapopen.split_like = [path.replace('cycle', task) for path in base_path]
|
| 64 |
+
datapopen.kfold_index = args.kfold_index
|
| 65 |
+
n_covar_dict[task] = datapopen.n_covar
|
| 66 |
+
|
| 67 |
+
elif (task in ['RP_293T', 'RP_muscle', 'RP_PC3']):
|
| 68 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3R/schedule_MTL.ini')
|
| 69 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 70 |
+
datapopen.kfold_index = args.kfold_index
|
| 71 |
+
datapopen.pad_to = POPEN.pad_to
|
| 72 |
+
datapopen.aux_task_columns = POPEN.aux_task_columns
|
| 73 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 74 |
+
datapopen.n_covar = POPEN.n_covar
|
| 75 |
+
|
| 76 |
+
elif (task in ['pcr3', '293']):
|
| 77 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/karollus_RPs/rp_cycle.ini')
|
| 78 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 79 |
+
datapopen.kfold_index = args.kfold_index
|
| 80 |
+
datapopen.aux_task_columns = POPEN.aux_task_columns
|
| 81 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 82 |
+
datapopen.pad_to = POPEN.pad_to
|
| 83 |
+
datapopen.n_covar = POPEN.n_covar
|
| 84 |
+
datapopen.shuffle = False
|
| 85 |
+
loader_set[task] = reader.get_dataloader(datapopen)
|
| 86 |
+
|
| 87 |
+
POPEN.n_covar = n_covar_dict
|
| 88 |
+
POPEN.get_model_config() # update model config
|
| 89 |
+
|
| 90 |
+
# =========== setup model ===========
|
| 91 |
+
# train_iter = iter(train_loader)
|
| 92 |
+
# X,Y = next(train_iter)
|
| 93 |
+
# -- pretrain --
|
| 94 |
+
if POPEN.pretrain_pth is not None:
|
| 95 |
+
# load pretran model
|
| 96 |
+
logger.info("===============================| pretrain |===============================")
|
| 97 |
+
logger.info(f" {POPEN.pretrain_pth}")
|
| 98 |
+
pretrain_popen = Auto_popen(os.path.join(utils.script_dir, POPEN.pretrain_pth))
|
| 99 |
+
if not os.path.exists(pretrain_popen.vae_pth_path):
|
| 100 |
+
if type(args.kfold_index) == int:
|
| 101 |
+
pretrain_popen.kfold_index = args.kfold_index
|
| 102 |
+
pretrain_model = torch.load(pretrain_popen.vae_pth_path, map_location=torch.device('cpu'))['state_dict']
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
if POPEN.model_type == pretrain_popen.model_type:
|
| 106 |
+
# if not POPEN.Resumable:
|
| 107 |
+
# # we only load pre-train for the first time
|
| 108 |
+
# # later we can resume
|
| 109 |
+
model = pretrain_model.to(device)
|
| 110 |
+
del pretrain_model
|
| 111 |
+
|
| 112 |
+
if (POPEN.cycle_set != pretrain_popen.cycle_set):
|
| 113 |
+
model.all_tasks = POPEN.cycle_set
|
| 114 |
+
model.tower = torch.nn.ModuleDict(
|
| 115 |
+
{POPEN.cycle_set[i] : model.tower[t] for i, t in enumerate(pretrain_popen.cycle_set)}
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
elif POPEN.modual_to_fix is not None:
|
| 119 |
+
# POPEN.model_type != pretrain_popen.model_type
|
| 120 |
+
|
| 121 |
+
model = POPEN.Model_Class(*POPEN.model_args)
|
| 122 |
+
for modual in POPEN.modual_to_fix:
|
| 123 |
+
if modual in dir(pretrain_model):
|
| 124 |
+
eval(f'model.{modual}').load_state_dict(
|
| 125 |
+
eval(f'model.{modual}').state_dict()
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
state_dict = {'epoch': 0,
|
| 129 |
+
'validation_acc': 0,
|
| 130 |
+
'state_dict': model.to('cpu'),
|
| 131 |
+
'validation_loss': 0}
|
| 132 |
+
shared_pretrain_pth = POPEN.vae_pth_path.replace(f"_cv{args.kfold_index}", '')
|
| 133 |
+
if not os.path.exists(shared_pretrain_pth):
|
| 134 |
+
utils.snapshot(shared_pretrain_pth, state_dict)
|
| 135 |
+
utils.snapshot(POPEN.vae_pth_path, state_dict)
|
| 136 |
+
|
| 137 |
+
model = torch.load(POPEN.vae_pth_path, map_location=torch.device('cpu'))
|
| 138 |
+
model = model.to(device)
|
| 139 |
+
|
| 140 |
+
# -- end2end --
|
| 141 |
+
elif POPEN.model_type == "CrossStitch_Model":
|
| 142 |
+
backbone = {}
|
| 143 |
+
for t in POPEN.tasks:
|
| 144 |
+
task_popen = Auto_popen(POPEN.backbone_config[t])
|
| 145 |
+
task_model = task_popen.Model_Class(*task_popen.model_args)
|
| 146 |
+
utils.load_model(task_popen,task_model,logger)
|
| 147 |
+
backbone[t] = task_model.to(device)
|
| 148 |
+
POPEN.model_args = [backbone] + POPEN.model_args
|
| 149 |
+
model = POPEN.Model_Class(*POPEN.model_args).to(device)
|
| 150 |
+
else:
|
| 151 |
+
Model_Class = POPEN.Model_Class # DL_models.LSTM_AE
|
| 152 |
+
model = Model_Class(*POPEN.model_args).to(device)
|
| 153 |
+
|
| 154 |
+
if POPEN.Resumable:
|
| 155 |
+
model = utils.load_model(POPEN, model, logger)
|
| 156 |
+
|
| 157 |
+
# =========== fix parameters ===========
|
| 158 |
+
if isinstance(POPEN.modual_to_fix, list):
|
| 159 |
+
for modual in POPEN.modual_to_fix:
|
| 160 |
+
model = utils.fix_parameter(model,modual)
|
| 161 |
+
model = model.to(device)
|
| 162 |
+
logger.info(' \t \t ==============| %s fixed |============== \t \t \n'%POPEN.modual_to_fix)
|
| 163 |
+
# =========== set optimizer ===========
|
| 164 |
+
if POPEN.optimizer == 'Schedule':
|
| 165 |
+
optimizer = ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 166 |
+
betas=(0.9, 0.98),
|
| 167 |
+
eps=1e-09,
|
| 168 |
+
weight_decay=1e-4,
|
| 169 |
+
amsgrad=True),
|
| 170 |
+
n_warmup_steps=20)
|
| 171 |
+
elif type(POPEN.optimizer) == dict:
|
| 172 |
+
optimizer = eval(scheduleoptim_dict_str.format(**POPEN.optimizer))
|
| 173 |
+
else:
|
| 174 |
+
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 175 |
+
lr=POPEN.lr,
|
| 176 |
+
betas=(0.9, 0.98),
|
| 177 |
+
eps=1e-09,
|
| 178 |
+
weight_decay=POPEN.l2)
|
| 179 |
+
if POPEN.loss_schema == 'DTP':
|
| 180 |
+
POPEN.loss_schedualer = Dynamic_Task_Priority(POPEN.tasks,POPEN.gamma,POPEN.chimerla_weight)
|
| 181 |
+
elif POPEN.loss_schema == 'DWA':
|
| 182 |
+
POPEN.loss_schedualer = Dynamic_Weight_Averaging(POPEN.tasks,POPEN.tau,POPEN.chimerla_weight)
|
| 183 |
+
# =========== resume ===========
|
| 184 |
+
best_loss = np.inf
|
| 185 |
+
best_acc = 0
|
| 186 |
+
best_epoch = 0
|
| 187 |
+
previous_epoch = 0
|
| 188 |
+
epoch = 0
|
| 189 |
+
if POPEN.Resumable:
|
| 190 |
+
previous_epoch,best_loss,best_acc = utils.resume(POPEN, optimizer,logger)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
# |=====================================|
|
| 194 |
+
# |========== training part ==========|
|
| 195 |
+
# |=====================================|
|
| 196 |
+
epoch += previous_epoch
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
# -----------| validate |-----------
|
| 201 |
+
logger.info("===============================| test |===============================")
|
| 202 |
+
verbose_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch, which_set=2)
|
| 203 |
+
# matching task performance influence what to save
|
| 204 |
+
|
| 205 |
+
if np.any(['r2' in key for key in verbose_dict.keys()]):
|
| 206 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'r2' in key])
|
| 207 |
+
acc_dict = {f"cv{args.kfold_index}_{key}":values for key, values in verbose_dict.items() if 'r2' in key}
|
| 208 |
+
else:
|
| 209 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'acc' in key])
|
| 210 |
+
acc_dict = {}
|
| 211 |
+
val_total_loss = verbose_dict['Total']
|
| 212 |
+
|
| 213 |
+
# DICT ={"ran_epoch":epoch,"n_current_steps":optimizer.n_current_steps,"delta":optimizer.delta} if type(optimizer) == ScheduledOptim else {"ran_epoch":epoch}
|
| 214 |
+
# POPEN.update_ini_file(DICT,logger)
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
# POPEN.update_ini_file(acc_dict,logger)
|
model/src/mrl_te_optimization/script/iter_train.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser('the main to train model')
|
| 6 |
+
parser.add_argument('--config_file',type=str,required=True)
|
| 7 |
+
parser.add_argument('--cuda',type=str,default=0,required=False)
|
| 8 |
+
parser.add_argument("--kfold_index",type=int,default=1,required=False)
|
| 9 |
+
args = parser.parse_args()
|
| 10 |
+
|
| 11 |
+
cuda_id = args.cuda if args.cuda is not None else utils.get_config_cuda(args.config_file)
|
| 12 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_id)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
import torch
|
| 17 |
+
import copy
|
| 18 |
+
import utils
|
| 19 |
+
from torch import optim
|
| 20 |
+
import numpy as np
|
| 21 |
+
from models import reader,train_val
|
| 22 |
+
from models.ScheduleOptimizer import ScheduledOptim,scheduleoptim_dict_str
|
| 23 |
+
from models.popen import Auto_popen
|
| 24 |
+
from models.loss import Dynamic_Task_Priority,Dynamic_Weight_Averaging
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
POPEN = Auto_popen(args.config_file)
|
| 28 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 29 |
+
POPEN.cuda_id = device
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
POPEN.kfold_index = args.kfold_index
|
| 33 |
+
if POPEN.kfold_cv:
|
| 34 |
+
if args.kfold_index is None:
|
| 35 |
+
raise NotImplementedError("please specify the kfold index to perform K fold cross validation")
|
| 36 |
+
POPEN.vae_log_path = POPEN.vae_log_path.replace(".log","_cv%d.log"%args.kfold_index)
|
| 37 |
+
#POPEN.vae_pth_path = POPEN.vae_pth_path.replace(".pth","_cv%d.pth"%args.kfold_index)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Run name
|
| 41 |
+
if POPEN.run_name is None:
|
| 42 |
+
run_name = POPEN.model_type + time.strftime("__%Y_%m_%d_%H:%M")
|
| 43 |
+
else:
|
| 44 |
+
run_name = POPEN.run_name
|
| 45 |
+
|
| 46 |
+
# log dir
|
| 47 |
+
logger = utils.setup_logs(POPEN.vae_log_path)
|
| 48 |
+
logger.info(f" ===========================| device {device}{cuda_id} |=========================== ")
|
| 49 |
+
# built model dir or check resume
|
| 50 |
+
POPEN.check_experiment(logger)
|
| 51 |
+
|
| 52 |
+
# |=====================================|
|
| 53 |
+
# |=========== setup part ==========|
|
| 54 |
+
# |=====================================|
|
| 55 |
+
# read data
|
| 56 |
+
loader_set = {}
|
| 57 |
+
base_path = ['cycle_train_val.csv', 'cycle_test.csv']
|
| 58 |
+
base_csv = copy.deepcopy(POPEN.csv_path) #'cycle_MTL_transfer.csv'
|
| 59 |
+
for task in POPEN.cycle_set:
|
| 60 |
+
if (task in ['MPA_U', 'MPA_H', 'MPA_V', 'SubMPA_H']):
|
| 61 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3M/schedule_lr.ini')
|
| 62 |
+
datapopen.split_like = [path.replace('cycle', task) for path in base_path]
|
| 63 |
+
datapopen.kfold_index = args.kfold_index
|
| 64 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 65 |
+
datapopen.n_covar = POPEN.n_covar
|
| 66 |
+
|
| 67 |
+
elif (task in ['RP_293T', 'RP_muscle', 'RP_PC3']):
|
| 68 |
+
# base_csv = 'cycle_protein_coding.csv'
|
| 69 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/3R/schedule_MTL.ini')
|
| 70 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 71 |
+
datapopen.kfold_index = args.kfold_index
|
| 72 |
+
datapopen.kfold_cv = POPEN.kfold_cv
|
| 73 |
+
datapopen.pad_to = POPEN.pad_to
|
| 74 |
+
datapopen.aux_task_columns = POPEN.aux_task_columns
|
| 75 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 76 |
+
datapopen.n_covar = POPEN.n_covar
|
| 77 |
+
|
| 78 |
+
elif (task in ['pcr3', '293']):
|
| 79 |
+
datapopen = Auto_popen('log/Backbone/RL_hard_share/karollus_RPs/rp_cycle.ini')
|
| 80 |
+
datapopen.csv_path = base_csv.replace("cycle",task)
|
| 81 |
+
datapopen.kfold_index = args.kfold_index
|
| 82 |
+
datapopen.kfold_cv = POPEN.kfold_cv
|
| 83 |
+
datapopen.aux_task_columns = POPEN.aux_task_columns
|
| 84 |
+
datapopen.other_input_columns = POPEN.other_input_columns
|
| 85 |
+
datapopen.pad_to = POPEN.pad_to
|
| 86 |
+
datapopen.n_covar = POPEN.n_covar
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
loader_set[task] = reader.get_dataloader(datapopen)
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
# =========== setup model ===========
|
| 93 |
+
# train_iter = iter(train_loader)
|
| 94 |
+
# X,Y = next(train_iter)
|
| 95 |
+
# -- pretrain --
|
| 96 |
+
if POPEN.pretrain_pth is not None:
|
| 97 |
+
# load pretran model
|
| 98 |
+
logger.info("===============================| pretrain |===============================")
|
| 99 |
+
logger.info(f" {POPEN.pretrain_pth}")
|
| 100 |
+
pretrain_popen = Auto_popen(os.path.join(utils.script_dir, POPEN.pretrain_pth))
|
| 101 |
+
if not os.path.exists(pretrain_popen.vae_pth_path):
|
| 102 |
+
if type(args.kfold_index) == int:
|
| 103 |
+
pretrain_popen.kfold_index = args.kfold_index
|
| 104 |
+
pretrain_model = torch.load(pretrain_popen.vae_pth_path, map_location=torch.device('cpu'))['state_dict']
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
if POPEN.model_type == pretrain_popen.model_type:
|
| 108 |
+
# if not POPEN.Resumable:
|
| 109 |
+
# # we only load pre-train for the first time
|
| 110 |
+
# # later we can resume
|
| 111 |
+
model = pretrain_model.to(device)
|
| 112 |
+
del pretrain_model
|
| 113 |
+
|
| 114 |
+
if (POPEN.cycle_set != pretrain_popen.cycle_set):
|
| 115 |
+
model.all_tasks = POPEN.cycle_set
|
| 116 |
+
model.tower = torch.nn.ModuleDict(
|
| 117 |
+
{POPEN.cycle_set[i] : model.tower[t] for i, t in enumerate(pretrain_popen.cycle_set)}
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
elif POPEN.modual_to_fix is not None:
|
| 121 |
+
# POPEN.model_type != pretrain_popen.model_type
|
| 122 |
+
|
| 123 |
+
model = POPEN.Model_Class(*POPEN.model_args)
|
| 124 |
+
for modual in POPEN.modual_to_fix:
|
| 125 |
+
if modual in dir(pretrain_model):
|
| 126 |
+
eval(f'model.{modual}').load_state_dict(
|
| 127 |
+
eval(f'model.{modual}').state_dict()
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
state_dict = {'epoch': 0,
|
| 131 |
+
'validation_acc': 0,
|
| 132 |
+
'state_dict': model.to('cpu'),
|
| 133 |
+
'validation_loss': 0}
|
| 134 |
+
shared_pretrain_pth = POPEN.vae_pth_path.replace(f"_cv{args.kfold_index}", '')
|
| 135 |
+
if not os.path.exists(shared_pretrain_pth):
|
| 136 |
+
utils.snapshot(shared_pretrain_pth, state_dict)
|
| 137 |
+
utils.snapshot(POPEN.vae_pth_path, state_dict)
|
| 138 |
+
|
| 139 |
+
model = torch.load(POPEN.vae_pth_path, map_location=torch.device('cpu'))
|
| 140 |
+
model = model.to(device)
|
| 141 |
+
|
| 142 |
+
# -- end2end --
|
| 143 |
+
elif POPEN.model_type == "CrossStitch_Model":
|
| 144 |
+
backbone = {}
|
| 145 |
+
for t in POPEN.tasks:
|
| 146 |
+
task_popen = Auto_popen(POPEN.backbone_config[t])
|
| 147 |
+
task_model = task_popen.Model_Class(*task_popen.model_args)
|
| 148 |
+
utils.load_model(task_popen,task_model,logger)
|
| 149 |
+
backbone[t] = task_model.to(device)
|
| 150 |
+
POPEN.model_args = [backbone] + POPEN.model_args
|
| 151 |
+
model = POPEN.Model_Class(*POPEN.model_args).to(device)
|
| 152 |
+
else:
|
| 153 |
+
Model_Class = POPEN.Model_Class # DL_models.LSTM_AE
|
| 154 |
+
model = Model_Class(*POPEN.model_args).to(device)
|
| 155 |
+
|
| 156 |
+
if POPEN.Resumable:
|
| 157 |
+
model = utils.load_model(POPEN, model, logger)
|
| 158 |
+
|
| 159 |
+
# =========== fix parameters ===========
|
| 160 |
+
if isinstance(POPEN.modual_to_fix, list):
|
| 161 |
+
for modual in POPEN.modual_to_fix:
|
| 162 |
+
model = utils.fix_parameter(model,modual)
|
| 163 |
+
model = model.to(device)
|
| 164 |
+
logger.info(' \t \t ==============| %s fixed |============== \t \t \n'%POPEN.modual_to_fix)
|
| 165 |
+
# =========== set optimizer ===========
|
| 166 |
+
if POPEN.optimizer == 'Schedule':
|
| 167 |
+
optimizer = ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 168 |
+
betas=(0.9, 0.98),
|
| 169 |
+
eps=1e-09,
|
| 170 |
+
weight_decay=1e-4,
|
| 171 |
+
amsgrad=True),
|
| 172 |
+
n_warmup_steps=20)
|
| 173 |
+
elif type(POPEN.optimizer) == dict:
|
| 174 |
+
optimizer = eval(scheduleoptim_dict_str.format(**POPEN.optimizer))
|
| 175 |
+
else:
|
| 176 |
+
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 177 |
+
lr=POPEN.lr,
|
| 178 |
+
betas=(0.9, 0.98),
|
| 179 |
+
eps=1e-09,
|
| 180 |
+
weight_decay=POPEN.l2)
|
| 181 |
+
if POPEN.loss_schema == 'DTP':
|
| 182 |
+
POPEN.loss_schedualer = Dynamic_Task_Priority(POPEN.tasks,POPEN.gamma,POPEN.chimerla_weight)
|
| 183 |
+
elif POPEN.loss_schema == 'DWA':
|
| 184 |
+
POPEN.loss_schedualer = Dynamic_Weight_Averaging(POPEN.tasks,POPEN.tau,POPEN.chimerla_weight)
|
| 185 |
+
# =========== resume ===========
|
| 186 |
+
best_loss = np.inf
|
| 187 |
+
best_acc = 0
|
| 188 |
+
best_epoch = 0
|
| 189 |
+
previous_epoch = 0
|
| 190 |
+
if POPEN.Resumable:
|
| 191 |
+
previous_epoch,best_loss,best_acc = utils.resume(POPEN, optimizer,logger)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
# |=====================================|
|
| 195 |
+
# |========== training part ==========|
|
| 196 |
+
# |=====================================|
|
| 197 |
+
for epoch in range(POPEN.max_epoch-previous_epoch+1):
|
| 198 |
+
epoch += previous_epoch
|
| 199 |
+
|
| 200 |
+
#
|
| 201 |
+
logger.info("===============================| epoch {} |===============================".format(epoch))
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
train_val.iter_train(loader_set,model=model,optimizer=optimizer,popen=POPEN,epoch=epoch)
|
| 205 |
+
|
| 206 |
+
# -----------| validate |-----------
|
| 207 |
+
logger.info("===============================| start validation |===============================")
|
| 208 |
+
verbose_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch, which_set=1)
|
| 209 |
+
test_dict = train_val.cycle_validate(loader_set,model,optimizer,popen=POPEN,epoch=epoch, which_set=2)
|
| 210 |
+
|
| 211 |
+
if np.any(['r2' in key for key in verbose_dict.keys()]):
|
| 212 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'r2' in key])
|
| 213 |
+
else:
|
| 214 |
+
val_avg_acc = np.mean([values for key, values in verbose_dict.items() if 'acc' in key])
|
| 215 |
+
val_total_loss = verbose_dict['Total']
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
DICT ={"ran_epoch":epoch,"n_current_steps":optimizer.n_current_steps,"delta":optimizer.delta} if type(optimizer) == ScheduledOptim else {"ran_epoch":epoch}
|
| 219 |
+
POPEN.update_ini_file(DICT,logger)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
# -----------| compare the result |-----------
|
| 223 |
+
if (best_loss > val_total_loss) :
|
| 224 |
+
# update best performance
|
| 225 |
+
best_loss = min(best_loss,val_total_loss)
|
| 226 |
+
best_acc = max(best_acc,val_avg_acc)
|
| 227 |
+
best_epoch = epoch
|
| 228 |
+
|
| 229 |
+
# save
|
| 230 |
+
utils.snapshot(POPEN.vae_pth_path, {
|
| 231 |
+
'epoch': epoch + 1,
|
| 232 |
+
'validation_acc': val_avg_acc,
|
| 233 |
+
# 'state_dict': model.state_dict(),
|
| 234 |
+
'state_dict': model,
|
| 235 |
+
'validation_loss': val_total_loss,
|
| 236 |
+
'optimizer': optimizer.state_dict(),
|
| 237 |
+
})
|
| 238 |
+
|
| 239 |
+
# update the popen
|
| 240 |
+
POPEN.update_ini_file({'run_name':run_name,
|
| 241 |
+
"ran_epoch":epoch,
|
| 242 |
+
"best_acc":best_acc},
|
| 243 |
+
logger)
|
| 244 |
+
|
| 245 |
+
elif (epoch - best_epoch >= 30)&((type(optimizer) == ScheduledOptim)):
|
| 246 |
+
optimizer.increase_delta()
|
| 247 |
+
|
| 248 |
+
elif (epoch - best_epoch >= 60)&(epoch > POPEN.max_epoch/2):
|
| 249 |
+
# at the late phase of training
|
| 250 |
+
logger.info("<<<<<<<<<<< Early Stopping >>>>>>>>>>")
|
| 251 |
+
break
|
model/src/mrl_te_optimization/script/main_train.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,sys
|
| 2 |
+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
| 3 |
+
import argparse
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser('the main to train model')
|
| 6 |
+
parser.add_argument('--config_file',type=str,required=True)
|
| 7 |
+
parser.add_argument('--cuda',type=int,default=None,required=False)
|
| 8 |
+
parser.add_argument("--kfold_index",type=int,default=None,required=False)
|
| 9 |
+
args = parser.parse_args()
|
| 10 |
+
|
| 11 |
+
cuda_id = args.cuda
|
| 12 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(cuda_id)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
import torch
|
| 17 |
+
import utils
|
| 18 |
+
from torch import optim
|
| 19 |
+
import numpy as np
|
| 20 |
+
from models import Modules,reader,train_val
|
| 21 |
+
from models.ScheduleOptimizer import ScheduledOptim,scheduleoptim_dict_str
|
| 22 |
+
from models.popen import Auto_popen
|
| 23 |
+
from models.loss import Dynamic_Task_Priority,Dynamic_Weight_Averaging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
POPEN = Auto_popen(args.config_file)
|
| 27 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 28 |
+
torch.set_num_interop_threads(4)
|
| 29 |
+
POPEN.cuda_id = device
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
POPEN.kfold_index = args.kfold_index
|
| 33 |
+
if POPEN.kfold_cv:
|
| 34 |
+
if args.kfold_index is None:
|
| 35 |
+
raise NotImplementedError("please specify the kfold index to perform K fold cross validation")
|
| 36 |
+
POPEN.vae_log_path = POPEN.vae_log_path.replace(".log","_cv%d.log"%args.kfold_index)
|
| 37 |
+
#POPEN.vae_pth_path = POPEN.vae_pth_path.replace(".pth","_cv%d.pth"%args.kfold_index)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Run name
|
| 41 |
+
if POPEN.run_name is None:
|
| 42 |
+
run_name = POPEN.model_type + time.strftime("__%Y_%m_%d_%H:%M")
|
| 43 |
+
else:
|
| 44 |
+
run_name = POPEN.run_name
|
| 45 |
+
|
| 46 |
+
# log dir
|
| 47 |
+
logger = utils.setup_logs(POPEN.vae_log_path)
|
| 48 |
+
logger.info(f" ==============<<< device used: {device}:{cuda_id} >>>============== ")
|
| 49 |
+
# built model dir or check resume
|
| 50 |
+
POPEN.check_experiment(logger)
|
| 51 |
+
# |=====================================|
|
| 52 |
+
# |=========== setup part ==========|
|
| 53 |
+
# |=====================================|
|
| 54 |
+
# read data
|
| 55 |
+
train_loader,val_loader,test_loader = reader.get_dataloader(POPEN)
|
| 56 |
+
# =========== setup model ===========
|
| 57 |
+
# train_iter = iter(train_loader)
|
| 58 |
+
# X,Y = next(train_iter)
|
| 59 |
+
# -- pretrain --
|
| 60 |
+
if POPEN.pretrain_pth is not None:
|
| 61 |
+
# load pretran model
|
| 62 |
+
pretrain_popen = Auto_popen(os.path.join(utils.script_dir, POPEN.pretrain_pth))
|
| 63 |
+
pretrain_model = pretrain_popen.Model_Class(*pretrain_popen.model_args)
|
| 64 |
+
|
| 65 |
+
if not os.path.exists(pretrain_popen.vae_pth_path):
|
| 66 |
+
if type(args.kfold_index) == int:
|
| 67 |
+
pretrain_popen.kfold_index = args.kfold_index
|
| 68 |
+
pretrain_model = utils.load_model(pretrain_popen,pretrain_model,logger)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
if POPEN.Model_Class == pretrain_popen.Model_Class:
|
| 73 |
+
# if not POPEN.Resumable:
|
| 74 |
+
# # we only load pre-train for the first time
|
| 75 |
+
# # later we can resume
|
| 76 |
+
model = pretrain_model.to(device)
|
| 77 |
+
del pretrain_model
|
| 78 |
+
elif POPEN.modual_to_fix is not None:
|
| 79 |
+
# POPEN.model_type != pretrain_popen.model_type
|
| 80 |
+
|
| 81 |
+
model = POPEN.Model_Class(*POPEN.model_args)
|
| 82 |
+
for modual in POPEN.modual_to_fix:
|
| 83 |
+
if modual in dir(pretrain_model):
|
| 84 |
+
eval(f'model.{modual}').load_state_dict(
|
| 85 |
+
eval(f'model.{modual}').state_dict()
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
state_dict = {'epoch': 0,
|
| 89 |
+
'validation_acc': 0,
|
| 90 |
+
'state_dict': model.to('cpu'),
|
| 91 |
+
'validation_loss': np.inf}
|
| 92 |
+
shared_pretrain_pth = POPEN.vae_pth_path.replace(f"_cv{args.kfold_index}", '')
|
| 93 |
+
if not os.path.exists(shared_pretrain_pth):
|
| 94 |
+
utils.snapshot(shared_pretrain_pth, state_dict)
|
| 95 |
+
utils.snapshot(POPEN.vae_pth_path, state_dict)
|
| 96 |
+
|
| 97 |
+
model = torch.load(POPEN.vae_pth_path, map_location=torch.device('cpu'))['state_dict']
|
| 98 |
+
model = model.to(device)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# -- end2end --
|
| 102 |
+
elif POPEN.model_type == "CrossStitch_Model":
|
| 103 |
+
backbone = {}
|
| 104 |
+
for t in POPEN.tasks:
|
| 105 |
+
task_popen = Auto_popen(POPEN.backbone_config[t])
|
| 106 |
+
task_model = task_popen.Model_Class(*task_popen.model_args)
|
| 107 |
+
task_model = utils.load_model(task_popen,task_model,logger)
|
| 108 |
+
backbone[t] = task_model.to(device)
|
| 109 |
+
POPEN.model_args = [backbone] + POPEN.model_args
|
| 110 |
+
model = POPEN.Model_Class(*POPEN.model_args).to(device)
|
| 111 |
+
else:
|
| 112 |
+
Model_Class = POPEN.Model_Class # DL_models.LSTM_AE
|
| 113 |
+
model = Model_Class(*POPEN.model_args).to(device)
|
| 114 |
+
|
| 115 |
+
if POPEN.Resumable:
|
| 116 |
+
model = utils.load_model(POPEN, model, logger)
|
| 117 |
+
|
| 118 |
+
# =========== fix parameters ===========
|
| 119 |
+
if isinstance(POPEN.modual_to_fix, list):
|
| 120 |
+
for modual in POPEN.modual_to_fix:
|
| 121 |
+
model = utils.fix_parameter(model,modual)
|
| 122 |
+
logger.info(' \t \t ==============<<< %s part is fixed>>>============== \t \t \n'%POPEN.modual_to_fix)
|
| 123 |
+
# =========== set optimizer ===========
|
| 124 |
+
if POPEN.optimizer == 'Schedule':
|
| 125 |
+
optimizer = ScheduledOptim(optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 126 |
+
betas=(0.9, 0.98),
|
| 127 |
+
eps=1e-09,
|
| 128 |
+
weight_decay=1e-4,
|
| 129 |
+
amsgrad=True),
|
| 130 |
+
n_warmup_steps=20)
|
| 131 |
+
elif type(POPEN.optimizer) == dict:
|
| 132 |
+
optimizer = eval(scheduleoptim_dict_str.format(**POPEN.optimizer))
|
| 133 |
+
else:
|
| 134 |
+
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()),
|
| 135 |
+
lr=POPEN.lr,
|
| 136 |
+
betas=(0.9, 0.98),
|
| 137 |
+
eps=1e-09,
|
| 138 |
+
weight_decay=POPEN.l2)
|
| 139 |
+
if POPEN.loss_schema == 'DTP':
|
| 140 |
+
POPEN.loss_schedualer = Dynamic_Task_Priority(POPEN.tasks,POPEN.gamma,POPEN.chimerla_weight)
|
| 141 |
+
elif POPEN.loss_schema == 'DWA':
|
| 142 |
+
POPEN.loss_schedualer = Dynamic_Weight_Averaging(POPEN.tasks,POPEN.tau,POPEN.chimerla_weight)
|
| 143 |
+
# =========== resume ===========
|
| 144 |
+
best_loss = np.inf
|
| 145 |
+
best_acc = 0
|
| 146 |
+
best_epoch = 0
|
| 147 |
+
previous_epoch = 0
|
| 148 |
+
if POPEN.Resumable:
|
| 149 |
+
previous_epoch,best_loss,best_acc = utils.resume(POPEN, optimizer,logger)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
# |=====================================|
|
| 153 |
+
# |========== training part ==========|
|
| 154 |
+
# |=====================================|
|
| 155 |
+
for epoch in range(POPEN.max_epoch-previous_epoch+1):
|
| 156 |
+
epoch += previous_epoch
|
| 157 |
+
|
| 158 |
+
# ----------| train |----------
|
| 159 |
+
logger.info("===============================| epoch {} |===============================".format(epoch))
|
| 160 |
+
train_val.train(dataloader=train_loader,model=model,optimizer=optimizer,popen=POPEN,epoch=epoch)
|
| 161 |
+
|
| 162 |
+
# -----------| validate |-----------
|
| 163 |
+
|
| 164 |
+
if epoch % POPEN.config_dict['setp_to_check'] == 0:
|
| 165 |
+
logger.info("===============================| start validation |===============================")
|
| 166 |
+
val_total_loss,val_avg_acc = train_val.validate(val_loader,model,popen=POPEN,epoch=epoch)
|
| 167 |
+
_,_ = train_val.validate(test_loader,model,popen=POPEN,epoch=epoch)
|
| 168 |
+
|
| 169 |
+
DICT ={"ran_epoch":epoch,"n_current_steps":optimizer.n_current_steps,"delta":optimizer.delta} if type(optimizer) == ScheduledOptim else {"ran_epoch":epoch}
|
| 170 |
+
POPEN.update_ini_file(DICT,logger)
|
| 171 |
+
|
| 172 |
+
# -----------| compare the result |-----------
|
| 173 |
+
if (best_loss > val_total_loss): #| (best_acc < val_avg_acc):
|
| 174 |
+
# update best performance
|
| 175 |
+
best_loss = min(best_loss,val_total_loss)
|
| 176 |
+
best_acc = max(best_acc,val_avg_acc)
|
| 177 |
+
best_epoch = epoch
|
| 178 |
+
|
| 179 |
+
# save
|
| 180 |
+
utils.snapshot(POPEN.vae_pth_path, {
|
| 181 |
+
'epoch': epoch + 1,
|
| 182 |
+
'validation_acc': val_avg_acc,
|
| 183 |
+
'state_dict': model.to('cpu'),
|
| 184 |
+
'validation_loss': val_total_loss,
|
| 185 |
+
# 'optimizer': optimizer.state_dict(),
|
| 186 |
+
})
|
| 187 |
+
|
| 188 |
+
# update the popen
|
| 189 |
+
POPEN.update_ini_file({'run_name':run_name,
|
| 190 |
+
"ran_epoch":epoch,
|
| 191 |
+
"best_acc":best_acc,
|
| 192 |
+
"cuda_id":cuda_id},
|
| 193 |
+
logger)
|
| 194 |
+
|
| 195 |
+
elif (epoch - best_epoch >= 30)&((type(optimizer) == ScheduledOptim)):
|
| 196 |
+
optimizer.increase_delta()
|
| 197 |
+
|
| 198 |
+
elif (epoch - best_epoch >= 60)&(epoch > POPEN.max_epoch/2):
|
| 199 |
+
# at the late phase of training
|
| 200 |
+
logger.info("<<<<<<<<<<< Early Stopping >>>>>>>>>>")
|
| 201 |
+
break
|
model/src/mrl_te_optimization/script/preprocessing_MPA.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import torch
|
| 4 |
+
import PATH
|
| 5 |
+
import utils
|
| 6 |
+
import numpy as np
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import seaborn as sns
|
| 9 |
+
from matplotlib import pyplot as plt
|
| 10 |
+
|
| 11 |
+
from sklearn.preprocessing import StandardScaler
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
# ========== 1. preprocessing MPA datasets ==========
|
| 15 |
+
|
| 16 |
+
# read csv and load in to a dictionary
|
| 17 |
+
Ex_data_dir = utils.data_dir
|
| 18 |
+
csv_path_ls = [os.path.join(Ex_data_dir,csv) for csv in ['GSM3130435_egfp_unmod_1.csv','GSM3130443_designed_library.csv','GSM4084997_varying_length_25to100.csv']]
|
| 19 |
+
for path in csv_path_ls:
|
| 20 |
+
assert os.path.exists(path), f"The file {path} is not properly downloaded"
|
| 21 |
+
|
| 22 |
+
df_dict = {
|
| 23 |
+
csv_path.split("_")[-1].replace(".csv","") : pd.read_csv(csv_path,low_memory=False) for csv_path in csv_path_ls
|
| 24 |
+
}
|
| 25 |
+
# align the columns name across datasets
|
| 26 |
+
df_dict['library'].rename({'total':'total_reads'},axis=1,inplace=True)
|
| 27 |
+
df_dict['25to100']['r13'] = np.zeros((df_dict['25to100'].shape[0],))
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# - MPA_U -
|
| 32 |
+
df = df_dict['1']
|
| 33 |
+
df.sort_values('total_reads', inplace=True, ascending=False)
|
| 34 |
+
df.reset_index(inplace=True, drop=True)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
## train_val test spliting
|
| 38 |
+
# the most abundant 5'UTR is used as test set
|
| 39 |
+
test_df = df.iloc[:20000]
|
| 40 |
+
train_val_df = df.iloc[20000:280000]
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# - MPA_H -
|
| 45 |
+
df = df_dict['library']
|
| 46 |
+
# taking the natrual utr and sort by reads count
|
| 47 |
+
human_lib = df[(df['library'] == 'human_utrs') | (df['library'] == 'snv')]
|
| 48 |
+
human_lib = human_lib.sort_values('total_reads', ascending=False).reset_index(drop=True)
|
| 49 |
+
|
| 50 |
+
# the top 25k abundant reads as test set
|
| 51 |
+
sub = human_lib.iloc[:25000]
|
| 52 |
+
remaining = human_lib.iloc[25000:]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
# - MPA_V -
|
| 56 |
+
df1 = df_dict['25to100']
|
| 57 |
+
# take the random seqs
|
| 58 |
+
df = df1[df1['set']=='random']
|
| 59 |
+
|
| 60 |
+
## Filter out UTRs with too few less reads
|
| 61 |
+
df=df[df['total_reads']>=10]
|
| 62 |
+
|
| 63 |
+
df['utr100'] = 75*'N' +df['utr']
|
| 64 |
+
df['utr100'] = df['utr100'].str[-100:]
|
| 65 |
+
df.sort_values('total_reads', inplace=True, ascending=False)
|
| 66 |
+
df.reset_index(inplace=True, drop=True)
|
| 67 |
+
|
| 68 |
+
## some natural sequence
|
| 69 |
+
human = df1[df1['set']=='human']
|
| 70 |
+
## Filter out UTRs with too few less reads
|
| 71 |
+
human=human[human['total_reads']>=10]
|
| 72 |
+
human['utr100'] = 75*'N' +human['utr']
|
| 73 |
+
human['utr100'] = human['utr100'].str[-100:]
|
| 74 |
+
human.sort_values('total_reads', inplace=True, ascending=False)
|
| 75 |
+
human.reset_index(inplace=True, drop=True)
|
| 76 |
+
|
| 77 |
+
e_test = pd.DataFrame(columns=df.columns)
|
| 78 |
+
for i in range(25,101):
|
| 79 |
+
tmp = df[df['len']==i]
|
| 80 |
+
tmp.sort_values('total_reads', inplace=True, ascending=False)
|
| 81 |
+
tmp.reset_index(inplace=True, drop=True)
|
| 82 |
+
e_test = e_test.append(tmp.iloc[:100])
|
| 83 |
+
|
| 84 |
+
subhuman = pd.DataFrame(columns=human.columns)
|
| 85 |
+
for i in range(25,101):
|
| 86 |
+
tmp = human[human['len']==i]
|
| 87 |
+
tmp.sort_values('total_reads', inplace=True, ascending=False)
|
| 88 |
+
tmp.reset_index(inplace=True, drop=True)
|
| 89 |
+
subhuman = subhuman.append(tmp.iloc[:100])
|
| 90 |
+
|
| 91 |
+
e_train = pd.concat([df, e_test, e_test]).drop_duplicates(keep=False)
|
| 92 |
+
|
| 93 |
+
vleng_test = pd.concat([e_test,subhuman])
|
| 94 |
+
bins = np.arange(24, 105, 20)
|
| 95 |
+
labels = [ '25-44' , '45-64', '65-84', '85-100']
|
| 96 |
+
vleng_test['rng'] = pd.cut(vleng_test['len'], bins=bins)
|
| 97 |
+
|
| 98 |
+
# saving all
|
| 99 |
+
e_test.to_csv(os.path.join(Ex_data_dir,"MPA_V_test.csv"),index=False)
|
| 100 |
+
e_train.to_csv(os.path.join(Ex_data_dir,"MPA_V_train_val.csv"),index=False)
|
| 101 |
+
|
| 102 |
+
sub.to_csv(os.path.join(Ex_data_dir,"MPA_H_test.csv"),index=False)
|
| 103 |
+
remaining.to_csv(os.path.join(Ex_data_dir,"MPA_H_train_val.csv"),index=False)
|
| 104 |
+
|
| 105 |
+
# sub sample MPA-H
|
| 106 |
+
remaining.sample(frac=0.1).to_csv(os.path.join(Ex_data_dir,"SubMPA_H_train_val.csv"),index=False)
|
| 107 |
+
sub.to_csv(os.path.join(Ex_data_dir,"SubMPA_H_test.csv"),index=False)
|
| 108 |
+
|
| 109 |
+
test_df.to_csv(os.path.join(Ex_data_dir,"MPA_U_test.csv"),index=False)
|
| 110 |
+
train_val_df.to_csv(os.path.join(Ex_data_dir,"MPA_U_train_val.csv"),index=False)
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
print("The preprocssing for MPA tasks is Finished !!")
|
| 115 |
+
print(f"The files are saved to {utils.data_dir}")
|
model/src/mrl_te_optimization/script/preprocessing_RP.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import numpy as np
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import PATH
|
| 5 |
+
import utils
|
| 6 |
+
from Bio import SeqIO
|
| 7 |
+
from scipy import sparse
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
pj = lambda x: os.path.join(utils.data_dir,x)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
# read in the sequence
|
| 14 |
+
fa = SeqIO.parse(pj('gencode_v17_5utr_15bpcds.fa'),'fasta')
|
| 15 |
+
tx_seq=dict()
|
| 16 |
+
for seq_record in fa:
|
| 17 |
+
tx=seq_record.id
|
| 18 |
+
seq=seq_record.seq
|
| 19 |
+
if len(seq)<30: #skip when it too short
|
| 20 |
+
continue
|
| 21 |
+
if "ATG" not in seq:
|
| 22 |
+
continue
|
| 23 |
+
if tx not in tx_seq or len(seq)>len(tx_seq[tx]):
|
| 24 |
+
tx_seq[tx]=seq
|
| 25 |
+
|
| 26 |
+
# txt records TE and rkpm
|
| 27 |
+
RP_data_path = {}
|
| 28 |
+
RP_data_path['muscle'] = pj('df_counts_and_len.TE_sorted.Muscle.with_annot.txt')
|
| 29 |
+
RP_data_path['PC3'] = pj('df_counts_and_len.TE_sorted.pc3.with_annot.txt')
|
| 30 |
+
RP_data_path['293T'] = pj('df_counts_and_len.TE_sorted.HEK_Andrev2015.with_annot.txt')
|
| 31 |
+
|
| 32 |
+
# read the hand crafted features
|
| 33 |
+
# (57415, 33)
|
| 34 |
+
feat_mat = pd.read_csv("util/Zhang_et_al_features.csv",index_col=0)
|
| 35 |
+
feat_mat.insert(0, 'seq', [tx_seq[x].upper().__str__() for x in feat_mat.index.values])
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
processed_dict = {}
|
| 39 |
+
for cell_line, csv_path in RP_data_path.items():
|
| 40 |
+
|
| 41 |
+
assert os.path.exists(csv_path), f"The raw data file for {cell_line} does not exist!"
|
| 42 |
+
|
| 43 |
+
print(f"processing {cell_line}...\n")
|
| 44 |
+
RP_raw_data = pd.read_table(csv_path, sep=' ')
|
| 45 |
+
RP_raw_data.loc[:,'T_id'] = RP_raw_data.index.values
|
| 46 |
+
# adding sequence in
|
| 47 |
+
RP_raw_data = RP_raw_data.query('rpkm_rnaseq >5 & rpkm_riboseq > 0.1')
|
| 48 |
+
RP_raw_data['log_te'] = np.log(RP_raw_data.te.values)
|
| 49 |
+
|
| 50 |
+
RP_feat_merge = RP_raw_data.merge(feat_mat,left_on=['T_id'],right_index=True,suffixes=["",""])
|
| 51 |
+
RP_feat_merge.sort_values('rpkm_rnaseq', ascending=False, inplace=True)
|
| 52 |
+
|
| 53 |
+
# drop duplicated UTRs
|
| 54 |
+
RP_raw_dedup = RP_feat_merge.drop_duplicates(RP_feat_merge.columns[17:], keep='first')
|
| 55 |
+
RP_raw_dedup['utr'] = RP_raw_dedup['seq'].apply(lambda x: x[-216:-16]) # max len 200
|
| 56 |
+
RP_raw_dedup['utr_len'] = RP_raw_dedup.utr.apply(len)
|
| 57 |
+
RP_raw_dedup.query('`utr_len`>30')
|
| 58 |
+
RP_raw_dedup = RP_raw_dedup.drop_duplicates(['utr'], keep='first')
|
| 59 |
+
|
| 60 |
+
# save them
|
| 61 |
+
processed_dict[cell_line] = RP_raw_dedup
|
| 62 |
+
processed_dict[cell_line].to_csv(pj(f"RP_{cell_line}_MTL_transfer.csv"))
|
| 63 |
+
|
| 64 |
+
print("The preprocssing for RP tasks is Finished !!")
|
| 65 |
+
print(f"The files are saved to {utils.data_dir}")
|
model/src/mrl_te_optimization/script/run-TF-modisco.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
import PATH
|
| 6 |
+
import torch
|
| 7 |
+
import argparse
|
| 8 |
+
import h5py
|
| 9 |
+
#
|
| 10 |
+
from subprocess import DEVNULL, STDOUT, check_call
|
| 11 |
+
from models import train_val
|
| 12 |
+
from models.popen import Auto_popen
|
| 13 |
+
from models import max_activation_patch as MAP
|
| 14 |
+
#
|
| 15 |
+
from sklearn.linear_model import Lasso, Ridge, ElasticNet, LassoCV, RidgeCV, ElasticNetCV
|
| 16 |
+
import warnings
|
| 17 |
+
warnings.filterwarnings('ignore')
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
#
|
| 21 |
+
parser = argparse.ArgumentParser('the script to evlauate the effect of ')
|
| 22 |
+
parser.add_argument("-c", "--config", type=str, required=True, help='the model config file: xxx.ini')
|
| 23 |
+
parser.add_argument("-s", "--set", type=int, default=2, help='train - 0 ,val - 1, test - 2 ')
|
| 24 |
+
parser.add_argument("-p", "--n_max_act", type=int, default=500, help='the number of seq')
|
| 25 |
+
parser.add_argument("-k", "--kfold_cv", type=int, default=1, help='the repeat')
|
| 26 |
+
parser.add_argument("-d", "--device", type=str, default='cpu', help='the device to use to extract featmap, digit or cpu')
|
| 27 |
+
args = parser.parse_args()
|
| 28 |
+
|
| 29 |
+
config_path = args.config
|
| 30 |
+
save_path = config_path.replace(".ini", "_coef")
|
| 31 |
+
config = Auto_popen(config_path)
|
| 32 |
+
config.batch_size = 256
|
| 33 |
+
config.kfold_cv = 'train_val'
|
| 34 |
+
all_task = config.cycle_set
|
| 35 |
+
|
| 36 |
+
task_channel_effect = {}
|
| 37 |
+
task_performance = {}
|
| 38 |
+
|
| 39 |
+
# path check
|
| 40 |
+
if os.path.exists(config_path) and not os.path.exists(save_path):
|
| 41 |
+
os.mkdir(save_path)
|
| 42 |
+
|
| 43 |
+
for task in all_task:
|
| 44 |
+
|
| 45 |
+
# .... format featmap as data ....
|
| 46 |
+
print(f"\n\nevaluating for task: {task}")
|
| 47 |
+
# re-instance the map for each task
|
| 48 |
+
map_task = MAP.Maximum_activation_patch(popen=config, which_layer=4,
|
| 49 |
+
n_patch=args.n_max_act,
|
| 50 |
+
kfold_index=args.kfold_cv,
|
| 51 |
+
device_string=args.device)
|
| 52 |
+
|
| 53 |
+
# extract feature map and rl decision chain
|
| 54 |
+
# get X
|
| 55 |
+
model, dataloader= map_task.loading(task=task, which_set=args.set)
|
| 56 |
+
max_seq_len = map_task.df[config.seq_col].apply(len).max()
|
| 57 |
+
|
| 58 |
+
X_ls = []
|
| 59 |
+
for Data in dataloader:
|
| 60 |
+
# iter each batch
|
| 61 |
+
x,y = train_val.put_data_to_cuda(Data, map_task.popen,False)
|
| 62 |
+
X_ls.append(x.detach().cpu().numpy())
|
| 63 |
+
X = np.concatenate(X_ls, axis=0)
|
| 64 |
+
X = np.transpose(X, (0,2,1))
|
| 65 |
+
|
| 66 |
+
attribute = map_task.get_input_grad(task=task, focus=False, fm=X, starting_layer=0)
|
| 67 |
+
X = X[:, :, -1*max_seq_len:]
|
| 68 |
+
attribute = attribute[:,:, -1*max_seq_len:]
|
| 69 |
+
|
| 70 |
+
x_npz_path = os.path.join(save_path, f"{task}_set{args.set}_x.npz")
|
| 71 |
+
grad_npz_path = os.path.join(save_path, f"{task}_set{args.set}_grad.npz")
|
| 72 |
+
np.savez(x_npz_path, X)
|
| 73 |
+
np.savez(grad_npz_path, attribute)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
for n_seqlet in range(500, 4000, 500):
|
| 78 |
+
outfile = os.path.join(save_path, f"{task}_n{n_seqlet}_tfmodisco.h5")
|
| 79 |
+
command = f"modisco motifs -s {x_npz_path} -a {grad_npz_path} -n {n_seqlet} -o {outfile}"
|
| 80 |
+
|
| 81 |
+
check_call(command.split(), stdout=DEVNULL, stderr=STDOUT)
|
| 82 |
+
|
| 83 |
+
with h5py.File(outfile, "r") as f:
|
| 84 |
+
print(f.keys())
|
| 85 |
+
if 'pos_patterns' in f.keys():
|
| 86 |
+
pos_motif = f['pos_patterns']
|
| 87 |
+
n_pos = len(pos_motif.keys())
|
| 88 |
+
else:
|
| 89 |
+
n_pos = -1
|
| 90 |
+
|
| 91 |
+
if 'neg_patterns' in f.keys():
|
| 92 |
+
neg_motif = f['neg_patterns']
|
| 93 |
+
n_neg = len(neg_motif.keys())
|
| 94 |
+
else:
|
| 95 |
+
n_neg = -1
|
| 96 |
+
f.close()
|
| 97 |
+
|
| 98 |
+
print(f"discover {n_pos} pos pattern and {n_neg} neg patterns for n = {n_seqlet}")
|
| 99 |
+
print(f'done for {task}')
|
model/src/mrl_te_optimization/script/train_kmer_classifer.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, sys
|
| 2 |
+
# os.environ["CUDA_VISIBLE_DEVICES"] = str(3)
|
| 3 |
+
import pytorch_lightning as pl
|
| 4 |
+
from torch.nn import functional as F
|
| 5 |
+
import PATH, utils
|
| 6 |
+
import torch
|
| 7 |
+
from torch import nn, optim
|
| 8 |
+
from models import reader
|
| 9 |
+
from models.popen import Auto_popen
|
| 10 |
+
import pandas as pd
|
| 11 |
+
import numpy as np
|
| 12 |
+
from collections import OrderedDict
|
| 13 |
+
import torchmetrics
|
| 14 |
+
from torch.utils.data import DataLoader
|
| 15 |
+
from pytorch_lightning import callbacks
|
| 16 |
+
from sklearn.model_selection import train_test_split
|
| 17 |
+
import argparse
|
| 18 |
+
|
| 19 |
+
################
|
| 20 |
+
if __name__ == '__main__':
|
| 21 |
+
global_seed = int(sys.argv[6])
|
| 22 |
+
torch.manual_seed(global_seed)
|
| 23 |
+
torch.cuda.manual_seed_all(global_seed)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
###### data ######
|
| 27 |
+
def get_kmer_input_shape(csv_name, kernel_size):
|
| 28 |
+
MPA_U_test = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_test.csv"))
|
| 29 |
+
|
| 30 |
+
# dataset
|
| 31 |
+
test_DS = reader.kmer_scan_dataset(MPA_U_test, seq_col='utr',
|
| 32 |
+
kmer_size=kernel_size, aux_columns='rl')
|
| 33 |
+
return np.multiply(*test_DS[0][0].shape)
|
| 34 |
+
|
| 35 |
+
def get_kmer_dls(csv_name, kernel_size, seed, seq_col, label_col):
|
| 36 |
+
|
| 37 |
+
print("seed = %s"%seed)
|
| 38 |
+
train_df, val_df, test_df = reader.split_DF(csv_name, None, [0.8,0.1,0.1], kfold_cv=True, kfold_index=seed,seed=43)
|
| 39 |
+
|
| 40 |
+
# dataset
|
| 41 |
+
train_DS = reader.kmer_scan_dataset(train_df, seq_col=seq_col, kmer_size=kernel_size, aux_columns=label_col)
|
| 42 |
+
val_DS = reader.kmer_scan_dataset(val_df, seq_col=seq_col, kmer_size=kernel_size, aux_columns=label_col)
|
| 43 |
+
test_DS = reader.kmer_scan_dataset(test_df, seq_col=seq_col, kmer_size=kernel_size, aux_columns=label_col)
|
| 44 |
+
|
| 45 |
+
# dataloader
|
| 46 |
+
train_dl = DataLoader(train_DS, batch_size = 64, shuffle=True)
|
| 47 |
+
val_dl = DataLoader(val_DS, batch_size = 64, shuffle=False)
|
| 48 |
+
test_dl = DataLoader(test_DS, batch_size = 64, shuffle=False)
|
| 49 |
+
return train_dl, val_dl, test_dl
|
| 50 |
+
|
| 51 |
+
##################
|
| 52 |
+
# PyTorch Light model #
|
| 53 |
+
class mlp_models(pl.LightningModule):
|
| 54 |
+
def __init__(self, dims):
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.dims = dims
|
| 57 |
+
n_layer = len(dims) - 1
|
| 58 |
+
self.train_r2 = torchmetrics.R2Score()
|
| 59 |
+
self.val_r2 = torchmetrics.R2Score()
|
| 60 |
+
# add layers
|
| 61 |
+
nns = []
|
| 62 |
+
i = 1
|
| 63 |
+
for in_dim , out_dim in zip(dims[:-1], dims[1:]):
|
| 64 |
+
nns.append( (f"Linear_{i}", nn.Linear(in_dim, out_dim)) )
|
| 65 |
+
if i < n_layer:
|
| 66 |
+
nns += [(f"BN_{i}", nn.BatchNorm1d(out_dim)), (f"act_{i}", nn.Mish()) ]
|
| 67 |
+
i += 1
|
| 68 |
+
|
| 69 |
+
self.network = nn.Sequential(OrderedDict(nns))
|
| 70 |
+
|
| 71 |
+
def forward(self, x):
|
| 72 |
+
return self.network(x)
|
| 73 |
+
|
| 74 |
+
def configure_optimizers(self):
|
| 75 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
| 76 |
+
return optimizer
|
| 77 |
+
|
| 78 |
+
def training_step(self, train_batch, batch_idx):
|
| 79 |
+
x, y = train_batch
|
| 80 |
+
b = x.shape[0]
|
| 81 |
+
x = x.view(b, -1).float()
|
| 82 |
+
y = y.view(b,).float()
|
| 83 |
+
y_hat = self.network(x).view(b,)
|
| 84 |
+
loss = F.mse_loss(y_hat, y.float())
|
| 85 |
+
r2 = self.train_r2(y_hat, y)
|
| 86 |
+
self.log('train_loss', loss)
|
| 87 |
+
self.log('train_acc', self.train_r2)
|
| 88 |
+
return loss
|
| 89 |
+
|
| 90 |
+
def validation_step(self, val_batch, batch_idx):
|
| 91 |
+
x, y = val_batch
|
| 92 |
+
b = x.shape[0]
|
| 93 |
+
x = x.view(b, -1).float()
|
| 94 |
+
y = y.view(b,).float()
|
| 95 |
+
y_hat = self.network(x).view(b,)
|
| 96 |
+
|
| 97 |
+
loss = F.mse_loss(y_hat, y.float())
|
| 98 |
+
r2 = self.val_r2(y_hat, y)
|
| 99 |
+
self.log('val_loss', loss)
|
| 100 |
+
self.log('val_acc', self.val_r2)
|
| 101 |
+
|
| 102 |
+
# PyTorch Light model #
|
| 103 |
+
class rnn_models(pl.LightningModule):
|
| 104 |
+
def __init__(self, k, hidden=128):
|
| 105 |
+
super().__init__()
|
| 106 |
+
self.save_hyperparameters()
|
| 107 |
+
self.train_F1 = torchmetrics.F1Score()
|
| 108 |
+
self.train_AUROC = torchmetrics.AUROC()
|
| 109 |
+
self.train_ACC = torchmetrics.Accuracy()
|
| 110 |
+
|
| 111 |
+
self.val_F1 = torchmetrics.F1Score()
|
| 112 |
+
self.val_AUROC = torchmetrics.AUROC()
|
| 113 |
+
self.val_ACC = torchmetrics.Accuracy()
|
| 114 |
+
|
| 115 |
+
self.test_F1 = torchmetrics.F1Score()
|
| 116 |
+
self.test_AUROC = torchmetrics.AUROC()
|
| 117 |
+
self.test_ACC = torchmetrics.Accuracy()
|
| 118 |
+
|
| 119 |
+
tower = { f"GRU_layer" : nn.GRU(input_size=4**k, hidden_size=hidden,
|
| 120 |
+
num_layers=2,batch_first=True),
|
| 121 |
+
f"fc_out" : nn.Linear(hidden, 1),
|
| 122 |
+
}
|
| 123 |
+
self.sigmod = nn.Sigmoid()
|
| 124 |
+
self.tower = nn.ModuleDict(tower)
|
| 125 |
+
|
| 126 |
+
def forward(self, x):
|
| 127 |
+
|
| 128 |
+
x = x.transpose(1,2) # B C L -> B L C
|
| 129 |
+
h_prim,(c1,c2) = self.tower['GRU_layer'](x)
|
| 130 |
+
out = self.tower['fc_out'](c2)
|
| 131 |
+
return self.sigmod(out)
|
| 132 |
+
|
| 133 |
+
def configure_optimizers(self):
|
| 134 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
| 135 |
+
return optimizer
|
| 136 |
+
|
| 137 |
+
def training_step(self, train_batch, batch_idx):
|
| 138 |
+
x, y = train_batch
|
| 139 |
+
b = x.shape[0]
|
| 140 |
+
x = x.float()
|
| 141 |
+
y = y.view(b,)
|
| 142 |
+
y_hat = self.forward(x).view(b,)
|
| 143 |
+
|
| 144 |
+
loss = F.binary_cross_entropy(y_hat, y.float())
|
| 145 |
+
F1 = self.train_F1(y_hat, y.long())
|
| 146 |
+
auroc = self.train_AUROC(y_hat, y.long())
|
| 147 |
+
acc = self.train_ACC(y_hat, y.long())
|
| 148 |
+
self.log('train_loss', loss)
|
| 149 |
+
self.log('train_f1', self.train_F1)
|
| 150 |
+
self.log('train_AUROC', self.train_AUROC)
|
| 151 |
+
self.log('train_ACC', self.train_ACC)
|
| 152 |
+
return loss
|
| 153 |
+
|
| 154 |
+
def validation_step(self, val_batch, batch_idx):
|
| 155 |
+
x, y = val_batch
|
| 156 |
+
b = x.shape[0]
|
| 157 |
+
x = x.float()
|
| 158 |
+
y = y.view(b,)
|
| 159 |
+
y_hat = self.forward(x).view(b,)
|
| 160 |
+
|
| 161 |
+
loss = F.binary_cross_entropy(y_hat, y.float())
|
| 162 |
+
self.val_F1(y_hat, y.long())
|
| 163 |
+
self.val_AUROC(y_hat, y.long())
|
| 164 |
+
self.val_ACC(y_hat, y.long())
|
| 165 |
+
self.log('val_loss', loss)
|
| 166 |
+
self.log('val_F1', self.val_F1)
|
| 167 |
+
self.log('val_AUROC', self.val_AUROC)
|
| 168 |
+
self.log('val_ACC', self.val_ACC)
|
| 169 |
+
|
| 170 |
+
def test_step(self, test_batch, batch_idx):
|
| 171 |
+
x, y = test_batch
|
| 172 |
+
b = x.shape[0]
|
| 173 |
+
x = x.float()
|
| 174 |
+
y = y.view(b,)
|
| 175 |
+
y_hat = self.forward(x).view(b,)
|
| 176 |
+
|
| 177 |
+
loss = F.binary_cross_entropy(y_hat, y.float())
|
| 178 |
+
self.test_F1(y_hat, y.long())
|
| 179 |
+
self.test_AUROC(y_hat, y.long())
|
| 180 |
+
self.test_ACC(y_hat, y.long())
|
| 181 |
+
self.log('test_loss', loss)
|
| 182 |
+
self.log('test_F1', self.test_F1)
|
| 183 |
+
self.log('test_AUROC', self.test_AUROC)
|
| 184 |
+
self.log('test_ACC', self.test_ACC)
|
| 185 |
+
|
| 186 |
+
################
|
| 187 |
+
if __name__ == '__main__':
|
| 188 |
+
|
| 189 |
+
csv_name = sys.argv[1]
|
| 190 |
+
kmer_size = int(sys.argv[2])
|
| 191 |
+
hidden = int(sys.argv[3])
|
| 192 |
+
seq_col = sys.argv[4]
|
| 193 |
+
label_col = sys.argv[5]
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
train_dl, val_dl, test_dl = get_kmer_dls(csv_name, kmer_size, global_seed, seq_col, label_col)
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
#### hyper-params ####
|
| 201 |
+
Input_length = np.multiply(*train_dl.dataset[0][0].shape)
|
| 202 |
+
# dims = [Input_length] + hidden + [1]
|
| 203 |
+
|
| 204 |
+
model = rnn_models(kmer_size, hidden)
|
| 205 |
+
default_root_dir="/data/users/wergillius/UTR_VAE/pth/Kmer_Alan"
|
| 206 |
+
# default_root_dir="/ssd/users/wergillius/Project/MTtrans/evaluation/Kmer_results"
|
| 207 |
+
data_name = os.path.basename(csv_name).split("_")[0]
|
| 208 |
+
log_dir = os.path.join(default_root_dir, f"{data_name}_K{kmer_size}H{hidden}_sd{global_seed}")
|
| 209 |
+
################
|
| 210 |
+
|
| 211 |
+
# training
|
| 212 |
+
trainer = pl.Trainer(accelerator='gpu',devices=1, auto_select_gpus=False, #
|
| 213 |
+
default_root_dir=log_dir,
|
| 214 |
+
limit_train_batches=0.5, max_epochs=600,
|
| 215 |
+
#plugins=pl.plugins.DDPPlugin(find_unused_parameters=False),
|
| 216 |
+
callbacks=[
|
| 217 |
+
callbacks.ModelCheckpoint(monitor="val_loss",save_top_k=1),
|
| 218 |
+
callbacks.EarlyStopping(monitor="val_F1", mode="min", patience=15)
|
| 219 |
+
])
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
trainer.fit(model, train_dl, val_dl)
|
| 223 |
+
|
| 224 |
+
ckpt_dir = os.path.join(trainer.log_dir,'checkpoints')
|
| 225 |
+
ckpt_path = os.path.join(ckpt_dir, [file for file in os.listdir(ckpt_dir) if file.endswith('.ckpt')][0])
|
| 226 |
+
print('model saved to : %s\n'%ckpt_path)
|
| 227 |
+
# trainer.validate(model, test_dl)
|
| 228 |
+
|
| 229 |
+
saved_model = rnn_models.load_from_checkpoint(ckpt_path)
|
| 230 |
+
trainer.validate(saved_model, val_dl)
|
| 231 |
+
trainer.test(saved_model, test_dl)
|
| 232 |
+
|
| 233 |
+
# debugging args:
|
| 234 |
+
# "/data/users/wergillius/UTR_VAE/Alan_dataset/AlanAll_binary_10pctg.csv",
|
| 235 |
+
# "3",
|
| 236 |
+
# "64",
|
| 237 |
+
# "seq",
|
| 238 |
+
# "Binary_10pc",
|
| 239 |
+
# "1"
|
model/src/mrl_te_optimization/script/train_kmer_models.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, sys
|
| 2 |
+
# os.environ["CUDA_VISIBLE_DEVICES"] = str(3)
|
| 3 |
+
import pytorch_lightning as pl
|
| 4 |
+
from torch.nn import functional as F
|
| 5 |
+
import PATH, utils
|
| 6 |
+
import torch
|
| 7 |
+
from torch import nn, optim
|
| 8 |
+
from models import reader
|
| 9 |
+
from models.popen import Auto_popen
|
| 10 |
+
import pandas as pd
|
| 11 |
+
import numpy as np
|
| 12 |
+
from collections import OrderedDict
|
| 13 |
+
import torchmetrics
|
| 14 |
+
from torch.utils.data import DataLoader
|
| 15 |
+
from pytorch_lightning import callbacks
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
###### data ######
|
| 19 |
+
def get_kmer_input_shape(csv_name, kernel_size):
|
| 20 |
+
MPA_U_test = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_test.csv"))
|
| 21 |
+
|
| 22 |
+
# dataset
|
| 23 |
+
test_DS = reader.kmer_scan_dataset(MPA_U_test, seq_col='utr',
|
| 24 |
+
kmer_size=kernel_size, aux_columns='rl')
|
| 25 |
+
return np.multiply(*test_DS[0][0].shape)
|
| 26 |
+
|
| 27 |
+
def get_kmer_dls(csv_name, kernel_size, seed):
|
| 28 |
+
train_val = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_train_val.csv"))
|
| 29 |
+
MPA_U_test = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_test.csv"))
|
| 30 |
+
|
| 31 |
+
MPA_U_val = train_val.sample(frac=0.1, random_state=seed)
|
| 32 |
+
MPA_U_train = pd.concat([train_val, MPA_U_val]).drop_duplicates(keep=False)
|
| 33 |
+
|
| 34 |
+
# dataset
|
| 35 |
+
train_DS = reader.kmer_scan_dataset(MPA_U_train, seq_col='utr', kmer_size=kernel_size, aux_columns='rl')
|
| 36 |
+
val_DS = reader.kmer_scan_dataset(MPA_U_val, seq_col='utr', kmer_size=kernel_size, aux_columns='rl')
|
| 37 |
+
test_DS = reader.kmer_scan_dataset(MPA_U_test, seq_col='utr', kmer_size=kernel_size, aux_columns='rl')
|
| 38 |
+
|
| 39 |
+
# dataloader
|
| 40 |
+
train_dl = DataLoader(train_DS, batch_size = 64, shuffle=True)
|
| 41 |
+
val_dl = DataLoader(test_DS, batch_size = 64, shuffle=False)
|
| 42 |
+
test_dl = DataLoader(test_DS, batch_size = 64, shuffle=False)
|
| 43 |
+
return train_dl, val_dl, test_dl
|
| 44 |
+
|
| 45 |
+
##################
|
| 46 |
+
# PyTorch Light model #
|
| 47 |
+
class mlp_models(pl.LightningModule):
|
| 48 |
+
def __init__(self, dims):
|
| 49 |
+
super().__init__()
|
| 50 |
+
self.dims = dims
|
| 51 |
+
n_layer = len(dims) - 1
|
| 52 |
+
self.train_r2 = torchmetrics.R2Score()
|
| 53 |
+
self.val_r2 = torchmetrics.R2Score()
|
| 54 |
+
# add layers
|
| 55 |
+
nns = []
|
| 56 |
+
i = 1
|
| 57 |
+
for in_dim , out_dim in zip(dims[:-1], dims[1:]):
|
| 58 |
+
nns.append( (f"Linear_{i}", nn.Linear(in_dim, out_dim)) )
|
| 59 |
+
if i < n_layer:
|
| 60 |
+
nns += [(f"BN_{i}", nn.BatchNorm1d(out_dim)), (f"act_{i}", nn.Mish()) ]
|
| 61 |
+
i += 1
|
| 62 |
+
|
| 63 |
+
self.network = nn.Sequential(OrderedDict(nns))
|
| 64 |
+
|
| 65 |
+
def forward(self, x):
|
| 66 |
+
return self.network(x)
|
| 67 |
+
|
| 68 |
+
def configure_optimizers(self):
|
| 69 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
| 70 |
+
return optimizer
|
| 71 |
+
|
| 72 |
+
def training_step(self, train_batch, batch_idx):
|
| 73 |
+
x, y = train_batch
|
| 74 |
+
b = x.shape[0]
|
| 75 |
+
x = x.view(b, -1).float()
|
| 76 |
+
y = y.view(b,).float()
|
| 77 |
+
y_hat = self.network(x).view(b,)
|
| 78 |
+
loss = F.mse_loss(y_hat, y.float())
|
| 79 |
+
r2 = self.train_r2(y_hat, y)
|
| 80 |
+
self.log('train_loss', loss)
|
| 81 |
+
self.log('train_acc', self.train_r2)
|
| 82 |
+
return loss
|
| 83 |
+
|
| 84 |
+
def validation_step(self, val_batch, batch_idx):
|
| 85 |
+
x, y = val_batch
|
| 86 |
+
b = x.shape[0]
|
| 87 |
+
x = x.view(b, -1).float()
|
| 88 |
+
y = y.view(b,).float()
|
| 89 |
+
y_hat = self.network(x).view(b,)
|
| 90 |
+
|
| 91 |
+
loss = F.mse_loss(y_hat, y.float())
|
| 92 |
+
r2 = self.val_r2(y_hat, y)
|
| 93 |
+
self.log('val_loss', loss)
|
| 94 |
+
self.log('val_acc', self.val_r2)
|
| 95 |
+
|
| 96 |
+
# PyTorch Light model #
|
| 97 |
+
class rnn_models(pl.LightningModule):
|
| 98 |
+
def __init__(self, k):
|
| 99 |
+
super().__init__()
|
| 100 |
+
|
| 101 |
+
self.train_r2 = torchmetrics.R2Score()
|
| 102 |
+
self.val_r2 = torchmetrics.R2Score()
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
tower = { f"GRU_layer" : nn.GRU(input_size=4**k, hidden_size=128,
|
| 106 |
+
num_layers=2,batch_first=True),
|
| 107 |
+
f"fc_out" : nn.Linear(128, 1),
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
self.tower = nn.ModuleDict(tower)
|
| 111 |
+
|
| 112 |
+
def forward(self, x):
|
| 113 |
+
|
| 114 |
+
x = x.transpose(1,2) # B C L -> B L C
|
| 115 |
+
h_prim,(c1,c2) = self.tower['GRU_layer'](x)
|
| 116 |
+
out = self.tower['fc_out'](c2)
|
| 117 |
+
return out
|
| 118 |
+
|
| 119 |
+
def configure_optimizers(self):
|
| 120 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
| 121 |
+
return optimizer
|
| 122 |
+
|
| 123 |
+
def training_step(self, train_batch, batch_idx):
|
| 124 |
+
x, y = train_batch
|
| 125 |
+
b = x.shape[0]
|
| 126 |
+
x = x.float()
|
| 127 |
+
y = y.view(b,).float()
|
| 128 |
+
y_hat = self.forward(x).view(b,)
|
| 129 |
+
|
| 130 |
+
loss = F.mse_loss(y_hat, y)
|
| 131 |
+
r2 = self.train_r2(y_hat, y)
|
| 132 |
+
self.log('train_loss', loss)
|
| 133 |
+
self.log('train_acc', self.train_r2)
|
| 134 |
+
return loss
|
| 135 |
+
|
| 136 |
+
def validation_step(self, val_batch, batch_idx):
|
| 137 |
+
x, y = val_batch
|
| 138 |
+
b = x.shape[0]
|
| 139 |
+
x = x.float()
|
| 140 |
+
y = y.view(b,).float()
|
| 141 |
+
y_hat = self.forward(x).view(b,)
|
| 142 |
+
|
| 143 |
+
loss = F.mse_loss(y_hat, y)
|
| 144 |
+
self.val_r2(y_hat, y)
|
| 145 |
+
self.log('val_loss', loss)
|
| 146 |
+
self.log('val_acc', self.val_r2)
|
| 147 |
+
|
| 148 |
+
################
|
| 149 |
+
if __name__ == '__main__':
|
| 150 |
+
|
| 151 |
+
csv_name = sys.argv[1]
|
| 152 |
+
kmer_size = sys.argv[2]
|
| 153 |
+
hidden = sys.argv[3]
|
| 154 |
+
|
| 155 |
+
#### hyper-params ####
|
| 156 |
+
Input_length = np.multiply(*train_DS[0][0].shape)
|
| 157 |
+
hidden = [512]
|
| 158 |
+
dims = [Input_length] + hidden + [1]
|
| 159 |
+
################
|
| 160 |
+
|
| 161 |
+
# training
|
| 162 |
+
trainer = pl.Trainer(gpus=1, num_processes=8,
|
| 163 |
+
default_root_dir="/ssd/users/wergillius/Project/MTtrans/evaluation/Kmer_results",
|
| 164 |
+
limit_train_batches=0.5, max_epochs=6,
|
| 165 |
+
callbacks=[callbacks.EarlyStopping(monitor="val_loss", mode="min", patience=5)])
|
| 166 |
+
trainer.fit(model, train_dl, val_dl)
|
| 167 |
+
trainer.test(test_dl)
|
model/src/mrl_te_optimization/script/train_oneLayer_CNN.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, sys
|
| 2 |
+
import pytorch_lightning as pl
|
| 3 |
+
from torch.nn import functional as F
|
| 4 |
+
import PATH, utils
|
| 5 |
+
import torch
|
| 6 |
+
from torch import nn, optim
|
| 7 |
+
from models import reader
|
| 8 |
+
from models.popen import Auto_popen
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import numpy as np
|
| 11 |
+
from collections import OrderedDict
|
| 12 |
+
import torchmetrics
|
| 13 |
+
from torch.utils.data import DataLoader
|
| 14 |
+
from pytorch_lightning import callbacks
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
###### data ######
|
| 18 |
+
def get_dls(csv_name, kernel_size, seed):
|
| 19 |
+
train_val = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_train_val.csv"))
|
| 20 |
+
MPA_U_test = pd.read_csv(os.path.join(utils.data_dir, f"{csv_name}_test.csv"))
|
| 21 |
+
|
| 22 |
+
MPA_U_val = train_val.sample(frac=0.1, random_state=seed)
|
| 23 |
+
MPA_U_train = pd.concat([train_val, MPA_U_val]).drop_duplicates(keep=False)
|
| 24 |
+
|
| 25 |
+
# dataset
|
| 26 |
+
train_DS = reader.MTL_dataset(MPA_U_train, seq_col='utr', aux_columns=['rl'])
|
| 27 |
+
val_DS = reader.MTL_dataset(MPA_U_val, seq_col='utr', aux_columns=['rl'])
|
| 28 |
+
test_DS = reader.MTL_dataset(MPA_U_test, seq_col='utr', aux_columns=['rl'])
|
| 29 |
+
|
| 30 |
+
# dataloader
|
| 31 |
+
train_dl = DataLoader(train_DS, batch_size = 64, shuffle=True)
|
| 32 |
+
val_dl = DataLoader(test_DS, batch_size = 64, shuffle=False)
|
| 33 |
+
test_dl = DataLoader(test_DS, batch_size = 64, shuffle=False)
|
| 34 |
+
return train_dl, val_dl, test_dl
|
| 35 |
+
##################
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
# PyTorch Light model #
|
| 39 |
+
class Onelayer_CNN(pl.LightningModule):
|
| 40 |
+
def __init__(self, kernel_size):
|
| 41 |
+
super().__init__()
|
| 42 |
+
|
| 43 |
+
self.train_r2 = torchmetrics.R2Score()
|
| 44 |
+
self.val_r2 = torchmetrics.R2Score()
|
| 45 |
+
|
| 46 |
+
self.conv_layer = nn.Sequential(nn.Conv1d(4, 256, kernel_size),
|
| 47 |
+
nn.BatchNorm1d(256),
|
| 48 |
+
nn.Mish())
|
| 49 |
+
|
| 50 |
+
tower = { f"GRU_layer" : nn.GRU(input_size=256, hidden_size=128,
|
| 51 |
+
num_layers=2,batch_first=True),
|
| 52 |
+
f"fc_out" : nn.Linear(128, 1),
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
self.tower = nn.ModuleDict(tower)
|
| 56 |
+
|
| 57 |
+
def forward(self, x):
|
| 58 |
+
if x.shape[1] != 4:
|
| 59 |
+
x = x.transpose(1,2)
|
| 60 |
+
Z = self.conv_layer(x)
|
| 61 |
+
Z_t = torch.transpose(Z, 1, 2)
|
| 62 |
+
h_prim,(c1,c2) = self.tower['GRU_layer'](Z_t)
|
| 63 |
+
out = self.tower['fc_out'](c2)
|
| 64 |
+
return out
|
| 65 |
+
|
| 66 |
+
def configure_optimizers(self):
|
| 67 |
+
optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
|
| 68 |
+
return optimizer
|
| 69 |
+
|
| 70 |
+
def training_step(self, train_batch, batch_idx):
|
| 71 |
+
x, y = train_batch
|
| 72 |
+
b = x.shape[0]
|
| 73 |
+
x = x.float()
|
| 74 |
+
y = y.view(b,).float()
|
| 75 |
+
y_hat = self.forward(x).view(b,)
|
| 76 |
+
|
| 77 |
+
loss = F.mse_loss(y_hat, y)
|
| 78 |
+
r2 = self.train_r2(y_hat, y)
|
| 79 |
+
self.log('train_loss', loss)
|
| 80 |
+
self.log('train_acc', self.train_r2)
|
| 81 |
+
return loss
|
| 82 |
+
|
| 83 |
+
def validation_step(self, val_batch, batch_idx):
|
| 84 |
+
x, y = val_batch
|
| 85 |
+
b = x.shape[0]
|
| 86 |
+
x = x.float()
|
| 87 |
+
y = y.view(b,).float()
|
| 88 |
+
y_hat = self.forward(x).view(b,)
|
| 89 |
+
loss = F.mse_loss(y_hat, y)
|
| 90 |
+
self.val_r2(y_hat, y)
|
| 91 |
+
self.log('val_loss', loss)
|
| 92 |
+
self.log('val_acc', self.val_r2)
|
| 93 |
+
|
| 94 |
+
################
|
| 95 |
+
if __name__ == '__main__':
|
| 96 |
+
|
| 97 |
+
#### hyper-params ####
|
| 98 |
+
csv_name = sys.argv[1]
|
| 99 |
+
kernel_size = sys.argv[2]
|
| 100 |
+
seed = 41
|
| 101 |
+
|
| 102 |
+
################
|
| 103 |
+
train_dl, val_dl, test_dl = get_dls(csv_name, kernel_size, seed)
|
| 104 |
+
|
| 105 |
+
model = Onelayer_CNN(int(kernel_size))
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# training
|
| 109 |
+
trainer = pl.Trainer(gpus=1, num_processes=8,
|
| 110 |
+
default_root_dir="/ssd/users/wergillius/Project/MTtrans/evaluation/one_layer_logs",
|
| 111 |
+
limit_train_batches=0.5, max_epochs=60,
|
| 112 |
+
callbacks=[callbacks.EarlyStopping(monitor="val_loss", mode="min", patience=5)])
|
| 113 |
+
trainer.fit(model, train_dl, val_dl)
|
| 114 |
+
trainer.test(test_dl)
|
model/src/mrl_te_optimization/util.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import operator
|
| 3 |
+
import pickle
|
| 4 |
+
import time
|
| 5 |
+
import seaborn as sns
|
| 6 |
+
import matplotlib.pyplot as plt
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import numpy as np
|
| 9 |
+
import math
|
| 10 |
+
import itertools
|
| 11 |
+
import random
|
| 12 |
+
import os
|
| 13 |
+
from polyleven import levenshtein
|
| 14 |
+
import operator
|
| 15 |
+
import pickle
|
| 16 |
+
import time
|
| 17 |
+
import tensorflow as tf
|
| 18 |
+
|
| 19 |
+
tf.random.set_seed(35)
|
| 20 |
+
np.random.seed(35)
|
| 21 |
+
|
| 22 |
+
rna_vocab = {"A":0,
|
| 23 |
+
"C":1,
|
| 24 |
+
"G":2,
|
| 25 |
+
"U":3,
|
| 26 |
+
"*":4}
|
| 27 |
+
|
| 28 |
+
rev_rna_vocab = {v:k for k,v in rna_vocab.items()}
|
| 29 |
+
|
| 30 |
+
def recover_seq(samples, rev_charmap=rev_rna_vocab):
|
| 31 |
+
"""Convert samples to strings and save to log directory."""
|
| 32 |
+
|
| 33 |
+
char_probs = samples
|
| 34 |
+
argmax = np.argmax(char_probs, 2)
|
| 35 |
+
seqs = []
|
| 36 |
+
for line in argmax:
|
| 37 |
+
s = "".join(rev_charmap[d] for d in line)
|
| 38 |
+
s = s.replace('*','')
|
| 39 |
+
seqs.append(s)
|
| 40 |
+
return seqs
|
| 41 |
+
|
| 42 |
+
def file_to_list(file_name,size):
|
| 43 |
+
data = []
|
| 44 |
+
with open(file_name,'r') as f:
|
| 45 |
+
lines = f.readlines()
|
| 46 |
+
|
| 47 |
+
for seq in lines:
|
| 48 |
+
seq_ = seq.replace('\n','')
|
| 49 |
+
data.append(seq_)
|
| 50 |
+
# if len(seq) == size:
|
| 51 |
+
# data.append(seq)
|
| 52 |
+
|
| 53 |
+
return data
|
| 54 |
+
|
| 55 |
+
def one_hot_encode(seq):
|
| 56 |
+
mapping = dict(zip("ACGT", range(4)))
|
| 57 |
+
seq = seq.replace('U','T')
|
| 58 |
+
seq2 = [mapping[i] for i in seq]
|
| 59 |
+
return np.eye(4)[seq2]
|
| 60 |
+
|
| 61 |
+
def encode(seqs):
|
| 62 |
+
return np.reshape([one_hot_encode(seqs[i]) for i in range(len(seqs))],(np.array(seqs).shape[0],-1))
|
| 63 |
+
|
| 64 |
+
min_len = None
|
| 65 |
+
nuc_dict = {'a':[1.0,0.0,0.0,0.0],'c':[0.0,1.0,0.0,0.0],'g':[0.0,0.0,1.0,0.0],
|
| 66 |
+
'u':[0.0,0.0,0.0,1.0], 't':[0.0,0.0,0.0,1.0],
|
| 67 |
+
'n':[0.0,0.0,0.0,0.0], 'x':[1/4,1/4,1/4,1/4]}
|
| 68 |
+
|
| 69 |
+
def encode_seq_framepool(seq, max_len=128):
|
| 70 |
+
# print(seq)
|
| 71 |
+
|
| 72 |
+
length = len(seq)
|
| 73 |
+
if max_len > 0 and min_len is None:
|
| 74 |
+
padding_needed = max_len - length
|
| 75 |
+
seq = "N"*padding_needed + seq
|
| 76 |
+
if min_len is not None:
|
| 77 |
+
if len(seq) < min_len:
|
| 78 |
+
seq = "N"*(min_len - len(seq)) + seq
|
| 79 |
+
|
| 80 |
+
if len(seq) > min_len:
|
| 81 |
+
seq = seq[(len(seq) - min_len):]
|
| 82 |
+
seq = seq.lower()
|
| 83 |
+
one_hot = np.array([nuc_dict[x] for x in seq]) # get stacked on top of each other
|
| 84 |
+
|
| 85 |
+
return one_hot
|
| 86 |
+
|
| 87 |
+
def list_to_file(filename,list):
|
| 88 |
+
with open(filename + ".txt", 'w') as f:
|
| 89 |
+
for element in list[:-1]:
|
| 90 |
+
f.write(element+"\n")
|
| 91 |
+
f.write(list[-1])
|
| 92 |
+
|
| 93 |
+
def tsne_natural(file_name, length, key='seq'):
|
| 94 |
+
df = pd.read_csv(file_name)
|
| 95 |
+
seqs = np.array(df[key]).tolist()
|
| 96 |
+
|
| 97 |
+
selected_seqs = []
|
| 98 |
+
|
| 99 |
+
for i in range(len(seqs)):
|
| 100 |
+
seq = seqs[i]
|
| 101 |
+
seq = seq.upper()
|
| 102 |
+
if seq not in selected_seqs and len(seq) == length:
|
| 103 |
+
selected_seqs.append(seq)
|
| 104 |
+
|
| 105 |
+
return selected_seqs
|
| 106 |
+
|
| 107 |
+
def read_real(file_name, UTR_LEN, key='seq', all= True, samples= 128 ):
|
| 108 |
+
df = pd.read_csv(file_name)
|
| 109 |
+
seqs = np.array(df[key]).tolist()
|
| 110 |
+
|
| 111 |
+
selected_seqs = []
|
| 112 |
+
|
| 113 |
+
for i in range(len(seqs)):
|
| 114 |
+
if len(seqs[i]) < (UTR_LEN + 1) and len(seqs[i]) > int(UTR_LEN/2):
|
| 115 |
+
seqs[i] = seqs[i].upper()
|
| 116 |
+
if seqs[i] not in selected_seqs:
|
| 117 |
+
selected_seqs.append(seqs[i])
|
| 118 |
+
|
| 119 |
+
if all:
|
| 120 |
+
return selected_seqs
|
| 121 |
+
|
| 122 |
+
else:
|
| 123 |
+
indices = []
|
| 124 |
+
|
| 125 |
+
for i in range(len(selected_seqs)):
|
| 126 |
+
|
| 127 |
+
indices.append(i)
|
| 128 |
+
|
| 129 |
+
samples = np.random.choice(len(indices),samples,replace=False)
|
| 130 |
+
|
| 131 |
+
chosen = []
|
| 132 |
+
|
| 133 |
+
for i in range(len(samples)):
|
| 134 |
+
chosen.append(selected_seqs[samples[i]])
|
| 135 |
+
|
| 136 |
+
return chosen
|
| 137 |
+
|
| 138 |
+
def random_sample(length):
|
| 139 |
+
rna_vocab = {"A":0,
|
| 140 |
+
"C":1,
|
| 141 |
+
"G":2,
|
| 142 |
+
"T":3}
|
| 143 |
+
|
| 144 |
+
rev_rna_vocab = {v:k for k,v in rna_vocab.items()}
|
| 145 |
+
|
| 146 |
+
mapping = dict(zip([0,1,2,3],"ACGT"))
|
| 147 |
+
|
| 148 |
+
sample = ''
|
| 149 |
+
for i in range(length):
|
| 150 |
+
r = random.random()
|
| 151 |
+
if r < 0.6:
|
| 152 |
+
sample += random.choice(['C','G'])
|
| 153 |
+
else:
|
| 154 |
+
sample += random.choice(['A','T'])
|
| 155 |
+
# rsample = [random.randrange(4) for i in range(length)]
|
| 156 |
+
# rsample = [mapping[i] for i in rsample]
|
| 157 |
+
# string = ''
|
| 158 |
+
# for neuc in rsample:
|
| 159 |
+
# string += neuc
|
| 160 |
+
|
| 161 |
+
return sample
|
| 162 |
+
|
| 163 |
+
def random_data(length, size):
|
| 164 |
+
samples = []
|
| 165 |
+
for i in range(size):
|
| 166 |
+
samples.append(random_sample(length))
|
| 167 |
+
|
| 168 |
+
return samples
|
| 169 |
+
|
| 170 |
+
def motif_count(gens,motifs_path='./../../data/motifs.csv'):
|
| 171 |
+
motifs = pd.read_csv(motifs_path)
|
| 172 |
+
seqs = motifs['seq']
|
| 173 |
+
scores = motifs['spr']
|
| 174 |
+
gen_positive = 0
|
| 175 |
+
gen_negative = 0
|
| 176 |
+
for i in range(len(seqs)):
|
| 177 |
+
for j in range(len(gens)):
|
| 178 |
+
if seqs[i] in gens[j]:
|
| 179 |
+
if scores[i] < 0:
|
| 180 |
+
gen_negative += 1
|
| 181 |
+
else:
|
| 182 |
+
gen_positive += 1
|
| 183 |
+
|
| 184 |
+
return gen_positive, gen_negative
|
| 185 |
+
|
| 186 |
+
def tsne_gen(path,length=128,BATCH_SIZE=64,DIM=40):
|
| 187 |
+
wgan = tf.keras.models.load_model(path)
|
| 188 |
+
|
| 189 |
+
selected = []
|
| 190 |
+
while len(selected) < BATCH_SIZE:
|
| 191 |
+
|
| 192 |
+
noise = tf.Variable(tf.random.normal(shape=[64,DIM]))
|
| 193 |
+
|
| 194 |
+
sequences_init = wgan(noise)
|
| 195 |
+
|
| 196 |
+
gen_seqs_init = sequences_init.numpy().astype('float')
|
| 197 |
+
|
| 198 |
+
seqs_gen_init = recover_seq(gen_seqs_init, rev_rna_vocab)
|
| 199 |
+
|
| 200 |
+
for i in range(len(seqs_gen_init)):
|
| 201 |
+
if len(seqs_gen_init[i]) == length:
|
| 202 |
+
selected.append(seqs_gen_init[i])
|
| 203 |
+
|
| 204 |
+
return selected[:BATCH_SIZE]
|
| 205 |
+
|
| 206 |
+
def generate_data(path,BATCH_SIZE=64,UTR_LEN=128,DIM=40):
|
| 207 |
+
wgan = tf.keras.models.load_model(path)
|
| 208 |
+
|
| 209 |
+
gens = []
|
| 210 |
+
|
| 211 |
+
while len(gens) < BATCH_SIZE:
|
| 212 |
+
|
| 213 |
+
noise = tf.Variable(tf.random.normal(shape=[BATCH_SIZE,DIM]))
|
| 214 |
+
|
| 215 |
+
sequences_init = wgan(noise)
|
| 216 |
+
|
| 217 |
+
gen_seqs_init = sequences_init.numpy().astype('float')
|
| 218 |
+
|
| 219 |
+
seqs_gen_init = recover_seq(gen_seqs_init, rev_rna_vocab)
|
| 220 |
+
|
| 221 |
+
for i in range(len(seqs_gen_init)):
|
| 222 |
+
if len(seqs_gen_init[i]) > int(UTR_LEN/2) and len(seqs_gen_init[i])< UTR_LEN+1:
|
| 223 |
+
if seqs_gen_init[i] not in gens:
|
| 224 |
+
gens.append(seqs_gen_init[i])
|
| 225 |
+
if len(gens) == BATCH_SIZE:
|
| 226 |
+
break
|
| 227 |
+
|
| 228 |
+
return gens[:BATCH_SIZE]
|
| 229 |
+
|
| 230 |
+
def gc_percentage(seq):
|
| 231 |
+
count = 0.0
|
| 232 |
+
for char in seq:
|
| 233 |
+
if char == 'C' or char == 'G':
|
| 234 |
+
count +=1
|
| 235 |
+
|
| 236 |
+
return float(count/len(seq))
|
| 237 |
+
|
| 238 |
+
def get_gc_content(data):
|
| 239 |
+
gc_content = []
|
| 240 |
+
for seq in data:
|
| 241 |
+
seq.replace('\n','')
|
| 242 |
+
seq.replace('*','')
|
| 243 |
+
gc = gc_percentage(seq)
|
| 244 |
+
gc_content.append(gc)
|
| 245 |
+
|
| 246 |
+
return gc_content
|
| 247 |
+
|
| 248 |
+
def get_gc_content_many(data):
|
| 249 |
+
|
| 250 |
+
collection = []
|
| 251 |
+
gc_contents = []
|
| 252 |
+
for seq in data:
|
| 253 |
+
seq = seq.upper()
|
| 254 |
+
seq.replace('\n','')
|
| 255 |
+
seq.replace('*','')
|
| 256 |
+
gc = gc_percentage(seq)
|
| 257 |
+
gc_contents.append(gc)
|
| 258 |
+
|
| 259 |
+
return gc_contents
|
| 260 |
+
|
| 261 |
+
def get_4mers():
|
| 262 |
+
neucs = ['A','C','G','T']
|
| 263 |
+
|
| 264 |
+
mers = [p for p in itertools.product(neucs, repeat=4)]
|
| 265 |
+
for i in range(len(mers)):
|
| 266 |
+
mers[i] = mers[i][0] + mers[i][1] + mers[i][2] + mers[i][3]
|
| 267 |
+
|
| 268 |
+
return mers
|
| 269 |
+
|
| 270 |
+
def get_4mer_dic(seqs):
|
| 271 |
+
|
| 272 |
+
_4mers = get_4mers()
|
| 273 |
+
length = 0
|
| 274 |
+
dics = []
|
| 275 |
+
|
| 276 |
+
for seq in seqs:
|
| 277 |
+
dic = {}
|
| 278 |
+
for item in _4mers:
|
| 279 |
+
dic[item] = 0
|
| 280 |
+
|
| 281 |
+
# Iterate With the Sliding Window
|
| 282 |
+
length = len(seq)
|
| 283 |
+
limit = length - 4
|
| 284 |
+
for i in range(limit):
|
| 285 |
+
mer = seq[i:i+4]
|
| 286 |
+
dic[mer] += 1
|
| 287 |
+
|
| 288 |
+
dics.append(dic)
|
| 289 |
+
|
| 290 |
+
return dics
|
| 291 |
+
|
| 292 |
+
def euclidean_kmer(item, ref, mers):
|
| 293 |
+
dist = 0
|
| 294 |
+
for mer in mers:
|
| 295 |
+
diff = item[mer] - ref[mer]
|
| 296 |
+
dist += math.pow(diff,2)
|
| 297 |
+
|
| 298 |
+
return dist
|
| 299 |
+
|
| 300 |
+
def euclidean_kmer_all(item,refs,mers):
|
| 301 |
+
dists = []
|
| 302 |
+
for ref in refs:
|
| 303 |
+
dists.append(euclidean_kmer(item,ref,mers))
|
| 304 |
+
|
| 305 |
+
return min(dists)
|
| 306 |
+
|
| 307 |
+
def hamming_dist(src, target):
|
| 308 |
+
|
| 309 |
+
dists = []
|
| 310 |
+
for i in range(len(src)):
|
| 311 |
+
smallest = np.inf
|
| 312 |
+
for j in range(len(target)):
|
| 313 |
+
dist = levenshtein(src[i],target[j])
|
| 314 |
+
if dist > 0 and dist < smallest:
|
| 315 |
+
smallest = dist
|
| 316 |
+
|
| 317 |
+
dists.append(dist)
|
| 318 |
+
|
| 319 |
+
return np.array(dists)
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
def one_hot_motif(seq,length=128,complementary=False):
|
| 330 |
+
"""
|
| 331 |
+
one_hot encoding on sequence
|
| 332 |
+
complementary: encode nucleatide into complementary one
|
| 333 |
+
"""
|
| 334 |
+
|
| 335 |
+
if length == -1:
|
| 336 |
+
length = len(seq)
|
| 337 |
+
|
| 338 |
+
# seq = str(seq)
|
| 339 |
+
# setting
|
| 340 |
+
seq = list(seq.replace("U","T"))
|
| 341 |
+
seq_len = len(seq)
|
| 342 |
+
complementary = -1 if complementary else 1
|
| 343 |
+
# compose dict
|
| 344 |
+
keys = ['A', 'C', 'G', 'T'][::complementary]
|
| 345 |
+
oh_dict = {keys[i]:i for i in range(4)}
|
| 346 |
+
# array
|
| 347 |
+
oh_array = np.zeros((length,4),dtype=np.double)
|
| 348 |
+
for i,C in enumerate(seq):
|
| 349 |
+
try:
|
| 350 |
+
oh_array[i,oh_dict[C]]=1
|
| 351 |
+
except:
|
| 352 |
+
continue # for nucleotide that are not in A C G T
|
| 353 |
+
return oh_array
|
| 354 |
+
|
| 355 |
+
def one_hot_all_motif(seqs):
|
| 356 |
+
# length = np.max([len(seq) for seq in seqs])
|
| 357 |
+
return [one_hot_motif(seqs[i], length = 128) for i in range(len(seqs))]
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
def one_hot(seq):
|
| 363 |
+
convert = False
|
| 364 |
+
if isinstance(seq, tf.Tensor):
|
| 365 |
+
seq = seq.numpy().astype(str)
|
| 366 |
+
convert = True
|
| 367 |
+
|
| 368 |
+
num_seqs = len(seq)
|
| 369 |
+
seq_len = len(seq[0])
|
| 370 |
+
seqindex = {'A':0, 'C':1, 'G':2, 'T':3, 'a':0, 'c':1, 'g':2, 't':3}
|
| 371 |
+
seq_vec = np.zeros((num_seqs,seq_len,4), dtype='bool')
|
| 372 |
+
for i in range(num_seqs):
|
| 373 |
+
thisseq = seq[i]
|
| 374 |
+
for j in range(seq_len):
|
| 375 |
+
try:
|
| 376 |
+
seq_vec[i,j,seqindex[thisseq[j]]] = 1
|
| 377 |
+
except:
|
| 378 |
+
pass
|
| 379 |
+
|
| 380 |
+
if convert:
|
| 381 |
+
seq_vec = tf.convert_to_tensor(seq_vec,dtype=tf.float32)
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
return seq_vec
|
model/src/mrl_te_optimization/utils.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sklearn.preprocessing import OneHotEncoder
|
| 2 |
+
import logging
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pandas as pd
|
| 5 |
+
import os
|
| 6 |
+
import json
|
| 7 |
+
import re
|
| 8 |
+
import torch
|
| 9 |
+
import collections
|
| 10 |
+
# from models import reader
|
| 11 |
+
from models.ScheduleOptimizer import ScheduledOptim
|
| 12 |
+
|
| 13 |
+
print(os.path.dirname(__file__))
|
| 14 |
+
|
| 15 |
+
# ====================| some path |=======================
|
| 16 |
+
global script_dir
|
| 17 |
+
global data_dir
|
| 18 |
+
global log_dir
|
| 19 |
+
global pth_dir
|
| 20 |
+
# global cell_lines
|
| 21 |
+
|
| 22 |
+
global egfp_seq
|
| 23 |
+
|
| 24 |
+
with open(os.path.join(os.path.dirname(__file__),"machine_configure.json"),'r') as f:
|
| 25 |
+
config = json.load(f)
|
| 26 |
+
|
| 27 |
+
script_dir = config['script_dir']
|
| 28 |
+
data_dir = config['data_dir']
|
| 29 |
+
log_dir = config['log_dir']
|
| 30 |
+
pth_dir = config['pth_dir']
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# =====================| one hot encode |=======================
|
| 35 |
+
|
| 36 |
+
class Seq_one_hot(object):
|
| 37 |
+
def __init__(self,seq_type='nn',seq_len=100):
|
| 38 |
+
"""
|
| 39 |
+
initiate the sequence one hot encoder
|
| 40 |
+
"""
|
| 41 |
+
self.seq_len=seq_len
|
| 42 |
+
self.seq_type =seq_type
|
| 43 |
+
self.enable_encoder()
|
| 44 |
+
|
| 45 |
+
def enable_encoder(self):
|
| 46 |
+
if self.seq_type == 'nn':
|
| 47 |
+
self.encoder = OneHotEncoder(sparse=False)
|
| 48 |
+
self.encoder.drop_idx_ = None
|
| 49 |
+
self.encoder.categories_ = [np.array(['A', 'C', 'G', 'T'], dtype='<U1')]*self.seq_len
|
| 50 |
+
|
| 51 |
+
def discretize_seq(self,data):
|
| 52 |
+
"""
|
| 53 |
+
discretize sequence into character
|
| 54 |
+
argument:
|
| 55 |
+
...data: can be dataframe with UTR columns , or can be single string
|
| 56 |
+
"""
|
| 57 |
+
if type(data) is pd.DataFrame:
|
| 58 |
+
return np.stack(data.UTR.apply(lambda x: list(x)))
|
| 59 |
+
elif type(data) is str:
|
| 60 |
+
return np.array(list(data))
|
| 61 |
+
|
| 62 |
+
def transform(self,data,flattern=True):
|
| 63 |
+
"""
|
| 64 |
+
One hot encode
|
| 65 |
+
argument:
|
| 66 |
+
data : is a 2D array
|
| 67 |
+
flattern : True
|
| 68 |
+
"""
|
| 69 |
+
X = self.encoder.transform(data) # 400 for each seq
|
| 70 |
+
X_M = np.stack([seq.reshape(self.seq_len,4) for seq in X]) # i.e 100*4
|
| 71 |
+
return X if flattern else X_M
|
| 72 |
+
|
| 73 |
+
def d_transform(self,data,flattern=True):
|
| 74 |
+
"""
|
| 75 |
+
discretize data and put into transform
|
| 76 |
+
"""
|
| 77 |
+
X = self.discretize_seq(data)
|
| 78 |
+
return self.transform(X,flattern)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
# =====================| logger |=======================
|
| 82 |
+
|
| 83 |
+
def setup_logs(vae_log_path,level=None):
|
| 84 |
+
"""
|
| 85 |
+
|
| 86 |
+
:param save_dir: the directory to set up logs
|
| 87 |
+
:param type: 'model' for saving logs in 'logs/cpc'; 'imp' for saving logs in 'logs/imp'
|
| 88 |
+
:param run_name:
|
| 89 |
+
:return:logger
|
| 90 |
+
"""
|
| 91 |
+
# initialize logger
|
| 92 |
+
logger = logging.getLogger("VAE")
|
| 93 |
+
logger.setLevel(logging.INFO)
|
| 94 |
+
if level=='warning':
|
| 95 |
+
logger.setLevel(logging.WARNING)
|
| 96 |
+
|
| 97 |
+
# create the logging file handler
|
| 98 |
+
log_file = os.path.join(vae_log_path)
|
| 99 |
+
fh = logging.FileHandler(log_file)
|
| 100 |
+
|
| 101 |
+
# create the logging console handler
|
| 102 |
+
ch = logging.StreamHandler()
|
| 103 |
+
|
| 104 |
+
# format
|
| 105 |
+
formatter = logging.Formatter("%(asctime)s - %(message)s")
|
| 106 |
+
fh.setFormatter(formatter)
|
| 107 |
+
|
| 108 |
+
# add handlers to logger object
|
| 109 |
+
logger.addHandler(fh)
|
| 110 |
+
logger.addHandler(ch)
|
| 111 |
+
|
| 112 |
+
return logger
|
| 113 |
+
|
| 114 |
+
def clean_value_dict(dict):
|
| 115 |
+
"""
|
| 116 |
+
deal with verbose dict where the values maybe torch object, extact the item and return clean dict
|
| 117 |
+
"""
|
| 118 |
+
clean_dict={}
|
| 119 |
+
for k,v in dict.items():
|
| 120 |
+
|
| 121 |
+
try:
|
| 122 |
+
v = v.item()
|
| 123 |
+
except:
|
| 124 |
+
v = v
|
| 125 |
+
clean_dict[k] = v
|
| 126 |
+
return clean_dict
|
| 127 |
+
|
| 128 |
+
def fix_parameter(model,modual_to_fix,fix_or_unfix=False):
|
| 129 |
+
"""
|
| 130 |
+
for a given model, fix part of the parameter to fine-tuning / transfering
|
| 131 |
+
args:
|
| 132 |
+
model : `nn.Modual`,initiated model instance
|
| 133 |
+
modual_to_fix : str, define which part of the model will not update by gradient
|
| 134 |
+
e.g. "soft_share" then
|
| 135 |
+
"""
|
| 136 |
+
|
| 137 |
+
fix_part = eval("model."+modual_to_fix) # e.g. model.shoft_share
|
| 138 |
+
|
| 139 |
+
for param in fix_part.parameters():
|
| 140 |
+
param.requires_grad = fix_or_unfix
|
| 141 |
+
|
| 142 |
+
return model
|
| 143 |
+
|
| 144 |
+
def unfix_parameter(model,modual_to_fix,fix_or_unfix=False):
|
| 145 |
+
return fix_parameter(model,modual_to_fix,fix_or_unfix=True)
|
| 146 |
+
|
| 147 |
+
def snapshot(vae_pth_path, state):
|
| 148 |
+
logger = logging.getLogger("VAE")
|
| 149 |
+
# torch.save can save any object
|
| 150 |
+
# dict type object in our cases
|
| 151 |
+
torch.save(state, vae_pth_path)
|
| 152 |
+
logger.info("Snapshot saved to {}\n".format(vae_pth_path))
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def load_model(popen,model,logger=None):
|
| 156 |
+
|
| 157 |
+
info = lambda x: print(x) if logger==None else logger.info(x)
|
| 158 |
+
# popen.vae_pth_path = '/mnt/sina/run/ml/gan/dev/git/UTRGAN/src/mrl_optimization/script/checkpoint/RL_hard_share_MTL/3M/small_repective_filed_strides1113-model_best_cv1.pth'
|
| 159 |
+
checkpoint = torch.load(popen.vae_pth_path, map_location=torch.device('cpu'))
|
| 160 |
+
if isinstance(checkpoint['state_dict'], collections.OrderedDict):
|
| 161 |
+
# optimizer.load_state_dict(checkpoint['optimizer'])
|
| 162 |
+
model.load_state_dict(checkpoint['state_dict'])
|
| 163 |
+
else:
|
| 164 |
+
model = checkpoint['state_dict']
|
| 165 |
+
|
| 166 |
+
info(' \t \t ==============<<< encoder load from >>>============== \t \t ')
|
| 167 |
+
info(" \t"+popen.vae_pth_path)
|
| 168 |
+
|
| 169 |
+
return model
|
| 170 |
+
|
| 171 |
+
def get_config_cuda(config_file):
|
| 172 |
+
with open(config_file,'r') as f:
|
| 173 |
+
lines = f.read_lines()
|
| 174 |
+
for line in lines:
|
| 175 |
+
if "cuda_id =" in line:
|
| 176 |
+
device = line.split("=")[1].strip()
|
| 177 |
+
break
|
| 178 |
+
device = int(device) if device.isdigit() else device
|
| 179 |
+
return device
|
| 180 |
+
|
| 181 |
+
def resume(popen,optimizer,logger):
|
| 182 |
+
"""
|
| 183 |
+
for a experiment, check whether it;s a new run, and create dir
|
| 184 |
+
"""
|
| 185 |
+
#run_name = model_stype + time.strftime("__%Y_%m_%d_%H:%M"))
|
| 186 |
+
|
| 187 |
+
if popen.Resumable:
|
| 188 |
+
|
| 189 |
+
checkpoint = torch.load(popen.vae_pth_path, map_location=torch.device('cpu')) # xx-model-best.pth
|
| 190 |
+
previous_epoch = checkpoint['epoch']
|
| 191 |
+
previous_loss = checkpoint['validation_loss']
|
| 192 |
+
previous_acc = checkpoint['validation_acc']
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
# very important
|
| 196 |
+
if (type(optimizer) == ScheduledOptim):
|
| 197 |
+
optimizer.n_current_steps = popen.n_current_steps
|
| 198 |
+
optimizer.delta = popen.delta
|
| 199 |
+
|
| 200 |
+
logger.info(" \t \t ========================================================= \t \t ")
|
| 201 |
+
logger.info(' \t \t ==============<<< Resume from checkpoint>>>============== \t \t \n')
|
| 202 |
+
logger.info(" \t"+popen.vae_pth_path+'\n')
|
| 203 |
+
logger.info(" \t \t ========================================================= \t \t \n")
|
| 204 |
+
|
| 205 |
+
return previous_epoch,previous_loss,previous_acc
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
egfp_seq = "atgggcgaattaagtaagggcgaggagctgttcaccggggtggtgcccatcctggtcgagctggacggcgacgtaaacggccacaagttcagcgtgtccggcgagggcgagggcgatgccacctacggcaagctgaccctgaagttcatctgcaccaccggcaagctgcccgtgccctggcccaccctcgtgaccaccctgacctacggcgtgcagtgcttcagccgctaccccgaccacatgaagcagcacgacttcttcaagtccgccatgcccgaaggctacgtccaggagcgcaccatcttct"
|
| 209 |
+
eGFP_seq = egfp_seq.upper()
|
model/src/mrl_te_optimization/xpresso_input.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
requirements.txt
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# UTRGAN on the OneScience base environment
|
| 2 |
+
# Python 3.11; SCNet BW DCU
|
| 3 |
+
#
|
| 4 |
+
# IMPORTANT RUNTIME DIFFERENCE
|
| 5 |
+
# ----------------------------
|
| 6 |
+
# OneScience is pinned to DTK 25.04 / DAS1.7:
|
| 7 |
+
# torch==2.5.1+das.opt1.dtk25042
|
| 8 |
+
# tensorflow==2.18.0+das.opt1.dtk25042
|
| 9 |
+
# UTRGAN ReLU/model inference failed there with "Failure when generating HSACO".
|
| 10 |
+
# The validated UTRGAN environment therefore uses DTK 26.04 / DAS1.8 and must
|
| 11 |
+
# load `compiler/dtk/26.04` (or an equivalent /opt/dtk-26.04 runtime).
|
| 12 |
+
#
|
| 13 |
+
# Install the active entries without replacing their dependencies:
|
| 14 |
+
# python -m pip install --no-deps -r requirements.txt
|
| 15 |
+
# Recheck torch/TensorFlow/HIP/DCU visibility immediately after installation.
|
| 16 |
+
|
| 17 |
+
# Required replacements for the OneScience DTK 26.04 framework wheels.
|
| 18 |
+
tensorflow @ https://download.sourcefind.cn:65024/file/4/tensorflow/DAS1.8/tensorflow-2.18.0+das.opt1.dtk2604-cp311-cp311-manylinux_2_28_x86_64.whl
|
| 19 |
+
torch @ https://download.sourcefind.cn:65024/file/4/pytorch/DAS1.8/torch-2.5.1+das.opt1.dtk2604-cp311-cp311-manylinux_2_28_x86_64.whl
|
| 20 |
+
|
| 21 |
+
# Required compatibility/additional packages.
|
| 22 |
+
# OneScience includes tf-keras without a strict version; 2.18.0 is the tested
|
| 23 |
+
# version for loading the released legacy H5 files with TF_USE_LEGACY_KERAS=1.
|
| 24 |
+
tf-keras==2.18.0
|
| 25 |
+
polyleven==0.9.0
|
| 26 |
+
|
| 27 |
+
# Additional packages needed only by the repository's G4/analysis utilities.
|
| 28 |
+
# XGBoost is held below 2.3 because the released G4 JSON files use its old
|
| 29 |
+
# pre-1.6 JSON format, whose removal was announced for XGBoost 2.3.
|
| 30 |
+
xgboost==2.1.4
|
| 31 |
+
ViennaRNA==2.7.0
|
| 32 |
+
logomaker
|
| 33 |
+
ruptures
|
| 34 |
+
cliffs-delta
|
| 35 |
+
|
| 36 |
+
# NUPACK is used only by script/Nupack_MFE_prediction.py. NUPACK 4 is an
|
| 37 |
+
# externally licensed/downloaded Python package and is not installed from this
|
| 38 |
+
# requirements file. Install it separately from https://www.nupack.org/ only
|
| 39 |
+
# when that optional preprocessing script is needed.
|
| 40 |
+
# nupack # external optional dependency; no normal PyPI pin
|
| 41 |
+
|
| 42 |
+
# Provided by OneScience; complete UTRGAN dependency inventory follows.
|
| 43 |
+
# Keep these commented to avoid reinstalling generic wheels over OneScience.
|
| 44 |
+
# numpy==1.26.3
|
| 45 |
+
# pandas>=2.2.2
|
| 46 |
+
# scipy==1.14.1
|
| 47 |
+
# h5py>=3.7.0
|
| 48 |
+
# matplotlib
|
| 49 |
+
# seaborn
|
| 50 |
+
# tqdm>=4.60.0
|
| 51 |
+
# requests
|
| 52 |
+
# biopython==1.84
|
| 53 |
+
# scikit-learn>=1.2.2,<=1.6.0
|
| 54 |
+
# einops>=0.7.0
|
| 55 |
+
# pytorch-lightning==2.0.6
|
| 56 |
+
# torchmetrics
|
| 57 |
+
|
| 58 |
+
# Supplied transitively by the validated DTK TensorFlow stack; do not adjust
|
| 59 |
+
# these independently because doing so can break TensorFlow compatibility.
|
| 60 |
+
# keras==3.15.1
|
| 61 |
+
# protobuf
|
| 62 |
+
# ml-dtypes
|
scripts/optimize_te_mrl.py
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
| 7 |
+
MODEL_ROOT = PROJECT_ROOT / "model"
|
| 8 |
+
MODULE_ROOT = MODEL_ROOT / "src" / "mrl_te_optimization"
|
| 9 |
+
for import_root in (MODEL_ROOT, MODULE_ROOT):
|
| 10 |
+
if str(import_root) not in sys.path:
|
| 11 |
+
sys.path.insert(0, str(import_root))
|
| 12 |
+
|
| 13 |
+
os.environ.setdefault("TF_USE_LEGACY_KERAS", "1")
|
| 14 |
+
|
| 15 |
+
from tqdm import tqdm
|
| 16 |
+
import random
|
| 17 |
+
random.seed(1337)
|
| 18 |
+
import matplotlib.pyplot as plt
|
| 19 |
+
import argparse
|
| 20 |
+
import numpy as np
|
| 21 |
+
np.random.seed(1337)
|
| 22 |
+
import pandas as pd
|
| 23 |
+
import torch
|
| 24 |
+
from framepool import *
|
| 25 |
+
from util import *
|
| 26 |
+
|
| 27 |
+
import random
|
| 28 |
+
random.seed(1337)
|
| 29 |
+
import scipy.stats as stats
|
| 30 |
+
|
| 31 |
+
import tensorflow as tf
|
| 32 |
+
from tensorflow.keras import backend as K
|
| 33 |
+
from tensorflow.keras.models import load_model
|
| 34 |
+
|
| 35 |
+
tf.compat.v1.enable_eager_execution()
|
| 36 |
+
|
| 37 |
+
import pandas as pd
|
| 38 |
+
import numpy as np
|
| 39 |
+
import requests
|
| 40 |
+
|
| 41 |
+
parser = argparse.ArgumentParser()
|
| 42 |
+
parser.add_argument('-d', type=str, required=False,
|
| 43 |
+
default=str(PROJECT_ROOT / 'conf' / 'data' / 'utrdb2.csv'))
|
| 44 |
+
parser.add_argument('-bs', type=int, required=False ,default=64)
|
| 45 |
+
parser.add_argument('-lr', type=int, required=False ,default=1)
|
| 46 |
+
parser.add_argument('-task', type=str, required=False ,default="mrl")
|
| 47 |
+
parser.add_argument('-gpu', type=str, required=False ,default='-1')
|
| 48 |
+
parser.add_argument('-s', type=int, required=False ,default=10000)
|
| 49 |
+
parser.add_argument('--output-dir', type=str,
|
| 50 |
+
default=str(PROJECT_ROOT / 'outputs' / 'optimization'))
|
| 51 |
+
args = parser.parse_args()
|
| 52 |
+
|
| 53 |
+
if args.gpu == '-1':
|
| 54 |
+
device = 'cpu'
|
| 55 |
+
else:
|
| 56 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu
|
| 57 |
+
device = 'cuda'
|
| 58 |
+
|
| 59 |
+
def prepare_mttrans(seqs):
|
| 60 |
+
seqs_init = torch.tensor(np.array(one_hot_all_motif(seqs),dtype=np.float32))
|
| 61 |
+
|
| 62 |
+
seqs_init = torch.transpose(seqs_init, 1, 2)
|
| 63 |
+
seqs_init = torch.tensor(seqs_init,dtype=torch.float32).to(device)
|
| 64 |
+
return seqs_init
|
| 65 |
+
|
| 66 |
+
def prepare_framepool(seqs):
|
| 67 |
+
return tf.convert_to_tensor(np.array([encode_seq_framepool(seq) for seq in seqs]),dtype=tf.float32)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
BATCH_SIZE = args.bs
|
| 72 |
+
motifs_path = str(PROJECT_ROOT / 'conf' / 'data' / 'motifs.csv')
|
| 73 |
+
STEPS = args.s
|
| 74 |
+
LR = args.lr
|
| 75 |
+
DIM = 40
|
| 76 |
+
SEQ_LEN = 128
|
| 77 |
+
UTR_LEN = 128
|
| 78 |
+
|
| 79 |
+
TASK = args.task
|
| 80 |
+
|
| 81 |
+
gpath = str(PROJECT_ROOT / 'weight' / 'checkpoint_3000.h5')
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
if TASK == 'te':
|
| 85 |
+
path = str(PROJECT_ROOT / 'weight' / 'mttrans' / 'RL_hard_share_MTL' /
|
| 86 |
+
'3R' / 'schedule_MTL-model_best_cv1.pth')
|
| 87 |
+
OPT = 'TE'
|
| 88 |
+
else:
|
| 89 |
+
path = str(PROJECT_ROOT / 'weight' / 'utr_model_combined_residual_new.h5')
|
| 90 |
+
OPT = 'FMRL'
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# Check for GPU availability
|
| 94 |
+
gpus = tf.config.list_physical_devices('GPU')
|
| 95 |
+
|
| 96 |
+
if gpus:
|
| 97 |
+
print(f"GPU is available. Using GPU:{args.gpu} for computation.")
|
| 98 |
+
print("List of GPUs:", gpus)
|
| 99 |
+
else:
|
| 100 |
+
print("GPU is not available. Using CPU instead.")
|
| 101 |
+
|
| 102 |
+
out_folder = str(Path(args.output_dir).expanduser().resolve())
|
| 103 |
+
os.makedirs(out_folder, exist_ok=True)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def select_best(scores, seqs):
|
| 108 |
+
selected_scores = []
|
| 109 |
+
selected_seqs = []
|
| 110 |
+
for i in range(len(scores[0])):
|
| 111 |
+
best = scores[0][i]
|
| 112 |
+
best_seq = seqs[0][i]
|
| 113 |
+
for j in range(len(scores)-1):
|
| 114 |
+
if scores[j+1][i] > best:
|
| 115 |
+
best = scores[j+1][i]
|
| 116 |
+
best_seq = seqs[j+1][i]
|
| 117 |
+
selected_scores.append(best)
|
| 118 |
+
selected_seqs.append(best_seq)
|
| 119 |
+
|
| 120 |
+
return selected_seqs, selected_scores
|
| 121 |
+
|
| 122 |
+
if __name__ == '__main__':
|
| 123 |
+
|
| 124 |
+
if OPT == 'FMRL':
|
| 125 |
+
Optimize_FrameSlice = True
|
| 126 |
+
else:
|
| 127 |
+
Optimize_FrameSlice = False
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
if Optimize_FrameSlice:
|
| 132 |
+
model = load_framepool(path)
|
| 133 |
+
|
| 134 |
+
else:
|
| 135 |
+
|
| 136 |
+
model = torch.load(path,map_location=torch.device(device))['state_dict']
|
| 137 |
+
model.train()
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
wgan = tf.keras.models.load_model(gpath)
|
| 141 |
+
|
| 142 |
+
"""
|
| 143 |
+
Data:
|
| 144 |
+
"""
|
| 145 |
+
|
| 146 |
+
tf.random.set_seed(33)
|
| 147 |
+
np.random.seed(33)
|
| 148 |
+
|
| 149 |
+
diffs = []
|
| 150 |
+
init_exps = []
|
| 151 |
+
opt_exps = []
|
| 152 |
+
orig_vals = []
|
| 153 |
+
|
| 154 |
+
DIM = 40
|
| 155 |
+
MAX_LEN = 128
|
| 156 |
+
LR = np.exp(-LR)
|
| 157 |
+
|
| 158 |
+
tempnoise = tf.random.normal(shape=[BATCH_SIZE,DIM])
|
| 159 |
+
selectednoise = tempnoise
|
| 160 |
+
|
| 161 |
+
best = 10
|
| 162 |
+
|
| 163 |
+
LOW_START = False
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
if LOW_START:
|
| 167 |
+
|
| 168 |
+
for i in range(10000):
|
| 169 |
+
tempnoise = tf.random.normal(shape=[BATCH_SIZE,DIM])
|
| 170 |
+
sequences = wgan(tempnoise)
|
| 171 |
+
|
| 172 |
+
seqs_gen = recover_seq(sequences, rev_rna_vocab)
|
| 173 |
+
seqs_str = seqs_gen
|
| 174 |
+
|
| 175 |
+
shape_ = tf.shape(np.array([encode_seq_framepool(seq) for seq in recover_seq(sequences, rev_rna_vocab)]))
|
| 176 |
+
|
| 177 |
+
seqs = tf.convert_to_tensor(np.array([encode_seq_framepool(seq) for seq in recover_seq(sequences, rev_rna_vocab)]),dtype=tf.float32)
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
pred = model(seqs)
|
| 181 |
+
|
| 182 |
+
t = tf.reshape(pred,(-1))
|
| 183 |
+
t = t.numpy().astype('float')
|
| 184 |
+
score = np.mean(t)
|
| 185 |
+
|
| 186 |
+
if score < best:
|
| 187 |
+
best = score
|
| 188 |
+
selectednoise = tempnoise
|
| 189 |
+
noise = tf.Variable(selectednoise)
|
| 190 |
+
else:
|
| 191 |
+
noise = tf.Variable(tf.random.normal(shape=[BATCH_SIZE,DIM]))
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
noise_small = tf.random.normal(shape=[BATCH_SIZE,DIM],stddev=1e-4)
|
| 195 |
+
|
| 196 |
+
optimizer = tf.keras.optimizers.Adam(learning_rate=np.power(np.e,LR))
|
| 197 |
+
|
| 198 |
+
'''
|
| 199 |
+
Optimization takes place here.
|
| 200 |
+
'''
|
| 201 |
+
|
| 202 |
+
bind_scores_list = []
|
| 203 |
+
bind_scores_means = []
|
| 204 |
+
sequences_list = []
|
| 205 |
+
|
| 206 |
+
means = []
|
| 207 |
+
maxes = []
|
| 208 |
+
iters_ = []
|
| 209 |
+
|
| 210 |
+
OPTIMIZE = True
|
| 211 |
+
|
| 212 |
+
DNA_SEL = False
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
sequences_init = wgan(noise)
|
| 216 |
+
|
| 217 |
+
gen_seqs_init = sequences_init.numpy().astype('float')
|
| 218 |
+
|
| 219 |
+
seqs_gen_init = recover_seq(gen_seqs_init, rev_rna_vocab)
|
| 220 |
+
|
| 221 |
+
init_pos, init_neg = motif_count(seqs_gen_init,motifs_path)
|
| 222 |
+
|
| 223 |
+
if Optimize_FrameSlice:
|
| 224 |
+
seqs = prepare_framepool(seqs_gen_init)
|
| 225 |
+
|
| 226 |
+
seqs_init = prepare_mttrans(seqs_gen_init)
|
| 227 |
+
|
| 228 |
+
pred_init = model(seqs)
|
| 229 |
+
|
| 230 |
+
else:
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
one_hots = one_hot_all_motif(np.array(seqs_gen_init))
|
| 234 |
+
seqs = torch.tensor(one_hots,dtype=torch.double)
|
| 235 |
+
seqs = torch.transpose(seqs, 1, 2)
|
| 236 |
+
seqs = seqs.float().to(device)
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
pred_init = model.forward(seqs)
|
| 240 |
+
|
| 241 |
+
if Optimize_FrameSlice:
|
| 242 |
+
|
| 243 |
+
t = tf.reshape(pred_init,(-1))
|
| 244 |
+
|
| 245 |
+
init_t = t.numpy().astype('float')
|
| 246 |
+
|
| 247 |
+
else:
|
| 248 |
+
|
| 249 |
+
t = torch.flatten(pred_init)
|
| 250 |
+
t.float()
|
| 251 |
+
|
| 252 |
+
init_t = t.cpu().detach().numpy()
|
| 253 |
+
|
| 254 |
+
init_exp = np.mean(init_t)
|
| 255 |
+
|
| 256 |
+
max_init = np.max(init_t)
|
| 257 |
+
|
| 258 |
+
min_init = np.min(init_t)
|
| 259 |
+
|
| 260 |
+
predicted_mrls = []
|
| 261 |
+
|
| 262 |
+
STEPS = STEPS
|
| 263 |
+
|
| 264 |
+
seqs_collection = []
|
| 265 |
+
scores_collection = []
|
| 266 |
+
if OPTIMIZE:
|
| 267 |
+
iter_ = 0
|
| 268 |
+
for opt_iter in tqdm(range(int(STEPS))):
|
| 269 |
+
|
| 270 |
+
with tf.GradientTape() as gtape:
|
| 271 |
+
gtape.watch(noise)
|
| 272 |
+
sequences = wgan(noise)
|
| 273 |
+
|
| 274 |
+
seqs_gen = recover_seq(sequences, rev_rna_vocab)
|
| 275 |
+
seqs_collection.append(seqs_gen)
|
| 276 |
+
seqs_str = seqs_gen
|
| 277 |
+
|
| 278 |
+
if Optimize_FrameSlice:
|
| 279 |
+
|
| 280 |
+
seqs = tf.convert_to_tensor(np.array([encode_seq_framepool(seq) for seq in recover_seq(sequences, rev_rna_vocab)]),dtype=tf.float32)
|
| 281 |
+
|
| 282 |
+
else:
|
| 283 |
+
seqs = torch.tensor(np.array(one_hot_all_motif(seqs_gen),dtype=np.float32))
|
| 284 |
+
|
| 285 |
+
if Optimize_FrameSlice:
|
| 286 |
+
|
| 287 |
+
with tf.GradientTape() as ptape:
|
| 288 |
+
ptape.watch(seqs)
|
| 289 |
+
|
| 290 |
+
pred = model(seqs)
|
| 291 |
+
score = tf.reduce_mean(pred)
|
| 292 |
+
t = tf.reshape(pred,(-1))
|
| 293 |
+
mx = t.numpy().astype('float')
|
| 294 |
+
scores_collection.append(mx)
|
| 295 |
+
mx = np.max(mx)
|
| 296 |
+
|
| 297 |
+
sum_ = tf.reduce_sum(t).numpy().astype('float')
|
| 298 |
+
|
| 299 |
+
maxes.append(mx)
|
| 300 |
+
predicted_mrls.append(sum_/BATCH_SIZE)
|
| 301 |
+
means.append(sum_/BATCH_SIZE)
|
| 302 |
+
|
| 303 |
+
g1 = ptape.gradient(score,seqs)
|
| 304 |
+
|
| 305 |
+
OPTIMIZE_FULL = False
|
| 306 |
+
if OPTIMIZE_FULL:
|
| 307 |
+
tmp_g = g1.numpy().astype('float')
|
| 308 |
+
tmp_seqs = seqs_gen
|
| 309 |
+
tmp_lst = np.zeros(shape=(BATCH_SIZE,MAX_LEN,5))
|
| 310 |
+
for i in range(len(tmp_seqs)):
|
| 311 |
+
|
| 312 |
+
len_ = len(tmp_seqs[i])
|
| 313 |
+
edited_g = tmp_g[i][:len_,:]
|
| 314 |
+
edited_g = np.pad(edited_g,((0,MAX_LEN-len_),(0,1)),'constant')
|
| 315 |
+
tmp_lst[i] = edited_g
|
| 316 |
+
|
| 317 |
+
g1 = tf.convert_to_tensor(tmp_lst,dtype=tf.float32)
|
| 318 |
+
|
| 319 |
+
else:
|
| 320 |
+
|
| 321 |
+
g1 = tf.pad(g1,tf.constant([[0, 0], [0, 0], [0, 1]]),"CONSTANT")
|
| 322 |
+
|
| 323 |
+
g1 = tf.math.scalar_mul(-1.0,g1)
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
else:
|
| 327 |
+
|
| 328 |
+
seqs = torch.transpose(seqs, 1, 2)
|
| 329 |
+
seqs = seqs.float()
|
| 330 |
+
seqs = torch.tensor(seqs.to(device), requires_grad=True)
|
| 331 |
+
pred = model(seqs)
|
| 332 |
+
pred = torch.flatten(pred)
|
| 333 |
+
predicted_mrls.append(np.average(pred.cpu().detach().numpy()))
|
| 334 |
+
scores_collection.append(pred.cpu().detach().numpy())
|
| 335 |
+
score = torch.mean(pred)
|
| 336 |
+
t = torch.flatten(pred)
|
| 337 |
+
mx = t.cpu().detach().numpy()
|
| 338 |
+
mx = np.max(mx)
|
| 339 |
+
|
| 340 |
+
sum_ = torch.mean(t).cpu().detach().numpy()
|
| 341 |
+
|
| 342 |
+
maxes.append(mx)
|
| 343 |
+
means.append(sum_/BATCH_SIZE)
|
| 344 |
+
pred.backward(torch.ones_like(pred))
|
| 345 |
+
|
| 346 |
+
g1 = seqs.grad
|
| 347 |
+
|
| 348 |
+
g1 = g1.cpu().detach().numpy()
|
| 349 |
+
g1 = tf.convert_to_tensor(g1)
|
| 350 |
+
g1 = tf.transpose(g1, perm=[0,2,1])
|
| 351 |
+
g1 = tf.pad(g1,tf.constant([[0, 0], [0, 0], [0, 1]]),"CONSTANT")
|
| 352 |
+
g1 = tf.math.scalar_mul(-1.0,g1)
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
g2 = gtape.gradient(sequences,noise,output_gradients=g1)
|
| 356 |
+
|
| 357 |
+
a1 = g2 + noise_small
|
| 358 |
+
change = [(a1,noise)]
|
| 359 |
+
optimizer.apply_gradients(change)
|
| 360 |
+
|
| 361 |
+
iters_.append(iter_)
|
| 362 |
+
iter_ += 1
|
| 363 |
+
|
| 364 |
+
best_seqs, best_scores = select_best(scores_collection, seqs_collection)
|
| 365 |
+
|
| 366 |
+
sequences_opt = wgan(noise)
|
| 367 |
+
|
| 368 |
+
gen_seqs_opt = sequences_opt.numpy().astype('float')
|
| 369 |
+
|
| 370 |
+
seqs_gen_opt = recover_seq(gen_seqs_opt, rev_rna_vocab)
|
| 371 |
+
|
| 372 |
+
opt_pos, opt_neg = motif_count(seqs_gen_opt,motifs_path)
|
| 373 |
+
|
| 374 |
+
if Optimize_FrameSlice:
|
| 375 |
+
|
| 376 |
+
seqs_opt = prepare_framepool(seqs_gen_opt)
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
else:
|
| 381 |
+
|
| 382 |
+
one_hots = np.array(one_hot_all_motif(seqs_gen_opt))
|
| 383 |
+
# print(np.shape(one_hots))
|
| 384 |
+
seqs = torch.tensor(one_hots,dtype=torch.double)
|
| 385 |
+
seqs = torch.transpose(seqs, 1, 2)
|
| 386 |
+
seqs = seqs.float().to(device)
|
| 387 |
+
|
| 388 |
+
pred_opt = model(seqs)
|
| 389 |
+
|
| 390 |
+
if Optimize_FrameSlice:
|
| 391 |
+
|
| 392 |
+
t = tf.reshape(pred_opt,(-1))
|
| 393 |
+
|
| 394 |
+
opt_t = t.numpy().astype('float')
|
| 395 |
+
|
| 396 |
+
else:
|
| 397 |
+
|
| 398 |
+
t = torch.flatten(pred_opt)
|
| 399 |
+
|
| 400 |
+
|
| 401 |
+
opt_t = t.cpu().detach().numpy()
|
| 402 |
+
|
| 403 |
+
opt_exp = np.mean(opt_t)
|
| 404 |
+
|
| 405 |
+
min_opt = np.min(opt_t)
|
| 406 |
+
max_opt = np.max(opt_t)
|
| 407 |
+
|
| 408 |
+
with open(os.path.join(out_folder, f'init_mrl_{OPT}.txt'), 'w') as f:
|
| 409 |
+
f.writelines([str(x)+'\n' for x in init_t])
|
| 410 |
+
|
| 411 |
+
with open(os.path.join(out_folder, f'opt_mrl_{OPT}.txt'), 'w') as f:
|
| 412 |
+
f.writelines([str(x)+'\n' for x in best_scores])
|
| 413 |
+
|
| 414 |
+
with open(os.path.join(out_folder, f'opt_seqs_{OPT}.txt'), 'w') as f:
|
| 415 |
+
f.writelines([str(x)+'\n' for x in best_seqs])
|
| 416 |
+
|
| 417 |
+
with open(os.path.join(out_folder, f'init_seqs_{OPT}.txt'), 'w') as f:
|
| 418 |
+
f.writelines([str(x)+'\n' for x in seqs_gen_init])
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
print(f"Average Initial Pred: {np.average(init_t)}")
|
| 422 |
+
print(f"Max Initial Pred: {np.max(init_t)}")
|
| 423 |
+
print(f"Average Opt. Pred: {np.average(best_scores)}")
|
| 424 |
+
print(f"Max Opt. Pred: {np.max(best_scores)}")
|
scripts/predict.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate 5' UTR candidates and rank them with FramePool and MTtrans."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
| 11 |
+
MODEL_ROOT = PROJECT_ROOT / "model"
|
| 12 |
+
MODULE_ROOT = MODEL_ROOT / "src" / "mrl_te_optimization"
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def parse_args():
|
| 16 |
+
parser = argparse.ArgumentParser(
|
| 17 |
+
description="Generate UTRGAN candidates and rank by MRL and TE."
|
| 18 |
+
)
|
| 19 |
+
parser.add_argument("--num-candidates", type=int, default=1024)
|
| 20 |
+
parser.add_argument("--batch-size", type=int, default=128)
|
| 21 |
+
parser.add_argument("--seed", type=int, default=33)
|
| 22 |
+
parser.add_argument("--device", choices=("dcu", "cpu"), default="dcu")
|
| 23 |
+
parser.add_argument("--device-id", default="0")
|
| 24 |
+
parser.add_argument(
|
| 25 |
+
"--output-dir",
|
| 26 |
+
default=str(PROJECT_ROOT / "outputs" / "pretrained_batch_ranking"),
|
| 27 |
+
)
|
| 28 |
+
return parser.parse_args()
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def configure_runtime(args):
|
| 32 |
+
os.environ.setdefault("TF_USE_LEGACY_KERAS", "1")
|
| 33 |
+
os.environ.setdefault("TF_CPP_MIN_LOG_LEVEL", "2")
|
| 34 |
+
if args.device == "cpu":
|
| 35 |
+
os.environ["HIP_VISIBLE_DEVICES"] = "-1"
|
| 36 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
| 37 |
+
else:
|
| 38 |
+
os.environ["HIP_VISIBLE_DEVICES"] = args.device_id
|
| 39 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = args.device_id
|
| 40 |
+
for import_root in (MODEL_ROOT, MODULE_ROOT):
|
| 41 |
+
if str(import_root) not in sys.path:
|
| 42 |
+
sys.path.insert(0, str(import_root))
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def main():
|
| 46 |
+
args = parse_args()
|
| 47 |
+
if args.num_candidates < 1 or args.batch_size < 1:
|
| 48 |
+
raise ValueError("--num-candidates and --batch-size must be positive")
|
| 49 |
+
configure_runtime(args)
|
| 50 |
+
|
| 51 |
+
import numpy as np
|
| 52 |
+
import pandas as pd
|
| 53 |
+
import tensorflow as tf
|
| 54 |
+
import torch
|
| 55 |
+
|
| 56 |
+
import framepool
|
| 57 |
+
import util
|
| 58 |
+
|
| 59 |
+
output_dir = Path(args.output_dir).expanduser().resolve()
|
| 60 |
+
output_dir.mkdir(parents=True, exist_ok=True)
|
| 61 |
+
|
| 62 |
+
generator_path = PROJECT_ROOT / "weight" / "checkpoint_3000.h5"
|
| 63 |
+
framepool_path = PROJECT_ROOT / "weight" / "utr_model_combined_residual_new.h5"
|
| 64 |
+
mttrans_path = (
|
| 65 |
+
PROJECT_ROOT
|
| 66 |
+
/ "weight"
|
| 67 |
+
/ "mttrans"
|
| 68 |
+
/ "RL_hard_share_MTL"
|
| 69 |
+
/ "3R"
|
| 70 |
+
/ "schedule_MTL-model_best_cv1.pth"
|
| 71 |
+
)
|
| 72 |
+
for path in (generator_path, framepool_path, mttrans_path):
|
| 73 |
+
if not path.is_file():
|
| 74 |
+
raise FileNotFoundError(path)
|
| 75 |
+
|
| 76 |
+
tf_device = "/GPU:0" if args.device == "dcu" else "/CPU:0"
|
| 77 |
+
torch_device = torch.device("cuda:0" if args.device == "dcu" else "cpu")
|
| 78 |
+
if args.device == "dcu":
|
| 79 |
+
tf_gpus = tf.config.list_physical_devices("GPU")
|
| 80 |
+
if not tf_gpus:
|
| 81 |
+
raise RuntimeError("TensorFlow did not detect a DCU")
|
| 82 |
+
if not torch.cuda.is_available():
|
| 83 |
+
raise RuntimeError("PyTorch did not detect a DCU")
|
| 84 |
+
for gpu in tf_gpus:
|
| 85 |
+
try:
|
| 86 |
+
tf.config.experimental.set_memory_growth(gpu, True)
|
| 87 |
+
except RuntimeError:
|
| 88 |
+
pass
|
| 89 |
+
|
| 90 |
+
# Loading on CPU avoids device-side random-initializer kernels; inference
|
| 91 |
+
# is explicitly placed on the requested device below.
|
| 92 |
+
with tf.device("/CPU:0"):
|
| 93 |
+
generator = tf.keras.models.load_model(generator_path, compile=False)
|
| 94 |
+
mrl_model = framepool.load_framepool(str(framepool_path))
|
| 95 |
+
generator.trainable = False
|
| 96 |
+
mrl_model.trainable = False
|
| 97 |
+
|
| 98 |
+
checkpoint = torch.load(
|
| 99 |
+
mttrans_path, map_location="cpu", weights_only=False
|
| 100 |
+
)
|
| 101 |
+
te_model = checkpoint["state_dict"].to(torch_device)
|
| 102 |
+
te_model.eval()
|
| 103 |
+
|
| 104 |
+
np.random.seed(args.seed)
|
| 105 |
+
tf.random.set_seed(args.seed)
|
| 106 |
+
torch.manual_seed(args.seed)
|
| 107 |
+
if args.device == "dcu":
|
| 108 |
+
torch.cuda.manual_seed_all(args.seed)
|
| 109 |
+
|
| 110 |
+
noise = np.random.RandomState(args.seed).normal(
|
| 111 |
+
size=(args.num_candidates, 40)
|
| 112 |
+
).astype(np.float32)
|
| 113 |
+
|
| 114 |
+
generated_batches = []
|
| 115 |
+
with tf.device(tf_device):
|
| 116 |
+
for start in range(0, args.num_candidates, args.batch_size):
|
| 117 |
+
stop = min(start + args.batch_size, args.num_candidates)
|
| 118 |
+
generated_batches.append(
|
| 119 |
+
generator(tf.convert_to_tensor(noise[start:stop]), training=False).numpy()
|
| 120 |
+
)
|
| 121 |
+
generated = np.concatenate(generated_batches, axis=0)
|
| 122 |
+
if generated.shape != (args.num_candidates, 128, 5):
|
| 123 |
+
raise RuntimeError(f"Unexpected generator shape: {generated.shape}")
|
| 124 |
+
if not np.isfinite(generated).all():
|
| 125 |
+
raise RuntimeError("Generator output contains NaN/Inf")
|
| 126 |
+
|
| 127 |
+
sequences = list(util.recover_seq(generated, util.rev_rna_vocab))
|
| 128 |
+
mrl_scores = []
|
| 129 |
+
with tf.device(tf_device):
|
| 130 |
+
for start in range(0, len(sequences), args.batch_size):
|
| 131 |
+
chunk = sequences[start : start + args.batch_size]
|
| 132 |
+
encoded = np.asarray(
|
| 133 |
+
[util.encode_seq_framepool(seq) for seq in chunk],
|
| 134 |
+
dtype=np.float32,
|
| 135 |
+
)
|
| 136 |
+
prediction = mrl_model(tf.convert_to_tensor(encoded), training=False)
|
| 137 |
+
mrl_scores.extend(tf.reshape(prediction, (-1,)).numpy().tolist())
|
| 138 |
+
|
| 139 |
+
te_scores = []
|
| 140 |
+
with torch.inference_mode():
|
| 141 |
+
for start in range(0, len(sequences), args.batch_size):
|
| 142 |
+
chunk = sequences[start : start + args.batch_size]
|
| 143 |
+
encoded = np.asarray(util.one_hot_all_motif(chunk), dtype=np.float32)
|
| 144 |
+
encoded = torch.from_numpy(encoded).transpose(1, 2).to(torch_device)
|
| 145 |
+
prediction = te_model(encoded)
|
| 146 |
+
te_scores.extend(prediction.reshape(-1).cpu().numpy().tolist())
|
| 147 |
+
|
| 148 |
+
mrl_scores = np.asarray(mrl_scores, dtype=np.float32)
|
| 149 |
+
te_scores = np.asarray(te_scores, dtype=np.float32)
|
| 150 |
+
if not np.isfinite(mrl_scores).all() or not np.isfinite(te_scores).all():
|
| 151 |
+
raise RuntimeError("MRL/TE scores contain NaN/Inf")
|
| 152 |
+
|
| 153 |
+
table = pd.DataFrame(
|
| 154 |
+
{
|
| 155 |
+
"candidate_id": [
|
| 156 |
+
f"UTRGAN_{index + 1:05d}" for index in range(len(sequences))
|
| 157 |
+
],
|
| 158 |
+
"sequence": sequences,
|
| 159 |
+
"length": [len(sequence) for sequence in sequences],
|
| 160 |
+
"mrl_score": mrl_scores,
|
| 161 |
+
"te_score": te_scores,
|
| 162 |
+
}
|
| 163 |
+
)
|
| 164 |
+
table["is_duplicate"] = table.duplicated("sequence", keep="first")
|
| 165 |
+
table["mrl_rank"] = table["mrl_score"].rank(
|
| 166 |
+
method="first", ascending=False
|
| 167 |
+
).astype(int)
|
| 168 |
+
table["te_rank"] = table["te_score"].rank(
|
| 169 |
+
method="first", ascending=False
|
| 170 |
+
).astype(int)
|
| 171 |
+
unique = table.drop_duplicates("sequence", keep="first").copy()
|
| 172 |
+
|
| 173 |
+
table.to_csv(output_dir / "all_candidates_scores.csv", index=False)
|
| 174 |
+
unique.sort_values("mrl_score", ascending=False).to_csv(
|
| 175 |
+
output_dir / "ranked_by_mrl.csv", index=False
|
| 176 |
+
)
|
| 177 |
+
unique.sort_values("te_score", ascending=False).to_csv(
|
| 178 |
+
output_dir / "ranked_by_te.csv", index=False
|
| 179 |
+
)
|
| 180 |
+
np.save(output_dir / "generator_probabilities.npy", generated)
|
| 181 |
+
|
| 182 |
+
summary = {
|
| 183 |
+
"requested_candidates": args.num_candidates,
|
| 184 |
+
"generated_candidates": len(table),
|
| 185 |
+
"unique_sequences": len(unique),
|
| 186 |
+
"duplicate_sequences": int(table["is_duplicate"].sum()),
|
| 187 |
+
"generator_shape": list(generated.shape),
|
| 188 |
+
"generator_probability_max_error": float(
|
| 189 |
+
np.max(np.abs(generated.sum(axis=-1) - 1.0))
|
| 190 |
+
),
|
| 191 |
+
"length_min": int(table["length"].min()),
|
| 192 |
+
"length_max": int(table["length"].max()),
|
| 193 |
+
"mrl_min": float(mrl_scores.min()),
|
| 194 |
+
"mrl_max": float(mrl_scores.max()),
|
| 195 |
+
"mrl_mean": float(mrl_scores.mean()),
|
| 196 |
+
"te_min": float(te_scores.min()),
|
| 197 |
+
"te_max": float(te_scores.max()),
|
| 198 |
+
"te_mean": float(te_scores.mean()),
|
| 199 |
+
"tensorflow_version": tf.__version__,
|
| 200 |
+
"torch_version": torch.__version__,
|
| 201 |
+
"torch_hip": torch.version.hip,
|
| 202 |
+
"device": args.device,
|
| 203 |
+
"seed": args.seed,
|
| 204 |
+
}
|
| 205 |
+
(output_dir / "summary.json").write_text(
|
| 206 |
+
json.dumps(summary, indent=2), encoding="utf-8"
|
| 207 |
+
)
|
| 208 |
+
print(json.dumps(summary, indent=2))
|
| 209 |
+
print("UTRGAN_PRETRAINED_BATCH_MRL_TE_RANKING_PASS")
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
if __name__ == "__main__":
|
| 213 |
+
main()
|
scripts/train.py
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
# Keep the official ``src`` package importable after adopting the standard
|
| 6 |
+
# conf/model/scripts/weight layout.
|
| 7 |
+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
| 8 |
+
MODEL_ROOT = PROJECT_ROOT / "model"
|
| 9 |
+
if str(MODEL_ROOT) not in sys.path:
|
| 10 |
+
sys.path.insert(0, str(MODEL_ROOT))
|
| 11 |
+
|
| 12 |
+
# The released H5 files use the legacy Keras serialization format.
|
| 13 |
+
os.environ.setdefault("TF_USE_LEGACY_KERAS", "1")
|
| 14 |
+
|
| 15 |
+
import numpy as np
|
| 16 |
+
import pandas as pd
|
| 17 |
+
import pdb
|
| 18 |
+
import tensorflow as tf
|
| 19 |
+
# from IPython.display import clear_output
|
| 20 |
+
import time
|
| 21 |
+
from src.gan.lib import models
|
| 22 |
+
from src.gan.lib import utils
|
| 23 |
+
import socket
|
| 24 |
+
import datetime
|
| 25 |
+
from tqdm import tqdm
|
| 26 |
+
import random
|
| 27 |
+
import matplotlib.pyplot as plt
|
| 28 |
+
import argparse
|
| 29 |
+
|
| 30 |
+
import tensorflow.keras.backend as K
|
| 31 |
+
from tensorflow.keras.optimizers import Adam
|
| 32 |
+
|
| 33 |
+
tf.compat.v1.enable_eager_execution()
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
parser = argparse.ArgumentParser()
|
| 37 |
+
parser.add_argument('-d', type=str, required=False,
|
| 38 |
+
default=str(PROJECT_ROOT / 'conf' / 'data' / 'utrdb2.csv'))
|
| 39 |
+
parser.add_argument('-bs', type=int, required=False ,default=64)
|
| 40 |
+
parser.add_argument('-lr', type=int, required=False ,default=5)
|
| 41 |
+
parser.add_argument('-mil', type=int, required=False ,default=64)
|
| 42 |
+
parser.add_argument('-mxl', type=int, required=False ,default=128)
|
| 43 |
+
parser.add_argument('-dim', type=int, required=False ,default=40)
|
| 44 |
+
parser.add_argument('-gpu', type=str, required=False ,default='-1')
|
| 45 |
+
parser.add_argument('-e', '--epochs', type=int, default=4000,
|
| 46 |
+
help='Number of complete passes over the filtered UTRdb dataset.')
|
| 47 |
+
parser.add_argument('--output-dir', type=str,
|
| 48 |
+
default=str(PROJECT_ROOT / 'outputs' / 'train'),
|
| 49 |
+
help='Directory for logs, generated samples, and checkpoints.')
|
| 50 |
+
args = parser.parse_args()
|
| 51 |
+
|
| 52 |
+
MODEL_NAME = 'WGAN-TF2'
|
| 53 |
+
RUN_ROOT = Path(args.output_dir).expanduser().resolve()
|
| 54 |
+
OUTPUT_PATH = RUN_ROOT / 'outputs' / MODEL_NAME
|
| 55 |
+
TRAIN_LOGDIR = RUN_ROOT / 'tensorboard' / MODEL_NAME / 'train_data'
|
| 56 |
+
OUTPUT_PATH.mkdir(parents=True, exist_ok=True)
|
| 57 |
+
TRAIN_LOGDIR.mkdir(parents=True, exist_ok=True)
|
| 58 |
+
file_writer = tf.summary.create_file_writer(str(TRAIN_LOGDIR))
|
| 59 |
+
|
| 60 |
+
if args.gpu == '-1':
|
| 61 |
+
device = 'cpu'
|
| 62 |
+
else:
|
| 63 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu
|
| 64 |
+
device = 'cuda'
|
| 65 |
+
|
| 66 |
+
def plot(x, y, logdir, name, xlabel=None, ylabel=None, title=None):
|
| 67 |
+
|
| 68 |
+
plt.plot(x,y,'-')
|
| 69 |
+
plt.title(title)
|
| 70 |
+
plt.xlabel(xlabel)
|
| 71 |
+
plt.ylabel(ylabel)
|
| 72 |
+
plt.savefig(logdir+'/'+name+'.png')
|
| 73 |
+
plt.clf()
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def plot_valid(x1, y1, x2, y2, logdir, name, xlabel=None, ylabel=None, title=None):
|
| 77 |
+
|
| 78 |
+
plt.plot(x2,y2,'-',color='tab:blue')
|
| 79 |
+
plt.plot(x1,y1,'-',color='tab:orange')
|
| 80 |
+
|
| 81 |
+
plt.title(title)
|
| 82 |
+
plt.xlabel(xlabel)
|
| 83 |
+
plt.ylabel(ylabel)
|
| 84 |
+
|
| 85 |
+
plt.savefig(logdir+'/'+name+'.png')
|
| 86 |
+
plt.clf()
|
| 87 |
+
|
| 88 |
+
def gradient_penalty_loss( y_true, y_pred, discriminator):
|
| 89 |
+
"""
|
| 90 |
+
Computes gradient penalty based on prediction and weighted real / fake samples
|
| 91 |
+
"""
|
| 92 |
+
alpha = K.random_uniform((DIM, 1, 1))
|
| 93 |
+
averaged_samples = (alpha * y_pred) + ((1 - alpha) * y_true)
|
| 94 |
+
|
| 95 |
+
gradients = K.gradients(y_pred, averaged_samples)[0]
|
| 96 |
+
# compute the euclidean norm by squaring ...
|
| 97 |
+
gradients_sqr = K.square(gradients)
|
| 98 |
+
# ... summing over the rows ...
|
| 99 |
+
gradients_sqr_sum = K.sum(gradients_sqr,
|
| 100 |
+
axis=np.arange(1, len(gradients_sqr.shape)))
|
| 101 |
+
# ... and sqrt
|
| 102 |
+
gradient_l2_norm = K.sqrt(gradients_sqr_sum)
|
| 103 |
+
# compute lambda * (1 - ||grad||)^2 still for each single sample
|
| 104 |
+
gradient_penalty = K.square(1 - gradient_l2_norm)
|
| 105 |
+
# return the mean as loss over all the batch samples
|
| 106 |
+
return K.mean(gradient_penalty)
|
| 107 |
+
|
| 108 |
+
def log(samples_dir=False,suff=None):
|
| 109 |
+
stamp = datetime.date.strftime(datetime.datetime.now(), "%Y.%m.%d-%Hh%Mm%Ss") + "_{}".format(socket.gethostname())
|
| 110 |
+
full_logdir = os.path.join(str(RUN_ROOT / "logs"), stamp)
|
| 111 |
+
if suff:
|
| 112 |
+
full_logdir = full_logdir + suff
|
| 113 |
+
os.makedirs(full_logdir, exist_ok=True)
|
| 114 |
+
if samples_dir: os.makedirs(os.path.join(full_logdir, "samples"), exist_ok=True)
|
| 115 |
+
log_dir = "{}:{}".format(socket.gethostname(), full_logdir)
|
| 116 |
+
|
| 117 |
+
return full_logdir, 0
|
| 118 |
+
|
| 119 |
+
data_path = args.d
|
| 120 |
+
data_utr = pd.read_csv(data_path)
|
| 121 |
+
UTRdf = data_utr['seq'].to_numpy()
|
| 122 |
+
|
| 123 |
+
seqs = []
|
| 124 |
+
|
| 125 |
+
UTR_LEN = args.mxl
|
| 126 |
+
|
| 127 |
+
for i in range(len(UTRdf)):
|
| 128 |
+
if len(UTRdf[i]) < UTR_LEN+1 and len(UTRdf[i]) > int(UTR_LEN/2):
|
| 129 |
+
if UTRdf[i] not in seqs:
|
| 130 |
+
seqs.append(UTRdf[i])
|
| 131 |
+
|
| 132 |
+
sequences = np.array(seqs)
|
| 133 |
+
|
| 134 |
+
sequences = [x.upper() for x in sequences]
|
| 135 |
+
|
| 136 |
+
rna_vocab = {"A":0,
|
| 137 |
+
"C":1,
|
| 138 |
+
"G":2,
|
| 139 |
+
"U":3,
|
| 140 |
+
"*":4}
|
| 141 |
+
|
| 142 |
+
rev_rna_vocab = {v:k for k,v in rna_vocab.items()}
|
| 143 |
+
|
| 144 |
+
def one_hot_encode(seq, SEQ_LEN=UTR_LEN):
|
| 145 |
+
mapping = dict(zip("ACGT*", range(5)))
|
| 146 |
+
seq2 = [mapping[i] for i in seq]
|
| 147 |
+
if len(seq2) < SEQ_LEN:
|
| 148 |
+
extra = [np.eye(5)[4]] * (SEQ_LEN - len(seq2))
|
| 149 |
+
return np.vstack([np.eye(5)[seq2] , extra])
|
| 150 |
+
return np.eye(5)[seq2]
|
| 151 |
+
|
| 152 |
+
def one_hot_encode_2(seq, SEQ_LEN=UTR_LEN):
|
| 153 |
+
mapping = dict(zip("ACGT", range(4)))
|
| 154 |
+
seq2 = [mapping[i] for i in seq]
|
| 155 |
+
return np.eye(4)[seq2]
|
| 156 |
+
|
| 157 |
+
ohe_sequences = np.asarray([one_hot_encode(x) for x in sequences])
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
BATCH_SIZE = args.bs # Batch size
|
| 161 |
+
ITERS = args.epochs # How many complete dataset iterations to train for
|
| 162 |
+
SEQ_LEN = UTR_LEN # Sequence length in characters
|
| 163 |
+
DIM = args.dim # Model dimensionality.
|
| 164 |
+
CRITIC_ITERS = 5 # How many critic iterations per generator iteration.
|
| 165 |
+
LAMBDA = 10 # Gradient penalty lambda hyperparameter.
|
| 166 |
+
# README defines ``-lr 5`` as 1e-5. The upstream ``e**args.lr`` expression
|
| 167 |
+
# is inconsistent with that documented interface.
|
| 168 |
+
LR = np.power(10.0, -args.lr)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
LAMBDA = 10 # For gradient penalty
|
| 172 |
+
|
| 173 |
+
CURRENT_EPOCH = 1 # Epoch start from
|
| 174 |
+
SAVE_EVERY_N_EPOCH = 50 # Save checkpoint at every n epoch
|
| 175 |
+
|
| 176 |
+
MIN_LR = 0.000001 # Minimum value of learning rate
|
| 177 |
+
DECAY_FACTOR=1.00004 # learning rate decay factor
|
| 178 |
+
'''
|
| 179 |
+
Set seed for reproducibility
|
| 180 |
+
'''
|
| 181 |
+
seed = 35
|
| 182 |
+
np.random.seed(seed)
|
| 183 |
+
# tf.set_random_seed(seed)
|
| 184 |
+
tf.random.set_seed(seed)
|
| 185 |
+
|
| 186 |
+
logdir, checkpoint_baseline = log(samples_dir=True)
|
| 187 |
+
logdir2 = ''
|
| 188 |
+
|
| 189 |
+
'''
|
| 190 |
+
Build GAN
|
| 191 |
+
'''
|
| 192 |
+
model_type = "resnet"
|
| 193 |
+
data_enc_dim = 5
|
| 194 |
+
data_size = SEQ_LEN * data_enc_dim
|
| 195 |
+
# data_size = 256
|
| 196 |
+
gen_layers = 3
|
| 197 |
+
disc_layers = 3
|
| 198 |
+
lmbda = 10. #lipschitz penalty hyperparameter.
|
| 199 |
+
|
| 200 |
+
SAMPLE_SIZE = 128
|
| 201 |
+
|
| 202 |
+
N_CHANNELS = DIM
|
| 203 |
+
|
| 204 |
+
G = models.resnet_g2(DIM,N_CHANNELS,SEQ_LEN,5,res_layers=gen_layers)
|
| 205 |
+
D = models.resnet_d2(N_CHANNELS,SEQ_LEN,5,res_layers=disc_layers)
|
| 206 |
+
|
| 207 |
+
G.summary()
|
| 208 |
+
D.summary()
|
| 209 |
+
|
| 210 |
+
D_optimizer = Adam(learning_rate=LR, beta_1=0.5, beta_2=0.99)
|
| 211 |
+
G_optimizer = Adam(learning_rate=LR, beta_1=0.5, beta_2=0.99)
|
| 212 |
+
|
| 213 |
+
EPOCHs = ITERS
|
| 214 |
+
|
| 215 |
+
@tf.function
|
| 216 |
+
def WGAN_GP_train_d_step(real_sample, batch_size, step):
|
| 217 |
+
|
| 218 |
+
noise = tf.random.normal([batch_size, DIM])
|
| 219 |
+
epsilon = tf.random.uniform(shape=[batch_size, 1, 1], minval=0, maxval=1)
|
| 220 |
+
###################################
|
| 221 |
+
# Train D
|
| 222 |
+
###################################
|
| 223 |
+
with tf.GradientTape(persistent=True) as d_tape:
|
| 224 |
+
with tf.GradientTape() as gp_tape:
|
| 225 |
+
fake_sample = G([noise], training=True)
|
| 226 |
+
fake_sample_mixed = epsilon * tf.dtypes.cast(real_sample, tf.float32) + ((1 - epsilon) * fake_sample)
|
| 227 |
+
fake_mixed_pred = D([fake_sample_mixed], training=True)
|
| 228 |
+
|
| 229 |
+
# Compute gradient penalty
|
| 230 |
+
grads = gp_tape.gradient(fake_mixed_pred, fake_sample_mixed)
|
| 231 |
+
grad_norms = tf.sqrt(tf.reduce_sum(tf.square(grads), axis=[1,2])) # Originally axis=[1,2]
|
| 232 |
+
# grad_norms = tf.norm(grads, axis=[1,2])
|
| 233 |
+
gradient_penalty = tf.reduce_mean(tf.square(grad_norms - 1.))
|
| 234 |
+
|
| 235 |
+
fake_pred = D([fake_sample], training=True)
|
| 236 |
+
real_pred = D([real_sample], training=True)
|
| 237 |
+
|
| 238 |
+
D_loss = tf.reduce_mean(fake_pred) - tf.reduce_mean(real_pred) + LAMBDA * gradient_penalty
|
| 239 |
+
# Calculate the gradients for discriminator
|
| 240 |
+
D_gradients = d_tape.gradient(D_loss,D.trainable_variables)
|
| 241 |
+
# Apply the gradients to the optimizer
|
| 242 |
+
D_optimizer.apply_gradients(zip(D_gradients,D.trainable_variables))
|
| 243 |
+
# Write loss values to tensorboard
|
| 244 |
+
if step % 10 == 0:
|
| 245 |
+
with file_writer.as_default():
|
| 246 |
+
tf.summary.scalar('D_loss', tf.reduce_mean(D_loss), step=step)
|
| 247 |
+
|
| 248 |
+
return D_loss, gradient_penalty
|
| 249 |
+
|
| 250 |
+
@tf.function
|
| 251 |
+
def WGAN_GP_train_g_step(real_sample, batch_size, step):
|
| 252 |
+
|
| 253 |
+
noise = tf.random.normal([batch_size, DIM])
|
| 254 |
+
###################################
|
| 255 |
+
# Train G
|
| 256 |
+
###################################
|
| 257 |
+
with tf.GradientTape() as g_tape:
|
| 258 |
+
fake_sample = G([noise], training=True)
|
| 259 |
+
fake_pred = D([fake_sample], training=True)
|
| 260 |
+
G_loss = -tf.reduce_mean(fake_pred)
|
| 261 |
+
|
| 262 |
+
G_gradients = g_tape.gradient(G_loss,
|
| 263 |
+
G.trainable_variables)
|
| 264 |
+
# Apply the gradients to the optimizer
|
| 265 |
+
G_optimizer.apply_gradients(zip(G_gradients,
|
| 266 |
+
G.trainable_variables))
|
| 267 |
+
# Write loss values to tensorboard
|
| 268 |
+
if step % 10 == 0:
|
| 269 |
+
with file_writer.as_default():
|
| 270 |
+
tf.summary.scalar('G_loss', G_loss, step=step)
|
| 271 |
+
|
| 272 |
+
return G_loss, noise
|
| 273 |
+
|
| 274 |
+
checkpoint_path = os.path.join(str(RUN_ROOT), "checkpoints", "tensorflow", MODEL_NAME)
|
| 275 |
+
|
| 276 |
+
ckpt = tf.train.Checkpoint(generator=G,
|
| 277 |
+
discriminator=D,
|
| 278 |
+
G_optimizer=G_optimizer,
|
| 279 |
+
D_optimizer=D_optimizer)
|
| 280 |
+
|
| 281 |
+
ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=40)
|
| 282 |
+
|
| 283 |
+
def generate_and_save_samples(model, epoch, test_input, figure_size=(12,6), subplot=(3,6), save=True, is_flatten=False):
|
| 284 |
+
'''
|
| 285 |
+
Generate samples and plot it.
|
| 286 |
+
'''
|
| 287 |
+
predictions = model.predict(test_input)
|
| 288 |
+
utils.save_samples(logdir, predictions, epoch, rev_rna_vocab, annotated=False)
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
'''
|
| 292 |
+
load data
|
| 293 |
+
'''
|
| 294 |
+
|
| 295 |
+
Train = True
|
| 296 |
+
validate = True
|
| 297 |
+
|
| 298 |
+
data = ohe_sequences
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
if validate:
|
| 302 |
+
split = len(data) // 10
|
| 303 |
+
# print(split)
|
| 304 |
+
valid_data = data[:split]
|
| 305 |
+
train_data = data[split:]
|
| 306 |
+
if len(train_data) == 1: train_data = train_data[0]
|
| 307 |
+
if len(valid_data) == 1: valid_data = valid_data[0]
|
| 308 |
+
else:
|
| 309 |
+
train_data = data
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
train_data = train_data.astype('float32')
|
| 313 |
+
valid_data = valid_data.astype('float32')
|
| 314 |
+
|
| 315 |
+
train_seqs = tf.data.Dataset.from_tensor_slices(train_data).shuffle(len(train_data)).batch(BATCH_SIZE)
|
| 316 |
+
valid_seqs = tf.data.Dataset.from_tensor_slices(valid_data).shuffle(len(valid_data)).batch(split)
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
plot_iter = 10
|
| 320 |
+
|
| 321 |
+
current_learning_rate = LR
|
| 322 |
+
trace = True
|
| 323 |
+
n_critic_count = 0
|
| 324 |
+
|
| 325 |
+
d_losses = []
|
| 326 |
+
g_losses = []
|
| 327 |
+
gradient_penalties = []
|
| 328 |
+
iterations = 0
|
| 329 |
+
iteration_numbers = []
|
| 330 |
+
iteration_numbers_valid = []
|
| 331 |
+
d_validation_losses = []
|
| 332 |
+
|
| 333 |
+
random_name = time.strftime("%Y%m%d-%H%M%S")
|
| 334 |
+
|
| 335 |
+
gen_iters = 0
|
| 336 |
+
|
| 337 |
+
if Train:
|
| 338 |
+
sample_noise = tf.random.normal([BATCH_SIZE, DIM])
|
| 339 |
+
generate_and_save_samples(G, 0, [sample_noise], figure_size=(12,6), subplot=(3,6), save=False, is_flatten=False)
|
| 340 |
+
|
| 341 |
+
pbar = tqdm(range(EPOCHs))
|
| 342 |
+
for epoch in pbar:
|
| 343 |
+
start = time.time()
|
| 344 |
+
|
| 345 |
+
tdataset = train_seqs.enumerate()
|
| 346 |
+
|
| 347 |
+
for step, tdata in tdataset.as_numpy_iterator():
|
| 348 |
+
current_batch_size = tdata.shape[0]
|
| 349 |
+
|
| 350 |
+
d_loss, gp = WGAN_GP_train_d_step(tdata, batch_size=tf.constant(current_batch_size, dtype=tf.int64), step=tf.constant(step, dtype=tf.int64))
|
| 351 |
+
n_critic_count += 1
|
| 352 |
+
if n_critic_count >= CRITIC_ITERS:
|
| 353 |
+
g_loss, noise = WGAN_GP_train_g_step(tdata, batch_size= tf.constant(current_batch_size, dtype=tf.int64), step=tf.constant(step, dtype=tf.int64))
|
| 354 |
+
gen_iters += 1
|
| 355 |
+
n_critic_count = 0
|
| 356 |
+
|
| 357 |
+
if step % 10 == 0:
|
| 358 |
+
print ('.', end='')
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
if epoch % SAVE_EVERY_N_EPOCH == 0 and epoch != 0:
|
| 362 |
+
ckpt_save_path = ckpt_manager.save()
|
| 363 |
+
utils.save_checkpoints(logdir,G,epoch)
|
| 364 |
+
|
| 365 |
+
if epoch % 50 == 0:
|
| 366 |
+
|
| 367 |
+
generate_and_save_samples(G, epoch, [sample_noise], figure_size=(12,6), subplot=(3,6), save=True, is_flatten=False)
|
| 368 |
+
|
| 369 |
+
os.system('clear')
|
| 370 |
+
|
| 371 |
+
iteration_numbers.append(iterations)
|
| 372 |
+
g_losses.append(-g_loss)
|
| 373 |
+
d_losses.append(-d_loss)
|
| 374 |
+
gradient_penalties.append(gp)
|
| 375 |
+
# plot(iteration_numbers, d_losses, logdir, 'discriminator_loss', xlabel="Iteration", ylabel="Discriminator Cost")
|
| 376 |
+
# plot(iteration_numbers, g_losses, logdir, 'generator_loss', xlabel="Iteration", ylabel="Generator Cost")
|
| 377 |
+
# plot(iteration_numbers, gradient_penalties, logdir, 'gradient_penalty', xlabel="Iteration", ylabel="Gradient Penalty")
|
| 378 |
+
|
| 379 |
+
iterations+=1
|
| 380 |
+
|
| 381 |
+
iteration_numbers_valid.append(iterations)
|
| 382 |
+
fake_sample_valid = G([noise], training=True)
|
| 383 |
+
fake_pred_valid = D([fake_sample_valid], training=True)
|
| 384 |
+
real_pred_valid = D([tf.convert_to_tensor(list(valid_seqs.as_numpy_iterator())[0])], training=True)
|
| 385 |
+
|
| 386 |
+
D_loss_valid = tf.reduce_mean(fake_pred_valid) - tf.reduce_mean(real_pred_valid)
|
| 387 |
+
d_validation_losses.append(-D_loss_valid)
|
| 388 |
+
|
| 389 |
+
# plot_valid(iteration_numbers_valid, d_validation_losses, iteration_numbers, d_losses, logdir, 'validation_loss', xlabel="Iteration", ylabel="D Validation Loss")
|
| 390 |
+
|
| 391 |
+
ckpt_save_path = ckpt_manager.save()
|
| 392 |
+
print ('Saving checkpoint for epoch {} at {}'.format(EPOCHs,
|
| 393 |
+
ckpt_save_path))
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
print("####################################################")
|
| 397 |
+
print(f"############### Gen Iterations : {gen_iters} #####")
|
| 398 |
+
print("####################################################")
|