Created
October 1, 2021 12:28
-
-
Save jaume-ferrarons/7d5c67575cad164b1d25ed9fc45ab8b2 to your computer and use it in GitHub Desktop.
Extreme Learning Machine implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import math | |
from pathlib import Path | |
import shutil | |
import json | |
class ELM: | |
def __init__(self, n_hidden_units: int) -> None: | |
self._n_hidden_units = n_hidden_units | |
self._weights_hidden = None | |
self._weights_output = None | |
self._batch_size = 50000 | |
def fit(self, X, y): | |
self._weights_hidden = np.random.normal(size=[X.shape[1], self._n_hidden_units]) | |
activations = self._activations(X) | |
activations_t = np.transpose(activations) | |
dot = np.dot(activations_t, activations) | |
try: | |
inv = np.linalg.inv(dot) | |
except np.linalg.LinAlgError as err: | |
if 'Singular matrix' in str(err): | |
inv = np.linalg.pinv(dot) # Approximate if exact does not exists | |
else: | |
raise | |
self._weights_output = np.dot(inv, np.dot(activations_t, y)) | |
def predict(self, X): | |
res = np.zeros(len(X)) | |
n_groups = math.ceil(len(X) / self._batch_size) | |
groups = np.array_split(range(len(X)), n_groups) | |
for indices in groups: | |
activations = self._activations(X.iloc[indices]) | |
res[indices] += np.dot(activations, self._weights_output) | |
return res | |
def _activations(self, X): | |
a = np.dot(X, self._weights_hidden) | |
a = np.maximum(a, 0, a) # ReLU | |
return a | |
def save(self, path: str): | |
path = Path(path) | |
if path.exists(): | |
shutil.rmtree(path) | |
path.mkdir() | |
with (path / "arrays.npy").open("wb") as f: | |
np.savez_compressed(f, hidden=self._weights_hidden, output=self._weights_output) | |
with (path / "info.json").open("w") as f: | |
json.dump( | |
{ | |
"n_hidden_units": self._n_hidden_units | |
}, | |
f, | |
indent=2, | |
) | |
@classmethod | |
def load(cls, path: str): | |
path = Path(path) | |
with (path / "info.json").open("r") as f: | |
data = json.load(f) | |
matrices = np.load(path / "arrays.npy") | |
res = ELM(data['n_hidden_units']) | |
res._weights_hidden = matrices['hidden'] | |
res._weights_output = matrices['output'] | |
return res |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment