Ejemplo n.º 1
0
 def _inverse(self, y):
     return mult(y, pinv(self.sf)) + self.avg
Ejemplo n.º 2
0
 def _inverse(self, y):
     return mult(y, pinv(self.sf)) + self.avg
Ejemplo n.º 3
0
    def _train(self, x, block_size=None, train_mode=None, node_weights=None, edge_weights=None, **argv):
        self.input_dim = x.shape[1]

        if self.output_dim is None:
            self.output_dim = self.input_dim

        print "Training iGSFANode..."

        if (not self.reconstruct_with_sfa) and (self.offsetting_mode in [None, "data_dependent"]):
            self.multiple_train(x, block_size=block_size, train_mode=train_mode, node_weights=node_weights,
                                edge_weights=edge_weights)  # scheduler = None, n_parallel=None
            return

        if (not self.reconstruct_with_sfa) and (self.offsetting_mode not in [None, "data_dependent"]):
            er = "'reconstruct_with_sfa' (" + str(self.reconstruct_with_sfa) + ") must be True when the scaling" + \
                 "method (" + str(self.offsetting_mode) + ") is neither 'None' not 'data_dependent'"
            raise Exception(er)
        # else use regular method:

        # Remove mean before expansion
        self.x_mean = x.mean(axis=0)
        x_zm = x - self.x_mean

        # Reorder or pre-process the data before it is expanded, but only if there is really an expansion
        if self.pre_expansion_node_class and self.exp_node:
            self.pre_expansion_node = self.pre_expansion_node_class(
                output_dim=self.pre_expansion_output_dim)  # GSFANode() or a WhitheningNode()
            self.pre_expansion_node.train(x_zm, block_size=block_size,
                                          train_mode=train_mode)  # Some arguments might not be necessary
            self.pre_expansion_node.stop_training()
            x_pre_exp = self.pre_expansion_node.execute(x_zm)
        else:
            x_pre_exp = x_zm

        # Expand data
        if self.exp_node:
            print "expanding x..."
            exp_x = self.exp_node.execute(x_pre_exp)  # x_zm
        else:
            exp_x = x_pre_exp

        self.expanded_dim = exp_x.shape[1]

        if self.max_lenght_slow_part is None:
            sfa_output_dim = min(self.expanded_dim, self.output_dim)
        else:
            sfa_output_dim = min(self.max_lenght_slow_part, self.expanded_dim, self.output_dim)

        # Apply SFA to expanded data
        self.sfa_node = GSFANode(output_dim=sfa_output_dim)
        self.sfa_node.train_params(exp_x, params={"block_size": block_size, "train_mode": train_mode,
                                                  "node_weights": node_weights,
                                                  "edge_weights": edge_weights})
        # , node_weights=None, edge_weights=None, scheduler = None, n_parallel=None)
        self.sfa_node.stop_training()
        print "self.sfa_node.d", self.sfa_node.d

        # Decide how many slow features are preserved (either use Delta_T=max_preserved_sfa when
        # max_preserved_sfa is a float, or preserve max_preserved_sfa features when max_preserved_sfa is an integer)
        if isinstance(self.max_preserved_sfa, float):
            # here self.max_lenght_slow_part should be considered
            self.num_sfa_features_preserved = (self.sfa_node.d <= self.max_preserved_sfa).sum()
        elif isinstance(self.max_preserved_sfa, int):
            # here self.max_lenght_slow_part should be considered
            self.num_sfa_features_preserved = self.max_preserved_sfa
        else:
            ex = "Cannot handle type of self.max_preserved_sfa"
            print ex
            raise Exception(ex)

        if self.num_sfa_features_preserved > self.output_dim:
            self.num_sfa_features_preserved = self.output_dim

        SFANode_reduce_output_dim(self.sfa_node, self.num_sfa_features_preserved)
        print "sfa execute..."
        sfa_x = self.sfa_node.execute(exp_x)

        # Truncate leaving only slowest features (this might be redundant)
        # sfa_x = sfa_x[:,0:self.num_sfa_features_preserved].copy() #WARNING, MODIFIED

        # normalize sfa_x
        self.sfa_x_mean = sfa_x.mean(axis=0)
        self.sfa_x_std = sfa_x.std(axis=0)
        print "self.sfa_x_mean=", self.sfa_x_mean
        print "self.sfa_x_std=", self.sfa_x_std
        if (self.sfa_x_std == 0).any():
            er = "zero-component detected"
            raise Exception(er)
        n_sfa_x = (sfa_x - self.sfa_x_mean) / self.sfa_x_std

        if self.reconstruct_with_sfa:
            # Compress input
            if self.compress_input_with_pca:
                self.compress_node = mdp.nodes.PCANode(output_dim=self.compression_out_dim)
                self.compress_node.train(x_zm)
                x_pca = self.compress_node.execute(x_zm)
                print "compress: %d components out of %d sufficed for the desired compression_out_dim" % \
                      (x_pca.shape[1], x_zm.shape[1]), self.compression_out_dim
            else:
                x_pca = x_zm

            # approximate input linearly, done inline to preserve node for future use
            print "training linear regression..."
            self.lr_node = mdp.nodes.LinearRegressionNode()
            self.lr_node.train(n_sfa_x,
                               x_pca)  # Notice that the input "x"=n_sfa_x and the output to learn is "y" = x_pca
            self.lr_node.stop_training()
            x_pca_app = self.lr_node.execute(n_sfa_x)

            if self.compress_input_with_pca:
                x_app = self.compress_node.inverse(x_pca_app)
            else:
                x_app = x_pca_app
        else:
            x_app = numpy.zeros_like(x_zm)

        # Remove linear approximation
        sfa_removed_x = x_zm - x_app

        # print "Data_variance(x_zm)=", data_variance(x_zm)
        # print "Data_variance(x_app)=", data_variance(x_app)
        # print "Data_variance(sfa_removed_x)=", data_variance(sfa_removed_x)
        # print "x_app.mean(axis=0)=", x_app
        # TODO:Compute variance removed by linear approximation
        print "ranking method..."
        # AKA Laurenz method for feature scaling( +rotation)
        if self.reconstruct_with_sfa and self.offsetting_mode == "QR_decomposition":
            M = self.lr_node.beta[1:, :].T  # bias is used by default, we do not need to consider it
            Q, R = numpy.linalg.qr(M)
            self.Q = Q
            self.R = R
            self.Rpinv = pinv(R)
            s_n_sfa_x = numpy.dot(n_sfa_x, R.T)
        # AKA my method for feature scaling (no rotation)
        elif self.reconstruct_with_sfa and self.offsetting_mode == "sensitivity_based_pure":
            beta = self.lr_node.beta[1:, :]  # bias is used by default, we do not need to consider it
            sens = (beta ** 2).sum(axis=1)
            self.magn_n_sfa_x = sens
            s_n_sfa_x = n_sfa_x * self.magn_n_sfa_x ** self.exponent_variance
            print "method: sensitivity_based_pure enforced"
        # AKA alternative method for feature scaling (no rotation)
        elif self.reconstruct_with_sfa and self.offsetting_mode == "sensitivity_based_normalized":
            beta = self.lr_node.beta[1:, :]  # bias is used by default, we do not need to consider it
            sens = (beta ** 2).sum(axis=1)
            self.magn_n_sfa_x = sens * ((x_pca_app ** 2).sum(axis=1).mean() / sens.sum())
            s_n_sfa_x = n_sfa_x * self.magn_n_sfa_x ** self.exponent_variance
            print "method: sensitivity_based_normalized enforced"
        elif self.offsetting_mode is None:
            self.magn_n_sfa_x = 1.0
            s_n_sfa_x = n_sfa_x * self.magn_n_sfa_x
            print "method: constant amplitude for all slow features"
        elif self.offsetting_mode == "data_dependent":
            self.magn_n_sfa_x = 0.01 * numpy.min(x_zm.std(axis=0)) + 1e-1  # SFA components have the variance of the weakest PCA feature
            # self.magn_n_sfa_x = 0.01 * numpy.min(
            #     x_zm.var(axis=0))  # SFA components have a variance 1/10000 times the smallest data variance
            s_n_sfa_x = n_sfa_x * self.magn_n_sfa_x # Scale according to ranking
            print "method: data dependent (setting magn_n_fa_x later)"
        else:
            er = "unknown feature offsetting mode=" + str(self.offsetting_mode) + "for reconstruct_with_sfa=" + \
                 str(self.reconstruct_with_sfa)
            raise Exception(er)

        print "training PCA..."
        pca_output_dim = self.output_dim - self.num_sfa_features_preserved
        # if pca_output_dim == 0:
        #    self.pca_node = mdp.nodes.IdentityNode()
        # else:
        #
        # WARNING: WHY WAS I EXTRACTING ALL PCA COMPONENTS!!?? INEFFICIENT!!!!
        self.pca_node = mdp.nodes.PCANode(output_dim=pca_output_dim)  # reduce=True) #output_dim = pca_out_dim)
        self.pca_node.train(sfa_removed_x)
        self.pca_node.stop_training()

        # TODO:check that pca_out_dim > 0
        print "executing PCA..."

        pca_x = self.pca_node.execute(sfa_removed_x)

        if self.pca_node.output_dim + self.num_sfa_features_preserved < self.output_dim:
            er = "Error, the number of features computed is SMALLER than the output dimensionality of the node: " + \
                 "self.pca_node.output_dim=" + str(self.pca_node.output_dim) + ", self.num_sfa_features_preserved=" + \
                 str(self.num_sfa_features_preserved) + ", self.output_dim=" + str(self.output_dim)
            raise Exception(er)

        # Finally output is the concatenation of scaled slow features and remaining pca components
        sfa_pca_x = numpy.concatenate((s_n_sfa_x, pca_x), axis=1)

        sfa_pca_x_truncated = sfa_pca_x[:, 0:self.output_dim]

        # Compute explained variance from amplitudes of output compared to amplitudes of input
        # Only works because amplitudes of SFA are scaled to be equal to explained variance, because PCA is
        # a rotation, and because data has zero mean
        self.evar = (sfa_pca_x_truncated ** 2).sum() / (x_zm ** 2).sum()
        print "Variance(output) / Variance(input) is ", self.evar
        self.stop_training()
Ejemplo n.º 4
0
    def _inverse(self, y):
        """Return inverse of the slow feature response.

        :return: The inverse of the slow feature response.
        """
        return mult(y, pinv(self.sf)) + self.avgnode.avg
Ejemplo n.º 5
0
 def _inverse(self, y):
     """Return inverse of the slow feature response.
     
     :return: The inverse of the slow feature response.
     """
     return mult(y, pinv(self.sf)) + self.avgnode.avg