Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cupy to leverage cuda #58

Merged
merged 9 commits into from
Jul 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 17 additions & 46 deletions docs/notebooks/cluster_dbscan.ipynb

Large diffs are not rendered by default.

394 changes: 301 additions & 93 deletions docs/notebooks/neural_network.ipynb

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions fromscratchtoml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import logging
import numpy as np # noqa:F401

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


def use(backend):
global np
if backend == "numpy":
import numpy as np # noqa:F401
logging.debug("Using numpy backend.")
elif backend == "cupy":
import cupy as np
logging.debug("Using cupy backend.")
else:
raise ImportError('Only available backends are cupy or numpy.')
2 changes: 1 addition & 1 deletion fromscratchtoml/cluster/dbscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np

from ..base import BaseModel
from ..toolbox.exceptions import InvalidArgumentError
Expand Down
4 changes: 2 additions & 2 deletions fromscratchtoml/cluster/kmeans.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np

from ..base import BaseModel
from ..toolbox.exceptions import InvalidArgumentError
Expand All @@ -21,7 +21,7 @@ class KMeans(BaseModel):

Examples
--------
>>> import numpy as np
>>> from fromscratchtoml import np
>>> from fromscratchtoml.cluster import KMeans as KMeans
>>> from fromscratchtoml.toolbox.random import Distribution
>>> X1 = Distribution.linear(pts=500, covr=[[1.2, -1],[-1, 1]], mean=[0, 0])
Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/decomposition/decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np

import logging

Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/neighbors/knn.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np
from collections import Counter

from ..base import BaseModel
Expand Down
3 changes: 2 additions & 1 deletion fromscratchtoml/neural_network/activations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np

import logging

Expand Down Expand Up @@ -52,6 +52,7 @@ def sigmoid(x, return_deriv=False):
-------
numpy.ndarray : sigmoid of x
"""
x = np.clip(x, -100, 100)
_sigmoid = 1.0 / (1.0 + np.exp(-x))

if return_deriv:
Expand Down
3 changes: 2 additions & 1 deletion fromscratchtoml/neural_network/layers/dense.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
# from fromscratchtoml import np
from fromscratchtoml import np

from fromscratchtoml.neural_network.layers import Layer
import logging
Expand Down
39 changes: 37 additions & 2 deletions fromscratchtoml/neural_network/losses.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np
from fromscratchtoml import np

import logging

Expand Down Expand Up @@ -33,6 +33,41 @@ def mean_squared_error(y_predicted, y_target, return_deriv=False):
"""
if len(y_target.shape) == 1:
y_target = np.expand_dims(y_target, axis=1)

if return_deriv:
return np.mean(np.square(y_predicted - y_target)), y_predicted - y_target
return np.mean(np.square(y_predicted - y_target)), (y_predicted - y_target)

return np.mean(np.square(y_predicted - y_target))


def cross_entropy(y_predicted, y_target, return_deriv=False):
"""
Calculates the cross entropy loss between the predicted and the target ouputs.
Parameters
----------
y_predicted : numpy.ndarray
The ouput predicted by the model.
y_target : numpy.ndarray
The expected output.
return_deriv : bool, optional
If set to true, the function returns derivative of the error along with the error.
Returns
-------
numpy.array : The error.
numpy.array : The error's derivative, optional.
"""
if len(y_target.shape) == 1:
y_target = np.expand_dims(y_target, axis=1)

eps = 1e-9

y_predicted[y_predicted < eps] = eps
y_predicted[y_predicted > 1 - eps] = 1 - eps

crl = -(y_target * np.log(y_predicted) + (1 - y_target) * np.log(1 - y_predicted))

if return_deriv:
deriv = -(y_target / y_predicted) + (1 - y_target) / (1 - y_predicted)
return crl / len(y_target), deriv / len(y_target)

return crl / len(y_target)
10 changes: 7 additions & 3 deletions fromscratchtoml/neural_network/models/sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

