-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOperation.py
More file actions
182 lines (163 loc) · 6.99 KB
/
Operation.py
File metadata and controls
182 lines (163 loc) · 6.99 KB
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
178
179
180
181
182
from tinyTensor.Node import Node
import numpy as np
import typing
import tinyTensor.Graph
'''
This class is created by the node class when an operation is performed on two nodes, or when the
user uses one of the named functions that operation supports (e.g. sum or mean)
'''
oneParamFunctionList = ['sigmoid', 'tanh','relu','step']
onePlusParamFunctList = ['sum', 'mean']
twoParamFunctionList = ['+', '-', '/', '*', '%']
class Operation(Node):
def __init__(self, nodes, function: str) -> None:
super().__init__()
if(not isinstance(nodes,list)):
nodes = [nodes]
if(len(nodes) > 2): # oparation on a range of nodes
if (not function in onePlusParamFunctList ):
raise Exception('invalid operation: {0}'.format(function))
self.inputNodes = nodes
self.name = function
self.operator = function
elif(len(nodes) == 2): # simple operation on two nodes
operandA = nodes[0]
operandB = nodes[1]
if(not function in twoParamFunctionList):
raise Exception('invalid operator provided: {0}'.format(function))
elif(operandA == None or operandB == None):
raise Exception('provided operands cannot be None.')
self.operator = function
self.name = function
tinyTensor.Graph._default_graph.appendNode(self)
if(not isinstance(operandA,Node) and type(operandA) in [int,float]):
self.NodeA = Node.variable(operandA)
else:
self.NodeA = operandA
if (not isinstance(operandB, Node) and type(operandB) in [int, float]):
self.NodeB = Node.variable(operandB)
else:
self.NodeB = operandB
self.inputNodes = [operandA,operandB]
elif(len(nodes) == 1): # single node operations, e.g activation functions
if (not function in oneParamFunctionList + onePlusParamFunctList):
raise Exception('invalid operation: {0}'.format(function))
self.inputNodes = nodes
self.name = function
self.operator = function
"""'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
NAMED OPERATIONS
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"""
@classmethod
def sum(cls,*argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="sum")
return op
@classmethod
def mean(cls,*argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="mean")
return op
@staticmethod
def extractAndValidate(argv):
"""
extracts nodes from argv passed into function
:param argv:
"""
nodes = []
if(not isinstance(argv,list) and not isinstance(argv,tuple)):
argv = [argv]
for arg in argv:
# some basic input validation
if (arg == None):
raise Exception("Input node to operation cannot be of type NONE")
elif(type(arg) in (int,float)): # const needs to be converted to Node
tmpNode = Node.variable(arg)
nodes.append(tmpNode)
elif(isinstance(arg,Node)):
nodes.append(arg)
elif(isinstance(arg,list)): # dealing with lists of nodes passed into operation
for node in arg:
extracted = Operation.extractAndValidate(node)
if(isinstance(extracted,list)):
nodes.extend(extracted)
else:
nodes.append(extracted)
else:
raise Exception("Argument provided is not of type Node")
return nodes
"""'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ACTIVATION FUNCTIONS
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"""
@classmethod
def sigmoid_act(cls, *argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="sigmoid")
return op
@classmethod
def tanh_act(cls, *argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="tanh")
return op
@classmethod
def relu_act(cls, *argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="relu")
return op
@classmethod
def step_act(cls, *argv):
nodes = Operation.extractAndValidate(argv)
op = Operation(nodes=nodes, function="step")
return op
def sigmoid(self,value):
return 1 / (1 + np.exp(-value))
def tanh(self,value):
return np.tanh(value)
def relu(self,value):
if(value < 0):
return 0
else:
return value
def step(self,value):
if(value<0):
return -1
else:
return 1
"""'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
COMPUTE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"""
def compute(self,step) -> Node:
if (self.step == step):
return self
else:
self.step = step
if (self.operator == "+"):
self.value = self.NodeA.value + self.NodeB.value
elif (self.operator == "-"):
self.value = self.NodeA.value - self.NodeB.value
elif (self.operator == "/"):
self.value = self.NodeA.value / self.NodeB.value
elif (self.operator == "%"):
self.value = self.NodeA.value % self.NodeB.value
elif (self.operator == "*"):
self.value = self.NodeA.value * self.NodeB.value
elif (self.operator == "sum"):
self.value = 0
for node in self.inputNodes:
self.value += node.value
elif (self.operator == "mean"):
self.value = 0
for node in self.inputNodes:
self.value += node.value
self.value /= len(self.inputNodes)
elif(self.operator == "sigmoid"):
self.value = self.sigmoid(self.inputNodes[0].value)
elif (self.operator == "tanh"):
self.value = self.tanh(self.inputNodes[0].value)
elif (self.operator == "relu"):
self.value = self.relu(self.inputNodes[0].value)
elif (self.operator == "step"):
self.value = self.step(self.inputNodes[0].value)
else:
raise Exception("Unknown operator: {0}".format(self.operator))
return self