X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?a=blobdiff_plain;f=tasks.py;h=a3d47f54451464470bd9d37710bda4f42c1ab4ce;hb=c9dbc3abf436df8af1379d04ab51159e821496f1;hp=c5418b4bb616386d8f34e038ff96460dfafff585;hpb=e781d77071fa26f393f50451f91c70f4a0850ca5;p=picoclvr.git diff --git a/tasks.py b/tasks.py index c5418b4..a3d47f5 100755 --- a/tasks.py +++ b/tasks.py @@ -1021,6 +1021,124 @@ class Stack(Task): ############################################################## +###################################################################### + +import rpl + + +class RPL(Task): + def tensorize(self, sequences): + len_max = max([len(x) for x in sequences]) + return torch.cat( + [ + torch.tensor( + [ + [ + self.token2id[str(c)] + for c in s + [""] * (len_max - len(s)) + ] + for s in sequences + ] + ) + ], + 0, + ).to(self.device) + + def __init__( + self, + nb_train_samples, + nb_test_samples, + batch_size, + device=torch.device("cpu"), + ): + super().__init__() + + self.batch_size = batch_size + self.device = device + + train_sequences = [ + rpl.generate() + for _ in tqdm.tqdm(range(nb_train_samples), desc="train-data") + ] + test_sequences = [ + rpl.generate() for _ in tqdm.tqdm(range(nb_test_samples), desc="test-data") + ] + + symbols = list( + set([""] + [x for l in train_sequences + test_sequences for x in l]) + ) + val_max = max([x if type(x) is int else 0 for x in symbols]) + symbols = list(filter(lambda x: type(x) is str, symbols)) + symbols.sort() + symbols += [str(n) for n in range(val_max + 1)] + print(f"{val_max=}") + self.token2id = dict([(c, n) for n, c in enumerate(symbols)]) + self.id2token = dict([(n, c) for c, n in self.token2id.items()]) + + self.t_nul, self.t_prog = self.token2id[""], self.token2id[""] + + self.train_input = self.tensorize(train_sequences) + self.test_input = self.tensorize(test_sequences) + + self.nb_codes = max(self.train_input.max(), self.test_input.max()) + 1 + + def batches(self, split="train", nb_to_use=-1, desc=None): + assert split in {"train", "test"} + input = self.train_input if split == "train" else self.test_input + if nb_to_use > 0: + input = input[:nb_to_use] + if desc is None: + desc = f"epoch-{split}" + for batch in tqdm.tqdm( + input.split(self.batch_size), dynamic_ncols=True, desc=desc + ): + last = (batch != self.t_nul).max(0).values.nonzero().max() + 3 + batch = batch[:, :last] + yield batch + + def vocabulary_size(self): + return self.nb_codes + + def produce_results( + self, n_epoch, model, result_dir, logger, deterministic_synthesis + ): + def compute_nb_errors(input, nb_to_log=0): + result = input.clone() + s = (result == self.t_prog).long() + ar_mask = (s.cumsum(dim=1) - s).clamp(min=0, max=1) + result = (1 - ar_mask) * result + ar_mask * self.t_nul + + masked_inplace_autoregression( + model, + self.batch_size, + result, + ar_mask, + deterministic_synthesis, + device=self.device, + ) + + if nb_to_log > 0: + for x in result[:nb_to_log]: + s = " ".join([self.id2token[i.item()] for i in x]) + logger(f"check {n_epoch} {s}") + nb_to_log -= min(nb_to_log, result.size(0)) + + sum_nb_total, sum_nb_errors = 0, 0 + for x in result: + seq = [self.id2token[i.item()] for i in x] + nb_total, nb_errors = rpl.check(seq) + sum_nb_total += nb_total + sum_nb_errors += nb_errors + + return sum_nb_total, sum_nb_errors + + test_nb_total, test_nb_errors = compute_nb_errors(self.test_input, nb_to_log=10) + + logger( + f"accuracy_test {n_epoch} nb_total {test_nb_total} nb_errors {test_nb_errors} accuracy {100.0*(1-test_nb_errors/test_nb_total):.02f}%" + ) + + ######################################################################