from __future__ import print_function
import numpy as np
from fromscratchtoml import np

from fromscratchtoml.toolbox import progress, binary_visualize
from .. import losses
Expand Down Expand Up @@ -95,7 +95,7 @@ def accuracy(self, X, y):
total_samples = y.shape[0]

errors = np.count_nonzero(diff_arr) / 2
return (100 - (errors / (total_samples * 0.01)))
return float(100 - (errors / (total_samples * 0.01)))

def fit(self, X, y, epochs, batch_size=None):
"""
Expand All @@ -112,6 +112,9 @@ def fit(self, X, y, epochs, batch_size=None):
batch_size : int, optional
The number of data points to be processed in a single iteration.
"""
X = np.asarray(X, dtype=np.float64)
y = np.asarray(y, dtype=np.float64)

if batch_size is None:
batch_size = X.shape[0]

Expand All @@ -127,7 +130,7 @@ def fit(self, X, y, epochs, batch_size=None):
acc = self.accuracy(X, y)
print("\nepoch: {}/{} ".format(epoch + 1, epochs), end="")
print(" acc: {:0.2f} ".format(acc), end="")
print(" loss: {:0.3f} ".format(loss))
print(" loss: {:0.3f} ".format(float(np.sum(loss))))
if self.vis_each_epoch:
binary_visualize(X, clf=self, draw_contour=True)

Expand Down Expand Up @@ -204,6 +207,7 @@ def predict(self, X, prob=False):
-------
numpy.array : The prediction.
"""
X = np.asarray(X)
predictions = self.forwardpass(X)

if prob is False:
Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/svm/svc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import cvxopt
# import torch as ch
import numpy as np
from fromscratchtoml import np

from functools import partial

Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/test/cluster/test_dbscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import unittest
import numpy as np
from fromscratchtoml import np

from sklearn.datasets import load_iris

Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/test/cluster/test_kmeans.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import unittest
import numpy as np
from fromscratchtoml import np

from sklearn.cluster import KMeans as skl_KMeans
from fromscratchtoml.cluster import KMeans as fs2ml_KMeans
Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/test/neighbors/test_knn.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import unittest
import numpy as np
from fromscratchtoml import np

from sklearn.neighbors import KNeighborsClassifier as sk_KNeighborsClassifier
from sklearn import datasets
Expand Down
40 changes: 38 additions & 2 deletions fromscratchtoml/test/neural_network/test_neural_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import unittest

import numpy as np
from fromscratchtoml import np
from fromscratchtoml.neural_network.models import Sequential
from fromscratchtoml.neural_network.layers import Dense, Activation
from fromscratchtoml.neural_network.optimizers import StochasticGradientDescent
Expand Down Expand Up @@ -43,7 +43,7 @@ def setUp(self):

self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(X, y, test_size=50, random_state=42)

def test_dense_acts_sgd(self):
def test_dense_acts_sgd_mse(self):
model = Sequential()

model.add(Dense(10, input_dim=2, seed=1))
Expand Down Expand Up @@ -78,3 +78,39 @@ def test_dense_acts_sgd(self):
predictions = model.predict(self.X_test)

self.assertTrue(np.allclose((predictions), np.argmax(self.y_test, axis=1)))

def test_dense_acts_sgd_cross_entropy(self):
model = Sequential()

model.add(Dense(10, input_dim=2, seed=1))
model.add(Activation('sigmoid'))

model.add(Dense(2, seed=7))
model.add(Activation('tanh'))

model.add(Dense(2, seed=2))
model.add(Activation('relu'))

model.add(Dense(2, seed=3))
model.add(Activation('leaky_relu'))

model.add(Dense(2, seed=4))
model.add(Activation('linear'))

model.add(Dense(2, seed=6))
model.add(Activation('softmax'))

sgd = StochasticGradientDescent(learning_rate=0.05)
model.compile(optimizer=sgd, loss="cross_entropy")

model.fit(self.X_train, self.y_train, epochs=9, batch_size=2)

expected_biases = np.array([[1.38503523, -0.51962709]], dtype=np.float128)
self.assertTrue(np.allclose(expected_biases, model.layers[-2].biases))

expected_weights = np.array([[-1.15492119, 1.33037864], [0.04502013, -1.54036933]], dtype=np.float128)
self.assertTrue(np.allclose(expected_weights, model.layers[-2].weights))

predictions = model.predict(self.X_test)

self.assertTrue(np.allclose((predictions), np.argmax(self.y_test, axis=1)))
2 changes: 1 addition & 1 deletion fromscratchtoml/test/test_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import unittest

from fromscratchtoml.decomposition import Decomposition
import numpy as np
from fromscratchtoml import np

import logging

Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/test/test_support_vector_machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import unittest

import numpy as np
from fromscratchtoml import np

from fromscratchtoml import svm
from fromscratchtoml.test.toolbox import _tempfile, _test_data_path # noqa:F401
Expand Down
13 changes: 12 additions & 1 deletion fromscratchtoml/toolbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import sys
import logging

# from fromscratchtoml import np
import numpy as np

from .exceptions import ParameterRequiredException
Expand Down Expand Up @@ -71,6 +72,15 @@ def binary_visualize(X, y=None, clf=None, coarse=50, xlabel="x", ylabel="y",
The seed value for randomising plot colors.

"""
try:
import cupy
if isinstance(y, cupy.core.core.ndarray):
y = cupy.asnumpy(y)
if isinstance(X, cupy.core.core.ndarray):
X = cupy.asnumpy(X)
except ImportError:
pass

