Upload src/model/model.py with huggingface_hub
Browse files- src/model/model.py +128 -0
src/model/model.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
from model.mlp import MultiLayerPerceptron
|
| 5 |
+
from model.TMRB import TMRB
|
| 6 |
+
|
| 7 |
+
class Basic_Model(nn.Module):
|
| 8 |
+
def __init__(self, args):
|
| 9 |
+
super(Basic_Model, self).__init__()
|
| 10 |
+
self.device = "cuda:0" if torch.cuda.is_available() else "cpu"
|
| 11 |
+
self.dropout = args.dropout
|
| 12 |
+
self.activation = nn.GELU()
|
| 13 |
+
self.num_feat = args.emb["num_feat"]
|
| 14 |
+
self.args = args
|
| 15 |
+
self.num_layer = args.emb["num_layer"]
|
| 16 |
+
|
| 17 |
+
self.embed_dim = args.emb["adaptive_emb_dim"]
|
| 18 |
+
self.node_dim = args.emb["D^N"]
|
| 19 |
+
self.temp_dim_tid = args.emb["D^D"]
|
| 20 |
+
self.temp_dim_diw = args.emb["D^W"]
|
| 21 |
+
self.output_len = args.emb["output_len"]
|
| 22 |
+
self.tcn_dim = args.tcn["out_channel"]
|
| 23 |
+
self.is_TMRB = args.is_TMRB
|
| 24 |
+
self.is_update = args.is_update
|
| 25 |
+
self.select_k = args.select_k
|
| 26 |
+
self.TMRB_dropout = args.TMRB["dropout"]
|
| 27 |
+
|
| 28 |
+
self.node_embedding = nn.init.xavier_uniform_(
|
| 29 |
+
nn.Parameter(torch.empty(1, self.node_dim))
|
| 30 |
+
)
|
| 31 |
+
self.T_i_D_emb = nn.init.xavier_uniform_(nn.Parameter(torch.empty(288, self.temp_dim_tid)))
|
| 32 |
+
self.D_i_W_emb = nn.init.xavier_uniform_(nn.Parameter(torch.empty(7, self.temp_dim_diw)))
|
| 33 |
+
self.emb_layer_history = nn.Conv2d(in_channels=args.emb["input_dim"]*args.emb["input_len"], out_channels=self.embed_dim, kernel_size=(1, 1), bias=True)
|
| 34 |
+
self.tcn = nn.Conv1d(in_channels=args.tcn["in_channel"], out_channels=args.tcn["out_channel"], kernel_size=args.tcn["kernel_size"], \
|
| 35 |
+
dilation=args.tcn["dilation"], padding=int((args.tcn["kernel_size"]-1)*args.tcn["dilation"]/2))
|
| 36 |
+
self.hidden_dim = self.embed_dim + self.node_dim + args.TMRB["out_channel"]*self.is_TMRB +self.tcn_dim
|
| 37 |
+
self.encoder = nn.Sequential(
|
| 38 |
+
*[MultiLayerPerceptron(self.hidden_dim, self.hidden_dim) for _ in range(self.num_layer)]
|
| 39 |
+
)
|
| 40 |
+
self.projection_head = nn.Conv2d(
|
| 41 |
+
in_channels=self.hidden_dim, out_channels=self.output_len, kernel_size=(1, 1), bias=True
|
| 42 |
+
)
|
| 43 |
+
self.online_backbone = self.encoder
|
| 44 |
+
self.online_projection = self.projection_head
|
| 45 |
+
self.target_backbone = self.encoder
|
| 46 |
+
self.target_projection = self.projection_head
|
| 47 |
+
|
| 48 |
+
self.momentum = args.momentum
|
| 49 |
+
self.TMRB = TMRB(input_dim=args.TMRB["in_channel"], out_dim=args.TMRB["out_channel"],top_k = args.TMRB["top_k"],TMRB_dropout=self.TMRB_dropout,is_update=self.is_update,select_k = self.select_k).to(self.device)
|
| 50 |
+
self.hidden_states_per_year = {}
|
| 51 |
+
|
| 52 |
+
def prepare_inputs(self, history_data):
|
| 53 |
+
batch_size, in_steps, num_nodes, num_channels = history_data.shape
|
| 54 |
+
node_emb = self.node_embedding.expand(size=(num_nodes, *self.node_embedding.shape))
|
| 55 |
+
node_emb = node_emb.expand(size=(batch_size, *node_emb.shape)).transpose(1, 2)
|
| 56 |
+
|
| 57 |
+
time_in_day_feat = self.T_i_D_emb[(history_data[:, -1, :, self.num_feat] * 288).long()].to(self.device)
|
| 58 |
+
day_in_week_feat = self.D_i_W_emb[(history_data[:, -1, :, self.num_feat + 1]).long()].to(self.device)
|
| 59 |
+
|
| 60 |
+
input_data = history_data[:, :, :, :self.num_feat]
|
| 61 |
+
return input_data, time_in_day_feat, day_in_week_feat, node_emb
|
| 62 |
+
|
| 63 |
+
def forward(self, data, year):
|
| 64 |
+
current_data = data['x']
|
| 65 |
+
batch_size, in_steps, num_nodes, num_features = current_data.shape
|
| 66 |
+
input_data, time_in_day_feat, day_in_week_feat, node_emb = self.prepare_inputs(current_data)
|
| 67 |
+
|
| 68 |
+
current_data = current_data.transpose(1, 2).contiguous().view(batch_size, num_nodes, -1).transpose(1, 2).unsqueeze(-1)
|
| 69 |
+
node_emb_list = [node_emb.transpose(1, -1)]
|
| 70 |
+
emb_history = self.emb_layer_history(current_data)
|
| 71 |
+
tcn_emb = self.tcn(emb_history.squeeze(-1))
|
| 72 |
+
|
| 73 |
+
tem_emb = torch.cat([time_in_day_feat, day_in_week_feat],dim=-1)
|
| 74 |
+
combined_features = torch.cat([emb_history] + node_emb_list + [tcn_emb.unsqueeze(-1)], dim=1)
|
| 75 |
+
|
| 76 |
+
if self.is_TMRB:
|
| 77 |
+
hidden_state = self.TMRB(tem_emb, year,self.hidden_states_per_year)
|
| 78 |
+
self.hidden_states_per_year[year] = hidden_state.mean(dim=(0,2))
|
| 79 |
+
combined_features = torch.cat((combined_features,hidden_state.unsqueeze(-1)), dim=1)
|
| 80 |
+
|
| 81 |
+
online_features = self.online_backbone(combined_features)
|
| 82 |
+
online_proj = self.online_projection(online_features)
|
| 83 |
+
return online_proj
|
| 84 |
+
|
| 85 |
+
def update_target_network(self):
|
| 86 |
+
with torch.no_grad():
|
| 87 |
+
for param_o, param_t in zip(self.online_backbone.parameters(), self.target_backbone.parameters()):
|
| 88 |
+
param_t.data = param_t.data * self.momentum + param_o.data * (1. - self.momentum)
|
| 89 |
+
for param_o, param_t in zip(self.online_projection.parameters(), self.target_projection.parameters()):
|
| 90 |
+
param_t.data = param_t.data * self.momentum + param_o.data * (1. - self.momentum)
|
| 91 |
+
|
| 92 |
+
def calculate_similarity(self, online_proj, target_proj):
|
| 93 |
+
batch_size, time_steps, num_nodes, feature_dim = online_proj.shape
|
| 94 |
+
online_proj = online_proj.view(-1, feature_dim)
|
| 95 |
+
target_proj = target_proj.view(-1, feature_dim)
|
| 96 |
+
similarity = F.cosine_similarity(online_proj, target_proj)
|
| 97 |
+
similarity = similarity.view(batch_size, time_steps, num_nodes)
|
| 98 |
+
|
| 99 |
+
top_k_values, top_k_indices = torch.topk(similarity, self.top_k, dim=-1)
|
| 100 |
+
return top_k_indices
|
| 101 |
+
|
| 102 |
+
def target_branch(self, data, year):
|
| 103 |
+
history_data = data['x'].to(self.device)
|
| 104 |
+
batch_size, in_steps, num_nodes, num_features = history_data.shape
|
| 105 |
+
input_data, time_in_day_feat, day_in_week_feat, node_emb = self.prepare_inputs(history_data)
|
| 106 |
+
target_aug = history_data
|
| 107 |
+
target_aug = target_aug.transpose(1, 2).contiguous().view(batch_size, num_nodes, -1).transpose(1, 2).unsqueeze(-1)
|
| 108 |
+
|
| 109 |
+
node_emb_list = [node_emb.transpose(1, -1)]
|
| 110 |
+
emb_target = self.emb_layer_history(target_aug)
|
| 111 |
+
tcn_emb = self.tcn(emb_target.squeeze(-1)).unsqueeze(-1)
|
| 112 |
+
|
| 113 |
+
tem_emb = torch.cat([time_in_day_feat, day_in_week_feat],dim=-1)
|
| 114 |
+
combined_features = torch.cat([emb_target] + node_emb_list + [tcn_emb], dim=1)
|
| 115 |
+
|
| 116 |
+
if self.is_TMRB:
|
| 117 |
+
hidden_state = self.TMRB(tem_emb, year,self.hidden_states_per_year)
|
| 118 |
+
self.hidden_states_per_year[year] = hidden_state.mean(dim=(0,2))
|
| 119 |
+
combined_features = torch.cat((combined_features,hidden_state.unsqueeze(-1)), dim=1)
|
| 120 |
+
|
| 121 |
+
target_features = self.target_backbone(combined_features)
|
| 122 |
+
target_proj = self.target_projection(target_features)
|
| 123 |
+
|
| 124 |
+
return target_proj
|
| 125 |
+
|
| 126 |
+
def contrastive_loss(self, online_proj, target_proj):
|
| 127 |
+
top_k_indices = self.calculate_similarity(online_proj, target_proj)
|
| 128 |
+
return top_k_indices
|