Example #1
0
def normalize_cmaf(cmaf,
                   f_accept,
                   xs,
                   n_samples=10,
                   seed=None,
                   val_frac=0.1,
                   minibatch=100,
                   epochs=200,
                   verbose=False,
                   stop_on_nan=False):
    from snl.ml.models.mafs import ConditionalMaskedAutoregressiveFlow
    assert isinstance(cmaf, ConditionalMaskedAutoregressiveFlow)

    # first, sample from the existing MAF and apply our acceptance criterion
    xs = np.repeat(xs, n_samples, axis=0)
    thetas = np.full(xs.shape, np.nan)
    rng = np.random.randomstate(seed=seed)

    jj = 0  # index into final array of thetas
    for i, x in enumerate(xs):
        n_accepted = 0
        while n_accepted < n_samples:
            next_thetas = \
                cmaf.gen(x=x, n_samples=n_samples - n_accepted, rng=rng)
            for theta in next_thetas:
                if not f_accept(theta):
                    continue
                thetas[jj, :] = theta
                n_accepted += 1
                jj += 1

    # create a new MAF
    newrng = np.random.RandomState(seed=seed)
    cmaf_new = ConditionalMaskedAutoregressiveFlow(
        n_inputs=cmaf.n_inputs,
        n_outputs=cmaf.n_outputs,
        n_hiddens=cmaf.n_hiddens,
        act_fun=cmaf.act_fun,
        n_mades=cmaf.n_mades,
        batch_norm=cmaf.batch_norm,
        mode=cmaf.mode,
        input=None,  # is this ok?
        output=None,  # is this ok?
        rng=newrng,
        output_order=cmaf.output_order)  # hope this is ok?

    # train network by directly maximizing q(\theta | x)
    loss, trn_inputs = snpe_loss_prior_as_proposal(cmaf, svi=False)
    trn_data = (thetas, xs)

    t = Trainer(network=cmaf,
                loss=loss,
                trn_data=trn_data,
                trn_inputs=trn_inputs,
                seed=seed + 5)
    log = t.train(epochs=epochs,
                  minibatch=minibatch,
                  verbose=verbose,
                  stop_on_nan=stop_on_nan,
                  val_frac=val_frac)
Example #2
0
def test_trainer_updates():
    n_components = 1
    n_params = 2
    seed = 42
    svi = True

    m = Gauss(dim=n_params)
    p = dd.Gaussian(m=np.zeros((n_params, )), S=np.eye(n_params))
    s = ds.Identity()
    g = dg.Default(model=m, prior=p, summary=s)

    nn = NeuralNet(
        n_components=n_components,
        n_hiddens=[10],
        n_inputs=n_params,
        n_outputs=n_params,
        seed=seed,
        svi=svi)
    loss = -tt.mean(nn.lprobs)

    trn_inputs = [nn.params, nn.stats]
    trn_data = g.gen(100)  # params, stats
    trn_data = tuple(x.astype(dtype) for x in trn_data)

    t = Trainer(network=nn, loss=loss, trn_data=trn_data, trn_inputs=trn_inputs)

    # single update
    outputs = t.make_update(*trn_data)

    # training
    outputs = t.train(100, 50)
Example #3
0
    def run_MoG(self,
                n_train=100,
                epochs=100,
                minibatch=50,
                n_atoms=None,
                moo=None,
                train_on_all=False,
                round_cl=1,
                stop_on_nan=False,
                monitor=None,
                verbose=False,
                print_each_epoch=False,
                reuse_prior_samples=True,
                **kwargs):
        assert not train_on_all, "train_on_all is not yet implemented for MoG "\
                "proposals"

        # simulate data
        self.set_proposal(project_to_gaussian=False)
        prop = self.generator.proposal
        assert isinstance(prop, dd.MoG)
        trn_data, n_train_round = self.gen(n_train)

        # here we're just repeating the same fixed proposal, though we
        # could also introduce some variety if we wanted.
        nc = prop.n_components
        prop_Pms = repnewax(np.stack([x.Pm for x in prop.xs], axis=0),
                            n_train_round)
        prop_Ps = repnewax(np.stack([x.P for x in prop.xs], axis=0),
                           n_train_round)
        prop_ldetPs = repnewax(np.stack([x.logdetP for x in prop.xs], axis=0),
                               n_train_round)
        prop_las = repnewax(np.log(prop.a), n_train_round)
        prop_QFs = \
            repnewax(np.stack([np.sum(x.Pm * x.m) for x in prop.xs], axis=0),
                     n_train_round)

        trn_data += (prop_Pms, prop_Ps, prop_ldetPs, prop_las, prop_QFs)
        trn_data = tuple(trn_data)

        self.loss, trn_inputs = self.define_loss(n=n_train_round,
                                                 round_cl=round_cl,
                                                 proposal='mog')
        t = Trainer(self.network,
                    self.loss,
                    trn_data=trn_data,
                    trn_inputs=trn_inputs,
                    seed=self.gen_newseed(),
                    monitor=self.monitor_dict_from_names(monitor),
                    **kwargs)

        log = t.train(epochs=self.epochs_round(epochs),
                      minibatch=minibatch,
                      verbose=verbose,
                      print_each_epoch=print_each_epoch,
                      stop_on_nan=stop_on_nan)

        return log, trn_data
