| import torch |
| import numpy as np |
|
|
| all_tasks = ["assoc_recall", "assoc_recall_mk", "binary_copy", "binary_encode", "binary_recall", "binary_recall_mix", "binary_recall_last",\ |
| "binary_recall_rep", "median_last", "parity", "read_write", "sparse_parity", "threshold", "var_copy"] |
|
|
| def set_task_specific_parameters(args): |
| assert args.task_name in all_tasks, "Task not in list of all implemented tasks" |
| |
| if args.task_name == "assoc_recall": |
| args.num_numbers = 0 |
| args.vocab_size = args.num_vocab + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_vocab) |
|
|
| if args.task_name == "assoc_recall_mk": |
| print("Shifting the number of vocab to hits are as frequent") |
| args.size_query = 2 |
| args.num_vocab = int(1 + args.num_vocab ** (1./args.size_query)) |
| args.vocab_size = args.num_vocab + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_vocab) |
| print("Current query length:", args.size_query) |
|
|
| if args.task_name == "binary_copy": |
| args.vocab_size = 2 + args.num_vocab + 1 |
| args.data_name = "data_%d_%d_%d" % (args.sequence_len, args.num_vocab) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "binary_encode": |
| args.vocab_size = 2 ** args.num_bits + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_bits) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "binary_recall": |
| args.vocab_size = 2 + 2 ** args.num_bits + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_bits) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "binary_recall_mix": |
| args.vocab_size = 2 + 2 ** args.num_bits + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_bits) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "binary_recall_last": |
| args.vocab_size = 2 + 2 ** args.num_bits + 1 |
| args.data_name = "data_%d_%d.pt" % (args.sequence_len, args.num_bits) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "binary_recall_rep": |
| args.vocab_size = 2 + 2 ** args.num_bits + 1 |
| args.data_name = "data_%d_%d.pt" % (args.sequence_len, args.num_bits) |
| print("Using %d bits" % args.num_bits) |
|
|
| if args.task_name == "median_last": |
| assert args.num_numbers % 2 == 1 |
| |
| args.vocab_size = args.num_numbers + 1 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_numbers) |
|
|
| if args.task_name == "parity": |
| args.vocab_size = 2 + 1 |
| args.data_name = "data_%d" % (args.sequence_len,) |
|
|
| if args.task_name == "read_write": |
| args.num_numbers = 0 |
| args.vocab_size = args.num_vocab + 3 |
| args.data_name = "data_%d_%d" % (args.sequence_len, args.num_vocab) |
|
|
| if args.task_name == "sparse_parity": |
| args.vocab_size = 2 + 1 |
| args.data_name = "data_%d" % (args.sequence_len,) |
|
|
| if args.task_name == "threshold": |
| args.vocab_size = 2 + args.num_numbers + args.num_vocab + 1 |
| args.data_name = "data_%d_%d_%d" % (args.sequence_len, args.num_numbers, args.num_vocab) |
|
|
| if args.task_name == "var_copy": |
| args.min_num_token = 5 |
| |
| args.vocab_size = args.min_num_token + args.num_numbers + args.num_vocab + 1 |
| args.data_name = "data_%d_%d_%d" % (args.sequence_len, args.num_numbers, args.num_vocab) |
|
|
|
|
|
|
| def generate_seq(args, ood=False): |
| if args.task_name == "assoc_recall": |
| seq_in = torch.randint(0, args.num_vocab, (args.sequence_len,)) |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) - 1 |
| |
| lookup = {} |
| for i in range(1, args.sequence_len): |
| lookup[seq_in[i-1].item()] = seq_in[i].item() |
| if seq_in[i].item() in lookup.keys(): |
| seq_out[i] = lookup[seq_in[i].item()] |
| |
| if args.task_name == "assoc_recall_mk": |
| seq_in = torch.randint(0, args.num_vocab, (args.sequence_len,)) |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) - 1 |
| |
| lookup = {} |
| for i in range(args.size_query, args.sequence_len): |
| key = tuple(seq_in[i-args.size_query:i].tolist()) |
| lookup[key] = seq_in[i].item() |
|
|
| key = tuple(seq_in[i-args.size_query+1:i+1].tolist()) |
| if key in lookup.keys(): |
| seq_out[i] = lookup[key] |
| |
| if args.task_name == "binary_copy": |
| seq_in = torch.randint(2, 2 + args.num_vocab, (args.sequence_len,)) |
| seq_in[torch.multinomial(torch.tensor([1-args.p, args.p]), args.sequence_len, replacement=True).to(torch.bool)] = 0 |
| seq_in[torch.multinomial(torch.tensor([1-args.p, args.p]), args.sequence_len, replacement=True).to(torch.bool)] = 1 |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) - 1 |
| s = 0 |
| for i in range(args.sequence_len): |
| if seq_in[i] in [0, 1]: |
| s = (2*s + seq_in[i]) % (2 ** args.num_bits) |
|
|
| if i-s >= 0: |
| seq_out[i] = seq_in[i-s] |
| |
| if args.task_name == "binary_encode": |
| seq_in = torch.randint(0, 2, (args.sequence_len,)) |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) |
| s = 0 |
| for i in range(args.sequence_len): |
| s = (2*s + seq_in[i]) % (2 ** args.num_bits) |
| seq_out[i] = s |
| |
| if args.task_name == "binary_recall": |
| seq_in = torch.randint(2, 2 + 2 ** args.num_bits, (args.sequence_len,)) |
| |
| seq_in[torch.multinomial(torch.tensor([1-args.p, args.p]), args.sequence_len, replacement=True).to(torch.bool)] = 0 |
| seq_in[torch.multinomial(torch.tensor([1-args.p, args.p]), args.sequence_len, replacement=True).to(torch.bool)] = 1 |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| assoc = {i: -1 for i in range(2, 2 + 2**args.num_bits)} |
| s = 0 |
| for i in range(args.length): |
| if seq_in[i] in [0, 1]: |
| s = (2*s + seq_in[i].item()) % (2**args.num_bits) |
|
|
| if i >= 1 and 2 <= seq_in[i-1] and seq_in[i-1] < 2 + 2**args.num_bits: |
| assoc[seq_in[i-1].item()] = seq_in[i] |
|
|
| seq_out[i] = assoc[s+2] |
| |
| if args.task_name == "binary_recall_mix": |
| target = torch.randint(0, 2 ** args.num_bits, (1,)).item() |
| |
| seq_in = torch.randint(2, 2 + (2 ** args.num_bits), (args.sequence_len,)) |
| temp = target |
|
|
| bit_positions = np.random.randint(0, 2 ** args.num_bits - args.num_bits // 2, args.num_bits // 2).tolist() |
| bit_positions += list(range(args.sequence_len-1, args.sequence_len-1-args.num_bits // 2, -1)) |
| bit_positions.sort() |
| |
| for i in bit_positions: |
| seq_in[i] = temp % 2 |
| temp = temp // 2 |
| |
| assoc = {i: 0 for i in range(2 + 2 ** args.num_bits)} |
| for i in range(1,args.sequence_len-args.num_bits): |
| assoc[seq_in[i-1].item()] = seq_in[i] |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| seq_out[-1] = assoc[2 + target] |
| |
| if args.task_name == "binary_recall_last": |
| target = torch.randint(0, 2 ** args.num_bits, (1,)).item() |
| |
| seq_in = torch.randint(2, 2 + (2 ** args.num_bits), (args.sequence_len,)) |
| temp = target |
| for i in range(args.sequence_len-1, args.sequence_len-1-args.num_bits, -1): |
| seq_in[i] = temp % 2 |
| temp = temp // 2 |
| |
| assoc = {i: 0 for i in range(2 + 2 ** args.num_bits)} |
| for i in range(1,args.sequence_len-args.num_bits): |
| assoc[seq_in[i-1].item()] = seq_in[i] |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| seq_out[-1] = assoc[2 + target] |
|
|
| if args.task_name == "binary_recall_rep": |
| target = torch.randint(0, 2 ** args.num_bits, (1,)).item() |
|
|
| repeat_length = torch.randint(4, 10, (1,)).item() |
| seq_in = torch.randint(2, 2 + (2 ** args.num_bits), (repeat_length,)) |
| seq_in = seq_in.repeat(int(args.sequence_len / repeat_length) + 1)[:args.sequence_len] |
| |
| temp = target |
| for i in range(args.sequence_len-1, args.sequence_len-1-args.num_bits, -1): |
| seq_in[i] = temp % 2 |
| temp = temp // 2 |
| |
| assoc = {i: 0 for i in range(2 + 2 ** args.num_bits)} |
| for i in range(1,args.sequence_len-args.num_bits): |
| assoc[seq_in[i-1].item()] = seq_in[i] |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| seq_out[-1] = assoc[2 + target] |
| |
| if args.task_name == "median_last": |
| seq_in = torch.randint(0, args.num_numbers, (args.sequence_len,)) |
| seq_in[-1] = 1 |
| |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| seq_out[-1] = torch.median(seq_in[-args.num_numbers-1:-2]) |
| |
| if args.task_name == "parity": |
| seq_in = torch.multinomial(torch.Tensor([0.5, 0.5]), args.sequence_len, replacement=True) |
| seq_in[0] = 0 |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) |
| |
| for i in range(1, args.sequence_len): |
| seq_out[i] = (seq_out[i-1] + seq_in[i]) % 2 |
|
|
| if args.task_name == "read_write": |
| |
| |
| |
| seq_in = torch.randint(0, args.num_vocab, (args.sequence_len+1,)) |
| seq_in[::2] = torch.multinomial(torch.Tensor([0.1, 0.1, 0.8]), args.sequence_len // 2 + 1, replacement=True).to(torch.int32) - 3 |
| |
| lookup = {} |
| for i in range(0, args.sequence_len, 2): |
| if seq_in[i].item() == -2: |
| lookup[i] = seq_in[i+1].item() |
| elif seq_in[i].item() == -3: |
| if i in lookup.keys(): |
| seq_in[i+1] = lookup[i] |
| |
| |
| seq_out = seq_in[1:] |
| seq_in = seq_in[:-1] |
| |
| if args.task_name == "sparse_parity": |
| seq_in = torch.multinomial(torch.Tensor([1-args.p, args.p]), args.sequence_len, replacement=True) |
| seq_in[0] = 0 |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) |
| |
| for i in range(1, args.sequence_len): |
| seq_out[i] = (seq_out[i-1] + seq_in[i]) % 2 |
| |
| if args.task_name == "threshold": |
| threshold = args.num_numbers / args.p |
| |
| seq_in = torch.zeros(args.sequence_len, dtype=torch.int32) |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
| |
| lookup = {} |
| s = 0 |
| for i in range(args.length): |
| if torch.rand((1,)) > args.p: |
| |
| seq_in[i] = torch.randint(args.num_numbers+2, args.num_numbers+args.num_vocab+2, (1,)) |
| else: |
| |
| num = torch.randint(0, args.num_numbers, (1,)) |
| seq_in[i] = num + 2 |
| s += num |
| |
| if s < threshold: |
| seq_out[i] = 0 |
| else: |
| seq_out[i] = 1 |
| |
| if args.task_name == "var_copy": |
| vocab = torch.randint(args.min_num_token+args.num_numbers, args.min_num_token+args.num_numbers+args.num_vocab, (args.sequence_len,), dtype=torch.int32) |
| numbers = torch.randint(args.min_num_token, args.min_num_token+args.num_numbers, (args.sequence_len,), dtype=torch.int32) |
| mask = torch.rand_like(vocab, dtype=torch.float) < args.p |
|
|
| seq_in = torch.where(mask, numbers, vocab) |
| seq_out = torch.zeros(args.sequence_len, dtype=torch.int32) -1 |
|
|
| number_seq = [(i, v) for i, v in enumerate(seq_in) if args.min_num_token <= v and v < args.min_num_token+args.num_numbers] |
| for i in range(len(number_seq)-1): |
| this_i = number_seq[i][0] |
| this_v = number_seq[i][1] |
| next_i = number_seq[i+1][0] |
| next_v = number_seq[i+1][1] |
|
|
| if next_i-this_v > 0: |
| if this_i-this_v >= 0: |
| seq_out[this_i:next_i] = seq_in[this_i-this_v:next_i-this_v] |
| else: |
| seq_out[this_v:next_i] = seq_in[:next_i-this_v] |
|
|
| if len(number_seq) > 0: |
| this_i = number_seq[-1][0] |
| this_v = number_seq[-1][1] |
|
|
| if this_i-this_v >= 0: |
| seq_out[this_i:] = seq_in[this_i-this_v:-this_v] |
| else: |
| seq_out[this_v:] = seq_in[:-this_v] |
|
|
| return seq_in, seq_out |
|
|
|
|
| def generate_data(args, all_at_once=True): |
| sequences_in = [] |
| sequences_out = [] |
|
|
| if all_at_once: |
| print("Generating Data") |
| for i in range(args.batch_size * args.batches_per_epoch): |
| if i % 8000 == 0: |
| print("- Sequence Num:", i) |
| seq_in, seq_out = generate_seq(args) |
| |
| sequences_in.append(seq_in) |
| sequences_out.append(seq_out) |
| else: |
| for i in range(args.batch_size): |
| seq_in, seq_out = generate_seq(args) |
| |
| sequences_in.append(seq_in) |
| sequences_out.append(seq_out) |
|
|
| x_in = torch.stack(sequences_in) |
| x_out = torch.stack(sequences_out) |
|
|
| |
| x_in = (x_in + args.vocab_size) % args.vocab_size |
| x_out = (x_out + args.vocab_size) % args.vocab_size |
|
|
| return x_in, x_out |