├── L2MM_TKDD_ (1).pdf ├── README.md ├── mapmatching ├── begin.py ├── data_util.py ├── evaluate.py ├── init_latent.py ├── model.py ├── train.py ├── train_with_bucket.py ├── trajectory_dataset.py └── util.py └── sparse2dense ├── begin.py ├── data_util.py ├── evaluate.py ├── model.py ├── train.py ├── train_with_bucket.py ├── trajectory_dataset.py └── util.py /L2MM_TKDD_ (1).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiangLinLi/L2MM/f816ce241ca3abb288f11db8862b039016b840f8/L2MM_TKDD_ (1).pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description of L2MM 2 | source_code for L2MM (implement of L2MM model). 3 | 4 | 5 | --L2MM: Learning to Map Matching with Deep Models for Low-Quality GPS Trajectory Data 6 | 7 | # Environment 8 | pytorch 9 | 10 | python 3.5 11 | 12 | # Usage 13 | To run L2MM, run the following commands: 14 | 15 | python begin.py 16 | 17 | # Datasets 18 | We use two different datasets as follows. 19 | 20 | Porto: https://www.kaggle.com/c/pkdd-15-taxi-trip-time-prediction-ii 21 | 22 | CQ: a private dataset 23 | 24 | 25 | For each dataset, we employ HMM to ocquire its ground truth. 26 | 27 | 28 | 29 | 30 | Any comments and feedback are appreciated. 31 | -------------------------------------------------------------------------------- /mapmatching/begin.py: -------------------------------------------------------------------------------- 1 | #参数设置 2 | from train import train 3 | from train_with_bucket import train_bucket 4 | 5 | class Args(): 6 | def __init__(self): 7 | self.checkpoint = "trajectory2path.pt" 8 | self.num_layers = 2 #GRU layers 9 | self.de_layer = 1 10 | self.hidden_size = 256 #Hidden state size in GRUs 11 | self.embedding_size = 256 #Cell embedding size 12 | self.print = 50 #Print for x iters 13 | self.dropout = 0.1 #Dropout 14 | self.learning_rate = 0.001 15 | self.epochs = 10 #The number of training epochs 16 | self.save = 500 #Save frequency 17 | self.criterion_name = "CE" 18 | self.max_num_line =1000000 19 | self.bidirectional =True #True for bidirectional rnn in encoder 20 | self.max_length = 300 #The maximum length of the target sequence 21 | self.batch = 128 22 | self.bucketsize = [(50,50),(100,100),(200,200),(300,300),(400,400),(500,500),(600,600)] 23 | self.input_cell_size = 2245 24 | self.output_road_size = 6914 25 | self.mode = 1 26 | self.cuda = True 27 | self.min_lat = 29.59 28 | self.max_lat = 29.62 29 | self.min_lon = 106.47 30 | self.max_lon = 106.55 31 | self.width = 8900 32 | self.height = 3336 33 | self.patience = 10 34 | self.cluster_siz = 10 35 | 36 | 37 | args = Args() 38 | 39 | if args.mode == 1: 40 | print('train_with_bucket') 41 | train_bucket(args) 42 | else: 43 | print('train') 44 | train(args) 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /mapmatching/data_util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from torch.autograd import Variable 4 | #from funcy import merge 5 | def merge(seq): 6 | length = len(seq) 7 | print(length) 8 | res=[] 9 | for i in range(0,length): 10 | if(seq[i]): 11 | #print(i) 12 | #print(seq[i]) 13 | for j in range(0,len(seq[i])): 14 | res.append(seq[i][j]) 15 | res = np.array(res).squeeze() 16 | #print('shape',res.shape) 17 | return res 18 | 19 | def argsort(seq): 20 | return [x for x,y in sorted(enumerate(seq), 21 | key = lambda x: len(x[1]), 22 | reverse=True)] 23 | 24 | def pad_array(a, max_length, PAD=0): 25 | return np.concatenate((a, [PAD]*(max_length - len(a)))) 26 | 27 | def pad_arrays(a): 28 | max_length = max(map(len, a)) 29 | a = [pad_array(a[i], max_length) for i in range(len(a))] 30 | #print(a) 31 | #print('---'+str(max_length)) 32 | a = np.stack(a).astype(np.int) 33 | return torch.LongTensor(a) 34 | 35 | def pad_arrays_pair(src, trg): 36 | assert len(src) == len(trg), "source and target should have the same length" 37 | idx = argsort(src) 38 | src = list(np.array(src)[idx]) 39 | trg = list(np.array(trg)[idx]) 40 | lengths = list(map(len, src)) 41 | lengths = torch.LongTensor(lengths) 42 | src = pad_arrays(src) 43 | trg = pad_arrays(trg) 44 | return src.t().contiguous(), lengths.view(1, -1), trg.t().contiguous() 45 | 46 | def invpermute(p): 47 | p = np.asarray(p) 48 | invp = np.empty_like(p) 49 | for i in range(p.size): 50 | invp[p[i]] = i 51 | return invp 52 | 53 | def pad_arrays_keep_invp(src): 54 | idx = argsort(src) 55 | src = list(np.array(src)[idx]) 56 | lengths = list(map(len, src)) 57 | lengths = torch.LongTensor(lengths) 58 | src = pad_arrays(src) 59 | invp = torch.LongTensor(invpermute(idx)) 60 | return src.t().contiguous(), lengths.view(1, -1), invp 61 | 62 | 63 | class DataLoader(): 64 | def __init__(self, srcfile, trgfile, batch, bucketsize, validate=False): 65 | self.srcfile = srcfile 66 | self.trgfile = trgfile 67 | self.batch = batch 68 | self.validate = validate 69 | self.bucketsize = bucketsize 70 | 71 | def insert(self, s, t): 72 | for i in range(len(self.bucketsize)): #根据轨迹序列长度和对应的目标长度划分数据为多组 73 | if len(s) <= self.bucketsize[i][0] and len(t) <= self.bucketsize[i][1]: 74 | self.srcdata[i].append(np.array(s, dtype=np.int64)) 75 | #print(max(map(len, self.srcdata[i]))) 76 | self.trgdata[i].append(np.array(t, dtype=np.int64)) 77 | return 1 78 | return 0 79 | 80 | def load(self, max_num_line=0): 81 | self.srcdata = [[] for _ in range(len(self.bucketsize))] 82 | self.trgdata = [[] for _ in range(len(self.bucketsize))] 83 | srcstream, trgstream = open(self.srcfile, 'r'), open(self.trgfile, 'r') 84 | num_line = 0 85 | for (s, t) in zip(srcstream, trgstream): 86 | s = [int(x) for x in s.split()] 87 | t = [1] + [int(x) for x in t.split()] + [2] 88 | num_line += self.insert(s, t) 89 | 90 | if num_line >= max_num_line and max_num_line > 0: break 91 | if num_line % 100000 == 0: 92 | print("Read line {}".format(num_line)) 93 | 94 | if self.validate == False: 95 | self.srcdata = list(map(np.array, self.srcdata)) 96 | self.trgdata = list(map(np.array, self.trgdata)) 97 | self.allocation = list(map(len, self.srcdata)) 98 | self.p = np.array(self.allocation) / sum(self.allocation) 99 | else: 100 | print('validate1') 101 | self.srcdata = np.array(merge(self.srcdata)) #将各个桶下的数据进行合并 102 | self.trgdata = np.array(merge(self.trgdata)) 103 | self.start = 0 104 | self.size = len(self.srcdata) 105 | 106 | srcstream.close(), trgstream.close() 107 | 108 | def getbatch(self): 109 | if self.validate == True: 110 | src = self.srcdata[self.start:self.start+self.batch] 111 | trg = self.trgdata[self.start:self.start+self.batch] 112 | self.start += self.batch 113 | if self.start >= self.size: 114 | self.start = 0 115 | src, len, trg = pad_arrays_pair(src, trg) 116 | batch_mask = np.zeros((trg.shape[0], trg.shape[1]),dtype=float) 117 | for row in range(trg.shape[0]): 118 | for col in range(trg.shape[1]): 119 | if trg[row][col] != 0: 120 | batch_mask[row][col] = 1.0 121 | batch_mask = torch.FloatTensor(batch_mask) 122 | return src,len,trg,batch_mask 123 | else: 124 | sample = np.random.multinomial(1, self.p) 125 | #print('sample:'+str(sample)) 126 | bucket = np.nonzero(sample)[0][0] 127 | #print('bucket:'+str(bucket)) 128 | idx = np.random.choice(self.srcdata[bucket].shape[0], self.batch) 129 | src,len,trg = pad_arrays_pair(self.srcdata[bucket][idx], 130 | self.trgdata[bucket][idx]) 131 | return src, len, trg 132 | 133 | 134 | class DataOrderScaner(): 135 | def __init__(self, srcfile, batch): 136 | self.srcfile = srcfile 137 | self.batch = batch 138 | self.srcdata = [] 139 | self.start = 0 140 | def load(self, max_num_line=0): 141 | num_line = 0 142 | with open(self.srcfile, 'r') as srcstream: 143 | for s in srcstream: 144 | s = [int(x) for x in s.split()] 145 | self.srcdata.append(np.array(s, dtype=np.int32)) 146 | num_line += 1 147 | if max_num_line > 0 and num_line >= max_num_line: 148 | break 149 | self.size = len(self.srcdata) 150 | self.start = 0 151 | def getbatch(self): 152 | if self.start >= self.size: 153 | return None, None, None 154 | src = self.srcdata[self.start:self.start+self.batch] 155 | self.start += self.batch 156 | return pad_arrays_keep_invp(src) 157 | -------------------------------------------------------------------------------- /mapmatching/evaluate.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | from model import EncoderDecoder 5 | import os 6 | import time 7 | 8 | 9 | def evaluate(src, model, max_length): 10 | m0, m1 = model 11 | length = len(src) 12 | src = Variable(torch.LongTensor(src)) 13 | length = Variable(torch.LongTensor([[length]])) 14 | en_hn, H = m0.encoder(src, length) 15 | de_h0 = m0.encoder_hn2decoder_h0(en_hn) 16 | h = de_h0[-1].unsqueeze(0) 17 | input_ = Variable(torch.LongTensor([[1]])) 18 | tg = [] 19 | for _ in range(max_length): 20 | o, h = m0.decoder(input_, h, H) 21 | o = o.view(-1, o.size(2)) 22 | o = m1(o) 23 | _, id = o.data.topk(1) 24 | id = id[0][0] 25 | if id == 2: 26 | break 27 | tg.append(id.item()) 28 | input_ = Variable(torch.LongTensor([[id]])) 29 | return tg 30 | 31 | 32 | def evaluator(test_dataset, args, filename="trajectory2path.pt"): 33 | m0 = EncoderDecoder( 34 | args.input_cell_size, 35 | args.output_cell_size, 36 | args.embedding_size, 37 | args.hidden_size, 38 | args.num_layers, 39 | args.de_layer, 40 | args.dropout, 41 | args.bidirectional 42 | ) 43 | 44 | m1 = nn.Sequential( 45 | nn.Linear(args.hidden_size, args.output_cell_size), 46 | nn.LogSoftmax() 47 | ) 48 | 49 | if os.path.isfile(filename): 50 | print("loading checkpoint '{}'".format(filename)) 51 | checkpoint = torch.load(filename) 52 | m0.load_state_dict(checkpoint["m0"]) 53 | m1.load_state_dict(checkpoint["m1"]) 54 | test_len = test_dataset.__len__() 55 | count = 0 56 | p = 0 57 | r = 0 58 | t = 0 59 | for i in range(test_len): 60 | x, y = test_dataset.__getitem__(i) 61 | y_pred = evaluate(x, (m0, m1), args.max_length) 62 | start = time.time() 63 | end = time.time() 64 | t = t + end-start 65 | if len(y) >0: 66 | print('target', y) 67 | print('model_prediction', y_pred) 68 | 69 | intersect = set(y_pred) & set(y) 70 | p = p + len(intersect) / max(len(y_pred), len(y)) 71 | r = r + len(intersect) / len(y_pred) 72 | 73 | count = count + 1 74 | 75 | print("t {}".format(t / count)) 76 | print("p {}".format(p / count)) 77 | print("r {}".format(r / count)) 78 | else: 79 | print("no checkpoint found at {}".format(filename)) -------------------------------------------------------------------------------- /mapmatching/init_latent.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | from torch.nn.utils import clip_grad_norm 5 | from model import EncoderDecoder 6 | from data_util import DataLoader 7 | import time, os, shutil, logging 8 | import numpy as np 9 | from sklearn.cluster import KMeans 10 | device = torch.device("cuda:0") 11 | 12 | 13 | def batchloss(output, target, generator, lossF, g_batch): 14 | batch = output.size(1) 15 | loss = 0 16 | target = target[1:] 17 | for o, t in zip(output.split(g_batch), 18 | target.split(g_batch)): 19 | o = o.view(-1, o.size(2)) 20 | o = generator(o) 21 | t = t.view(-1) 22 | loss += lossF(o, t) 23 | return loss.div(batch/g_batch) 24 | 25 | 26 | def savecheckpoint(state, filename="pretrain_latent.pt"): 27 | torch.save(state, filename) 28 | 29 | def save_mu_c(args, m0, filename="pretrain_latent.pt"): 30 | test_src = ".\data\Freq90_cell_data_porto_train.txt" 31 | test_trg = ".\data\Freq15_path_data_porto_train.txt" 32 | trainData = DataLoader(test_src, test_trg, args.batch, args.bucketsize) 33 | print("Read training data") 34 | trainData.load(10000) 35 | num_iteration = sum(trainData.allocation) // args.batch 36 | 37 | with torch.no_grad(): 38 | x_embedded = [] 39 | for iteration in range(num_iteration): 40 | input, lengths, target = trainData.getbatch() 41 | input, lengths, target = Variable(input), Variable(lengths), Variable(target) 42 | if args.cuda and torch.cuda.is_available(): 43 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 44 | 45 | z = m0(input, lengths, target, 'test') 46 | 47 | z = z.unsqueeze(0) 48 | x_embedded.append(z) 49 | 50 | x_embedded = torch.cat(x_embedded, dim=0) 51 | x_embedded = torch.reshape(x_embedded,(-1,args.hidden_size)) 52 | x_embedded = x_embedded.cpu().numpy() 53 | kmeans = KMeans(n_clusters=args.cluster_size) 54 | kmeans.fit(x_embedded) 55 | init_mu_c = kmeans.cluster_centers_ 56 | savecheckpoint({ 57 | "init_mu_c": init_mu_c 58 | }, filename="init_latent.pt") 59 | 60 | 61 | def pretrain_bucket(args): 62 | trainsrc = '.\data\Freq90_cell_data_porto_train.txt' 63 | traintrg = '.\data\Freq15_path_data_porto_train.txt' 64 | 65 | trainData = DataLoader(trainsrc, traintrg, args.batch, args.bucketsize) 66 | print("Read training data") 67 | trainData.load(10000) 68 | 69 | if args.criterion_name == "CE": 70 | criterion = nn.CrossEntropyLoss(ignore_index=0).to(device) 71 | lossF = lambda o, t: criterion(o, t) 72 | else: 73 | criterion = nn.NLLLoss(ignore_index=0).to(device) 74 | lossF = lambda o, t: criterion(o, t) 75 | 76 | m0 = EncoderDecoder(args.cluster_size, 77 | args.input_cell_size, 78 | args.output_road_size, 79 | args.embedding_size, 80 | args.hidden_size, 81 | args.num_layers, 82 | args.de_layer, 83 | args.dropout, 84 | args.bidirectional) 85 | 86 | m1 = nn.Sequential(nn.Linear(args.hidden_size, args.output_road_size), 87 | nn.LogSoftmax()) 88 | 89 | if args.cuda and torch.cuda.is_available(): 90 | print("=> training with GPU") 91 | m0.to(device) 92 | m1.to(device) 93 | criterion.to(device) 94 | else: 95 | print("=> training with CPU") 96 | 97 | m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate) 98 | m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate) 99 | best_prec_loss = float('inf') 100 | start_iteration = 0 101 | num_iteration = args.epochs * sum(trainData.allocation) // args.batch 102 | print("Start at {} " 103 | "and end at {}".format(start_iteration, num_iteration-1)) 104 | 105 | early_stop = False 106 | early_count = 0 107 | 108 | for iteration in range(start_iteration, num_iteration): 109 | if early_stop: 110 | break 111 | input, lengths, target = trainData.getbatch() 112 | 113 | input, lengths, target = Variable(input), Variable(lengths), Variable(target) 114 | 115 | if args.cuda and torch.cuda.is_available(): 116 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 117 | 118 | m0_optimizer.zero_grad() 119 | m1_optimizer.zero_grad() 120 | 121 | output = m0(input, lengths, target, kind="pretrain") 122 | loss = batchloss(output, target, m1, lossF, 2) 123 | loss.backward() 124 | clip_grad_norm(m0.parameters(), 5) 125 | clip_grad_norm(m1.parameters(), 5) 126 | m0_optimizer.step() 127 | m1_optimizer.step() 128 | avg_loss = loss.item() / target.size(0) 129 | if iteration % args.print == 0: 130 | print("Iteration: {}\tLoss: {}".format(iteration, avg_loss)) 131 | 132 | if iteration % args.save == 0 and iteration > 0: 133 | if avg_loss < best_prec_loss: 134 | best_prec_loss = avg_loss 135 | early_count = 0 136 | savecheckpoint({ 137 | "iteration": iteration, 138 | "m0": m0.state_dict(), 139 | "m1": m1.state_dict(), 140 | "m0_optimizer": m0_optimizer.state_dict(), 141 | "m1_optimizer": m1_optimizer.state_dict() 142 | }) 143 | else: 144 | early_count += 1 145 | if early_count < args.patience: 146 | early_stop = True 147 | print('Early stopped') 148 | else: 149 | print("Early stopping {} / {}".format(early_count, args.patience)) 150 | print("init_latent") 151 | checkpoint = torch.load("pretrain_latent.pt") 152 | m0.load_state_dict(checkpoint["m0"]) 153 | save_mu_c(args, m0) 154 | -------------------------------------------------------------------------------- /mapmatching/model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.nn.utils.rnn import pad_packed_sequence 4 | from torch.nn.utils.rnn import pack_padded_sequence 5 | import os 6 | import torch.nn.functional as F 7 | 8 | 9 | class Encoder(nn.Module): 10 | def __init__(self, input_size, hidden_size, num_layers, dropout, 11 | bidirectional, embedding): 12 | super(Encoder, self).__init__() 13 | self.num_directions = 2 if bidirectional else 1 14 | assert hidden_size % self.num_directions == 0 15 | self.hidden_size = hidden_size // self.num_directions 16 | self.num_layers = num_layers 17 | 18 | self.embedding = embedding 19 | self.rnn = nn.GRU(input_size, self.hidden_size, 20 | num_layers=num_layers, 21 | bidirectional=bidirectional, 22 | dropout=dropout) 23 | 24 | def forward(self, input, lengths, h0=None): 25 | embed = self.embedding(input) 26 | lengths = lengths.data.view(-1).tolist() 27 | if lengths is not None: 28 | embed = pack_padded_sequence(embed, lengths) 29 | output, hn = self.rnn(embed, h0) 30 | if lengths is not None: 31 | output = pad_packed_sequence(output)[0] 32 | return hn, output 33 | 34 | 35 | class LatentDistribution(nn.Module): 36 | def __init__(self, cluster_size, hidden_size, path="init_latent.pt"): 37 | super(LatentDistribution, self).__init__() 38 | self.cluter_size = cluster_size 39 | self.hidden_size = hidden_size 40 | if os.path.isfile(path): 41 | mu_c = torch.load(path)["init_mu_c"] 42 | mu_c = torch.from_numpy(mu_c) 43 | if torch.cuda.is_available(): 44 | mu_c = mu_c.to("cuda") 45 | self.mu_c = nn.Parameter(mu_c, requires_grad=True) 46 | 47 | else: 48 | mu_c = torch.rand(cluster_size, hidden_size) 49 | self.mu_c = nn.Parameter(mu_c, requires_grad=True) 50 | 51 | log_sigma_sq_c = torch.zeros(cluster_size, hidden_size) 52 | if torch.cuda.is_available(): 53 | log_sigma_sq_c = log_sigma_sq_c.to("cuda") 54 | self.log_sigma_sq_c = nn.Parameter(log_sigma_sq_c, requires_grad=True) 55 | 56 | self.cal_mu_z = nn.Linear(hidden_size, hidden_size) 57 | nn.init.normal_(self.cal_mu_z.weight, std=0.02) 58 | nn.init.constant_(self.cal_mu_z.bias, 0.0) 59 | 60 | self.cal_log_sigma_z = nn.Linear(hidden_size, hidden_size) 61 | nn.init.normal_(self.cal_log_sigma_z.weight, std=0.02) 62 | nn.init.constant_(self.cal_log_sigma_z.bias, 0.0) 63 | 64 | def batch_laten_loss(self, stack_log_sigma_sq_c, stack_mu_c, stack_log_sigma_sq_z, stack_mu_z, att, log_sigma_sq_z): 65 | avg_ = torch.mean(stack_log_sigma_sq_c 66 | + torch.exp(stack_log_sigma_sq_z) / torch.exp(stack_log_sigma_sq_c) 67 | + torch.pow(stack_mu_z - stack_mu_c, 2) / torch.exp(stack_log_sigma_sq_c), dim=-1) 68 | 69 | sum_ = torch.sum(att * avg_, dim=-1).squeeze() 70 | 71 | mean_ = torch.mean(1 + log_sigma_sq_z, dim=-1).squeeze() 72 | 73 | batch_latent_loss = 0.5 * sum_ - 0.5 * mean_ 74 | batch_latent_loss = torch.mean(batch_latent_loss).squeeze() 75 | 76 | cate_mean = torch.mean(att, dim=0).squeeze() 77 | batch_cate_loss = torch.mean(cate_mean * torch.log(cate_mean)).squeeze() 78 | batch_cate_loss = torch.mean(batch_cate_loss).squeeze() 79 | 80 | return batch_latent_loss, batch_cate_loss 81 | 82 | def forward(self, h, kind="train"): 83 | h = h.squeeze() 84 | mu_z = self.cal_mu_z(h) 85 | if kind == "test": 86 | return mu_z 87 | log_sigma_sq_z = self.cal_log_sigma_z(h) 88 | eps_z = torch.rand(size=log_sigma_sq_z.shape) 89 | if kind == "pretrain" or kind=="train": 90 | if torch.cuda.is_available(): 91 | eps_z = eps_z.to("cuda") 92 | 93 | z = mu_z + torch.sqrt(torch.exp(log_sigma_sq_z)) * eps_z 94 | 95 | if kind == "pretrain": 96 | return z 97 | else: 98 | stack_mu_c = torch.stack([self.mu_c] * z.shape[0], dim=0) 99 | stack_log_sigma_sq_c = torch.stack([self.log_sigma_sq_c] * z.shape[0], dim=0) 100 | stack_mu_z = torch.stack([mu_z] * self.cluter_size, dim=1) 101 | stack_log_sigma_sq_z = torch.stack([log_sigma_sq_z] * self.cluter_size, dim=1) 102 | stack_z = torch.stack([z] * self.cluter_size, dim=1) 103 | att_logits = - torch.sum(torch.pow(stack_z - stack_mu_c, 2) / torch.exp(stack_log_sigma_sq_c), dim=-1) 104 | att_logits = att_logits.squeeze() 105 | att = F.softmax(att_logits)+ 1e-10 106 | 107 | batch_latent_loss, batch_cate_loss = self.batch_laten_loss(stack_log_sigma_sq_c, stack_mu_c, stack_log_sigma_sq_z, stack_mu_z, att, 108 | log_sigma_sq_z) 109 | return z, batch_latent_loss, batch_cate_loss 110 | 111 | 112 | class GlobalAttention(nn.Module): 113 | def __init__(self, hidden_size): 114 | super(GlobalAttention, self).__init__() 115 | self.L1 = nn.Linear(hidden_size, hidden_size, bias=False) 116 | self.L2 = nn.Linear(2*hidden_size, hidden_size, bias=False) 117 | self.softmax = nn.Softmax() 118 | self.tanh = nn.Tanh() 119 | 120 | def forward(self, q, H): 121 | q1 = q.unsqueeze(2) 122 | a = torch.bmm(H, q1).squeeze(2) 123 | a = self.softmax(a) 124 | a = a.unsqueeze(1) 125 | c = torch.bmm(a, H).squeeze(1) 126 | c = torch.cat([c, q], 1) 127 | return self.tanh(self.L2(c)) 128 | 129 | 130 | class Decoder(nn.Module): 131 | def __init__(self, input_size, hidden_size, num_layers, dropout, embedding): 132 | super(Decoder, self).__init__() 133 | self.embedding = embedding 134 | self.rnn = StackingGRUCell(input_size, hidden_size, num_layers, 135 | dropout) 136 | self.attention = GlobalAttention(hidden_size) 137 | self.dropout = nn.Dropout(dropout) 138 | self.num_layers = num_layers 139 | 140 | def forward(self, input, h, H, use_attention=True): 141 | assert input.dim() == 2, "The input should be of (seq_len, batch)" 142 | embed = self.embedding(input) 143 | output = [] 144 | for e in embed.split(1): 145 | e = e.squeeze(0) 146 | o, h = self.rnn(e, h) 147 | if use_attention: 148 | o = self.attention(o, H.transpose(0, 1)) 149 | o = self.dropout(o) 150 | output.append(o) 151 | output = torch.stack(output) 152 | return output, h 153 | 154 | 155 | class EncoderDecoder(nn.Module): 156 | def __init__(self, cluster_size, input_vocab_size, output_vocab_size, embedding_size, 157 | hidden_size, num_layers, de_layer, dropout, bidirectional, is_pretrain=True): 158 | super(EncoderDecoder, self).__init__() 159 | self.input_vocab_size = input_vocab_size 160 | self.output_vocab_size = output_vocab_size 161 | self.embedding_size = embedding_size 162 | self.embedding1 = nn.Embedding(input_vocab_size, embedding_size, padding_idx=0) 163 | self.embedding2 = nn.Embedding(output_vocab_size, embedding_size, padding_idx=0) 164 | self.encoder = Encoder(embedding_size, hidden_size, num_layers, 165 | dropout, bidirectional, self.embedding1) 166 | if is_pretrain: 167 | filename = "sparse2dense.pt" 168 | if os.path.isfile(filename): 169 | checkpoint = torch.load(filename) 170 | self.encoder.load_state_dict(checkpoint["encoder_m0"]) 171 | self.decoder = Decoder(embedding_size, hidden_size, de_layer, 172 | dropout, self.embedding2) 173 | self.latent = LatentDistribution(cluster_size, hidden_size) 174 | self.num_layers = num_layers 175 | 176 | def encoder_hn2decoder_h0(self, h): 177 | if self.encoder.num_directions == 2: 178 | num_layers, batch, hidden_size = h.size(0)//2, h.size(1), h.size(2) 179 | return h.view(num_layers, 2, batch, hidden_size)\ 180 | .transpose(1, 2).contiguous()\ 181 | .view(num_layers, batch, hidden_size * 2) 182 | else: 183 | return h 184 | 185 | def forward(self, src, lengths, trg, kind="train"): 186 | encoder_hn, H = self.encoder(src, lengths) 187 | decoder_h0 = self.encoder_hn2decoder_h0(encoder_hn) 188 | if kind == "train": 189 | z, batch_latent_loss, batch_cate_loss = self.latent(decoder_h0[-1].unsqueeze(0)) 190 | z = z.unsqueeze(0) 191 | output, de_hn = self.decoder(trg[:-1], z, H) 192 | return output, batch_latent_loss, batch_cate_loss 193 | elif kind == "pretrain": 194 | z = self.latent(decoder_h0[-1].unsqueeze(0), kind) 195 | z = z.unsqueeze(0) 196 | output, de_hn = self.decoder(trg[:-1], z, H) 197 | return output 198 | elif kind == 'test': 199 | z = self.latent(decoder_h0[-1].unsqueeze(0), kind) 200 | return z 201 | 202 | 203 | class StackingGRUCell(nn.Module): 204 | def __init__(self, input_size, hidden_size, num_layers, dropout): 205 | super(StackingGRUCell, self).__init__() 206 | self.num_layers = num_layers 207 | self.grus = nn.ModuleList() 208 | self.dropout = nn.Dropout(dropout) 209 | 210 | self.grus.append(nn.GRUCell(input_size, hidden_size)) 211 | for i in range(1, num_layers): 212 | self.grus.append(nn.GRUCell(hidden_size, hidden_size)) 213 | 214 | def forward(self, input, h0): 215 | hn = [] 216 | output = input 217 | for i, gru in enumerate(self.grus): 218 | hn_i = gru(output, h0[i]) 219 | hn.append(hn_i) 220 | if i != self.num_layers - 1: 221 | output = self.dropout(hn_i) 222 | else: 223 | output = hn_i 224 | hn = torch.stack(hn) 225 | return output, hn 226 | 227 | -------------------------------------------------------------------------------- /mapmatching/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.nn.utils import clip_grad_norm 4 | from model import EncoderDecoder 5 | import time, os, shutil, logging 6 | import numpy as np 7 | import json 8 | from torch.utils.data import DataLoader 9 | from trajectory_dataset import Trajectory, collate_fn, convert_tensor 10 | from util import DenseLoss 11 | from evaluate import evaluator 12 | 13 | def links2ids(file): 14 | # include all the road 15 | link2id = {} 16 | link_id = 0 17 | with open(file) as f: 18 | for line in f: 19 | data = json.loads(line) 20 | link = data['link_id'] 21 | if link not in link2id: 22 | link_id +=1 23 | link2id[link] = link_id 24 | return link2id, link_id 25 | 26 | # link2id = {} 27 | # link_id = 3 28 | # with open(file) as f: 29 | # for line in f: 30 | # data = json.loads(line) 31 | # path = data['links'] 32 | # for l in path: 33 | # if l not in link2id: 34 | # link2id[l] = link_id 35 | # link_id +=1 36 | # return link2id, link_id 37 | 38 | 39 | def get_grids(min_lat, min_lon, max_lat, max_lon, height, width, grid_size=100): 40 | x_size = int(width/grid_size) 41 | y_size = int(height/grid_size) 42 | lon_vec = np.linspace(min_lon, max_lon, x_size) 43 | lat_vec = np.linspace(min_lat, max_lat, y_size) 44 | return lon_vec, lat_vec 45 | 46 | 47 | def point2grid(lon, lat, lon_vec, lat_vec): 48 | lon_i = len(lon_vec[lon_vec < lon]) 49 | lat_i = len(lat_vec[lat_vec < lat]) 50 | if lon_i == 0 or lat_i == 0 or lon_i == len(lon_vec) or lat_i == len(lat_vec): 51 | return -1 52 | else: 53 | return (lat_i - 1)*(len(lon_vec)-1)+lon_i 54 | 55 | 56 | def data_prepare(file, lat_vec, lon_vec, link2id): 57 | res = [] 58 | with open(file) as f: 59 | for line in f: 60 | data = json.loads(line) 61 | points = data['locs'] 62 | if len(points) > 1000: 63 | continue 64 | grids = [] 65 | flag = 1 66 | index = point2grid(points[0][0], points[0][1], lon_vec, lat_vec) 67 | if index == -1: 68 | flag = 0 69 | else: 70 | grids.append(index) 71 | pre_lon, pre_lat = points[0][0], points[0][1] 72 | pre_index = index 73 | for i in range(1, len(points)): 74 | cur_lon, cur_lat = points[i][0], points[i][1] 75 | index = point2grid(cur_lon, cur_lat, lon_vec, lat_vec) 76 | if index == -1: 77 | flag = 0 78 | else: 79 | if pre_index != index: 80 | grids.append(index) 81 | pre_index = index 82 | if flag: 83 | links = data['links'] 84 | ids = [] 85 | for x in links: 86 | ids.append(link2id[x]) 87 | 88 | res.append([grids,ids]) 89 | return res 90 | 91 | 92 | def get_data_loaders(mydataset, batch_size): 93 | loader = DataLoader(mydataset, 94 | batch_size= batch_size, 95 | collate_fn=collate_fn, 96 | shuffle=False) 97 | loader._dataset_kind = None 98 | return loader 99 | 100 | 101 | def savecheckpoint(state, file_name='sparse2dense.pt'): 102 | torch.save(state, file_name) 103 | 104 | 105 | def validate(valData, model, loss_f, args): 106 | m0, m1 = model 107 | m0.eval() 108 | m1.eval() 109 | t_loss = 0 110 | with torch.no_grad(): 111 | for x, y in valData: 112 | if args.cuda and torch.cuda.is_available(): 113 | x, y = (convert_tensor(x, device="cuda"), convert_tensor(y, device="cuda")) 114 | input, lengths = x 115 | input = torch.transpose(input, 0, 1) 116 | target, mask = torch.transpose(0, 1) 117 | mask = torch.transpose(mask, 0, 1) 118 | output, batch_gaussian_loss, batch_cate_loss = m0(input, lengths, target) 119 | output = m1(output) 120 | loss = loss_f(output, (target, mask)).item()/lengths.size(0) 121 | if args.cluater_size == 1: 122 | loss = loss + batch_gaussian_loss.item() 123 | else: 124 | loss = loss + 1.0/args.hidden_size * batch_gaussian_loss.item() + 0.1 * batch_cate_loss.item() 125 | 126 | t_loss += loss 127 | m0.train() 128 | m1.train() 129 | return t_loss 130 | 131 | 132 | def train(args): 133 | lat_vec, lon_vec = get_grids(args.min_lat, args.min_lon, args.max_lat, args.max_lon, args.height, args.width) 134 | data_file = './data/trajectory.json' 135 | args.input_cell_size = len(lat_vec)*len(lon_vec)+3 136 | args.output_cell_size = len(lat_vec)*len(lon_vec)+3 137 | all_data = data_prepare(data_file, lat_vec=lat_vec, lon_vec=lon_vec) 138 | all_dataset = Trajectory(all_data) 139 | train_size = int(0.8 * len(all_dataset)) 140 | val_size = int((len(all_dataset)-train_size) / 2) 141 | test_size = len(all_dataset)-train_size-val_size 142 | train_dataset, val_dataset, test_dataset = torch.utils.data.random_split(all_dataset, 143 | [train_size, val_size, test_size]) 144 | trainData = get_data_loaders(train_dataset, args.batch) 145 | valData = get_data_loaders(val_dataset, args.batch) 146 | 147 | m0 = EncoderDecoder( 148 | args.input_cell_size, 149 | args.output_road_size, 150 | args.embedding_size, 151 | args.hidden_size, 152 | args.num_layers, 153 | args.de_layer, 154 | args.dropout, 155 | args.bidirectional 156 | ) 157 | 158 | m1 = nn.Sequential( 159 | nn.Linear(args.hidden_size, args.output_road_size), 160 | nn.LogSoftmax() 161 | ) 162 | loss_f = DenseLoss() 163 | if args.cuda and torch.cuda.is_available(): 164 | m0.to("cuda") 165 | m1.to("cuda") 166 | loss_f.to("cuda") 167 | 168 | m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate) 169 | m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate) 170 | 171 | if os.path.isfile(args.checkpoint): 172 | checkpoint = torch.load(args.checkpoint) 173 | best_prec_loss = checkpoint["val_loss"] 174 | m0.load_state_dict(checkpoint["m0"]) 175 | m1.load_state_dict(checkpoint["m1"]) 176 | m0_optimizer.load_state_dict(checkpoint["m0_optimizer"]) 177 | m1_optimizer.load_state_dict(checkpoint["m1_optimizer"]) 178 | 179 | else: 180 | best_prec_loss = float('inf') 181 | 182 | early_stop = False 183 | early_count = 0 184 | for epoch in range(args.epochs): 185 | if early_stop: 186 | break 187 | epoch_loss = 0 188 | for x, y in trainData: 189 | m0_optimizer.zero_grad() 190 | m1_optimizer.zero_grad() 191 | if args.cuda and torch.cuda.is_available(): 192 | x, y = (convert_tensor(x, device="cuda"), convert_tensor(y, device="cuda")) 193 | input, lengths = x 194 | input = torch.transpose(input, 0, 1) 195 | target, mask = torch.transpose(0, 1) 196 | mask = torch.transpose(mask, 0, 1) 197 | output, batch_gaussian_loss, batch_cate_loss = m0(input, lengths, target) 198 | output = m1(output) 199 | loss = loss_f(output, (target, mask)) 200 | if args.cluater_size == 1: 201 | loss = loss + batch_gaussian_loss 202 | else: 203 | loss = loss + 1.0/args.hidden_size * batch_gaussian_loss + 0.1 * batch_cate_loss 204 | loss.backward() 205 | clip_grad_norm(m0.parameters(), 5) 206 | clip_grad_norm(m1.parameters(), 5) 207 | m0_optimizer.step() 208 | m1_optimizer.step() 209 | 210 | epoch_loss += loss.item()/lengths.size(0) 211 | 212 | val_loss = validate(valData, (m0, m1), loss_f, args) 213 | print("epoch: {}, train_loss: {}, val_loss: {}".format(epoch, epoch_loss, val_loss)) 214 | 215 | if val_loss < best_prec_loss: 216 | best_prec_loss = val_loss 217 | early_count = 0 218 | savecheckpoint({ 219 | "epoch": epoch, 220 | "val_loss": best_prec_loss, 221 | "m0": m0.state_dict(), 222 | "m1": m1.state_dict(), 223 | "m0_optimizer": m0_optimizer.state_dict(), 224 | "m1_optimizer": m1_optimizer.state_dict() 225 | }) 226 | else: 227 | early_count += 1 228 | if early_count >args.patience: 229 | early_stop = True 230 | print("Early stopped") 231 | else: 232 | print("EarlyStopping: {} / {}".format(early_count, args.patience)) 233 | 234 | print("begin evaluate") 235 | evaluator(test_dataset, args) 236 | -------------------------------------------------------------------------------- /mapmatching/train_with_bucket.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | from torch.nn.utils import clip_grad_norm 5 | from model import EncoderDecoder 6 | from data_util import DataLoader 7 | import time, os, shutil, logging 8 | from init_latent import pretrain_bucket 9 | device = torch.device("cuda:0") 10 | 11 | 12 | def batchloss(output, target, generator, lossF, g_batch): 13 | batch = output.size(1) 14 | loss = 0 15 | target = target[1:] 16 | for o, t in zip(output.split(g_batch), 17 | target.split(g_batch)): 18 | o = o.view(-1, o.size(2)) 19 | o = generator(o) 20 | t = t.view(-1) 21 | loss += lossF(o, t) 22 | return loss.div(batch/g_batch) 23 | 24 | def maskloss(output, target, generator, lossF, g_batch): 25 | output = ouput.view(-1, output.size(2)) 26 | ouput = generator(output) 27 | target = target[1:] 28 | target = target.view(-1) 29 | loss = lossF(output, target) 30 | return loss 31 | 32 | 33 | def init_parameters(model): 34 | for p in model.parameters(): 35 | p.data.uniform_(-0.1, 0.1) 36 | 37 | def savecheckpoint(state, filename="trajectory2path.pt"): 38 | torch.save(state, filename) 39 | 40 | def validate(valData, model, lossF, args): 41 | m0, m1 = model 42 | m0.eval() 43 | m1.eval() 44 | 45 | num_iteration = valData.size // args.batch 46 | if valData.size % args.batch > 0: num_iteration += 1 47 | 48 | total_loss = 0 49 | for iteration in range(num_iteration): 50 | input, lengths, target, batch_mask = valData.getbatch() 51 | with torch.no_grad(): 52 | input = Variable(input) 53 | lengths = Variable(lengths) 54 | target = Variable(target) 55 | if args.cuda and torch.cuda.is_available(): 56 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 57 | output, batch_gaussian_loss, batch_cate_loss = m0(input, lengths, target) 58 | # loss = batchloss(output, target, m1, lossF, 2) 59 | loss = maskloss(output, target, m1, lossF, 2) 60 | if args.cluater_size == 1: 61 | loss = loss + batch_gaussian_loss 62 | else: 63 | loss = loss + 1.0/args.hidden_size * batch_gaussian_loss + 0.1 * batch_cate_loss 64 | total_loss += loss * output.size(1) 65 | m0.train() 66 | m1.train() 67 | return total_loss.item() / valData.size 68 | 69 | def evaluate(src, model, max_length): 70 | m0, m1 = model 71 | length = len(src) 72 | src = Variable(torch.LongTensor(src)) 73 | src = src.view(-1, 1) 74 | length = Variable(torch.LongTensor([[length]])) 75 | en_hn, H = m0.encoder(src, length) 76 | de_h0 = m0.encoder_hn2decoder_h0(en_hn) 77 | z = m0.latent(de_h0[-1].unsqueeze(0), 'test') 78 | h = z.unsqueeze(0).unsqueeze(0) 79 | input_ = Variable(torch.LongTensor([[1]])) 80 | tg = [] 81 | for _ in range(max_length): 82 | o, h = m0.decoder(input_, h, H) 83 | o = o.view(-1, o.size(2)) 84 | o = m1(o) 85 | _, id = o.data.topk(1) 86 | id = id[0][0] 87 | if id == 2: 88 | break 89 | tg.append(id.item()) 90 | input_ = Variable(torch.LongTensor([[id]])) 91 | return tg 92 | 93 | 94 | def evaluator(args, filename="trajectory2path.pt"): 95 | test_src = open(".\data\Freq90_cell_data_porto_test.txt") 96 | test_trg = open(".\data\Freq15_path_data_porto_test.txt") 97 | src = [] 98 | for line in test_src: 99 | line = line.strip('\n').split(' ') 100 | line = [int(x) for x in line] 101 | src.append(line) 102 | trg = [] 103 | for line in test_trg: 104 | line = line.strip('\n').split(' ') 105 | line = [int(x) for x in line] 106 | trg.append(line) 107 | 108 | 109 | m0 = EncoderDecoder( 110 | args.cluster_size, 111 | args.input_cell_size, 112 | args.output_road_size, 113 | args.embedding_size, 114 | args.hidden_size, 115 | args.num_layers, 116 | args.de_layer, 117 | args.dropout, 118 | args.bidirectional 119 | ) 120 | 121 | m1 = nn.Sequential( 122 | nn.Linear(args.hidden_size, args.output_road_size), 123 | nn.LogSoftmax() 124 | ) 125 | 126 | if os.path.isfile(filename): 127 | print("loading checkpoint '{}'".format(filename)) 128 | checkpoint = torch.load(filename) 129 | m0.load_state_dict(checkpoint["m0"]) 130 | m1.load_state_dict(checkpoint["m1"]) 131 | test_len = len(src) 132 | count = 0 133 | p = 0 134 | r = 0 135 | t = 0 136 | for i in range(test_len): 137 | x, y = src[i], trg[i] 138 | y_pred = evaluate(x, (m0, m1), args.max_length) 139 | start = time.time() 140 | end = time.time() 141 | t = t + end-start 142 | if len(y) >0: 143 | print('target', y) 144 | print('model_prediction', y_pred) 145 | 146 | intersect = set(y_pred) & set(y) 147 | p = p + len(intersect) / max(len(y_pred), len(y)) 148 | r = r + len(intersect) / len(y_pred) 149 | 150 | count = count + 1 151 | 152 | print("t {}".format(t / count)) 153 | print("p {}".format(p / count)) 154 | print("r {}".format(r / count)) 155 | else: 156 | print("no checkpoint found at {}".format(filename)) 157 | 158 | 159 | 160 | def train_bucket(args): 161 | pretrain_bucket(args) 162 | 163 | trainsrc = '.\data\Freq90_cell_data_porto_train.txt' 164 | traintrg = '.\data\Freq15_path_data_porto_train.txt' 165 | 166 | trainData = DataLoader(trainsrc, traintrg, args.batch, args.bucketsize) 167 | print("Read training data") 168 | trainData.load(args.max_num_line) 169 | 170 | valsrc = '.\data\Freq90_cell_data_porto_val.txt' 171 | valtrg = '.\data\Freq15_path_data_porto_val.txt' 172 | 173 | if os.path.isfile(valsrc) and os.path.isfile(valtrg): 174 | valData = DataLoader(valsrc, valtrg, args.batch, args.bucketsize, True) 175 | print("Read validation data") 176 | valData.load() 177 | print("Load validation data") 178 | else: 179 | print("No validation data") 180 | 181 | if args.criterion_name == "CE": 182 | criterion = nn.CrossEntropyLoss(ignore_index=0).to(device) 183 | lossF = lambda o, t: criterion(o, t) 184 | else: 185 | criterion = nn.NLLLoss(ignore_index=0).to(device) 186 | lossF = lambda o, t: criterion(o, t) 187 | 188 | m0 = EncoderDecoder(args.cluster_size, 189 | args.input_cell_size, 190 | args.output_road_size, 191 | args.embedding_size, 192 | args.hidden_size, 193 | args.num_layers, 194 | args.de_layer, 195 | args.dropout, 196 | args.bidirectional) 197 | 198 | m1 = nn.Sequential(nn.Linear(args.hidden_size, args.output_road_size), 199 | nn.LogSoftmax()) 200 | 201 | if args.cuda and torch.cuda.is_available(): 202 | print("=> training with GPU") 203 | m0.to(device) 204 | m1.to(device) 205 | criterion.to(device) 206 | else: 207 | print("=> training with CPU") 208 | 209 | m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate) 210 | m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate) 211 | 212 | if os.path.isfile(args.checkpoint): 213 | checkpoint = torch.load(args.checkpoint) 214 | best_prec_loss = checkpoint["val_loss"] 215 | m0.load_state_dict(checkpoint["m0"]) 216 | m1.load_state_dict(checkpoint["m1"]) 217 | m0_optimizer.load_state_dict(checkpoint["m0_optimizer"]) 218 | m1_optimizer.load_state_dict(checkpoint["m1_optimizer"]) 219 | else: 220 | best_prec_loss = float('inf') 221 | start_iteration = 0 222 | num_iteration = args.epochs * sum(trainData.allocation) // args.batch 223 | print("Start at {} " 224 | "and end at {}".format(start_iteration, num_iteration-1)) 225 | 226 | early_stop = False 227 | early_count = 0 228 | 229 | for iteration in range(start_iteration, num_iteration): 230 | if early_stop: 231 | break 232 | input, lengths, target = trainData.getbatch() 233 | 234 | input, lengths, target = Variable(input), Variable(lengths), Variable(target) 235 | 236 | if args.cuda and torch.cuda.is_available(): 237 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 238 | 239 | m0_optimizer.zero_grad() 240 | m1_optimizer.zero_grad() 241 | 242 | output, batch_gaussian_loss, batch_cate_loss = m0(input, lengths, target) 243 | # loss = batchloss(output, target, m1, lossF, 2) 244 | loss = maskloss(output, target, m1, lossF, 2) 245 | 246 | if args.cluater_size == 1: 247 | loss = loss + batch_gaussian_loss 248 | else: 249 | loss = loss + 1.0/args.hidden_size * batch_gaussian_loss + 0.1 * batch_cate_loss 250 | loss.backward() 251 | clip_grad_norm(m0.parameters(), 5) 252 | clip_grad_norm(m1.parameters(), 5) 253 | m0_optimizer.step() 254 | m1_optimizer.step() 255 | avg_loss = loss.item() / target.size(0) 256 | if iteration % args.print == 0: 257 | print("Iteration: {}\tLoss: {}".format(iteration, avg_loss)) 258 | 259 | if iteration % args.save == 0 and iteration > 0: 260 | val_loss = validate(valData, (m0, m1), lossF, args) 261 | print("Iteration: {}, train_loss: {}, val_loss: {}".format(iteration, avg_loss, val_loss)) 262 | 263 | if val_loss < best_prec_loss: 264 | best_prec_loss = val_loss 265 | early_count = 0 266 | savecheckpoint({ 267 | "iteration": iteration, 268 | "val_loss": best_prec_loss, 269 | "m0": m0.state_dict(), 270 | "m1": m1.state_dict(), 271 | "m0_optimizer": m0_optimizer.state_dict(), 272 | "m1_optimizer": m1_optimizer.state_dict() 273 | }) 274 | else: 275 | early_count += 1 276 | if early_count= max_num_line and max_num_line > 0: break 91 | if num_line % 100000 == 0: 92 | print("Read line {}".format(num_line)) 93 | 94 | if self.validate == False: 95 | self.srcdata = list(map(np.array, self.srcdata)) 96 | self.trgdata = list(map(np.array, self.trgdata)) 97 | self.allocation = list(map(len, self.srcdata)) 98 | self.p = np.array(self.allocation) / sum(self.allocation) 99 | else: 100 | print('validate1') 101 | self.srcdata = np.array(merge(self.srcdata)) #将各个桶下的数据进行合并 102 | self.trgdata = np.array(merge(self.trgdata)) 103 | self.start = 0 104 | self.size = len(self.srcdata) 105 | 106 | srcstream.close(), trgstream.close() 107 | 108 | def getbatch(self): 109 | if self.validate == True: 110 | src = self.srcdata[self.start:self.start+self.batch] 111 | trg = self.trgdata[self.start:self.start+self.batch] 112 | self.start += self.batch 113 | if self.start >= self.size: 114 | self.start = 0 115 | src, len, trg = pad_arrays_pair(src, trg) 116 | batch_mask = np.zeros((trg.shape[0], trg.shape[1]),dtype=float) 117 | for row in range(trg.shape[0]): 118 | for col in range(trg.shape[1]): 119 | if trg[row][col] != 0: 120 | batch_mask[row][col] = 1.0 121 | batch_mask = torch.FloatTensor(batch_mask) 122 | return src,len,trg,batch_mask 123 | else: 124 | sample = np.random.multinomial(1, self.p) 125 | #print('sample:'+str(sample)) 126 | bucket = np.nonzero(sample)[0][0] 127 | #print('bucket:'+str(bucket)) 128 | idx = np.random.choice(self.srcdata[bucket].shape[0], self.batch) 129 | src,len,trg = pad_arrays_pair(self.srcdata[bucket][idx], 130 | self.trgdata[bucket][idx]) 131 | return src, len, trg 132 | 133 | 134 | class DataOrderScaner(): 135 | def __init__(self, srcfile, batch): 136 | self.srcfile = srcfile 137 | self.batch = batch 138 | self.srcdata = [] 139 | self.start = 0 140 | def load(self, max_num_line=0): 141 | num_line = 0 142 | with open(self.srcfile, 'r') as srcstream: 143 | for s in srcstream: 144 | s = [int(x) for x in s.split()] 145 | self.srcdata.append(np.array(s, dtype=np.int32)) 146 | num_line += 1 147 | if max_num_line > 0 and num_line >= max_num_line: 148 | break 149 | self.size = len(self.srcdata) 150 | self.start = 0 151 | def getbatch(self): 152 | if self.start >= self.size: 153 | return None, None, None 154 | src = self.srcdata[self.start:self.start+self.batch] 155 | self.start += self.batch 156 | return pad_arrays_keep_invp(src) 157 | -------------------------------------------------------------------------------- /sparse2dense/evaluate.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | from model import EncoderDecoder 5 | import os 6 | import time 7 | 8 | 9 | def evaluate(src, model, max_length): 10 | m0, m1 = model 11 | length = len(src) 12 | src = Variable(torch.LongTensor(src)) 13 | length = Variable(torch.LongTensor([[length]])) 14 | en_hn, H = m0.encoder(src, length) 15 | de_h0 = m0.encoder_hn2decoder_h0(en_hn) 16 | h = de_h0[-1].unsqueeze(0) 17 | input_ = Variable(torch.LongTensor([[1]])) 18 | tg = [] 19 | for _ in range(max_length): 20 | o, h = m0.decoder(input_, h, H) 21 | o = o.view(-1, o.size(2)) 22 | o = m1(o) 23 | _, id = o.data.topk(1) 24 | id = id[0][0] 25 | if id == 2: 26 | break 27 | tg.append(id.item()) 28 | input_ = Variable(torch.LongTensor([[id]])) 29 | return tg 30 | 31 | 32 | def evaluator(test_dataset, args, filename="sparse2dense.pt"): 33 | m0 = EncoderDecoder( 34 | args.input_cell_size, 35 | args.output_cell_size, 36 | args.embedding_size, 37 | args.hidden_size, 38 | args.num_layers, 39 | args.de_layer, 40 | args.dropout, 41 | args.bidirectional 42 | ) 43 | 44 | m1 = nn.Sequential( 45 | nn.Linear(args.hidden_size, args.output_cell_size), 46 | nn.LogSoftmax() 47 | ) 48 | 49 | if os.path.isfile(filename): 50 | print("loading checkpoint '{}'".format(filename)) 51 | checkpoint = torch.load(filename) 52 | m0.load_state_dict(checkpoint["m0"]) 53 | m1.load_state_dict(checkpoint["m1"]) 54 | test_len = test_dataset.__len__() 55 | count = 0 56 | p = 0 57 | r = 0 58 | t = 0 59 | for i in range(test_len): 60 | x, y = test_dataset.__getitem__(i) 61 | y_pred = evaluate(x, (m0, m1), args.max_length) 62 | start = time.time() 63 | end = time.time() 64 | t = t + end-start 65 | if len(y) >0: 66 | print('target', y) 67 | print('model_prediction', y_pred) 68 | 69 | intersect = set(y_pred) & set(y) 70 | p = p + len(intersect) / max(len(y_pred), len(y)) 71 | r = r + len(intersect) / len(y_pred) 72 | 73 | count = count + 1 74 | 75 | print("t {}".format(t / count)) 76 | print("p {}".format(p / count)) 77 | print("r {}".format(r / count)) 78 | else: 79 | print("no checkpoint found at {}".format(filename)) -------------------------------------------------------------------------------- /sparse2dense/model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.nn.utils.rnn import pad_packed_sequence 4 | from torch.nn.utils.rnn import pack_padded_sequence 5 | 6 | class Encoder(nn.Module): 7 | def __init__(self, input_size, hidden_size, num_layers, dropout, 8 | bidirectional, embedding): 9 | super(Encoder, self).__init__() 10 | self.num_directions = 2 if bidirectional else 1 11 | assert hidden_size % self.num_directions == 0 12 | self.hidden_size = hidden_size // self.num_directions 13 | self.num_layers = num_layers 14 | 15 | self.embedding = embedding 16 | self.rnn = nn.GRU(input_size, self.hidden_size, 17 | num_layers=num_layers, 18 | bidirectional=bidirectional, 19 | dropout=dropout) 20 | 21 | def forward(self, input, lengths, h0=None): 22 | embed = self.embedding(input) 23 | lengths = lengths.data.view(-1).tolist() 24 | if lengths is not None: 25 | embed = pack_padded_sequence(embed, lengths) 26 | output, hn = self.rnn(embed, h0) 27 | if lengths is not None: 28 | output = pad_packed_sequence(output)[0] 29 | return hn, output 30 | 31 | 32 | class GlobalAttention(nn.Module): 33 | def __init__(self, hidden_size): 34 | super(GlobalAttention, self).__init__() 35 | self.L1 = nn.Linear(hidden_size, hidden_size, bias=False) 36 | self.L2 = nn.Linear(2*hidden_size, hidden_size, bias=False) 37 | self.softmax = nn.Softmax() 38 | self.tanh = nn.Tanh() 39 | 40 | def forward(self, q, H): 41 | q1 = q.unsqueeze(2) 42 | a = torch.bmm(H, q1).squeeze(2) 43 | a = self.softmax(a) 44 | a = a.unsqueeze(1) 45 | c = torch.bmm(a, H).squeeze(1) 46 | c = torch.cat([c, q], 1) 47 | return self.tanh(self.L2(c)) 48 | 49 | 50 | class Decoder(nn.Module): 51 | def __init__(self, input_size, hidden_size, num_layers, dropout, embedding): 52 | super(Decoder, self).__init__() 53 | self.embedding = embedding 54 | self.rnn = StackingGRUCell(input_size, hidden_size, num_layers, 55 | dropout) 56 | self.attention = GlobalAttention(hidden_size) 57 | self.dropout = nn.Dropout(dropout) 58 | self.num_layers = num_layers 59 | 60 | def forward(self, input, h, H, use_attention=True): 61 | assert input.dim() == 2, "The input should be of (seq_len, batch)" 62 | embed = self.embedding(input) 63 | output = [] 64 | for e in embed.split(1): 65 | e = e.squeeze(0) 66 | o, h = self.rnn(e, h) 67 | if use_attention: 68 | o = self.attention(o, H.transpose(0, 1)) 69 | o = self.dropout(o) 70 | output.append(o) 71 | output = torch.stack(output) 72 | return output, h 73 | 74 | 75 | class EncoderDecoder(nn.Module): 76 | def __init__(self, input_vocab_size, output_vocab_size, embedding_size, 77 | hidden_size, num_layers, de_layer, dropout, bidirectional): 78 | super(EncoderDecoder, self).__init__() 79 | self.input_vocab_size = input_vocab_size 80 | self.output_vocab_size = output_vocab_size 81 | self.embedding_size = embedding_size 82 | self.embedding = nn.Embedding(input_vocab_size, embedding_size, padding_idx=0) 83 | self.encoder = Encoder(embedding_size, hidden_size, num_layers, 84 | dropout, bidirectional, self.embedding) 85 | self.decoder = Decoder(embedding_size, hidden_size, de_layer, 86 | dropout, self.embedding) 87 | self.num_layers = num_layers 88 | 89 | def encoder_hn2decoder_h0(self, h): 90 | if self.encoder.num_directions == 2: 91 | num_layers, batch, hidden_size = h.size(0)//2, h.size(1), h.size(2) 92 | return h.view(num_layers, 2, batch, hidden_size)\ 93 | .transpose(1, 2).contiguous()\ 94 | .view(num_layers, batch, hidden_size * 2) 95 | else: 96 | return h 97 | 98 | def forward(self, src, lengths, trg): 99 | encoder_hn, H = self.encoder(src, lengths) 100 | decoder_h0 = self.encoder_hn2decoder_h0(encoder_hn) 101 | decoder_h0 = decoder_h0[-1].unsqueeze(0) 102 | output, decoder_hn = self.decoder(trg[:-1], decoder_h0, H) 103 | return output 104 | 105 | 106 | class StackingGRUCell(nn.Module): 107 | def __init__(self, input_size, hidden_size, num_layers, dropout): 108 | super(StackingGRUCell, self).__init__() 109 | self.num_layers = num_layers 110 | self.grus = nn.ModuleList() 111 | self.dropout = nn.Dropout(dropout) 112 | 113 | self.grus.append(nn.GRUCell(input_size, hidden_size)) 114 | for i in range(1, num_layers): 115 | self.grus.append(nn.GRUCell(hidden_size, hidden_size)) 116 | 117 | def forward(self, input, h0): 118 | hn = [] 119 | output = input 120 | for i, gru in enumerate(self.grus): 121 | hn_i = gru(output, h0[i]) 122 | hn.append(hn_i) 123 | if i != self.num_layers - 1: 124 | output = self.dropout(hn_i) 125 | else: 126 | output = hn_i 127 | hn = torch.stack(hn) 128 | return output, hn 129 | 130 | -------------------------------------------------------------------------------- /sparse2dense/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.nn.utils import clip_grad_norm 4 | from model import EncoderDecoder 5 | import time, os, shutil, logging 6 | import numpy as np 7 | import json 8 | from torch.utils.data import DataLoader 9 | from trajectory_dataset import Trajectory, collate_fn, convert_tensor 10 | from util import DenseLoss 11 | from evaluate import evaluator 12 | 13 | 14 | def get_grids(min_lat, min_lon, max_lat, max_lon, height, width, grid_size=100): 15 | x_size = int(width/grid_size) 16 | y_size = int(height/grid_size) 17 | lon_vec = np.linspace(min_lon, max_lon, x_size) 18 | lat_vec = np.linspace(min_lat, max_lat, y_size) 19 | return lon_vec, lat_vec 20 | 21 | 22 | def point2grid(lon, lat, lon_vec, lat_vec): 23 | lon_i = len(lon_vec[lon_vec < lon]) 24 | lat_i = len(lat_vec[lat_vec < lat]) 25 | if lon_i == 0 or lat_i == 0 or lon_i == len(lon_vec) or lat_i == len(lat_vec): 26 | return -1 27 | else: 28 | return (lat_i - 1)*(len(lon_vec)-1)+lon_i 29 | 30 | 31 | def data_prepare(file, lat_vec, lon_vec): 32 | res = [] 33 | with open(file) as f: 34 | for line in f: 35 | data = json.loads(line) 36 | points = data['locs'] 37 | if len(points) > 1000: 38 | continue 39 | grids = [] 40 | flag = 1 41 | index = point2grid(points[0][0], points[0][1], lon_vec, lat_vec) 42 | if index == -1: 43 | flag = 0 44 | else: 45 | grids.append(index) 46 | pre_lon, pre_lat = points[0][0], points[0][1] 47 | pre_index = index 48 | for i in range(1, len(points)): 49 | cur_lon, cur_lat = points[i][0], points[i][1] 50 | index = point2grid(cur_lon, cur_lat, lon_vec, lat_vec) 51 | if index == -1: 52 | flag = 0 53 | else: 54 | if pre_index != index: 55 | grids.append(index) 56 | pre_index = index 57 | if flag: 58 | res.append(grids) 59 | return res 60 | 61 | 62 | def get_data_loaders(mydataset, batch_size): 63 | loader = DataLoader(mydataset, 64 | batch_size= batch_size, 65 | collate_fn=collate_fn, 66 | shuffle=False) 67 | loader._dataset_kind = None 68 | return loader 69 | 70 | 71 | def savecheckpoint(state, file_name='sparse2dense.pt'): 72 | torch.save(state, file_name) 73 | 74 | 75 | def validate(valData, model, loss_f, args): 76 | m0, m1 = model 77 | m0.eval() 78 | m1.eval() 79 | loss = 0 80 | with torch.no_grad(): 81 | for x, y in valData: 82 | if args.cuda and torch.cuda.is_available(): 83 | x, y = (convert_tensor(x, device="cuda"), convert_tensor(y, device="cuda")) 84 | input, lengths = x 85 | input = torch.transpose(input, 0, 1) 86 | target, mask = torch.transpose(0, 1) 87 | mask = torch.transpose(mask, 0, 1) 88 | output = m0(input, lengths, target) 89 | output = m1(output) 90 | loss += loss_f(output, (target, mask)).item()/lengths.size(0) 91 | m0.train() 92 | m1.train() 93 | return loss 94 | 95 | 96 | def train(args): 97 | lat_vec, lon_vec = get_grids(args.min_lat, args.min_lon, args.max_lat, args.max_lon, args.height, args.width) 98 | data_file = './data/trajectory.json' 99 | args.input_cell_size = len(lat_vec)*len(lon_vec)+3 100 | args.output_cell_size = len(lat_vec)*len(lon_vec)+3 101 | all_data = data_prepare(data_file, lat_vec=lat_vec, lon_vec=lon_vec) 102 | all_dataset = Trajectory(all_data) 103 | train_size = int(0.8 * len(all_dataset)) 104 | val_size = int((len(all_dataset)-train_size) / 2) 105 | test_size = len(all_dataset)-train_size-val_size 106 | train_dataset, val_dataset, test_dataset = torch.utils.data.random_split(all_dataset, 107 | [train_size, val_size, test_size]) 108 | trainData = get_data_loaders(train_dataset, args.batch) 109 | valData = get_data_loaders(val_dataset, args.batch) 110 | 111 | m0 = EncoderDecoder( 112 | args.input_cell_size, 113 | args.output_cell_size, 114 | args.embedding_size, 115 | args.hidden_size, 116 | args.num_layers, 117 | args.de_layer, 118 | args.dropout, 119 | args.bidirectional 120 | ) 121 | 122 | m1 = nn.Sequential( 123 | nn.Linear(args.hidden_size, args.output_cell_size), 124 | nn.LogSoftmax() 125 | ) 126 | loss_f = DenseLoss() 127 | if args.cuda and torch.cuda.is_available(): 128 | m0.to("cuda") 129 | m1.to("cuda") 130 | loss_f.to("cuda") 131 | 132 | m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate) 133 | m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate) 134 | 135 | if os.path.isfile(args.checkpoint): 136 | checkpoint = torch.load(args.checkpoint) 137 | best_prec_loss = checkpoint["val_loss"] 138 | m0.load_state_dict(checkpoint["m0"]) 139 | m1.load_state_dict(checkpoint["m1"]) 140 | m0_optimizer.load_state_dict(checkpoint["m0_optimizer"]) 141 | m1_optimizer.load_state_dict(checkpoint["m1_optimizer"]) 142 | 143 | else: 144 | best_prec_loss = float('inf') 145 | 146 | early_stop = False 147 | early_count = 0 148 | for epoch in range(args.epochs): 149 | if early_stop: 150 | break 151 | epoch_loss = 0 152 | for x, y in trainData: 153 | m0_optimizer.zero_grad() 154 | m1_optimizer.zero_grad() 155 | if args.cuda and torch.cuda.is_available(): 156 | x, y = (convert_tensor(x, device="cuda"), convert_tensor(y, device="cuda")) 157 | input, lengths = x 158 | input = torch.transpose(input, 0, 1) 159 | target, mask = torch.transpose(0, 1) 160 | mask = torch.transpose(mask, 0, 1) 161 | output = m0(input, lengths, target) 162 | output = m1(output) 163 | loss = loss_f(output, (target, mask)) 164 | loss.backward() 165 | clip_grad_norm(m0.parameters(), 5) 166 | clip_grad_norm(m1.parameters(), 5) 167 | m0_optimizer.step() 168 | m1_optimizer.step() 169 | 170 | epoch_loss += loss.item()/lengths.size(0) 171 | 172 | val_loss = validate(valData, (m0, m1), loss_f, args) 173 | print("epoch: {}, train_loss: {}, val_loss: {}".format(epoch, epoch_loss, val_loss)) 174 | 175 | if val_loss < best_prec_loss: 176 | best_prec_loss = val_loss 177 | early_count = 0 178 | savecheckpoint({ 179 | "epoch": epoch, 180 | "val_loss": best_prec_loss, 181 | "encoder_m0": m0.encoder.state_dict(), 182 | "m0": m0.state_dict(), 183 | "m1": m1.state_dict(), 184 | "m0_optimizer": m0_optimizer.state_dict(), 185 | "m1_optimizer": m1_optimizer.state_dict() 186 | }) 187 | else: 188 | early_count += 1 189 | if early_count >args.patience: 190 | early_stop = True 191 | print("Early stopped") 192 | else: 193 | print("EarlyStopping: {} / {}".format(early_count, args.patience)) 194 | 195 | print("begin evaluate") 196 | evaluator(test_dataset, args) 197 | -------------------------------------------------------------------------------- /sparse2dense/train_with_bucket.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | from torch.nn.utils import clip_grad_norm 5 | from model import EncoderDecoder 6 | from data_util import DataLoader 7 | import time, os, shutil, logging 8 | 9 | device = torch.device("cuda:0") 10 | 11 | def NLLcriterion(vocab_size): 12 | weight = torch.ones(vocab_size) 13 | weight[0] = 0 14 | criterion = nn.NLLLoss(weight, ignore_index=0,size_average=False) 15 | print(criterion) 16 | return criterion 17 | 18 | 19 | 20 | def batchloss(output, target, generator, lossF, g_batch): 21 | batch = output.size(1) 22 | loss = 0 23 | target = target[1:] 24 | for o, t in zip(output.split(g_batch), 25 | target.split(g_batch)): 26 | o = o.view(-1, o.size(2)) 27 | o = generator(o) 28 | t = t.view(-1) 29 | loss += lossF(o, t) 30 | return loss.div(batch/g_batch) 31 | 32 | 33 | def init_parameters(model): 34 | for p in model.parameters(): 35 | p.data.uniform_(-0.1, 0.1) 36 | 37 | def savecheckpoint(state, filename="sparse2dense.pt"): 38 | torch.save(state, filename) 39 | 40 | def validate(valData, model, lossF, args, inputdata,Adj_mat,Adj_mask,D): 41 | m0, m1 = model 42 | m0.eval() 43 | m1.eval() 44 | 45 | num_iteration = valData.size // args.batch 46 | if valData.size % args.batch > 0: num_iteration += 1 47 | 48 | total_loss = 0 49 | for iteration in range(num_iteration): 50 | input, lengths, target, batch_mask = valData.getbatch() 51 | with torch.no_grad(): 52 | input = Variable(input) 53 | lengths = Variable(lengths) 54 | target = Variable(target) 55 | if args.cuda and torch.cuda.is_available(): 56 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 57 | output = m0(input, lengths, target) 58 | loss = batchloss(output, target, m1, lossF, 1,inputdata) 59 | total_loss += loss * output.size(1) 60 | m0.train() 61 | m1.train() 62 | return total_loss.item() / valData.size 63 | 64 | def evaluate(src, model, max_length): 65 | m0, m1 = model 66 | length = len(src) 67 | src = Variable(torch.LongTensor(src)) 68 | length = Variable(torch.LongTensor([[length]])) 69 | en_hn, H = m0.encoder(src, length) 70 | de_h0 = m0.encoder_hn2decoder_h0(en_hn) 71 | h = de_h0[-1].unsqueeze(0) 72 | input_ = Variable(torch.LongTensor([[1]])) 73 | tg = [] 74 | for _ in range(max_length): 75 | o, h = m0.decoder(input_, h, H) 76 | o = o.view(-1, o.size(2)) 77 | o = m1(o) 78 | _, id = o.data.topk(1) 79 | id = id[0][0] 80 | if id == 2: 81 | break 82 | tg.append(id.item()) 83 | input_ = Variable(torch.LongTensor([[id]])) 84 | return tg 85 | 86 | 87 | def evaluator(args, filename="sparse2dense.pt"): 88 | test_src = ".\data\Freq60_cell_data_porto_test.txt" 89 | test_trg = ".\data\Freq30_cell_data_porto_test.txt" 90 | src = [] 91 | for line in test_src: 92 | line = line.strip('\n').split(' ') 93 | line = [int(x) for x in line] 94 | src.append(line) 95 | trg = [] 96 | for line in test_trg: 97 | line = line.strip('\n').split(' ') 98 | line = [int(x) for x in line] 99 | trg.append(line) 100 | 101 | 102 | m0 = EncoderDecoder( 103 | args.input_cell_size, 104 | args.output_cell_size, 105 | args.embedding_size, 106 | args.hidden_size, 107 | args.num_layers, 108 | args.de_layer, 109 | args.dropout, 110 | args.bidirectional 111 | ) 112 | 113 | m1 = nn.Sequential( 114 | nn.Linear(args.hidden_size, args.output_cell_size), 115 | nn.LogSoftmax() 116 | ) 117 | 118 | if os.path.isfile(filename): 119 | print("loading checkpoint '{}'".format(filename)) 120 | checkpoint = torch.load(filename) 121 | m0.load_state_dict(checkpoint["m0"]) 122 | m1.load_state_dict(checkpoint["m1"]) 123 | test_len = len(src) 124 | count = 0 125 | p = 0 126 | r = 0 127 | t = 0 128 | for i in range(test_len): 129 | x, y = src[i], trg[i] 130 | y_pred = evaluate(x, (m0, m1), args.max_length) 131 | start = time.time() 132 | end = time.time() 133 | t = t + end-start 134 | if len(y) >0: 135 | print('target', y) 136 | print('model_prediction', y_pred) 137 | 138 | intersect = set(y_pred) & set(y) 139 | p = p + len(intersect) / max(len(y_pred), len(y)) 140 | r = r + len(intersect) / len(y_pred) 141 | 142 | count = count + 1 143 | 144 | print("t {}".format(t / count)) 145 | print("p {}".format(p / count)) 146 | print("r {}".format(r / count)) 147 | else: 148 | print("no checkpoint found at {}".format(filename)) 149 | 150 | 151 | def train_bucket(args): 152 | trainsrc = './data/Freq60_cell_data_Porto_(raw-point)_train_100000.txt' 153 | traintrg = './data/Freq30_cell_data_Porto_(raw-point)_train_100000.txt' 154 | 155 | trainData = DataLoader(trainsrc, traintrg, args.batch, args.bucketsize) 156 | print("Read training data") 157 | trainData.load(args.max_num_line) 158 | 159 | valsrc = './data/Freq60_cell_data_Porto_(raw-point)_val.txt' 160 | valtrg = './data/Freq30_cell_data_Porto_(raw-point)_val.txt' 161 | 162 | if os.path.isfile(valsrc) and os.path.isfile(valtrg): 163 | valData = DataLoader(valsrc, valtrg, args.batch, args.bucketsize, True) 164 | print("Read validation data") 165 | valData.load() 166 | print("Load validation data") 167 | else: 168 | print("No validation data") 169 | 170 | if args.criterion_name == "CE": 171 | criterion = nn.CrossEntropyLoss(ignore_index=0).to(device) 172 | lossF = lambda o, t: criterion(o, t) 173 | else: 174 | criterion = nn.NLLLoss(ignore_index=0).to(device) 175 | lossF = lambda o, t: criterion(o, t) 176 | 177 | m0 = EncoderDecoder( 178 | args.input_cell_size, 179 | args.output_cell_size, 180 | args.embedding_size, 181 | args.hidden_size, 182 | args.num_layers, 183 | args.de_layer, 184 | args.dropout, 185 | args.bidirectional 186 | ) 187 | 188 | m1 = nn.Sequential(nn.Linear(args.hidden_size, args.output_cell_size), 189 | nn.LogSoftmax()) 190 | 191 | if args.cuda and torch.cuda.is_available(): 192 | print("=> training with GPU") 193 | m0.to(device) 194 | m1.to(device) 195 | criterion.to(device) 196 | else: 197 | print("=> training with CPU") 198 | 199 | m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate) 200 | m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate) 201 | 202 | if os.path.isfile(args.checkpoint): 203 | checkpoint = torch.load(args.checkpoint) 204 | best_prec_loss = checkpoint["val_loss"] 205 | m0.load_state_dict(checkpoint["m0"]) 206 | m1.load_state_dict(checkpoint["m1"]) 207 | m0_optimizer.load_state_dict(checkpoint["m0_optimizer"]) 208 | m1_optimizer.load_state_dict(checkpoint["m1_optimizer"]) 209 | else: 210 | best_prec_loss = float('inf') 211 | 212 | num_iteration = args.epochs * sum(trainData.allocation) // args.batch 213 | start_iteration = 0 214 | print("Start at {} " 215 | "and end at {}".format(start_iteration, num_iteration-1)) 216 | 217 | early_stop = False 218 | early_count = 0 219 | 220 | for iteration in range(start_iteration, num_iteration): 221 | if early_stop: 222 | break 223 | input, lengths, target = trainData.getbatch() 224 | 225 | input, lengths, target = Variable(input), Variable(lengths), Variable(target) 226 | 227 | if args.cuda and torch.cuda.is_available(): 228 | input, lengths, target = input.to(device), lengths.to(device), target.to(device) 229 | 230 | m0_optimizer.zero_grad() 231 | m1_optimizer.zero_grad() 232 | 233 | output = m0(input, lengths, target) 234 | 235 | loss = batchloss(output, target, m1, lossF, 2) 236 | loss.backward() 237 | clip_grad_norm(m0.parameters(), 5) 238 | clip_grad_norm(m1.parameters(), 5) 239 | m0_optimizer.step() 240 | m1_optimizer.step() 241 | avg_loss = loss.item() / target.size(0) 242 | if iteration % args.print == 0: 243 | print("Iteration: {}\tLoss: {}".format(iteration, avg_loss)) 244 | 245 | if iteration % args.save == 0 and iteration > 0: 246 | if avg_loss < best_prec_loss: 247 | best_prec_loss = avg_loss 248 | early_count = 0 249 | savecheckpoint({ 250 | "iteration": iteration, 251 | "val_loss": best_prec_loss, 252 | "m0": m0.state_dict(), 253 | "encoder_m0": m0.encoder.state_dict(), 254 | "m1": m1.state_dict(), 255 | "m0_optimizer": m0_optimizer.state_dict(), 256 | "m1_optimizer": m1_optimizer.state_dict() 257 | }) 258 | else: 259 | early_count += 1 260 | if early_count