-
Notifications
You must be signed in to change notification settings - Fork 0
/
Perceptron.py
177 lines (156 loc) · 5.74 KB
/
Perceptron.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import numpy as np
# Activation function for 2LP
def tanh(x):
return np.tanh(x)
# Derivative of activation function
def tanh_deriv(x):
return 1.0 - np.tanh(x)**2
# Two Layer Perceptron classifier
class Two_Layer_Perceptron_Classifier:
# Initialize
###############################################################################
# INPUT
# size_h: Units in hidden layer (default=2)
# alpha: Momentum factor (default=0.1)
# learning_rate: Learning rate (default=0.1)
# epochs: Max epochs when training (default=5000)
# error_rate: Accepted error rate to stop training (default=0.01)
# ###############################################################################
def __init__(self, size_h=2, alpha=0.1, learning_rate=0.1, epochs=5000, error_rate=0.01):
self.size_h = size_h
self.alpha = alpha
self.learning_rate = learning_rate
self.epochs = epochs
self.error_rate = error_rate
# Training function
###############################################################################
# INPUT
# X: N x d array with training data
# Y: N x 1 array with training data labels
# ###############################################################################
def train(self, X, y):
N = X.shape[0]
# Add column for bias
X = np.c_[X, np.ones(N)]
d = X.shape[1]
# Initialize hidden layer weight array
self.hl_weight = np.random.uniform(size=(d, self.size_h))
# Initialize hidden layer output array
self.hl_output = np.empty((N, self.size_h))
# Initialize output layer weight array
self.ol_weight = np.random.uniform(size=(self.size_h, y.shape[1]))
# Initialize output layer output array
self.ol_output = np.empty_like(y)
# Initialize momentum to zero
self.hl_momentum = 0
self.ol_momentum = 0
# Start backpropagation
for i in range(self.epochs):
self.propagate_forward(X)
self.propagate_backward(X, y)
self.update_weights(X)
# Stop training if accepted error rate is reached
if self.sqe <= self.error_rate:
break
# Backpropagation functions
def propagate_forward(self, X):
# Compute output vector of hidden layer
self.hl_output = tanh(np.dot(X, self.hl_weight))
# Compute output vector of output layer
self.ol_output = tanh(np.dot(self.hl_output, self.ol_weight))
def propagate_backward(self, X, y):
# Compute delta for output layer
self.ol_delta = (y - self.ol_output) * tanh_deriv(self.ol_output)
# Compute delta for hidden layer
self.hl_delta = np.dot(self.ol_delta, self.ol_weight.T) * tanh_deriv(self.hl_output)
# Sum of squared errors
self.sqe = (0.5*(y - self.ol_output)**2).sum()
print "Error rate: " + str(self.sqe)
def update_weights(self, X):
# Calculate the hidden layer gradient
hl_Delta_w = self.learning_rate * np.dot(X.T, self.hl_delta) + (self.alpha * self.hl_momentum)
# Update hidden layer weight
self.hl_weight += hl_Delta_w
# Set hidden layer momentum to gradient
self.hl_momentum = hl_Delta_w
# Caculate the output layer gradient
ol_Delta_w = self.learning_rate * np.dot(self.hl_output.T, self.ol_delta) + (self.alpha * self.ol_momentum)
# Update output layer weight
self.ol_weight += ol_Delta_w
# Set output layer momentum to gradient
self.ol_momentum = ol_Delta_w
# Classify function
###############################################################################
# INPUT
# X: N x d array with test data
###############################################################################
# OUTPUT
# Y: N x 1 array with predicted data labels
###############################################################################
def classify(self, X):
N = X.shape[0]
# Add column for bias
X = np.c_[X, np.ones(N)]
# Get predicted labels
self.propagate_forward(X)
return np.sign(self.ol_output)
# Perceptron classifier
class Perceptron_Classifier:
# Initialize
###############################################################################
# INPUT
# learning_rate: Learning rate (default=0.1)
# n_iter: Max iterations when training (default=5000)
# ###############################################################################
def __init__(self, learning_rate=0.1, n_iter=5000):
self.learning_rate = learning_rate
self.n_iter = n_iter
# Training function
###############################################################################
# INPUT
# X: N x d array with training data
# Y: N x 1 array with training data labels
###############################################################################
def train(self, X, y):
N = X.shape[0]
# Add column for bias
X = np.c_[X, np.ones(N)]
d = X.shape[1]
# Initalize random weight vector
self.w = np.random.uniform(size=(d, 1))
# Start iteration count
t = 0
while True:
# Start error count
error = 0
# Create new gradient with zeros
gradient = np.zeros((1,d))
# Check for misclassified points in X
for i in range(N):
if (-y[i])*np.dot(X[i], self.w) >= 0:
# If misclassified update error count and gradient
error += 1
gradient = gradient + self.learning_rate*(X[i]*-y[i])
# Update weight vector
self.w = self.w - (self.learning_rate*gradient.T)
print "Missclassified: " + str(error)
# Update iteration count
t += 1
# Stop training if there are 0 missclassified or iteration limit is reached
if error == 0 or t >= self.n_iter:
break
# Classify function
###############################################################################
# INPUT
# X: N x d array with test data
###############################################################################
# OUTPUT
# Y: N x 1 array with predicted data labels
###############################################################################
def classify(self, X):
N = X.shape[0]
# Add column for bias
X = np.c_[X, np.ones(N)]
# Get predicted labels
Y = np.sign(np.dot(X, self.w))
return Y