コード例 #1
0
ファイル: logistic_regression.py プロジェクト: acad2/pypuf
    def learn(self,
              init_weight_array=None,
              eta_minus=0.5,
              eta_plus=1.2,
              refresh_updater=True):
        """
        Compute a model according to the given LTF Array parameters and training set.
        Note that this function can take long to return.
        :return: pypuf.simulation.arbiter_based.LTFArray
                 The computed model.
        """

        # log format
        def log_state():
            """
            This method is used to log a snapshot of learning variables while running.
            """
            if self.logger is None:
                return
            self.logger.debug('%i\t%f\t%f\t%s' % (
                self.iteration_count,
                distance,
                norm(self.updater.step),
                ','.join(map(str, model.weight_array.flatten())),
            ))

        # let numpy raise exceptions
        seterr(all='raise')

        # Prepare challenges
        self.efba_sub_challenges = LTFArray.efba_bit(
            self.transformation(self.training_set.challenges, self.k))

        # we start with a random model
        model = LTFArray(
            weight_array=LTFArray.normal_weights(self.n, self.k,
                                                 self.weights_mu,
                                                 self.weights_sigma,
                                                 self.weights_prng),
            transform=self.transformation,
            combiner=self.combiner,
            bias=0.0,
        )

        if init_weight_array is not None:
            model.weight_array = init_weight_array

        if refresh_updater:
            self.updater = self.RPropModelUpdate(model,
                                                 eta_minus=eta_minus,
                                                 eta_plus=eta_plus)
        converged = False
        distance = 1
        self.iteration_count = 0
        log_state()
        number_of_batches = (self.training_set.N + 1) // self.minibatch_size
        efba_challenge_batches = []
        response_batches = []
        if not self.shuffle:
            efba_challenge_batches = array_split(self.efba_sub_challenges,
                                                 number_of_batches)
            response_batches = array_split(self.training_set.responses,
                                           number_of_batches)
        while not converged and self.iteration_count < self.iteration_limit:
            self.iteration_count += 1
            self.epoch_count += 1

            if self.shuffle:
                if self.epoch_count > 1:
                    RandomState(seed=self.epoch_count).shuffle(
                        self.efba_sub_challenges)
                    RandomState(seed=self.epoch_count).shuffle(
                        self.training_set.responses)
                efba_challenge_batches = array_split(self.efba_sub_challenges,
                                                     number_of_batches)
                response_batches = array_split(self.training_set.responses,
                                               number_of_batches)

            # compute gradient & update model
            for batch in range(number_of_batches):
                gradient = self.gradient(model, efba_challenge_batches[batch],
                                         response_batches[batch])
                model.weight_array += self.updater.update(gradient)
                self.gradient_step_count += 1

                # check convergence
                converged = norm(
                    self.updater.step) < 10**-self.convergence_decimals

                # log
                log_state()

                if converged:
                    break

        if not converged:
            self.converged = False
        else:
            self.converged = True

        return model
