Skip to content

Commit 7d2ed63

Browse files
author
Olcay Taner YILDIZ
committed
Added different activation functions and updated deep network codes.
1 parent b670adc commit 7d2ed63

10 files changed

Lines changed: 112 additions & 28 deletions

Classification/Model/AutoEncoderModel.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from Classification.Instance.Instance import Instance
55
from Classification.InstanceList.InstanceList import InstanceList
66
from Classification.Model.NeuralNetworkModel import NeuralNetworkModel
7+
from Classification.Parameter.ActivationFunction import ActivationFunction
78
from Classification.Parameter.MultiLayerPerceptronParameter import MultiLayerPerceptronParameter
89
import copy
910

@@ -46,7 +47,7 @@ def __init__(self, trainSet: InstanceList, validationSet: InstanceList, paramete
4647
for j in range(trainSet.size()):
4748
self.createInputVector(trainSet.get(j))
4849
self.r = trainSet.get(j).toVector()
49-
hidden = self.calculateHidden(self.x, self.__W)
50+
hidden = self.calculateHidden(self.x, self.__W, ActivationFunction.SIGMOID)
5051
hiddenBiased = hidden.biased()
5152
self.y = self.__V.multiplyWithVectorFromRight(hiddenBiased)
5253
rMinusY = self.r.difference(self.y)
@@ -121,11 +122,11 @@ def __predictInput(self, instance: Instance) -> Vector:
121122
Predicted value.
122123
"""
123124
self.createInputVector(instance)
124-
self.calculateForwardSingleHiddenLayer(self.__W, self.__V)
125+
self.calculateForwardSingleHiddenLayer(self.__W, self.__V, ActivationFunction.SIGMOID)
125126
return self.y
126127

127128
def calculateOutput(self):
128129
"""
129130
The calculateOutput method calculates a forward single hidden layer.
130131
"""
131-
self.calculateForwardSingleHiddenLayer(self.__W, self.__V)
132+
self.calculateForwardSingleHiddenLayer(self.__W, self.__V, ActivationFunction.SIGMOID)

Classification/Model/DeepNetworkModel.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from Classification.InstanceList.InstanceList import InstanceList
22
from Classification.Model.NeuralNetworkModel import NeuralNetworkModel
3+
from Classification.Parameter.ActivationFunction import ActivationFunction
34
from Classification.Parameter.DeepNetworkParameter import DeepNetworkParameter
45
from Math.Matrix import Matrix
6+
from Math.Vector import Vector
57
import copy
68

79
from Classification.Performance.ClassificationPerformance import ClassificationPerformance
@@ -11,6 +13,7 @@ class DeepNetworkModel(NeuralNetworkModel):
1113

1214
__weights: list
1315
__hiddenLayerSize: int
16+
__activationFunction: ActivationFunction
1417

1518
def __init__(self, trainSet: InstanceList, validationSet: InstanceList, parameters: DeepNetworkParameter):
1619
"""
@@ -36,6 +39,7 @@ def __init__(self, trainSet: InstanceList, validationSet: InstanceList, paramete
3639
deltaWeights = []
3740
hidden = []
3841
hiddenBiased = []
42+
self.__activationFunction = parameters.getActivationFunction()
3943
self.__allocateWeights(parameters)
4044
bestWeights = self.__setBestWeights()
4145
bestClassificationPerformance = ClassificationPerformance(0.0)
@@ -50,18 +54,30 @@ def __init__(self, trainSet: InstanceList, validationSet: InstanceList, paramete
5054
deltaWeights.clear()
5155
for k in range(self.__hiddenLayerSize):
5256
if k == 0:
53-
hidden.append(self.calculateHidden(self.x, self.__weights[k]))
57+
hidden.append(self.calculateHidden(self.x, self.__weights[k], self.__activationFunction))
5458
else:
55-
hidden.append(self.calculateHidden(hiddenBiased[k - 1], self.__weights[k]))
59+
hidden.append(self.calculateHidden(hiddenBiased[k - 1], self.__weights[k], self.__activationFunction))
5660
hiddenBiased.append(hidden[k].biased())
5761
rMinusY = self.calculateRMinusY(trainSet.get(j), hiddenBiased[self.__hiddenLayerSize - 1],
5862
self.__weights[len(self.__weights) - 1])
5963
deltaWeights.insert(0, Matrix(rMinusY, hiddenBiased[self.__hiddenLayerSize - 1]))
6064
for k in range(len(self.__weights) - 2, -1, -1):
61-
oneMinusHidden = self.calculateOneMinusHidden(hidden[k])
62-
tmph = deltaWeights[0].elementProduct(self.__weights[k + 1]).sumOfRows()
65+
if k == len(self.__weights) - 2:
66+
tmph = self.__weights[k + 1].multiplyWithVectorFromLeft(rMinusY)
67+
else:
68+
tmph = self.__weights[k + 1].multiplyWithVectorFromLeft(tmpHidden)
6369
tmph.remove(0)
64-
tmpHidden = oneMinusHidden.elementProduct(tmph)
70+
if self.__activationFunction == ActivationFunction.SIGMOID:
71+
oneMinusHidden = self.calculateOneMinusHidden(hidden[k])
72+
activationDerivative = oneMinusHidden.elementProduct(hidden[k])
73+
elif self.__activationFunction == ActivationFunction.TANH:
74+
one = Vector(hidden[k].size(), 1.0)
75+
hidden[k].tanh()
76+
activationDerivative = one.difference(hidden[k].elementProduct(hidden[k]))
77+
elif self.__activationFunction == ActivationFunction.RELU:
78+
hidden[k].reluDerivative()
79+
activationDerivative = hidden
80+
tmpHidden = tmph.elementProduct(activationDerivative)
6581
if k == 0:
6682
deltaWeights.insert(0, Matrix(tmpHidden, self.x))
6783
else:
@@ -121,8 +137,8 @@ def calculateOutput(self):
121137
hiddenBiased = None
122138
for i in range(len(self.__weights) - 1):
123139
if i == 0:
124-
hidden = self.calculateHidden(self.x, self.__weights[i])
140+
hidden = self.calculateHidden(self.x, self.__weights[i], self.__activationFunction)
125141
else:
126-
hidden = self.calculateHidden(hiddenBiased, self.__weights[i])
142+
hidden = self.calculateHidden(hiddenBiased, self.__weights[i], self.__activationFunction)
127143
hiddenBiased = hidden.biased()
128144
self.y = self.__weights[len(self.__weights) - 1].multiplyWithVectorFromRight(hiddenBiased)

Classification/Model/MultiLayerPerceptronModel.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from Math.Matrix import Matrix
2+
from Math.Vector import Vector
23

34
from Classification.InstanceList.InstanceList import InstanceList
45
from Classification.Model.LinearPerceptronModel import LinearPerceptronModel
6+
from Classification.Parameter.ActivationFunction import ActivationFunction
57
from Classification.Parameter.MultiLayerPerceptronParameter import MultiLayerPerceptronParameter
68
import copy
79

@@ -11,6 +13,7 @@
1113
class MultiLayerPerceptronModel(LinearPerceptronModel):
1214

1315
__V: Matrix
16+
__activationFunction: ActivationFunction
1417

1518
def __allocateWeights(self, H: int, seed: int):
1619
"""
@@ -42,6 +45,7 @@ def __init__(self, trainSet: InstanceList, validationSet: InstanceList, paramete
4245
hiddenNodes.
4346
"""
4447
super().initWithTrainSet(trainSet)
48+
self.__activationFunction = parameters.getActivationFunction()
4549
self.__allocateWeights(parameters.getHiddenNodes(), parameters.getSeed())
4650
bestW = copy.deepcopy(self.W)
4751
bestV = copy.deepcopy(self.__V)
@@ -52,14 +56,23 @@ def __init__(self, trainSet: InstanceList, validationSet: InstanceList, paramete
5256
trainSet.shuffle(parameters.getSeed())
5357
for j in range(trainSet.size()):
5458
self.createInputVector(trainSet.get(j))
55-
hidden = self.calculateHidden(self.x, self.W)
59+
hidden = self.calculateHidden(self.x, self.W, self.__activationFunction)
5660
hiddenBiased = hidden.biased()
5761
rMinusY = self.calculateRMinusY(trainSet.get(j), hiddenBiased, self.__V)
5862
deltaV = Matrix(rMinusY, hiddenBiased)
59-
oneMinusHidden = self.calculateOneMinusHidden(hidden)
6063
tmph = self.__V.multiplyWithVectorFromLeft(rMinusY)
6164
tmph.remove(0)
62-
tmpHidden = oneMinusHidden.elementProduct(hidden.elementProduct(tmph))
65+
if self.__activationFunction == ActivationFunction.SIGMOID:
66+
oneMinusHidden = self.calculateOneMinusHidden(hidden)
67+
activationDerivative = oneMinusHidden.elementProduct(hidden)
68+
elif self.__activationFunction == ActivationFunction.TANH:
69+
one = Vector(hidden.size(), 1.0)
70+
hidden.tanh()
71+
activationDerivative = one.difference(hidden.elementProduct(hidden))
72+
elif self.__activationFunction == ActivationFunction.RELU:
73+
hidden.reluDerivative()
74+
activationDerivative = hidden
75+
tmpHidden = tmph.elementProduct(activationDerivative)
6376
deltaW = Matrix(tmpHidden, self.x)
6477
deltaV.multiplyWithConstant(learningRate)
6578
self.__V.add(deltaV)
@@ -78,4 +91,4 @@ def calculateOutput(self):
7891
"""
7992
The calculateOutput method calculates the forward single hidden layer by using Matrices W and V.
8093
"""
81-
self.calculateForwardSingleHiddenLayer(self.W, self.__V)
94+
self.calculateForwardSingleHiddenLayer(self.W, self.__V, self.__activationFunction)

Classification/Model/NeuralNetworkModel.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import math
1212

13+
from Classification.Parameter.ActivationFunction import ActivationFunction
14+
1315

1416
class NeuralNetworkModel(ValidatedModel):
1517
classLabels: list
@@ -99,7 +101,7 @@ def createInputVector(self, instance: Instance):
99101
self.x = instance.toVector()
100102
self.x.insert(0, 1.0)
101103

102-
def calculateHidden(self, input: Vector, weights: Matrix) -> Vector:
104+
def calculateHidden(self, input: Vector, weights: Matrix, activationFunction: ActivationFunction) -> Vector:
103105
"""
104106
The calculateHidden method takes a {@link Vector} input and {@link Matrix} weights, It multiplies the weights
105107
Matrix with given input Vector than applies the sigmoid function and returns the result.
@@ -110,14 +112,21 @@ def calculateHidden(self, input: Vector, weights: Matrix) -> Vector:
110112
Vector to multiply weights.
111113
weights : Matrix
112114
Matrix is multiplied with input Vector.
115+
activationFunction : ActivationFunction
116+
Activation function
113117
114118
RETURNS
115119
-------
116120
Vector
117121
Result of sigmoid function.
118122
"""
119123
z = weights.multiplyWithVectorFromRight(input)
120-
z.sigmoid()
124+
if activationFunction == ActivationFunction.SIGMOID:
125+
z.sigmoid()
126+
elif activationFunction == ActivationFunction.TANH:
127+
z.tanh()
128+
elif activationFunction == ActivationFunction.RELU:
129+
z.relu()
121130
return z
122131

123132
def calculateOneMinusHidden(self, hidden: Vector) -> Vector:
@@ -139,7 +148,7 @@ def calculateOneMinusHidden(self, hidden: Vector) -> Vector:
139148
one.initAllSame(hidden.size(), 1.0)
140149
return one.difference(hidden)
141150

142-
def calculateForwardSingleHiddenLayer(self, W: Matrix, V: Matrix):
151+
def calculateForwardSingleHiddenLayer(self, W: Matrix, V: Matrix, activationFunction: ActivationFunction):
143152
"""
144153
The calculateForwardSingleHiddenLayer method takes two matrices W and V. First it multiplies W with x, then
145154
multiplies V with the result of the previous multiplication.
@@ -150,8 +159,10 @@ def calculateForwardSingleHiddenLayer(self, W: Matrix, V: Matrix):
150159
Matrix to multiply with x.
151160
V : Matrix
152161
Matrix to multiply.
162+
activationFunction : ActivationFunction
163+
Activation function
153164
"""
154-
hidden = self.calculateHidden(self.x, W)
165+
hidden = self.calculateHidden(self.x, W, activationFunction)
155166
hiddenBiased = hidden.biased()
156167
self.y = V.multiplyWithVectorFromRight(hiddenBiased)
157168

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from enum import Enum, auto
2+
3+
4+
class ActivationFunction(Enum):
5+
6+
SIGMOID = auto()
7+
TANH = auto()
8+
RELU = auto()

Classification/Parameter/DeepNetworkParameter.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
from Classification.Parameter.ActivationFunction import ActivationFunction
12
from Classification.Parameter.LinearPerceptronParameter import LinearPerceptronParameter
23

34

45
class DeepNetworkParameter(LinearPerceptronParameter):
56

67
__hiddenLayers: list
8+
__activationFunction: ActivationFunction
79

8-
def __init__(self, seed: int, learningRate: float, etaDecrease: float, crossValidationRatio: float, epoch: int, hiddenLayers: list):
10+
def __init__(self, seed: int, learningRate: float, etaDecrease: float, crossValidationRatio: float, epoch: int,
11+
hiddenLayers: list, activationFunction: ActivationFunction):
912
"""
1013
Parameters of the deep network classifier.
1114
@@ -23,9 +26,12 @@ def __init__(self, seed: int, learningRate: float, etaDecrease: float, crossVali
2326
Integer value for epoch number of the algorithm.
2427
hiddenLayers : list
2528
An integer list for hidden layers of the algorithm.
29+
activationFunction : ActivationFunction
30+
Activation function.
2631
"""
2732
super().__init__(seed, learningRate, etaDecrease, crossValidationRatio, epoch)
2833
self.__hiddenLayers = hiddenLayers
34+
self.__activationFunction = activationFunction
2935

3036
def layerSize(self) -> int:
3137
"""
@@ -54,3 +60,14 @@ def getHiddenNodes(self, layerIndex: int) -> int:
5460
The element at the layerIndex of hiddenLayers list.
5561
"""
5662
return self.__hiddenLayers[layerIndex]
63+
64+
def getActivationFunction(self) -> ActivationFunction:
65+
"""
66+
Accessor for the activationFunction.
67+
68+
RETURNS
69+
-------
70+
int
71+
The activation function.
72+
"""
73+
return self.__activationFunction

Classification/Parameter/MultiLayerPerceptronParameter.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
from Classification.Parameter.ActivationFunction import ActivationFunction
12
from Classification.Parameter.LinearPerceptronParameter import LinearPerceptronParameter
23

34

45
class MultiLayerPerceptronParameter(LinearPerceptronParameter):
56

67
__hiddenNodes: int
8+
__activationFunction: ActivationFunction
79

810
def __init__(self, seed: int, learningRate: float, etaDecrease: float, crossValidationRatio: float, epoch: int,
9-
hiddenNodes: int):
11+
hiddenNodes: int, activationFunction: ActivationFunction):
1012
"""
1113
Parameters of the multi layer perceptron algorithm.
1214
@@ -24,9 +26,12 @@ def __init__(self, seed: int, learningRate: float, etaDecrease: float, crossVali
2426
Integer value for epoch number of the algorithm.
2527
hiddenNodes : int
2628
Integer value for the number of hidden nodes.
29+
activationFunction : ActivationFunction
30+
Activation function.
2731
"""
2832
super().__init__(seed, learningRate, etaDecrease, crossValidationRatio, epoch)
2933
self.__hiddenNodes = hiddenNodes
34+
self.__activationFunction = activationFunction
3035

3136
def getHiddenNodes(self) -> int:
3237
"""
@@ -38,3 +43,14 @@ def getHiddenNodes(self) -> int:
3843
The hiddenNodes.
3944
"""
4045
return self.__hiddenNodes
46+
47+
def getActivationFunction(self) -> ActivationFunction:
48+
"""
49+
Accessor for the activationFunction.
50+
51+
RETURNS
52+
-------
53+
int
54+
The activation function.
55+
"""
56+
return self.__activationFunction

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='NlpToolkit-Classification',
5-
version='1.0.9',
5+
version='1.0.10',
66
packages=['Classification', 'Classification.Model', 'Classification.Model.DecisionTree', 'Classification.Filter',
77
'Classification.DataSet', 'Classification.Instance', 'Classification.Attribute',
88
'Classification.Parameter', 'Classification.Classifier', 'Classification.Experiment',

test/Classifier/DeepNetworkTest.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22

33
from Classification.Classifier.DeepNetwork import DeepNetwork
4+
from Classification.Parameter.ActivationFunction import ActivationFunction
45
from Classification.Parameter.DeepNetworkParameter import DeepNetworkParameter
56
from test.Classifier.ClassifierTest import ClassifierTest
67

@@ -9,13 +10,13 @@ class DeepNetworkTest(ClassifierTest):
910

1011
def test_Train(self):
1112
deepNetwork = DeepNetwork()
12-
deepNetworkParameter = DeepNetworkParameter(1, 0.1, 0.99, 0.2, 100, [5, 5])
13+
deepNetworkParameter = DeepNetworkParameter(1, 0.1, 0.99, 0.2, 100, [5, 5], ActivationFunction.SIGMOID)
1314
deepNetwork.train(self.iris.getInstanceList(), deepNetworkParameter)
1415
self.assertAlmostEqual(4.00, 100 * deepNetwork.test(self.iris.getInstanceList()).getErrorRate(), 2)
15-
deepNetworkParameter = DeepNetworkParameter(1, 0.01, 0.99, 0.2, 100, [15, 15])
16+
deepNetworkParameter = DeepNetworkParameter(1, 0.01, 0.99, 0.2, 100, [15, 15], ActivationFunction.SIGMOID)
1617
deepNetwork.train(self.bupa.getInstanceList(), deepNetworkParameter)
1718
self.assertAlmostEqual(28.12, 100 * deepNetwork.test(self.bupa.getInstanceList()).getErrorRate(), 2)
18-
deepNetworkParameter = DeepNetworkParameter(1, 0.01, 0.99, 0.2, 100, [20])
19+
deepNetworkParameter = DeepNetworkParameter(1, 0.01, 0.99, 0.2, 100, [20], ActivationFunction.SIGMOID)
1920
deepNetwork.train(self.dermatology.getInstanceList(), deepNetworkParameter)
2021
self.assertAlmostEqual(3.55, 100 * deepNetwork.test(self.dermatology.getInstanceList()).getErrorRate(), 2)
2122

test/Classifier/MultiLayerPerceptronTest.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22

33
from Classification.Classifier.MultiLayerPerceptron import MultiLayerPerceptron
4+
from Classification.Parameter.ActivationFunction import ActivationFunction
45
from Classification.Parameter.MultiLayerPerceptronParameter import MultiLayerPerceptronParameter
56
from test.Classifier.ClassifierTest import ClassifierTest
67

@@ -9,13 +10,13 @@ class MultiLayerPerceptronTest(ClassifierTest):
910

1011
def test_Train(self):
1112
multiLayerPerceptron = MultiLayerPerceptron()
12-
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.1, 0.99, 0.2, 100, 3)
13+
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.1, 0.99, 0.2, 100, 3, ActivationFunction.SIGMOID)
1314
multiLayerPerceptron.train(self.iris.getInstanceList(), multiLayerPerceptronParameter)
1415
self.assertAlmostEqual(2.67, 100 * multiLayerPerceptron.test(self.iris.getInstanceList()).getErrorRate(), 2)
15-
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.01, 0.99, 0.2, 100, 30)
16+
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.01, 0.99, 0.2, 100, 30, ActivationFunction.SIGMOID)
1617
multiLayerPerceptron.train(self.bupa.getInstanceList(), multiLayerPerceptronParameter)
17-
self.assertAlmostEqual(29.86, 100 * multiLayerPerceptron.test(self.bupa.getInstanceList()).getErrorRate(), 2)
18-
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.01, 0.99, 0.2, 100, 20)
18+
self.assertAlmostEqual(30.72, 100 * multiLayerPerceptron.test(self.bupa.getInstanceList()).getErrorRate(), 2)
19+
multiLayerPerceptronParameter = MultiLayerPerceptronParameter(1, 0.01, 0.99, 0.2, 100, 20, ActivationFunction.SIGMOID)
1920
multiLayerPerceptron.train(self.dermatology.getInstanceList(), multiLayerPerceptronParameter)
2021
self.assertAlmostEqual(3.55, 100 * multiLayerPerceptron.test(self.dermatology.getInstanceList()).getErrorRate(), 2)
2122

0 commit comments

Comments
 (0)