Skip to content

Commit f9317d0

Browse files
committed
Now using jitclass instead of tuple
1 parent a7c3be1 commit f9317d0

File tree

4 files changed

+72
-78
lines changed

4 files changed

+72
-78
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ __pycache__/
44
data/mnist_train.csv
55
data/mnist_outputs.npy
66
data/mnist_inputs.npy
7+
other/mlp.ipynb

main.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22
import numba_neural_network as nn
33
import z_helper as h
44
import time
5-
65
np.set_printoptions(linewidth=200)
76

87
data_input = np.load("data/ci_inputs.npy")
98
data_output = np.load("data/ci_outputs.npy")
109

1110
print("Begin compiling!")
1211
begin_time = time.time_ns()
13-
compiled_nn_values = nn.make_neural_network(layer_sizes=[data_input.shape[1], data_output.shape[1]], layer_activations=["sigmoid"])
12+
compiled_nn_values = nn.make_neural_network(layer_sizes=[data_input.shape[1], data_output.shape[1]], layer_activations=[h.softmax])
1413
nn.train_auto(data_input[:1], data_output[:1], data_input[1: 2], data_output[1: 2], compiled_nn_values)
1514
end_time = time.time_ns()
1615
print("Compile time:", (end_time-begin_time) / 1e9)
1716

1817
np.random.seed(420)
19-
total_time = 0.0
20-
n = 1
18+
total_accuracy = 0.0
19+
begin_total = time.time_ns()
20+
n = 10
2121
for i in range(n):
2222

2323
random_seed = np.random.randint(10, 1010)
@@ -26,14 +26,7 @@
2626
train_input, validate_input, test_input = h.kfold(7, data_input, random_seed)
2727
train_output, validate_output, test_output = h.kfold(7, data_output, random_seed)
2828

29-
nn_values = nn.make_neural_network(layer_sizes=[train_input.shape[1], 20, train_output.shape[1]], layer_activations=["sigmoid", "sigmoid"])
30-
# n2 = 100
31-
# begin_time = time.time_ns()
32-
# for ii in range(n2):
33-
# nn.calculate_MSE(validate_input, validate_output, nn_values)
34-
# # nn.train_single(validate_input[ii], validate_output[ii], nn_values)
35-
# end_time = time.time_ns()
36-
# print("Average 1:", ((end_time-begin_time)/1e9) / n2)
29+
nn_values = nn.make_neural_network(layer_sizes=[train_input.shape[1], 20, train_output.shape[1]], layer_activations=[h.sigmoid, h.softmax])
3730

3831
begin_time = time.time_ns()
3932
epochs, current_mse = nn.train_auto(train_input, train_output, validate_input, validate_output, nn_values)
@@ -43,6 +36,6 @@
4336
test_mse = nn.calculate_MSE(test_input, test_output, nn_values)
4437

4538
accuracy_test = nn.evaluate(test_input, test_output, nn_values)
46-
total_time += (end_time-begin_time)/1e9
39+
total_accuracy += accuracy_test
4740
print("Seed:", random_seed, "Epochs:", epochs, "Time:", (end_time-begin_time)/1e9, "Accuracy:", accuracy_test, "Tr:", train_mse, "V:", current_mse, "T:", test_mse)
48-
print("Average 2:", total_time / n)
41+
print("Average Accuracy:", total_accuracy / n, "Average Time:", ((time.time_ns()-begin_total)/1e9) / n)

numba_neural_network.py

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
11
import numpy as np
2-
# import cupy as cp
2+
from numba.experimental import jitclass
33
from numba import njit, types, typed, prange
44
import z_helper as h
55
import time
66

7+
from numba.core.errors import NumbaTypeSafetyWarning
8+
import warnings
9+
10+
warnings.simplefilter('ignore', category=NumbaTypeSafetyWarning)
11+
12+
spec = [
13+
("layer_sizes", types.ListType(types.int64)),
14+
("layer_activations", types.ListType(types.FunctionType(types.float64[:, ::1](types.float64[:, ::1], types.boolean)))),
15+
("weights", types.ListType(types.float64[:, ::1])),
16+
("biases", types.ListType(types.float64[:, ::1])),
17+
("layer_outputs", types.ListType(types.float64[:, ::1])),
18+
("learning_rate", types.float64),
19+
]
20+
@jitclass(spec)
21+
class NeuralNetwork:
22+
def __init__(self, layer_sizes, layer_activations, weights, biases, layer_outputs, learning_rate):
23+
self.layer_sizes = layer_sizes
24+
self.layer_activations = layer_activations
25+
self.weights = weights
26+
self.biases = biases
27+
self.layer_outputs = layer_outputs
28+
self.learning_rate = learning_rate
29+
730

831
def make_neural_network(layer_sizes, layer_activations, learning_rate=0.05, low=-2, high=2):
32+
for size in layer_sizes:
33+
assert size > 0
934

1035
# Initialize typed layer sizes list.
1136
typed_layer_sizes = typed.List()
@@ -14,10 +39,10 @@ def make_neural_network(layer_sizes, layer_activations, learning_rate=0.05, low=
1439
# print(typeof(typed_layer_sizes))
1540

1641
# Initialie typed layer activation method strings list.
17-
typed_layer_activations = typed.List()
42+
prototype = types.FunctionType(types.float64[:, ::1](types.float64[:, ::1], types.boolean))
43+
typed_layer_activations = typed.List.empty_list(prototype)
1844
for activation in layer_activations:
1945
typed_layer_activations.append(activation)
20-
# print(typeof(typed_layer_activations))
2146

2247
# Initialize weights between every neuron in all adjacent layers.
2348
typed_weights = typed.List()
@@ -38,49 +63,42 @@ def make_neural_network(layer_sizes, layer_activations, learning_rate=0.05, low=
3863
# print(typeof(typed_layer_outputs))
3964

4065
typed_learning_rate = learning_rate
41-
return (typed_layer_sizes, typed_layer_activations, typed_weights, typed_biases, typed_layer_outputs, typed_learning_rate)
42-
43-
# typed_layer_sizes = 0
44-
# typed_layer_activations = 1
45-
# typed_weights = 2
46-
# typed_biases = 3
47-
# typed_layer_outputs = 4
48-
# typed_learning_rate = 5
66+
return NeuralNetwork(typed_layer_sizes, typed_layer_activations, typed_weights, typed_biases, typed_layer_outputs, typed_learning_rate)
4967

5068

5169
@njit
5270
def calculate_output(input_data, nn):
53-
assert len(input_data) == nn[0][0]
71+
assert len(input_data) == nn.layer_sizes[0]
5472
y = input_data
55-
for i in prange(len(nn[2])):
56-
y = h.activation(np.dot(nn[2][i].T, y) + nn[3][i], nn[1][i], False)
73+
for i in prange(len(nn.weights)):
74+
y = nn.layer_activations[i](np.dot(nn.weights[i].T, y) + nn.biases[i], False)
5775
return y
5876

5977

6078
@njit
6179
def feed_forward_layers(input_data, nn):
62-
assert len(input_data) == nn[0][0]
63-
nn[4][0] = input_data
64-
for i in range(len(nn[2])):
65-
nn[4][i+1] = h.activation(np.dot(nn[2][i].T, nn[4][i]) + nn[3][i], nn[1][i], False)
80+
assert len(input_data) == nn.layer_sizes[0]
81+
nn.layer_outputs[0] = input_data
82+
for i in prange(len(nn.weights)):
83+
nn.layer_outputs[i+1] = nn.layer_activations[i](np.dot(nn.weights[i].T, nn.layer_outputs[i]) + nn.biases[i], False)
6684

6785

6886
@njit
6987
def train_single(input_data, desired_output_data, nn):
70-
assert len(input_data) == nn[0][0]
71-
assert len(desired_output_data) == nn[0][-1]
88+
assert len(input_data) == nn.layer_sizes[0]
89+
assert len(desired_output_data) == nn.layer_sizes[-1]
7290
feed_forward_layers(input_data, nn)
7391

74-
error = (desired_output_data - nn[4][-1]) * h.activation(nn[4][-1], nn[1][-1], True)
75-
nn[2][-1] += (nn[5] * nn[4][-2] * error.T)
76-
nn[3][-1] += nn[5] * error
92+
error = (desired_output_data - nn.layer_outputs[-1]) * nn.layer_activations[-1](nn.layer_outputs[-1], True)
93+
nn.weights[-1] += nn.learning_rate * nn.layer_outputs[-2] * error.T
94+
nn.biases[-1] += nn.learning_rate * error
7795

78-
length_weights = len(nn[2])
79-
for i in range(1, length_weights):
96+
length_weights = len(nn.weights)
97+
for i in prange(1, length_weights):
8098
i = length_weights - i - 1
81-
error = np.dot(nn[2][i+1], error) * h.activation(nn[4][i+1], nn[1][i], True)
82-
nn[2][i] += (nn[5] * nn[4][i] * error.T)
83-
nn[3][i] += nn[5] * error
99+
error = np.dot(nn.weights[i+1], error) * nn.layer_activations[i](nn.layer_outputs[i+1], True)
100+
nn.weights[i] += nn.learning_rate * nn.layer_outputs[i] * error.T
101+
nn.biases[i] += nn.learning_rate * error
84102
return nn
85103

86104

@@ -135,5 +153,5 @@ def evaluate(input_data, desired_output_data, nn):
135153

136154
@njit
137155
def print_weights_and_biases(nn):
138-
print(nn[2])
139-
print(nn[3])
156+
print(nn.weights)
157+
print(nn.biases)

z_helper.py

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import numpy as np
2-
from numba import cuda
3-
from numba import njit, types, typed
2+
from numba import njit
43

54

65
def import_from_csv(path, data_type):
@@ -19,49 +18,32 @@ def kfold(k, data, seed=99):
1918
fold_size = int(len(data) / k)
2019
return data[fold_size*2:], data[:fold_size], data[fold_size:fold_size*2]
2120

22-
# @cuda.jit
23-
# def multiply_stride(a, b, c):
24-
# s1, s2 = cuda.grid(2)
25-
# d1, d2 = cuda.gridsize(2)
26-
# for i1 in range(s1, a.shape[0], d1):
27-
# for i2 in range(s2, b.shape[1], d2):
28-
# the_sum = 0
29-
# for k in range(b.shape[0]): # or a.shape[1]
30-
# the_sum += a[i1][k]*b[k][i2]
31-
# c[i1, i2] = the_sum
3221

33-
34-
# @njit
35-
# def multiply(a, b):
36-
# d_a = cuda.to_device(a)
37-
# d_b = cuda.to_device(b)
38-
# c = np.zeros((a.shape[0], b.shape[1]))
39-
# d_c = cuda.to_device(c)
40-
# multiply_stride[(1,), (2,2)](d_a, d_b, d_c)
41-
# print(d_c.copy_to_host())
42-
43-
44-
@njit
45-
def activation(x, ftype, derivative):
22+
@njit('float64[:, ::1](float64[:, ::1], boolean)')
23+
def sigmoid(x, derivative):
4624
if derivative:
4725
return x * (1.0 - x)
4826
else:
4927
return 1.0 / (1.0 + np.exp(-x))
5028

5129

52-
@njit
30+
@njit('float64[:, ::1](float64[:, ::1], boolean)')
5331
def relu(x, derivative):
5432
if derivative:
55-
return np.where(x <= 0, 0, 1)
33+
return np.where(x <= 0.0, 0.0, 1.0)
5634
else:
57-
return np.maximum(0, x)
35+
return np.maximum(0.0, x)
5836

5937

60-
def softmax(x):
61-
return np.exp(x) / np.sum(np.exp(x))
62-
38+
@njit('float64[:, ::1](float64[:, ::1], boolean)')
39+
def leaky_relu(x, derivative):
40+
if derivative:
41+
return np.where(x <= 0.0, -0.01*x, 1.0)
42+
else:
43+
return np.maximum(-0.01*x, x)
6344

64-
# aa = np.arange(1000*1000).reshape(1000,1000)
65-
# bb = np.arange(1000*1000).reshape(1000,1000)
6645

67-
# multiply(aa, bb)
46+
@njit('float64[:, ::1](float64[:, ::1], boolean)')
47+
def softmax(x, derivative):
48+
e_x = np.exp(x - np.max(x))
49+
return e_x / e_x.sum()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy