# -*- coding: utf8 # Author: David C. Lambert [dcl -at- panix -dot- com] # Copyright(c) 2013 # License: Simple BSD """ The :mod:`elm` module implements the Extreme Learning Machine Classifiers and Regressors (ELMClassifier, ELMRegressor, SimpleELMRegressor, SimpleELMClassifier). An Extreme Learning Machine (ELM) is a single layer feedforward network with a random hidden layer components and ordinary linear least squares fitting of the hidden->output weights by default. [1][2] References ---------- .. [1] http://www.extreme-learning-machines.org .. [2] G.-B. Huang, Q.-Y. Zhu and C.-K. Siew, "Extreme Learning Machine: Theory and Applications", Neurocomputing, vol. 70, pp. 489-501, 2006. """ from abc import ABCMeta, abstractmethod import numpy as np from scipy.linalg import pinv2 from sklearn.utils import as_float_array from sklearn.utils.extmath import safe_sparse_dot from sklearn.base import BaseEstimator, ClassifierMixin, RegressorMixin from sklearn.preprocessing import LabelBinarizer from random_layer import RandomLayer, MLPRandomLayer __all__ = ["ELMRegressor", "ELMClassifier", "GenELMRegressor", "GenELMClassifier"] # BaseELM class, regressor and hidden_layer attributes # and provides defaults for docstrings class BaseELM(BaseEstimator): """ Base class for ELMs. Warning: This class should not be used directly. Use derived classes instead. """ __metaclass__ = ABCMeta def __init__(self, hidden_layer, regressor): self.regressor = regressor self.hidden_layer = hidden_layer @abstractmethod def fit(self, X, y): """ Fit the model using X, y as training data. Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like of shape [n_samples, n_outputs] Target values (class labels in classification, real numbers in regression) Returns ------- self : object Returns an instance of self. """ @abstractmethod def predict(self, X): """ Predict values using the model Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Returns ------- C : numpy array of shape [n_samples, n_outputs] Predicted values. """ class GenELMRegressor(BaseELM, RegressorMixin): """ ELMRegressor is a regressor based on the Extreme Learning Machine. An Extreme Learning Machine (ELM) is a single layer feedforward network with a random hidden layer components and ordinary linear least squares fitting of the hidden->output weights by default. [1][2] Parameters ---------- `hidden_layer` : random_layer instance, optional (default=MLPRandomLayer(random_state=0)) `regressor` : regressor instance, optional (default=None) If provided, this object is used to perform the regression from hidden unit activations to the outputs and subsequent predictions. If not present, an ordinary linear least squares fit is performed Attributes ---------- `coefs_` : numpy array Fitted regression coefficients if no regressor supplied. `fitted_` : bool Flag set when fit has been called already. `hidden_activations_` : numpy array of shape [n_samples, n_hidden] Hidden layer activations for last input. See Also -------- RBFRandomLayer, MLPRandomLayer, ELMRegressor, ELMClassifier References ---------- .. [1] http://www.extreme-learning-machines.org .. [2] G.-B. Huang, Q.-Y. Zhu and C.-K. Siew, "Extreme Learning Machine: Theory and Applications", Neurocomputing, vol. 70, pp. 489-501, 2006. """ def __init__(self, hidden_layer=MLPRandomLayer(random_state=0), regressor=None): super(GenELMRegressor, self).__init__(hidden_layer, regressor) self.coefs_ = None self.fitted_ = False self.hidden_activations_ = None def _fit_regression(self, y): """ fit regression using pseudo-inverse or supplied regressor """ if (self.regressor is None): self.coefs_ = safe_sparse_dot(pinv2(self.hidden_activations_), y) else: self.regressor.fit(self.hidden_activations_, y) self.fitted_ = True def fit(self, X, y): """ Fit the model using X, y as training data. Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like of shape [n_samples, n_outputs] Target values (class labels in classification, real numbers in regression) Returns ------- self : object Returns an instance of self. """ # fit random hidden layer and compute the hidden layer activations self.hidden_activations_ = self.hidden_layer.fit_transform(X) # solve the regression from hidden activations to outputs self._fit_regression(as_float_array(y, copy=True)) return self def _get_predictions(self): """get predictions using internal least squares/supplied regressor""" if (self.regressor is None): preds = safe_sparse_dot(self.hidden_activations_, self.coefs_) else: preds = self.regressor.predict(self.hidden_activations_) return preds def predict(self, X): """ Predict values using the model Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Returns ------- C : numpy array of shape [n_samples, n_outputs] Predicted values. """ if (not self.fitted_): raise ValueError("ELMRegressor not fitted") # compute hidden layer activations self.hidden_activations_ = self.hidden_layer.transform(X) # compute output predictions for new hidden activations predictions = self._get_predictions() return predictions class GenELMClassifier(BaseELM, ClassifierMixin): """ GenELMClassifier is a classifier based on the Extreme Learning Machine. An Extreme Learning Machine (ELM) is a single layer feedforward network with a random hidden layer components and ordinary linear least squares fitting of the hidden->output weights by default. [1][2] Parameters ---------- `hidden_layer` : random_layer instance, optional (default=MLPRandomLayer(random_state=0)) `binarizer` : LabelBinarizer, optional (default=LabelBinarizer(-1, 1)) `regressor` : regressor instance, optional (default=None) If provided, this object is used to perform the regression from hidden unit activations to the outputs and subsequent predictions. If not present, an ordinary linear least squares fit is performed Attributes ---------- `classes_` : numpy array of shape [n_classes] Array of class labels `genelm_regressor_` : ELMRegressor instance Performs actual fit of binarized values See Also -------- RBFRandomLayer, MLPRandomLayer, ELMRegressor, ELMClassifier References ---------- .. [1] http://www.extreme-learning-machines.org .. [2] G.-B. Huang, Q.-Y. Zhu and C.-K. Siew, "Extreme Learning Machine: Theory and Applications", Neurocomputing, vol. 70, pp. 489-501, 2006. """ def __init__(self, hidden_layer=MLPRandomLayer(random_state=0), binarizer=LabelBinarizer(-1, 1), regressor=None): super(GenELMClassifier, self).__init__(hidden_layer, regressor) self.binarizer = binarizer self.classes_ = None self.genelm_regressor_ = GenELMRegressor(hidden_layer, regressor) def decision_function(self, X): """ This function return the decision function values related to each class on an array of test vectors X. Parameters ---------- X : array-like of shape [n_samples, n_features] Returns ------- C : array of shape [n_samples, n_classes] or [n_samples,] Decision function values related to each class, per sample. In the two-class case, the shape is [n_samples,] """ return self.genelm_regressor_.predict(X) def fit(self, X, y): """ Fit the model using X, y as training data. Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like of shape [n_samples, n_outputs] Target values (class labels in classification, real numbers in regression) Returns ------- self : object Returns an instance of self. """ self.classes_ = np.unique(y) y_bin = self.binarizer.fit_transform(y) self.genelm_regressor_.fit(X, y_bin) return self def predict(self, X): """Predict values using the model Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Returns ------- C : numpy array of shape [n_samples, n_outputs] Predicted values. """ raw_predictions = self.decision_function(X) class_predictions = self.binarizer.inverse_transform(raw_predictions) return class_predictions # ELMRegressor with default RandomLayer class ELMRegressor(BaseEstimator, RegressorMixin): """ ELMRegressor is a regressor based on the Extreme Learning Machine. An Extreme Learning Machine (ELM) is a single layer feedforward network with a random hidden layer components and ordinary linear least squares fitting of the hidden->output weights by default. [1][2] ELMRegressor is a wrapper for an GenELMRegressor that uses a RandomLayer and passes the __init__ parameters through to the hidden layer generated by the fit() method. Parameters ---------- `n_hidden` : int, optional (default=20) Number of units to generate in the SimpleRandomLayer `alpha` : float, optional (default=0.5) Mixing coefficient for distance and dot product input activations: activation = alpha*mlp_activation + (1-alpha)*rbf_width*rbf_activation `rbf_width` : float, optional (default=1.0) multiplier on rbf_activation `activation_func` : {callable, string} optional (default='tanh') Function used to transform input activation It must be one of 'tanh', 'sine', 'tribas', 'inv_tribase', 'sigmoid', 'hardlim', 'softlim', 'gaussian', 'multiquadric', 'inv_multiquadric' or a callable. If none is given, 'tanh' will be used. If a callable is given, it will be used to compute the hidden unit activations. `activation_args` : dictionary, optional (default=None) Supplies keyword arguments for a callable activation_func `user_components`: dictionary, optional (default=None) dictionary containing values for components that woud otherwise be randomly generated. Valid key/value pairs are as follows: 'radii' : array-like of shape [n_hidden] 'centers': array-like of shape [n_hidden, n_features] 'biases' : array-like of shape [n_hidden] 'weights': array-like of shape [n_hidden, n_features] `regressor` : regressor instance, optional (default=None) If provided, this object is used to perform the regression from hidden unit activations to the outputs and subsequent predictions. If not present, an ordinary linear least squares fit is performed `random_state` : int, RandomState instance or None (default=None) Control the pseudo random number generator used to generate the hidden unit weights at fit time. Attributes ---------- `genelm_regressor_` : GenELMRegressor object Wrapped object that actually performs the fit. See Also -------- RandomLayer, RBFRandomLayer, MLPRandomLayer, GenELMRegressor, GenELMClassifier, ELMClassifier References ---------- .. [1] http://www.extreme-learning-machines.org .. [2] G.-B. Huang, Q.-Y. Zhu and C.-K. Siew, "Extreme Learning Machine: Theory and Applications", Neurocomputing, vol. 70, pp. 489-501, 2006. """ def __init__(self, n_hidden=20, alpha=0.5, rbf_width=1.0, activation_func='tanh', activation_args=None, user_components=None, regressor=None, random_state=None): self.n_hidden = n_hidden self.alpha = alpha self.random_state = random_state self.activation_func = activation_func self.activation_args = activation_args self.user_components = user_components self.rbf_width = rbf_width self.regressor = regressor self._genelm_regressor = None def _create_random_layer(self): """Pass init params to RandomLayer""" return RandomLayer(n_hidden=self.n_hidden, alpha=self.alpha, random_state=self.random_state, activation_func=self.activation_func, activation_args=self.activation_args, user_components=self.user_components, rbf_width=self.rbf_width) def fit(self, X, y): """ Fit the model using X, y as training data. Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like of shape [n_samples, n_outputs] Target values (class labels in classification, real numbers in regression) Returns ------- self : object Returns an instance of self. """ rhl = self._create_random_layer() self._genelm_regressor = GenELMRegressor(hidden_layer=rhl, regressor=self.regressor) self._genelm_regressor.fit(X, y) return self def predict(self, X): """ Predict values using the model Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Returns ------- C : numpy array of shape [n_samples, n_outputs] Predicted values. """ if (self._genelm_regressor is None): raise ValueError("SimpleELMRegressor not fitted") return self._genelm_regressor.predict(X) class ELMClassifier(ELMRegressor): """ ELMClassifier is a classifier based on the Extreme Learning Machine. An Extreme Learning Machine (ELM) is a single layer feedforward network with a random hidden layer components and ordinary linear least squares fitting of the hidden->output weights by default. [1][2] ELMClassifier is an ELMRegressor subclass that first binarizes the data, then uses the superclass to compute the decision function that is then unbinarized to yield the prediction. The params for the RandomLayer used in the input transform are exposed in the ELMClassifier constructor. Parameters ---------- `n_hidden` : int, optional (default=20) Number of units to generate in the SimpleRandomLayer `activation_func` : {callable, string} optional (default='tanh') Function used to transform input activation It must be one of 'tanh', 'sine', 'tribas', 'inv_tribase', 'sigmoid', 'hardlim', 'softlim', 'gaussian', 'multiquadric', 'inv_multiquadric' or a callable. If none is given, 'tanh' will be used. If a callable is given, it will be used to compute the hidden unit activations. `activation_args` : dictionary, optional (default=None) Supplies keyword arguments for a callable activation_func `random_state` : int, RandomState instance or None (default=None) Control the pseudo random number generator used to generate the hidden unit weights at fit time. Attributes ---------- `classes_` : numpy array of shape [n_classes] Array of class labels See Also -------- RandomLayer, RBFRandomLayer, MLPRandomLayer, GenELMRegressor, GenELMClassifier, ELMClassifier References ---------- .. [1] http://www.extreme-learning-machines.org .. [2] G.-B. Huang, Q.-Y. Zhu and C.-K. Siew, "Extreme Learning Machine: Theory and Applications", Neurocomputing, vol. 70, pp. 489-501, 2006. """ def __init__(self, n_hidden=20, alpha=0.5, rbf_width=1.0, activation_func='tanh', activation_args=None, user_components=None, regressor=None, binarizer=LabelBinarizer(-1, 1), random_state=None): super(ELMClassifier, self).__init__(n_hidden=n_hidden, alpha=alpha, random_state=random_state, activation_func=activation_func, activation_args=activation_args, user_components=user_components, rbf_width=rbf_width, regressor=regressor) self.classes_ = None self.binarizer = binarizer def decision_function(self, X): """ This function return the decision function values related to each class on an array of test vectors X. Parameters ---------- X : array-like of shape [n_samples, n_features] Returns ------- C : array of shape [n_samples, n_classes] or [n_samples,] Decision function values related to each class, per sample. In the two-class case, the shape is [n_samples,] """ return super(ELMClassifier, self).predict(X) def fit(self, X, y): """ Fit the model using X, y as training data. Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like of shape [n_samples, n_outputs] Target values (class labels in classification, real numbers in regression) Returns ------- self : object Returns an instance of self. """ self.classes_ = np.unique(y) y_bin = self.binarizer.fit_transform(y) super(ELMClassifier, self).fit(X, y_bin) return self def predict(self, X): """ Predict values using the model Parameters ---------- X : {array-like, sparse matrix} of shape [n_samples, n_features] Returns ------- C : numpy array of shape [n_samples, n_outputs] Predicted values. """ raw_predictions = self.decision_function(X) class_predictions = self.binarizer.inverse_transform(raw_predictions) return class_predictions def score(self, X, y): """Force use of accuracy score since we don't inherit from ClassifierMixin""" from sklearn.metrics import accuracy_score return accuracy_score(y, self.predict(X))