Example #4
0
    def run_prior(self,
                  n_train=100,
                  epochs=100,
                  minibatch=50,
                  n_atoms=None,
                  moo=None,
                  train_on_all=False,
                  round_cl=1,
                  stop_on_nan=False,
                  monitor=None,
                  verbose=False,
                  print_each_epoch=False,
                  patience=20,
                  monitor_every=None,
                  reuse_prior_samples=True,
                  **kwargs):

        # simulate data
        self.generator.proposal = self.generator.prior
        trn_data, n_train_round = self.gen(n_train)
        self.trn_datasets.append(trn_data)

        if train_on_all and reuse_prior_samples:
            prior_datasets = [
                d for i, d in enumerate(self.trn_datasets)
                if self.proposal_used[i] == 'prior'
            ]
            trn_data = combine_trn_datasets(prior_datasets)
            n_train_round = trn_data[0].shape[0]

        # train network
        self.loss, trn_inputs = self.define_loss(n=n_train_round,
                                                 round_cl=round_cl,
                                                 proposal='prior')
        t = Trainer(self.network,
                    self.loss,
                    trn_data=trn_data,
                    trn_inputs=trn_inputs,
                    seed=self.gen_newseed(),
                    monitor=self.monitor_dict_from_names(monitor),
                    **kwargs)
        log = t.train(epochs=self.epochs_round(epochs),
                      minibatch=minibatch,
                      verbose=verbose,
                      print_each_epoch=print_each_epoch,
                      stop_on_nan=stop_on_nan,
                      patience=patience,
                      monitor_every=monitor_every)

        return log, trn_data
Example #5
0
    def run(self,
            n_train=100,
            epochs=100,
            minibatch=50,
            monitor=None,
            **kwargs):
        """Run algorithm

        Generate training data using the generator. Set up the Trainer with a
        neural net, a loss function and the generated training data. Train the
        network with the specified training arguments.

        Parameters
        ----------
        n_train : int
            Number of training samples
        epochs : int
            Number of epochs used for neural network training
        minibatch : int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        log: dict
            dict containing the loss values as returned by Trainer.train()
        trn_data : (params, stats)
            training dataset, z-transformed
        """
        trn_data = self.gen(n_train, verbose=self.verbose)  # z-transformed
        trn_inputs = [self.network.params, self.network.stats]

        t = Trainer(self.network,
                    self.loss(N=n_train),
                    trn_data=trn_data,
                    trn_inputs=trn_inputs,
                    monitor=self.monitor_dict_from_names(monitor),
                    seed=self.gen_newseed(),
                    **kwargs)
        log = t.train(epochs=epochs, minibatch=minibatch, verbose=self.verbose)

        return log, trn_data