np.random.seed(color_seed)

if len(X.shape) != 2 or X.shape[1] != 2:
Expand All @@ -79,6 +89,7 @@ def binary_visualize(X, y=None, clf=None, coarse=50, xlabel="x", ylabel="y",

if clf:
y = clf.predict(X)
y = cupy.asnumpy(y)

# Also handles the cases when y is None
unq, y = np.unique(y, return_inverse=True)
Expand All @@ -104,7 +115,7 @@ def binary_visualize(X, y=None, clf=None, coarse=50, xlabel="x", ylabel="y",
_X, _Y = np.meshgrid(np.arange(x_min, x_max, 1 / (coarse * 1.0)), np.arange(y_min, y_max, 1 / (coarse * 1.0)))

Z = np.c_[_X.ravel(), _Y.ravel()]
Z = clf.predict(Z)
Z = cupy.asnumpy(clf.predict(Z))

unq, Z = np.unique(Z, return_inverse=True)
Z = Z.reshape(_X.shape)
Expand Down
2 changes: 1 addition & 1 deletion fromscratchtoml/toolbox/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html
import numpy as np
from fromscratchtoml import np


def linear(x, y, **kwargs):
Expand Down
26 changes: 18 additions & 8 deletions fromscratchtoml/toolbox/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# Copyright (C) 2017 Mohit Rathore <mrmohitrathoremr@gmail.com>
# Licensed under the GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.en.html

import numpy as np

from fromscratchtoml import np
import numpy

import logging

Expand All @@ -15,12 +15,22 @@


def to_onehot(y):
unq, y5 = np.unique(y, return_inverse=True)

a = []
try:
import cupy
if isinstance(y, cupy.core.core.ndarray):
y = np.asnumpy(y)
except ImportError:
pass

unq, _ = numpy.unique(y, return_inverse=True)

# a = []
a = np.zeros((len(y), len(unq)))
for i in range(len(y)):
x = np.zeros(len(unq))
x[int(y[i])] = 1.
a.append(x)
# x = np.zeros(len(unq))
a[i][int(y[i])] = 1.
# a.append(x)

return np.array(a, dtype=np.float128)
# return np.array(a)
return a
Loading