コード例 #2
0
    def learn(self, init_weight_array=None, eta_minus=0.5, eta_plus=1.2, refresh_updater=True):
        """
        Compute a model according to the given LTF Array parameters and training set.
        Note that this function can take long to return.
        :return: pypuf.simulation.arbiter_based.LTFArray
                 The computed model.
        """
        self.logger.debug('LR learner started')
        test_set_accuracies = []

        # log format
        def log_state(step_size):
            """
            This method is used to log a snapshot of learning variables while running.
            """
            if self.logger is None:
                return
            self.logger.debug(
                '%i\t%s\t%f\t%f\t%f\t%s' % (
                    self.iteration_count,
                    f'{self.test_set_dist:.4f}' if self.test_set else '<no test set given>',
                    self.training_set_dist_sign,
                    self.training_set_dist,
                    step_size,
                    ','.join(map(str, model.weight_array.flatten())) if self.n <= 1024 else '<weight array too large>',
                )
            )

        # let numpy raise exceptions
        seterr(all='raise')

        # Prepare challenges
        self.logger.debug(f'Challenge bit type {self.training_set.challenges.dtype}')
        self.logger.debug(f'Transforming {len(self.training_set.challenges)} given {self.n}-bit '
                          f'challenges using {self.transformation.__name__} for k={self.k} ...')
        transformed_challenges = self.transformation(self.training_set.challenges, self.k)
        if self.bias:
            self.logger.debug(f'Efba\'ing {len(self.training_set.challenges)} given {self.n}-bit challenges')
            self.efba_sub_challenges = LTFArray.efba_bit(transformed_challenges)
        else:
            self.logger.debug(f'Not efba\'ing {len(self.training_set.challenges)} challenges, assuming unbiased target')
            self.efba_sub_challenges = transformed_challenges

        # we start with a random model
        self.logger.debug(f'Initializing random unbiased model')
        model = LTFArray(
            weight_array=LTFArray.normal_weights(self.n, self.k, self.weights_mu, self.weights_sigma,
                                                 self.weights_prng),
            transform=self.transformation,
            combiner=self.combiner,
            bias=0.0,
        )

        if init_weight_array is not None:
            model.weight_array = init_weight_array

        if refresh_updater:
            self.updater = self.RPropModelUpdate(model, bias=self.bias, eta_minus=eta_minus, eta_plus=eta_plus)
        converged = False
        self.iteration_count = 0
        log_state(0)
        number_of_batches = ceil(self.training_set.N / (self.minibatch_size or self.training_set.N))
        self.logger.debug(f'using {self.training_set.N} examples with batches of size '
                          f'{self.minibatch_size}, i.e. {number_of_batches} batches')
        efba_challenge_batches = []
        response_batches = []
        if not self.shuffle:
            efba_challenge_batches = array_split(self.efba_sub_challenges, number_of_batches)
            response_batches = array_split(self.training_set.responses, number_of_batches)

        self.logger.debug(f'Starting learning loop!')
        self.logger.debug(f'stopping when step size smaller than {10**-self.convergence_decimals} or '
                          f'{self.iteration_limit} epochs')
        while not converged and self.iteration_count < self.iteration_limit:
            self.iteration_count += 1
            self.epoch_count += 1

            if self.shuffle:
                if self.epoch_count > 1:
                    RandomState(seed=self.epoch_count).shuffle(self.efba_sub_challenges)
                    RandomState(seed=self.epoch_count).shuffle(self.training_set.responses)
                efba_challenge_batches = array_split(self.efba_sub_challenges, number_of_batches)
                response_batches = array_split(self.training_set.responses, number_of_batches)

            # compute gradient & update model
            for batch in range(number_of_batches):
                gradient = self.gradient(model, efba_challenge_batches[batch], response_batches[batch])
                if self.bias:
                    model.weight_array += self.updater.update(gradient)
                else:
                    model.weight_array[:, :-1] += self.updater.update(gradient)
                self.gradient_step_count += 1

                # check convergence
                current_step_size = norm(self.updater.step)
                if self.test_set and self.test_set.N:
                    self.test_set_dist = approx_dist_nonrandom(model, self.test_set)
                    test_set_accuracies.append(1 - self.test_set_dist)
                converged = (
                    current_step_size < 10**-self.convergence_decimals
                    or (self.target_test_accuracy and 1 - self.test_set_dist > self.target_test_accuracy)
                    or (
                        self.test_accuracy_improvement
                        and self.test_accuracy_patience
                        and len(test_set_accuracies) >= self.test_accuracy_patience
                        and (
                            abs(
                                min(test_set_accuracies[-self.test_accuracy_patience:])
                                - max(test_set_accuracies[-self.test_accuracy_patience:])
                            ) < self.test_accuracy_improvement
                        )
                    )
                ) and (
                    self.iteration_count > self.min_iterations
                )

                # log
                log_state(current_step_size)

                if converged:
                    break

        self.efba_sub_challenges = None  # del ref to training set memory to allow GC if the t-set is also dereferenced
        self.converged = converged
        return model
コード例 #3
0
    def __init__(self,
                 n,
                 k,
                 training_set,
                 validation_set,
                 weights_mu=0,
                 weights_sigma=1,
                 weights_prng=RandomState(),
                 lr_iteration_limit=1000,
                 mini_batch_size=0,
                 convergence_decimals=2,
                 shuffle=False,
                 logger=None):
        """
        Initialize a Correlation Attack Learner for the specified LTF Array which uses transform_lightweight_secure.

        :param n: Input length
        :param k: Number of parallel LTFs in the LTF Array
        :param training_set: The training set, i.e. a data structure containing challenge response pairs
        :param validation_set: The validation set, i.e. a data structure containing challenge response pairs. Used for
        approximating accuracies of permuted models (can be smaller e.g. 0.1*training_set_size)
        :param weights_mu: mean of the Gaussian that is used to choose the initial model
        :param weights_sigma: standard deviation of the Gaussian that is used to choose the initial model
        :param weights_prng: PRNG to draw the initial model from. Defaults to fresh `numpy.random.RandomState` instance.
        :param lr_iteration_limit: Iteration limit for a single LR learner run
        :param logger: logging.Logger
                       Logger which is used to log detailed information of learn iterations.
        """
        self.n = n
        self.k = k

        self.validation_set_efba = ChallengeResponseSet(
            challenges=LTFArray.efba_bit(
                LTFArray.transform_lightweight_secure(
                    validation_set.challenges, k)),
            responses=validation_set.responses)

        self.logger = logger

        self.lr_learner = LogisticRegression(
            t_set=training_set,
            n=n,
            k=k,
            transformation=LTFArray.transform_lightweight_secure,
            combiner=LTFArray.combiner_xor,
            weights_mu=weights_mu,
            weights_sigma=weights_sigma,
            weights_prng=weights_prng,
            logger=logger,
            iteration_limit=lr_iteration_limit,
            minibatch_size=mini_batch_size,
            convergence_decimals=convergence_decimals,
            shuffle=shuffle)

        self.initial_accuracy = .5
        self.initial_lr_iterations = 0
        self.initial_model = None
        self.total_lr_iterations = 0
        self.best_permutation_iteration = 0
        self.total_permutation_iterations = 0
        self.best_permutation = None
        self.best_accuracy = None

        assert n in (
            64, 128
        ), 'Correlation attack for %i bit is currently not supported.' % n
        assert validation_set.N >= 1000, 'Validation set should contain at least 1000 challenges.'

        self.correlation_permutations = loadmat(
            'data/correlation_permutations_lightweight_secure_%i_10.mat' %
            n)['shiftOverviewData'][:, :, 0].astype('int64')