Example #6
0
    def run(self, n_train=100, n_rounds=2, epochs=100, minibatch=50,
            monitor=None, **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs: int
            Number of epochs used for neural network training
        minibatch: int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of posteriors
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        for r in range(n_rounds):  # start at 1
            self.round += 1

            # if round > 1, set new proposal distribution before sampling
            if self.round > 1:
                # posterior becomes new proposal prior
                posterior = self.predict(self.obs)
                self.generator.proposal = posterior.project_to_gaussian()
            # number of training examples for this round
            if type(n_train) == list:
                try:
                    n_train_round = n_train[self.round - 1]
                except:
                    n_train_round = n_train[-1]
            else:
                n_train_round = n_train

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(r) if self.verbose else False
            trn_data = self.gen(n_train_round, verbose=verbose)

            # algorithm 2 of Papamakarios and Murray
            if r + 1 == n_rounds and self.n_components > 1:
                # get parameters of current network
                old_params = self.network.params_dict.copy()

                # create new network
                network_spec = self.network.spec_dict.copy()
                network_spec.update({'n_components': self.n_components})
                self.network = NeuralNet(**network_spec)
                new_params = self.network.params_dict

                """In order to go from 1 component in previous rounds to
                self.n_components in the current round we will duplicate
                component 1 self.n_components times, with small random
                perturbations to the parameters affecting component means
                and precisions, and the SVI s.d.s of those parameters. Set the
                mixture coefficients to all be equal"""
                mp_param_names = [s for s in new_params if 'means' in s or \
                    'precisions' in s]  # list of dict keys
                for param_name in mp_param_names:
                    """for each param_name, get the corresponding old parameter
                    name/value for what was previously the only mixture
                    component"""
                    source_param_name = param_name[:-1] + '0'
                    source_param_val = old_params[source_param_name]
                    # copy it to the new component, add noise to break symmetry
                    old_params[param_name] = source_param_val.copy() + \
                        1.0e-6 * self.rng.randn(*source_param_val.shape)

                # initialize with equal mixture coefficients for all data
                old_params['weights.mW'] = 0. * new_params['weights.mW']
                old_params['weights.mb'] = 0. * new_params['weights.mb']

                self.network.params_dict = old_params

            trn_inputs = [self.network.params, self.network.stats]

            t = Trainer(self.network, self.loss(N=n_train_round),
                        trn_data=trn_data, trn_inputs=trn_inputs,
                        monitor=self.monitor_dict_from_names(monitor),
                        seed=self.gen_newseed(), **kwargs)
            logs.append(t.train(epochs=epochs, minibatch=minibatch,
                                verbose=verbose))

            trn_datasets.append(trn_data)
            try:
                posteriors.append(self.predict(self.obs))
            except:
                posteriors.append(None)
                print('analytic correction for proposal seemingly failed!')
                break

        return logs, trn_datasets, posteriors
Example #7
0
    def run(self,
            n_train=100,
            n_rounds=2,
            epochs=100,
            minibatch=50,
            round_cl=1,
            stop_on_nan=False,
            proposal=None,
            monitor=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs : int
            Number of epochs used for neural network training
        minibatch : int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        round_cl : int
            Round after which to start continual learning
        stop_on_nan : bool
            If True, will halt if NaNs in the loss are encountered
        proposal : Distribution of None
            If given, will use this distribution as the starting proposal prior
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of distributions
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        for r in range(n_rounds):
            self.round += 1

            if r == 0 and proposal is not None:
                self.generator.proposal = proposal
            # if round > 1, set new proposal distribution before sampling
            elif self.round > 1:
                # posterior becomes new proposal prior
                proposal = self.predict(self.obs)  # see super

                # convert proposal to student's T?
                if self.convert_to_T is not None:
                    if type(self.convert_to_T) == int:
                        dofs = self.convert_to_T
                    else:
                        dofs = 10
                    proposal = proposal.convert_to_T(dofs=dofs)

                self.generator.proposal = proposal

            # number of training examples for this round
            if type(n_train) == list:
                try:
                    n_train_round = n_train[self.round - 1]
                except:
                    n_train_round = n_train[-1]
            else:
                n_train_round = n_train

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(
                self.round) if self.verbose else False

            trn_data = self.gen(n_train_round,
                                prior_mixin=self.prior_mixin,
                                verbose=verbose)
            n_train_round = trn_data[0].shape[0]

            # precompute importance weights
            if self.generator.proposal is not None:
                params = self.params_std * trn_data[0] + self.params_mean
                p_prior = self.generator.prior.eval(params, log=False)
                p_proposal = self.generator.proposal.eval(params, log=False)
                iws = p_prior / (self.prior_mixin * p_prior +
                                 (1 - self.prior_mixin) * p_proposal)
            else:
                iws = np.ones((n_train_round, ))

            # normalize weights
            iws /= np.mean(iws)

            if self.kernel is not None:
                iws *= self.kernel.eval(trn_data[1].reshape(n_train_round, -1))

            trn_data = (trn_data[0], trn_data[1], iws)
            trn_inputs = [
                self.network.params, self.network.stats, self.network.iws
            ]

            t = Trainer(self.network,
                        self.loss(N=n_train_round, round_cl=round_cl),
                        trn_data=trn_data,
                        trn_inputs=trn_inputs,
                        seed=self.gen_newseed(),
                        monitor=self.monitor_dict_from_names(monitor),
                        **kwargs)
            logs.append(
                t.train(epochs=epochs,
                        minibatch=minibatch,
                        verbose=verbose,
                        stop_on_nan=stop_on_nan))

            trn_datasets.append(trn_data)

            try:
                posteriors.append(self.predict(self.obs))
            except np.linalg.LinAlgError:
                posteriors.append(None)
                print("Cannot predict posterior after round {} due to NaNs".
                      format(r))
                break

        return logs, trn_datasets, posteriors
Example #8
0
    def run(self,
            n_train=100,
            n_rounds=1,
            epochs=100,
            minibatch=50,
            round_cl=1,
            stop_on_nan=False,
            monitor=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs : int
            Number of epochs used for neural network training
        minibatch : int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        round_cl : int
            Round after which to start continual learning
        stop_on_nan : bool
            If True, will halt if NaNs in the loss are encountered
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of distributions
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        for r in range(n_rounds):
            self.round += 1

            # number of training examples for this round
            if type(n_train) == list:
                try:
                    n_train_round = n_train[self.round - 1]
                except:
                    n_train_round = n_train[-1]
            else:
                n_train_round = n_train

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(
                self.round) if self.verbose else False
            trn_data = self.gen(n_train_round, verbose=verbose)
            n_train_round = trn_data[0].shape[0]

            trn_data = (trn_data[0], trn_data[1])
            trn_inputs = [self.network.params, self.network.stats]

            t = Trainer(self.network,
                        self.loss(N=n_train_round, round_cl=round_cl),
                        trn_data=trn_data,
                        trn_inputs=trn_inputs,
                        seed=self.gen_newseed(),
                        monitor=self.monitor_dict_from_names(monitor),
                        **kwargs)
            logs.append(
                t.train(epochs=epochs,
                        minibatch=minibatch,
                        verbose=verbose,
                        stop_on_nan=stop_on_nan))
            trn_datasets.append(trn_data)

            try:
                if self.obs is None:
                    posteriors.append(None)
                else:
                    posteriors.append(self.predict(self.obs))
            except:
                posteriors.append(None)
                print('Posterior inference failed')
                break

        return logs, trn_datasets, posteriors
Example #9
0
    def run(self,
            n_train=100,
            n_rounds=2,
            epochs=100,
            minibatch=50,
            monitor=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs : int
            Number of epochs used for neural network training
        minibatch : int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            Training datasets
        posteriors : list of distributions
            Posterior after each round
        """
        logs = []
        trn_datasets = []
        optim_state = []
        posteriors = []

        if not self.verbose:
            pbar = no_tqdm()
        else:
            pbar = progressbar(total=n_rounds)
            desc = 'Round '
            pbar.set_description(desc)

        with pbar:
            for r in range(n_rounds):
                self.round += 1

                # if round > 1, set new proposal distribution before sampling
                if self.round > 1:
                    # posterior becomes new proposal prior
                    proposal = self.predict(self.obs)  # see super

                    # convert proposal to student's T?
                    if self.convert_to_T is not None:
                        if type(self.convert_to_T) == int:
                            dofs = self.convert_to_T
                        else:
                            dofs = 10
                        proposal = proposal.convert_to_T(dofs=dofs)

                    self.generator.proposal = proposal

                # number of training examples to generate for this round
                if type(n_train) == list:
                    try:
                        n_train_round = n_train[self.round - 1]
                    except:
                        n_train_round = n_train[-1]
                else:
                    n_train_round = n_train

                # draw training data (z-transformed params and stats)
                verbose = '(round {}) '.format(
                    self.round) if self.verbose else False
                trn_data = self.gen(n_train_round, verbose=False)

                # precompute importance weights
                iws = np.ones((n_train_round, ))
                if self.generator.proposal is not None:
                    params = self.params_std * trn_data[0] + self.params_mean
                    p_prior = self.generator.prior.eval(params, log=False)
                    p_proposal = self.generator.proposal.eval(params,
                                                              log=False)
                    iws *= p_prior / p_proposal

                trn_data = (trn_data[0], trn_data[1], iws)
                trn_datasets.append(trn_data)

                params_ = np.array([i for sub in trn_datasets for i in sub[0]])
                stats_ = np.array([i for sub in trn_datasets for i in sub[1]])
                iws_ = np.array([i for sub in trn_datasets for i in sub[2]])

                trn_data_round = (params_, stats_, iws_)

                trn_inputs = [
                    self.network.params, self.network.stats, self.network.iws
                ]

                t = Trainer(self.network,
                            self.loss(N=n_train_round),
                            trn_data=trn_data_round,
                            trn_inputs=trn_inputs,
                            seed=self.gen_newseed(),
                            monitor=self.monitor_dict_from_names(monitor),
                            **kwargs)

                # recover adam state variables
                if self.recover_adam and len(optim_state) != 0:
                    for p, value in zip(t.updates.keys(), optim_state):
                        p.set_value(value)

                # train
                logs.append(
                    t.train(epochs=epochs,
                            minibatch=minibatch,
                            verbose=verbose))

                # save state of optimizer
                optim_state = [p.get_value() for p in t.updates.keys()]

                # append posterior to list
                posteriors.append(self.predict(self.obs))

                pbar.update(1)

            return logs, trn_datasets, posteriors
Example #10
0
    def run(self,
            n_train=100,
            n_rounds=2,
            epochs=100,
            minibatch=50,
            monitor=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs: int
            Number of epochs used for neural network training
        minibatch: int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of posteriors
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        for r in range(1, n_rounds + 1):  # start at 1
            # if round > 1, set new proposal distribution before sampling
            if r > 1:
                # posterior becomes new proposal prior
                posterior = self.predict(self.obs)
                self.generator.proposal = posterior.project_to_gaussian()

            # number of training examples for this round
            if type(n_train) == list:
                try:
                    n_train_round = n_train[r - 1]
                except:
                    n_train_round = n_train[-1]
            else:
                n_train_round = n_train

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(r) if self.verbose else False
            trn_data = self.gen(n_train_round, verbose=verbose)

            # algorithm 2 of Papamakarios and Murray
            if r == n_rounds and self.n_components > 1:
                # get parameters of current network
                old_params = self.network.params_dict.copy()

                # create new network
                network_spec = self.network.spec_dict.copy()
                network_spec.update({'n_components': self.n_components})
                self.network = NeuralNet(**network_spec)
                new_params = self.network.params_dict

                # set weights of new network
                # weights of additional components are duplicates
                for p in [
                        s for s in new_params
                        if 'means' in s or 'precisions' in s
                ]:
                    new_params[p] = old_params[p[:-1] + '0']
                    new_params[p] += 1.0e-6 * self.rng.randn(
                        *new_params[p].shape)

                self.network.params_dict = new_params

            trn_inputs = [self.network.params, self.network.stats]

            t = Trainer(self.network,
                        self.loss(N=n_train_round),
                        trn_data=trn_data,
                        trn_inputs=trn_inputs,
                        monitor=self.monitor_dict_from_names(monitor),
                        seed=self.gen_newseed(),
                        **kwargs)
            logs.append(
                t.train(epochs=epochs, minibatch=minibatch, verbose=verbose))
            trn_datasets.append(trn_data)

            posteriors.append(self.predict(self.obs))

        return logs, trn_datasets, posteriors
Example #11
0
    def run(self,
            n_train=100,
            n_rounds=2,
            epochs=100,
            minibatch=50,
            round_cl=1,
            stop_on_nan=False,
            monitor=None,
            kernel_loss=None,
            epochs_cbk=None,
            cbk_feature_layer=0,
            minibatch_cbk=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs : int
            Number of epochs used for neural network training
        minibatch : int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        round_cl : int
            Round after which to start continual learning
        stop_on_nan : bool
            If True, will halt if NaNs in the loss are encountered
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of distributions
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        minibatch_cbk = minibatch if minibatch_cbk is None else minibatch_cbk

        for r in range(n_rounds):
            self.round += 1

            # if round > 1, set new proposal distribution before sampling
            if self.round > 1:
                # posterior becomes new proposal prior
                proposal = self.predict(self.obs)  # see super

                # convert proposal to student's T?
                if self.convert_to_T is not None:
                    if type(self.convert_to_T) == int:
                        dofs = self.convert_to_T
                    else:
                        dofs = 10
                    proposal = proposal.convert_to_T(dofs=dofs)

                self.generator.proposal = proposal

            if self.round > 1 and self.reinit_weights_each_round:
                print('re-initializing network weights')
                self.reinit_network()

            # number of training examples for this round
            if type(n_train) == list:
                try:
                    n_train_round = n_train[self.round - 1]
                except:
                    n_train_round = n_train[-1]
            else:
                n_train_round = n_train

            if type(epochs) == list:
                try:
                    epochs_round = epochs[self.round - 1]
                except:
                    epochs_round = epochs[-1]
            else:
                epochs_round = epochs

            epochs_cbk_round = epochs_round if epochs_cbk is None else epochs_cbk

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(
                self.round) if self.verbose else False
            trn_data = self.gen(n_train_round,
                                prior_mixin=self.prior_mixin,
                                verbose=verbose)
            n_train_round = trn_data[0].shape[0]

            # precompute importance weights
            iws = np.ones((n_train_round, ))

            cbkrnl, cbl = None, None
            if self.generator.proposal is not None:
                params = self.params_std * trn_data[0] + self.params_mean
                p_prior = self.generator.prior.eval(params, log=False)
                p_proposal = self.generator.proposal.eval(params, log=False)
                iws *= p_prior / (self.prior_mixin * p_prior +
                                  (1. - self.prior_mixin) * p_proposal)

                # train calibration kernel (learns own normalization)
                if not kernel_loss is None:
                    if verbose:
                        print('fitting calibration kernel ...')

                    ks = list(self.network.layer.keys())
                    #hiddens = np.where([i[:6]=='hidden' for i in ks])[0]
                    #cbk_feature_layer = hiddens[-1] # pick last hidden layer
                    hl = self.network.layer[ks[cbk_feature_layer]]

                    stat_features = theano.function(
                        inputs=[self.network.stats], outputs=ll.get_output(hl))

                    fstats = stat_features(trn_data[1].astype(dtype)).reshape(
                        n_train_round, -1)

                    obs_z = (self.obs - self.stats_mean) / self.stats_std
                    fobs_z = stat_features(obs_z.astype(dtype)).reshape(1, -1)

                    cbkrnl, cbl = kernel_opt(
                        iws=iws.astype(np.float32),
                        stats=fstats,
                        obs=fobs_z,
                        kernel_loss=kernel_loss,
                        epochs=epochs_cbk_round,
                        minibatch=minibatch_cbk,
                        stop_on_nan=stop_on_nan,
                        seed=self.gen_newseed(),
                        monitor=self.monitor_dict_from_names(monitor),
                        **kwargs)
                    if verbose:
                        print('done.')

                    fstats = stat_features(trn_data[1].reshape(
                        n_train_round,
                        *self.network.n_inputs))[0].reshape(n_train_round, -1)

                    iws *= cbkrnl.eval(fstats)

            # normalize weights
            iws = (iws / np.sum(iws)) * n_train_round

            trn_data = (trn_data[0], trn_data[1], iws)

            trn_inputs = [
                self.network.params, self.network.stats, self.network.iws
            ]

            t = Trainer(self.network,
                        self.loss(N=n_train_round, round_cl=round_cl),
                        trn_data=trn_data,
                        trn_inputs=trn_inputs,
                        seed=self.gen_newseed(),
                        monitor=self.monitor_dict_from_names(monitor),
                        **kwargs)
            logs.append(
                t.train(epochs=epochs_round,
                        minibatch=minibatch,
                        verbose=verbose,
                        stop_on_nan=stop_on_nan))

            logs[-1]['cbkrnl'] = cbkrnl
            logs[-1]['cbk_loss'] = cbl

            trn_datasets.append(trn_data)

            try:
                posteriors.append(self.predict(self.obs))
            except:
                posteriors.append(None)
                print('analytic correction for proposal seemingly failed!')
                break

        return logs, trn_datasets, posteriors
Example #12
0
    def run_gaussian(self,
                     n_train=100,
                     epochs=100,
                     minibatch=50,
                     n_atoms=None,
                     moo=None,
                     train_on_all=False,
                     round_cl=1,
                     stop_on_nan=False,
                     monitor=None,
                     verbose=False,
                     reuse_prior_samples=True,
                     **kwargs):

        # simulate data
        self.set_proposal(project_to_gaussian=True)
        prop = self.generator.proposal
        assert isinstance(prop, dd.Gaussian)
        trn_data, n_train_round = self.gen(n_train)

        # here we're just repeating the same fixed proposal, though we
        # could also introduce some variety if we wanted.
        prop_m = np.expand_dims(prop.m, 0).repeat(n_train_round, axis=0)
        prop_P = np.expand_dims(prop.P, 0).repeat(n_train_round, axis=0)
        trn_data = (*trn_data, prop_m, prop_P)
        self.trn_datasets.append(trn_data)

        if train_on_all:
            prev_datasets = []
            for i, d in enumerate(self.trn_datasets):
                if self.proposal_used[i] == 'gaussian':
                    prev_datasets.append(d)
                    continue
                elif self.proposal_used[
                        i] != 'prior' or not reuse_prior_samples:
                    continue
                # prior samples. the Gauss loss will reduce to the prior loss
                if isinstance(self.generator.prior, dd.Gaussian):
                    prop_m = self.generator.prior.mean
                    prop_P = self.generator.prior.P
                elif isinstance(self.generator.prior, dd.Uniform):
                    # model a uniform as an zero-precision Gaussian:
                    prop_m = np.zeros(self.generator.prior.ndim, dtype)
                    prop_P = np.zeros(
                        (self.generator.prior.ndim, self.generator.prior.ndim),
                        dtype)
                else:  # can't reuse prior samples unless prior is uniform or Gaussian
                    continue
                prop_m = np.expand_dims(prop_m, 0).repeat(d[0].shape[0],
                                                          axis=0)
                prop_P = np.expand_dims(prop_P, 0).repeat(d[0].shape[0],
                                                          axis=0)
                prev_datasets.append((*d, prop_m, prop_P))

            trn_data = combine_trn_datasets(prev_datasets)
            n_train_round = trn_data[0].shape[0]

        # train network
        self.loss, trn_inputs = self.define_loss(n=n_train_round,
                                                 round_cl=round_cl,
                                                 proposal='gaussian')
        t = Trainer(self.network,
                    self.loss,
                    trn_data=trn_data,
                    trn_inputs=trn_inputs,
                    seed=self.gen_newseed(),
                    monitor=self.monitor_dict_from_names(monitor),
                    **kwargs)

        log = t.train(epochs=self.epochs_round(epochs),
                      minibatch=minibatch,
                      verbose=verbose,
                      stop_on_nan=stop_on_nan)

        return log, trn_data
Example #13
0
    def run_MoG(self,
                n_train=100,
                epochs=100,
                minibatch=50,
                n_atoms=None,
                moo=None,
                train_on_all=False,
                round_cl=1,
                stop_on_nan=False,
                monitor=None,
                verbose=False,
                print_each_epoch=False,
                reuse_prior_samples=True,
                patience=20,
                monitor_every=None,
                **kwargs):

        # simulate data
        self.set_proposal(project_to_gaussian=False)
        assert isinstance(self.generator.proposal, dd.MoG)
        prop = self.generator.proposal.ztrans(self.params_mean,
                                              self.params_std)

        trn_data, n_train_round = self.gen(n_train)
        trn_data = (*trn_data, *MoG_prop_APT_training_vars(
            prop, n_train_round, prop.n_components))

        self.trn_datasets.append(trn_data)

        if train_on_all:
            prev_datasets = []
            for i, d in enumerate(self.trn_datasets):
                if self.proposal_used[i] == 'mog':
                    prev_datasets.append(d)
                elif self.proposal_used == 'prior' and reuse_prior_samples:
                    prior = self.generator.prior
                    if not isinstance(prior, dd.Uniform):
                        prior = prior.ztrans(self.params_mean, self.params_std)
                    d = (*d, *MoG_prop_APT_training_vars(prior, n_train_round))
                    prev_datasets.append(d)
                elif self.proposal_used[i] == 'gaussian':
                    params, stats, prop_m, prop_P = d
                    if np.diff(prop_m, axis=0).any() or np.diff(prop_P,
                                                                axis=0).any():
                        continue  # reusing samples with proposals that changed within a round is not yet supported
                    prop = dd.Gaussian(m=prop_m[0], P=prop_P[0])
                    d = (params, stats,
                         *MoG_prop_APT_training_vars(prop, n_train_round))
                    prev_datasets.append(d)
                else:  # can't re-use samples from this proposal
                    continue

            trn_data = combine_trn_datasets(prev_datasets)
            n_train_round = trn_data[0].shape[0]

        self.loss, trn_inputs = self.define_loss(n=n_train_round,
                                                 round_cl=round_cl,
                                                 proposal='mog')

        t = Trainer(self.network,
                    self.loss,
                    trn_data=trn_data,
                    trn_inputs=trn_inputs,
                    seed=self.gen_newseed(),
                    monitor=self.monitor_dict_from_names(monitor),
                    **kwargs)

        log = t.train(epochs=self.epochs_round(epochs),
                      minibatch=minibatch,
                      verbose=verbose,
                      print_each_epoch=print_each_epoch,
                      stop_on_nan=stop_on_nan,
                      patience=patience,
                      monitor_every=monitor_every)

        return log, trn_data
Example #14
0
    def run(self,
            n_train=100,
            n_rounds=2,
            epochs=100,
            minibatch=50,
            monitor=None,
            n_components=1,
            stndrd_comps=False,
            project_proposal=False,
            sbc_fun=None,
            **kwargs):
        """Run algorithm

        Parameters
        ----------
        n_train : int or list of ints
            Number of data points drawn per round. If a list is passed, the
            nth list element specifies the number of training examples in the
            nth round. If there are fewer list elements than rounds, the last
            list element is used.
        n_rounds : int
            Number of rounds
        epochs: int
            Number of epochs used for neural network training
        minibatch: int
            Size of the minibatches used for neural network training
        monitor : list of str
            Names of variables to record during training along with the value
            of the loss function. The observables attribute contains all
            possible variables that can be monitored
        n_components : int
            Number of components in final round (if > 1, gives PM's algorithm 2)
        kwargs : additional keyword arguments
            Additional arguments for the Trainer instance

        Returns
        -------
        logs : list of dicts
            Dictionaries contain information logged while training the networks
        trn_datasets : list of (params, stats)
            training datasets, z-transformed
        posteriors : list of posteriors
            posterior after each round
        """
        logs = []
        trn_datasets = []
        posteriors = []

        #assert self.kwargs['n_components'] == 1
        # could also allow to go back to single Gaussian via project_to_gaussian()

        for r in range(1, n_rounds + 1):  # start at 1

            self.round += 1

            if self.round > 1:
                # posterior becomes new proposal prior
                proposal = self.predict(self.obs)
                if isinstance(proposal, BaseMixture) and (len(proposal.xs) == 1
                                                          or project_proposal):
                    proposal = proposal.project_to_gaussian()
                self.generator.proposal = proposal

            # number of training examples for this round
            epochs_round = per_round(epochs)
            n_train_round = per_round(n_train)

            # draw training data (z-transformed params and stats)
            verbose = '(round {}) '.format(
                self.round) if self.verbose else False
            trn_data = self.gen(n_train_round, verbose=verbose)[:2]

            if r == n_rounds:
                self.kwargs.update({'n_components': n_components})
                self.split_components(standardize=stndrd_comps)

            if r > 1:
                self.reinit_network()  # reinits network if flag is set

            if hasattr(self.network, 'extra_stats'):
                trn_inputs = [
                    self.network.params, self.network.stats,
                    self.network.extra_stats
                ]
            else:
                trn_inputs = [self.network.params, self.network.stats]

            t = Trainer(self.network,
                        self.loss(N=n_train_round),
                        trn_data=trn_data,
                        trn_inputs=trn_inputs,
                        monitor=self.monitor_dict_from_names(monitor),
                        seed=self.gen_newseed(),
                        **kwargs)
            logs.append(
                t.train(epochs=epochs, minibatch=minibatch, verbose=verbose))
            trn_datasets.append(trn_data)

            try:
                posteriors.append(self.predict(self.obs))
            except:
                posteriors.append(None)
                print('analytical correction broke !')
                break

            if not sbc_fun is None:
                print('computing simulation-based calibration')
                sbc = SBC(generator=self.generator, inf=self, f=sbc_fun)
                data = (trn_data[0] * self.params_std + self.params_mean,
                        trn_data[1])
                logs[-1]['sbc'] = sbc.test(N=None, L=100, data=data)

        return logs, trn_datasets, posteriors