Skip to content

Commit

Permalink
Random generation of data for TSP
Browse files Browse the repository at this point in the history
  • Loading branch information
pemami4911 committed Sep 29, 2017
1 parent 174f764 commit e4dcec8
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 46 deletions.
19 changes: 11 additions & 8 deletions neural_combinatorial_rl.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ def recurrence(x, hidden):
outputs.append(outs[:, 0,:])
else:
outputs.append(outs.squeeze(0))
# Check for indexing
selections.append(idxs)
# Should be done decoding
if len(active) == 0:
Expand All @@ -223,13 +224,8 @@ def decode_stochastic(self, logits, embedded_inputs, prev=None, logit_mask=None)
selected for this iteration of the decoding
"""
batch_size = logits.size(0)
#batch_idxs = torch.arange(0, batch_size).long()
#if USE_CUDA:
# batch_idxs = batch_idxs.cuda()

logits_ = logits.clone()
# Set the logits in prev to 0
#for p in prev:

if logit_mask is None:
logit_mask = torch.zeros(logits.size()).byte()
if USE_CUDA:
Expand All @@ -238,9 +234,12 @@ def decode_stochastic(self, logits, embedded_inputs, prev=None, logit_mask=None)
# to prevent them from being reselected.
# Or, allow re-selection and penalize in the objective function
if prev is not None:
#import pdb; pdb.set_trace()
logit_mask[[x for x in range(batch_size)],
prev.data] = 1
logits_[logit_mask] = 0
# renormalize
logits_ /= logits_.sum()

# idxs is [batch_size]
idxs = logits_.multinomial().squeeze(1)
Expand All @@ -260,6 +259,7 @@ def decode_beam(self, logits, embedded_inputs, beam, batch_size, n_best, prev=No
if prev is not None:
logit_mask[0,:,prev.data[0]] = 1
logits_[logit_mask] = 0
logits_ /= logits_.sum()

active = []
for b in range(batch_size):
Expand Down Expand Up @@ -488,10 +488,13 @@ def forward(self, inputs):
# Select the actions (inputs pointed to
# by the pointer net) and the corresponding
# logits
# should be size [batch_size x
actions = []

# inputs is [batch_size, input_dim, sourceL]
inputs_ = inputs.transpose(1, 2)
# inputs_ is [batch_size, sourceL, input_dim]
for action_id in action_idxs:
actions.append(inputs[..., action_id.data[0]])
actions.append(inputs_[[x for x in range(batch_size)], action_id.data, :])

if self.is_train:
# logits_ is a list of len sourceL of [batch_size x sourceL]
Expand Down
16 changes: 7 additions & 9 deletions sorting_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import torch
from torch.utils.data import Dataset
from torch.autograd import Variable
from tqdm import trange
from tqdm import trange, tqdm
import os
import sys

Expand Down Expand Up @@ -35,11 +35,11 @@ def reward(sample_solution, USE_CUDA=False):
batch_size = sample_solution[0].size(0)
sourceL = len(sample_solution)

#longest = Variable(torch.ones(batch_size), requires_grad=False)
longest = Variable(torch.ones(batch_size), requires_grad=False)
current = Variable(torch.ones(batch_size), requires_grad=False)

if USE_CUDA:
#longest = longest.cuda()
longest = longest.cuda()
current = current.cuda()

for i in range(1, sourceL):
Expand All @@ -48,14 +48,12 @@ def reward(sample_solution, USE_CUDA=False):
# if res[i,j] == 1, increment length of current sorted subsequence
current += res.float()
# else, reset current to 1
# penalty
current[torch.eq(res, 0)] = 1
#current[torch.eq(res, 0)] -= 1
# if, for any, current > longest, update longest
#mask = torch.gt(current, longest)
#longest[mask] = current[mask]
#return torch.div(longest, sourceL)
return torch.div(current, sourceL)
mask = torch.gt(current, longest)
longest[mask] = current[mask]
return torch.div(longest, sourceL)

def create_dataset(
train_size,
Expand Down Expand Up @@ -131,7 +129,7 @@ def __init__(self, dataset_fname):
self.data_set = []
with open(dataset_fname, 'r') as dset:
lines = dset.readlines()
for next_line in lines:
for next_line in tqdm(lines):
toks = next_line.split()
sample = torch.zeros(1, len(toks)).long()
for idx, tok in enumerate(toks):
Expand Down
21 changes: 14 additions & 7 deletions trainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def str2bool(v):
parser.add_argument('--batch_size', default=128, help='')
parser.add_argument('--train_size', default=1000000, help='')
parser.add_argument('--val_size', default=10000, help='')
parser.add_argument('--test_size', default=10000, help='')
# Network
parser.add_argument('--embedding_dim', default=128, help='Dimension of input embedding')
parser.add_argument('--hidden_dim', default=128, help='Dimension of hidden layers in Enc/Dec')
Expand All @@ -41,8 +40,8 @@ def str2bool(v):
parser.add_argument('--terminating_symbol', default='<0>', help='')
parser.add_argument('--beam_size', default=1, help='Beam width for beam search')
# Training
parser.add_argument('--actor_net_lr', default=1e-4, help="Set the learning rate for the actor network")
parser.add_argument('--critic_net_lr', default=1e-4, help="Set the learning rate for the critic network")
parser.add_argument('--actor_net_lr', default=1e-3, help="Set the learning rate for the actor network")
parser.add_argument('--critic_net_lr', default=1e-3, help="Set the learning rate for the critic network")
parser.add_argument('--actor_lr_decay_step', default=5000, help='')
parser.add_argument('--critic_lr_decay_step', default=5000, help='')
parser.add_argument('--actor_lr_decay_rate', default=0.96, help='')
Expand Down Expand Up @@ -99,11 +98,12 @@ def str2bool(v):

input_dim = 2
reward_fn = tsp_task.reward
train_fname, val_fname = tsp_task.create_dataset(
val_fname = tsp_task.create_dataset(
problem_size=str(size),
data_dir=data_dir)
training_dataset = tsp_task.TSPDataset(train_fname)
val_dataset = tsp_task.TSPDataset(val_fname)
training_dataset = tsp_task.TSPDataset(train=True, size=size,
num_samples=int(args['train_size']))
val_dataset = tsp_task.TSPDataset(dataset_fname=val_fname)
else:
print('Currently unsupported task!')
exit(1)
Expand Down Expand Up @@ -224,7 +224,10 @@ def str2bool(v):
example_output = []
example_input = []
for idx, action in enumerate(actions):
example_output.append(action[0].data[0]) # <-- ??
if task[0] == 'tsp':
example_output.append(actions_idxs[idx][0].data[0])
else:
example_output.append(action[0].data[0]) # <-- ??
example_input.append(sample_batch[0, :, idx][0])
print('Example train input: {}'.format(example_input))
print('Example train output: {}'.format(example_output))
Expand Down Expand Up @@ -291,3 +294,7 @@ def str2bool(v):

torch.save(model, os.path.join(save_dir, 'epoch-{}.pt'.format(i)))

print('Generating and loading new training set')

training_dataset = tsp_task.TSPDataset(train=True, size=size,
num_samples=int(args['train_size']))
72 changes: 50 additions & 22 deletions tsp_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def reward(sample_solution, USE_CUDA=False):

tour_len += torch.norm(sample_solution[n-1] - sample_solution[0], dim=1)

return tour_len
return -tour_len

#######################################
# Functions for downloading dataset
Expand Down Expand Up @@ -166,37 +166,65 @@ def create_dataset(
problem_size,
data_dir):

train_fname = os.path.join(data_dir, 'tsp{}.txt'.format(problem_size))
val_fname = os.path.join(data_dir, 'tsp{}_test.txt'.format(problem_size))

if not os.path.isdir(data_dir):
os.mkdir(data_dir)
else:
if os.path.exists(train_fname) and os.path.exists(val_fname):
return train_fname, val_fname
def find_or_return_empty(data_dir, problem_size):
#train_fname1 = os.path.join(data_dir, 'tsp{}.txt'.format(problem_size))
val_fname1 = os.path.join(data_dir, 'tsp{}_test.txt'.format(problem_size))
#train_fname2 = os.path.join(data_dir, 'tsp-{}.txt'.format(problem_size))
val_fname2 = os.path.join(data_dir, 'tsp-{}_test.txt'.format(problem_size))

if not os.path.isdir(data_dir):
os.mkdir(data_dir)
else:
# if os.path.exists(train_fname1) and os.path.exists(val_fname1):
# return train_fname1, val_fname1
# if os.path.exists(train_fname2) and os.path.exists(val_fname2):
# return train_fname2, val_fname2
# return None, None

# train, val = find_or_return_empty(data_dir, problem_size)
# if train is None and val is None:
# download_google_drive_file(data_dir,
# 'tsp', '', problem_size)
# train, val = find_or_return_empty(data_dir, problem_size)

# return train, val
if os.path.exists(val_fname1):
return val_fname1
if os.path.exists(val_fname2):
return val_fname2
return None

val = find_or_return_empty(data_dir, problem_size)
if val is None:
download_google_drive_file(data_dir, 'tsp', '', problem_size)
val = find_or_return_empty(data_dir, problem_size)

return val

download_google_drive_file(data_dir,
'tsp', '', problem_size)

return train_fname, val_fname

#######################################
# Dataset
#######################################
class TSPDataset(Dataset):

def __init__(self, dataset_fname):
def __init__(self, dataset_fname=None, train=False, size=50, num_samples=1000000):
super(TSPDataset, self).__init__()

self.data_set = []
with open(dataset_fname, 'r') as dset:
for l in tqdm(dset):
inputs, outputs = l.split(' output ')
sample = torch.zeros(1, )
x = np.array(inputs.split(), dtype=np.float32).reshape([-1, 2]).T
#y.append(np.array(outputs.split(), dtype=np.int32)[:-1]) # skip the last one
if not train:
with open(dataset_fname, 'r') as dset:
for l in tqdm(dset):
inputs, outputs = l.split(' output ')
sample = torch.zeros(1, )
x = np.array(inputs.split(), dtype=np.float32).reshape([-1, 2]).T
#y.append(np.array(outputs.split(), dtype=np.int32)[:-1]) # skip the last one
self.data_set.append(x)
else:
# randomly sample points uniformly from [0, 1]
for l in tqdm(range(num_samples)):
x = torch.FloatTensor(2, size).uniform_(0, 1)
self.data_set.append(x)

self.size = len(self.data_set)

def __len__(self):
Expand All @@ -206,4 +234,4 @@ def __getitem__(self, idx):
return self.data_set[idx]

if __name__ == '__main__':
paths = download_google_drive_file('data', 'tsp', '', '5')
paths = download_google_drive_file('data/tsp', 'tsp', '', '50')

0 comments on commit e4dcec8

Please sign in to comment.