Spaces:
Sleeping
Sleeping
Upload 4 files
Browse files- PRNN.py +271 -0
- PRNNSigmoid.py +287 -0
- PRNN_utils.py +403 -0
- PRNN_utilsSigmoid.py +407 -0
PRNN.py
ADDED
@@ -0,0 +1,271 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from PRNN_utils import tags2sentence, check_conditions
|
3 |
+
|
4 |
+
class PRNN():
|
5 |
+
|
6 |
+
def __init__(self, seed=18):
|
7 |
+
np.random.seed(seed) # Set the seed
|
8 |
+
self.params = np.random.normal(0, 1, size=10)
|
9 |
+
self.w = np.random.normal(0, 1, size=1)
|
10 |
+
|
11 |
+
def step(self, x):
|
12 |
+
out = (x>0.0).astype('float')
|
13 |
+
return out
|
14 |
+
|
15 |
+
def relu(self, x):
|
16 |
+
return np.maximum(x, 0.0)
|
17 |
+
|
18 |
+
def relu_dash(self, x):
|
19 |
+
return np.where(x > 0.0, 1.0, 0.0)
|
20 |
+
|
21 |
+
def forward(self, x, h):
|
22 |
+
'''
|
23 |
+
Process x(t) and h(t-1) ie Single pass of RNN
|
24 |
+
Parameters:
|
25 |
+
x:np.array = [-upper_input_1-hot- -1 -lower_input_1-hot-]
|
26 |
+
h:float {0,1}
|
27 |
+
Returns:
|
28 |
+
out(float): Sigmoid(params_trans x(t) + w h(t-1))
|
29 |
+
'''
|
30 |
+
h_t = np.dot(self.params, x) + self.w*h # p_trans x(t) + w h(t-1)
|
31 |
+
|
32 |
+
return h_t
|
33 |
+
|
34 |
+
def process_seq(self, sequence, h_0=0.0):
|
35 |
+
"""
|
36 |
+
Process the whole sequence
|
37 |
+
Parameters:
|
38 |
+
sequence List[List]
|
39 |
+
Returns:
|
40 |
+
list of hidden states
|
41 |
+
"""
|
42 |
+
|
43 |
+
hidden_states = [h_0]
|
44 |
+
h_tminus1 = h_0
|
45 |
+
# Sequentially process the
|
46 |
+
for x_t in sequence:
|
47 |
+
|
48 |
+
h_t = self.forward(x=x_t, h=h_tminus1)
|
49 |
+
hidden_states.append(h_t[0]) # Just extract the numerical value
|
50 |
+
|
51 |
+
h_tminus1 = h_t
|
52 |
+
|
53 |
+
out = np.array(hidden_states).reshape(-1)
|
54 |
+
return out
|
55 |
+
|
56 |
+
def predict_tags(self, sequence):
|
57 |
+
''''
|
58 |
+
Predict Tags {0,1} using step function
|
59 |
+
The op is [[y_cap(1), y_cap(2), .... y_cap(T)]]
|
60 |
+
Each y_cap(i) is either 0 or 1
|
61 |
+
'''
|
62 |
+
|
63 |
+
out = self.process_seq(sequence)
|
64 |
+
out = self.step(out).reshape(-1)[1:]
|
65 |
+
return out
|
66 |
+
|
67 |
+
|
68 |
+
def process_batch(self, batch):
|
69 |
+
"""
|
70 |
+
Processes a batch of sequences throught the model(rnn)
|
71 |
+
Parameters:
|
72 |
+
batch (dtaframe) : containint the field <pos_tags>
|
73 |
+
Oututput
|
74 |
+
outputs list[numpy_array] : Output of each sequence through RNN, hidden state
|
75 |
+
|
76 |
+
"""
|
77 |
+
|
78 |
+
outputs = []
|
79 |
+
for _, row in batch.iterrows():
|
80 |
+
|
81 |
+
x = tags2sentence(row.pos_tags)
|
82 |
+
out = self.process_seq(x)
|
83 |
+
out = out.reshape(-1)
|
84 |
+
|
85 |
+
outputs.append(out)
|
86 |
+
|
87 |
+
return outputs
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
def view_params(self):
|
92 |
+
'''
|
93 |
+
prints perceptron parameters along with names
|
94 |
+
'''
|
95 |
+
print("PERCEPTRON PARAMETERS")
|
96 |
+
|
97 |
+
print(f"Vcap : {self.params[0]}" , end = ' | ')
|
98 |
+
print(f"Vnn : {self.params[1]}" , end = ' | ')
|
99 |
+
print(f"Vdt : {self.params[2]}" , end = ' | ')
|
100 |
+
print(f"Vjj : {self.params[3]}" , end = ' | ')
|
101 |
+
print(f"Vot : {self.params[4]}" )
|
102 |
+
print(f"T [Theta] : {self.params[5]}" , end = ' | ')
|
103 |
+
print(f"Wnn : {self.params[6]}" , end = ' | ')
|
104 |
+
print(f"Wdt : {self.params[7]}" , end = ' | ')
|
105 |
+
print(f"Wjj : {self.params[8]}" , end = ' | ')
|
106 |
+
print(f"Wot : {self.params[9]}")
|
107 |
+
|
108 |
+
print(f"W : {self.w[0]}")
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
def set_perfect_params(self):
|
113 |
+
'''
|
114 |
+
Params are of the form
|
115 |
+
params = [Vcap, Vnn, Vdt, Vjj, Vot, [T]Theta, Wnn, Wdt, Wjj, Wot]
|
116 |
+
'''
|
117 |
+
print("RESETTING TO PERFECT PARAMETERS \n")
|
118 |
+
self.params = np.array([1.5, .3, .1, .2, 2.5, 1.2, .3, 1.3, .2, 2.0])
|
119 |
+
self.w[0] = 0.1
|
120 |
+
self.view_params()
|
121 |
+
|
122 |
+
|
123 |
+
|
124 |
+
def gradient_descent_step(self, grad_p, grad_w, lr=0.05):
|
125 |
+
'''
|
126 |
+
Updates the self. parama and self.w according to the fradient descent rule
|
127 |
+
Parameters:
|
128 |
+
grad_p : numpy array (10,)
|
129 |
+
grad_w : sigle float
|
130 |
+
'''
|
131 |
+
self.params = self.params - lr*grad_p
|
132 |
+
self.w = self.w - lr*grad_w
|
133 |
+
|
134 |
+
|
135 |
+
|
136 |
+
def batch_hinge_loss(self, batch):
|
137 |
+
"""
|
138 |
+
Processes a batch of sequences and calculates the ReLU loss
|
139 |
+
Parameters:
|
140 |
+
batch (dtaframe) : containint the field <pos_tags> and <chunk_tags>
|
141 |
+
Oututput
|
142 |
+
Total Loss Relu
|
143 |
+
"""
|
144 |
+
|
145 |
+
total_loss = 0
|
146 |
+
for _, row in batch.iterrows():
|
147 |
+
|
148 |
+
sent_pos_tags = row.pos_tags
|
149 |
+
X = tags2sentence(sent_pos_tags)
|
150 |
+
H = self.process_seq(X)[1:] # Exclude h(0)
|
151 |
+
|
152 |
+
sent_tags = row.chunk_tags
|
153 |
+
Y = np.array(sent_tags)
|
154 |
+
|
155 |
+
loss = self.relu((.5-Y)*H) # J(t) = ReLU((0.5-y(t))*h(t))
|
156 |
+
loss = loss.mean()
|
157 |
+
|
158 |
+
total_loss += loss
|
159 |
+
|
160 |
+
total_loss = total_loss/len(batch)
|
161 |
+
|
162 |
+
return total_loss
|
163 |
+
|
164 |
+
|
165 |
+
|
166 |
+
def batch_accuracy(self, batch):
|
167 |
+
|
168 |
+
correct = 0 # Predictions that match
|
169 |
+
total = 0 # Total predictions
|
170 |
+
|
171 |
+
for _, row in batch.iterrows():
|
172 |
+
|
173 |
+
sent_pos_tags = row.pos_tags
|
174 |
+
x = tags2sentence(sent_pos_tags)
|
175 |
+
|
176 |
+
sent_tags = row.chunk_tags
|
177 |
+
y_target = np.array(sent_tags)
|
178 |
+
|
179 |
+
y_pred = self.predict_tags(x)
|
180 |
+
correct += np.sum(y_pred == y_target)
|
181 |
+
total += len(y_pred)
|
182 |
+
|
183 |
+
acc = (correct/total)*100 # Accuracy in percentage
|
184 |
+
|
185 |
+
return acc
|
186 |
+
|
187 |
+
|
188 |
+
def batch_sentence_accuracy(self, batch):
|
189 |
+
|
190 |
+
match = 0
|
191 |
+
|
192 |
+
for _, row in batch.iterrows():
|
193 |
+
|
194 |
+
sent_pos_tags = row.pos_tags
|
195 |
+
x = tags2sentence(sent_pos_tags)
|
196 |
+
|
197 |
+
sent_tags = row.chunk_tags
|
198 |
+
y_target = np.array(sent_tags)
|
199 |
+
|
200 |
+
y_pred = self.predict_tags(x)
|
201 |
+
if np.array_equal(y_pred, y_target):
|
202 |
+
match +=1
|
203 |
+
|
204 |
+
sent_acc = (match/len(batch))*100
|
205 |
+
|
206 |
+
return sent_acc
|
207 |
+
|
208 |
+
|
209 |
+
def set_parameter(self, Vcap=1.5, Vnn=.3, Vdt=.1, Vjj=.2, Vot=2.5, T=1.2, Wnn=.3, Wdt=1.3, Wjj=.2, Wot=2.0, W=.10):
|
210 |
+
|
211 |
+
self.params[0] = Vcap
|
212 |
+
self.params[1] = Vnn
|
213 |
+
self.params[2] = Vdt
|
214 |
+
self.params[3] = Vjj
|
215 |
+
self.params[4] = Vot
|
216 |
+
self.params[5] = T
|
217 |
+
self.params[6] = Wnn
|
218 |
+
self.params[7] = Wdt
|
219 |
+
self.params[8] = Wjj
|
220 |
+
self.params[9] = Wot
|
221 |
+
|
222 |
+
self.w[0] = W
|
223 |
+
|
224 |
+
def does_RNN_satisfy_conditions(self):
|
225 |
+
"""
|
226 |
+
Checks whether the RNN satisfies the inequality conditions
|
227 |
+
"""
|
228 |
+
check_conditions(Vcap = np.round(self.params[0],4),
|
229 |
+
Vnn = np.round(self.params[1],4),
|
230 |
+
Vdt = np.round(self.params[2],4),
|
231 |
+
Vjj = np.round(self.params[3],4),
|
232 |
+
Vot = np.round(self.params[4],4),
|
233 |
+
T = np.round(self.params[5],4),
|
234 |
+
Wnn = np.round(self.params[6],4),
|
235 |
+
Wdt = np.round(self.params[7],4),
|
236 |
+
Wjj = np.round(self.params[8],4),
|
237 |
+
Wot = np.round(self.params[9],4),
|
238 |
+
W = np.round(self.w[0],4), verbose=True)
|
239 |
+
|
240 |
+
|
241 |
+
|
242 |
+
|
243 |
+
|
244 |
+
|
245 |
+
|
246 |
+
|
247 |
+
|
248 |
+
|
249 |
+
|
250 |
+
|
251 |
+
|
252 |
+
|
253 |
+
|
254 |
+
|
255 |
+
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
|
264 |
+
|
265 |
+
|
266 |
+
|
267 |
+
|
268 |
+
|
269 |
+
|
270 |
+
|
271 |
+
|
PRNNSigmoid.py
ADDED
@@ -0,0 +1,287 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from PRNN_utils import tags2sentence, check_conditions
|
3 |
+
|
4 |
+
class PRNNSigmoid():
|
5 |
+
|
6 |
+
def __init__(self, seed=15):
|
7 |
+
np.random.seed(seed) # Set the seed
|
8 |
+
self.params = np.random.normal(0, 1, size=10)
|
9 |
+
self.w = np.random.normal(0, 1, size=1)
|
10 |
+
|
11 |
+
def step(self, x, threshold=0.5):
|
12 |
+
out = (x>threshold).astype('float')
|
13 |
+
return out
|
14 |
+
|
15 |
+
def sigmoid(self, x, max_val=10):
|
16 |
+
|
17 |
+
x = np.clip(x, -max_val, max_val)
|
18 |
+
out = 1 / (1 + np.exp(-x))
|
19 |
+
return out
|
20 |
+
|
21 |
+
def sigmoid_dash(self, x):
|
22 |
+
sig_x = self.sigmoid(x)
|
23 |
+
out = sig_x*(1-sig_x)
|
24 |
+
return out
|
25 |
+
|
26 |
+
|
27 |
+
def forward(self, x, h):
|
28 |
+
'''
|
29 |
+
Process x(t) and h(t-1) ie Single pass of RNN
|
30 |
+
Parameters:
|
31 |
+
x:np.array = [-upper_input_1-hot- -1 -lower_input_1-hot-]
|
32 |
+
h:float {0,1}
|
33 |
+
Returns:
|
34 |
+
out(float): Sigmoid(params_trans x(t) + w h(t-1))
|
35 |
+
'''
|
36 |
+
c_t = np.dot(self.params, x) + self.w*h # p_trans x(t) + w h(t-1)
|
37 |
+
h_t = self.sigmoid(c_t)
|
38 |
+
|
39 |
+
return c_t, h_t
|
40 |
+
|
41 |
+
def process_seq(self, sequence, h_0=0.0):
|
42 |
+
"""
|
43 |
+
Process the whole sequence
|
44 |
+
Parameters:
|
45 |
+
sequence List[List]
|
46 |
+
Returns:
|
47 |
+
list of hidden states
|
48 |
+
"""
|
49 |
+
|
50 |
+
hidden_states = [h_0]
|
51 |
+
C_states = [0] #Assume c(0) is 0
|
52 |
+
|
53 |
+
h_tminus1 = h_0
|
54 |
+
# Sequentially process the
|
55 |
+
for x_t in sequence:
|
56 |
+
|
57 |
+
c_t, h_t = self.forward(x=x_t, h=h_tminus1)
|
58 |
+
hidden_states.append(h_t[0]) # Just extract the numerical value
|
59 |
+
C_states.append(c_t[0])
|
60 |
+
|
61 |
+
h_tminus1 = h_t
|
62 |
+
|
63 |
+
C = np.array(C_states).reshape(-1)
|
64 |
+
H = np.array(hidden_states).reshape(-1)
|
65 |
+
return C, H
|
66 |
+
|
67 |
+
def predict_tags(self, sequence):
|
68 |
+
''''
|
69 |
+
Predict Tags {0,1} using step function
|
70 |
+
The op is [[y_cap(1), y_cap(2), .... y_cap(T)]]
|
71 |
+
Each y_cap(i) is either 0 or 1
|
72 |
+
'''
|
73 |
+
|
74 |
+
C, H = self.process_seq(sequence)
|
75 |
+
out = self.step(H).reshape(-1)[1:]
|
76 |
+
return out
|
77 |
+
|
78 |
+
|
79 |
+
def process_batch(self, batch):
|
80 |
+
"""
|
81 |
+
Processes a batch of sequences throught the model(rnn)
|
82 |
+
Parameters:
|
83 |
+
batch (dtaframe) : containint the field <pos_tags>
|
84 |
+
Oututput
|
85 |
+
outputs list[numpy_array] : Output of each sequence through RNN, hidden state
|
86 |
+
|
87 |
+
"""
|
88 |
+
|
89 |
+
H_outputs = []
|
90 |
+
C_outputs = []
|
91 |
+
for _, row in batch.iterrows():
|
92 |
+
|
93 |
+
x = tags2sentence(row.pos_tags)
|
94 |
+
C, H = self.process_seq(x)
|
95 |
+
H = H.reshape(-1)
|
96 |
+
C = C.reshape(-1)
|
97 |
+
|
98 |
+
C_outputs.append(C)
|
99 |
+
H_outputs.append(H)
|
100 |
+
|
101 |
+
return C_outputs, H_outputs
|
102 |
+
|
103 |
+
|
104 |
+
|
105 |
+
def view_params(self):
|
106 |
+
'''
|
107 |
+
prints perceptron parameters along with names
|
108 |
+
'''
|
109 |
+
print("PERCEPTRON PARAMETERS")
|
110 |
+
|
111 |
+
print(f"Vcap : {self.params[0]}" , end = ' | ')
|
112 |
+
print(f"Vnn : {self.params[1]}" , end = ' | ')
|
113 |
+
print(f"Vdt : {self.params[2]}" , end = ' | ')
|
114 |
+
print(f"Vjj : {self.params[3]}" , end = ' | ')
|
115 |
+
print(f"Vot : {self.params[4]}" )
|
116 |
+
print(f"T [Theta] : {self.params[5]}" , end = ' | ')
|
117 |
+
print(f"Wnn : {self.params[6]}" , end = ' | ')
|
118 |
+
print(f"Wdt : {self.params[7]}" , end = ' | ')
|
119 |
+
print(f"Wjj : {self.params[8]}" , end = ' | ')
|
120 |
+
print(f"Wot : {self.params[9]}")
|
121 |
+
|
122 |
+
print(f"W : {self.w[0]}")
|
123 |
+
|
124 |
+
|
125 |
+
|
126 |
+
def set_perfect_params(self):
|
127 |
+
'''
|
128 |
+
Params are of the form
|
129 |
+
params = [Vcap, Vnn, Vdt, Vjj, Vot, [T]Theta, Wnn, Wdt, Wjj, Wot]
|
130 |
+
'''
|
131 |
+
print("RESETTING TO PERFECT PARAMETERS \n")
|
132 |
+
self.params = np.array([1.5, .3, .1, .2, 2.5, 1.2, .3, 1.3, .2, 2.0])
|
133 |
+
self.w[0] = 0.1
|
134 |
+
self.view_params()
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
def gradient_descent_step(self, grad_p, grad_w, lr=0.05):
|
139 |
+
'''
|
140 |
+
Updates the self. parama and self.w according to the fradient descent rule
|
141 |
+
Parameters:
|
142 |
+
grad_p : numpy array (10,)
|
143 |
+
grad_w : sigle float
|
144 |
+
'''
|
145 |
+
self.params = self.params - lr*grad_p
|
146 |
+
self.w = self.w - lr*grad_w
|
147 |
+
|
148 |
+
|
149 |
+
|
150 |
+
def batch_CE_loss(self, batch):
|
151 |
+
"""
|
152 |
+
Processes a batch of sequences and calculates the ReLU loss
|
153 |
+
Parameters:
|
154 |
+
batch (dtaframe) : containint the field <pos_tags> and <chunk_tags>
|
155 |
+
Oututput
|
156 |
+
Total Loss Relu
|
157 |
+
"""
|
158 |
+
|
159 |
+
total_loss = 0
|
160 |
+
for _, row in batch.iterrows():
|
161 |
+
|
162 |
+
sent_pos_tags = row.pos_tags
|
163 |
+
X = tags2sentence(sent_pos_tags)
|
164 |
+
|
165 |
+
_, H = self.process_seq(X)
|
166 |
+
H = H[1:] # Exclude h(0)
|
167 |
+
|
168 |
+
sent_tags = row.chunk_tags
|
169 |
+
Y = np.array(sent_tags)
|
170 |
+
|
171 |
+
loss = -(Y*np.log(H) + (1-Y)*np.log(1-H))
|
172 |
+
loss = loss.mean()
|
173 |
+
|
174 |
+
total_loss += loss
|
175 |
+
|
176 |
+
total_loss = total_loss/len(batch)
|
177 |
+
|
178 |
+
return total_loss
|
179 |
+
|
180 |
+
|
181 |
+
|
182 |
+
def batch_accuracy(self, batch):
|
183 |
+
|
184 |
+
correct = 0 # Predictions that match
|
185 |
+
total = 0 # Total predictions
|
186 |
+
|
187 |
+
for _, row in batch.iterrows():
|
188 |
+
|
189 |
+
sent_pos_tags = row.pos_tags
|
190 |
+
x = tags2sentence(sent_pos_tags)
|
191 |
+
|
192 |
+
sent_tags = row.chunk_tags
|
193 |
+
y_target = np.array(sent_tags)
|
194 |
+
|
195 |
+
y_pred = self.predict_tags(x)
|
196 |
+
correct += np.sum(y_pred == y_target)
|
197 |
+
total += len(y_pred)
|
198 |
+
|
199 |
+
acc = (correct/total)*100 # Accuracy in percentage
|
200 |
+
|
201 |
+
return acc
|
202 |
+
|
203 |
+
|
204 |
+
def batch_sentence_accuracy(self, batch):
|
205 |
+
|
206 |
+
match = 0
|
207 |
+
|
208 |
+
for _, row in batch.iterrows():
|
209 |
+
|
210 |
+
sent_pos_tags = row.pos_tags
|
211 |
+
x = tags2sentence(sent_pos_tags)
|
212 |
+
|
213 |
+
sent_tags = row.chunk_tags
|
214 |
+
y_target = np.array(sent_tags)
|
215 |
+
|
216 |
+
y_pred = self.predict_tags(x)
|
217 |
+
if np.array_equal(y_pred, y_target):
|
218 |
+
match +=1
|
219 |
+
|
220 |
+
sent_acc = (match/len(batch))*100
|
221 |
+
|
222 |
+
return sent_acc
|
223 |
+
|
224 |
+
|
225 |
+
def set_parameter(self, Vcap=1.5, Vnn=.3, Vdt=.1, Vjj=.2, Vot=2.5, T=1.2, Wnn=.3, Wdt=1.3, Wjj=.2, Wot=2.0, W=.10):
|
226 |
+
|
227 |
+
self.params[0] = Vcap
|
228 |
+
self.params[1] = Vnn
|
229 |
+
self.params[2] = Vdt
|
230 |
+
self.params[3] = Vjj
|
231 |
+
self.params[4] = Vot
|
232 |
+
self.params[5] = T
|
233 |
+
self.params[6] = Wnn
|
234 |
+
self.params[7] = Wdt
|
235 |
+
self.params[8] = Wjj
|
236 |
+
self.params[9] = Wot
|
237 |
+
|
238 |
+
self.w[0] = W
|
239 |
+
|
240 |
+
def does_RNN_satisfy_conditions(self):
|
241 |
+
"""
|
242 |
+
Checks whether the RNN satisfies the inequality conditions
|
243 |
+
"""
|
244 |
+
check_conditions(Vcap = np.round(self.params[0],4),
|
245 |
+
Vnn = np.round(self.params[1],4),
|
246 |
+
Vdt = np.round(self.params[2],4),
|
247 |
+
Vjj = np.round(self.params[3],4),
|
248 |
+
Vot = np.round(self.params[4],4),
|
249 |
+
T = np.round(self.params[5],4),
|
250 |
+
Wnn = np.round(self.params[6],4),
|
251 |
+
Wdt = np.round(self.params[7],4),
|
252 |
+
Wjj = np.round(self.params[8],4),
|
253 |
+
Wot = np.round(self.params[9],4),
|
254 |
+
W = np.round(self.w[0],4), verbose=True)
|
255 |
+
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
|
264 |
+
|
265 |
+
|
266 |
+
|
267 |
+
|
268 |
+
|
269 |
+
|
270 |
+
|
271 |
+
|
272 |
+
|
273 |
+
|
274 |
+
|
275 |
+
|
276 |
+
|
277 |
+
|
278 |
+
|
279 |
+
|
280 |
+
|
281 |
+
|
282 |
+
|
283 |
+
|
284 |
+
|
285 |
+
|
286 |
+
|
287 |
+
|
PRNN_utils.py
ADDED
@@ -0,0 +1,403 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import pandas as pd
|
3 |
+
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
|
7 |
+
|
8 |
+
def check_all_conditions(Vcap, Vdt, Vjj, Vnn, Vot, Wdt, Wjj, Wnn, Wot, W, T):
|
9 |
+
|
10 |
+
"""
|
11 |
+
Checks RNN Perceptron Conditions
|
12 |
+
"""
|
13 |
+
|
14 |
+
conditions = []
|
15 |
+
|
16 |
+
# Vcap conditions
|
17 |
+
conditions.append(Vcap + Wdt > T)
|
18 |
+
conditions.append(Vcap + Wjj > T)
|
19 |
+
conditions.append(Vcap + Wnn > T)
|
20 |
+
conditions.append(Vcap + Wot > T)
|
21 |
+
|
22 |
+
# Vdt conditions1
|
23 |
+
conditions.append(Vdt + Wdt > T)
|
24 |
+
conditions.append(Vdt + Wjj < T)
|
25 |
+
conditions.append(Vdt + Wnn < T)
|
26 |
+
conditions.append(Vdt + Wot > T)
|
27 |
+
# Vdt conditions2
|
28 |
+
conditions.append(W + Vdt + Wdt > T)
|
29 |
+
conditions.append(W + Vdt + Wjj < T)
|
30 |
+
conditions.append(W + Vdt + Wnn < T)
|
31 |
+
conditions.append(W + Vdt + Wot > T)
|
32 |
+
|
33 |
+
# Vjj conditions 1
|
34 |
+
conditions.append(Vjj + Wdt > T)
|
35 |
+
conditions.append(Vjj + Wjj < T)
|
36 |
+
conditions.append(Vjj + Wnn < T)
|
37 |
+
conditions.append(Vjj + Wot > T)
|
38 |
+
# Vjj conditions 2
|
39 |
+
conditions.append(W + Vjj + Wdt > T)
|
40 |
+
conditions.append(W + Vjj + Wjj < T)
|
41 |
+
conditions.append(W + Vjj + Wnn < T)
|
42 |
+
conditions.append(W + Vjj + Wot > T)
|
43 |
+
|
44 |
+
#Vnn conditions1
|
45 |
+
conditions.append(Vnn + Wdt > T)
|
46 |
+
conditions.append(Vnn + Wjj < T)
|
47 |
+
conditions.append(Vnn + Wnn < T)
|
48 |
+
conditions.append(Vnn + Wot > T)
|
49 |
+
#Vnn conditions2
|
50 |
+
conditions.append(W + Vnn + Wdt > T)
|
51 |
+
conditions.append(W + Vnn + Wjj < T)
|
52 |
+
conditions.append(W + Vnn + Wnn < T)
|
53 |
+
conditions.append(W + Vnn + Wot > T)
|
54 |
+
|
55 |
+
conditions.append(W + Vot + Wdt > T)
|
56 |
+
conditions.append(W + Vot + Wjj > T)
|
57 |
+
conditions.append(W + Vot + Wnn > T)
|
58 |
+
conditions.append(W + Vot + Wot > T)
|
59 |
+
|
60 |
+
if np.sum(conditions) == len(conditions):
|
61 |
+
print("ALL INEQUALITIES SATISFIED FOR THE GIVEN PARAMETERS")
|
62 |
+
|
63 |
+
return conditions
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
def check_conditions(Vcap, Vdt, Vjj, Vnn, Vot, Wdt, Wjj, Wnn, Wot, W, T, verbose=False):
|
68 |
+
|
69 |
+
"""
|
70 |
+
Checks RNN Perceptron Conditions
|
71 |
+
"""
|
72 |
+
conditions = []
|
73 |
+
|
74 |
+
# CAP[^] conditions
|
75 |
+
if Vcap + Wdt > T and verbose:
|
76 |
+
string = f"Vcap [{Vcap}] + Wdt [{Wdt}] > T [{T}]\t\tSATISFIED"
|
77 |
+
print(string)
|
78 |
+
conditions.append(Vcap + Wdt > T)
|
79 |
+
|
80 |
+
if Vcap + Wjj > T and verbose:
|
81 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wjj}] > T [{T}]\t\tSATISFIED"
|
82 |
+
print(string)
|
83 |
+
conditions.append(Vcap + Wjj > T)
|
84 |
+
|
85 |
+
if Vcap + Wnn > T and verbose:
|
86 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wnn}] > T [{T}]\t\tSATISFIED"
|
87 |
+
print(string)
|
88 |
+
conditions.append(Vcap + Wnn > T)
|
89 |
+
|
90 |
+
if Vcap + Wot > T and verbose:
|
91 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wot}] > T [{T}]\t\tSATISFIED"
|
92 |
+
print(string)
|
93 |
+
print()
|
94 |
+
conditions.append(Vcap + Wot > T)
|
95 |
+
|
96 |
+
|
97 |
+
|
98 |
+
# DT Conditions
|
99 |
+
if W + Vdt + Wjj < T and verbose:
|
100 |
+
string = f"W [{W}] + Vdt [{Vdt}] + Wjj [{Wjj}] < T [{T}]\tSATISFIED"
|
101 |
+
print(string)
|
102 |
+
conditions.append(W + Vdt + Wjj < T)
|
103 |
+
|
104 |
+
if W + Vdt + Wnn < T and verbose:
|
105 |
+
string = f"W [{W}] + Vdt [{Vdt}] + Wnn [{Wnn}] < T [{T}]\tSATISFIED"
|
106 |
+
print(string)
|
107 |
+
print()
|
108 |
+
conditions.append(W + Vdt + Wnn < T)
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
|
113 |
+
# JJ Consitions
|
114 |
+
if Vjj + Wjj < T and verbose:
|
115 |
+
string = f"Vjj [{Vjj}] + Wjj [{Wjj}] < T [{T}]\t\tSATISFIED"
|
116 |
+
print(string)
|
117 |
+
conditions.append(Vjj + Wjj < T)
|
118 |
+
|
119 |
+
if Vjj + Wnn < T and verbose:
|
120 |
+
string = f"Vjj [{Vjj}] + Wnn [{Wnn}] < T [{T}]\t\tSATISFIED"
|
121 |
+
print(string)
|
122 |
+
conditions.append(Vjj + Wnn < T)
|
123 |
+
|
124 |
+
if W + Vjj + Wjj < T and verbose:
|
125 |
+
string = f"W [{W}] + Vjj [{Vjj}] + Wjj [{Wjj}] < T [{T}]\tSATISFIED"
|
126 |
+
print(string)
|
127 |
+
conditions.append(W + Vjj + Wjj < T)
|
128 |
+
|
129 |
+
if W + Vjj + Wnn < T and verbose:
|
130 |
+
string = f"W [{W}] + Vjj [{Vjj}] + Wnn [{Wnn}] < T [{T}]\tSATISFIED"
|
131 |
+
print(string)
|
132 |
+
print()
|
133 |
+
conditions.append(W + Vjj + Wnn < T)
|
134 |
+
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
# NN Consitions
|
139 |
+
if Vnn + Wot > T and verbose:
|
140 |
+
string = f"Vnn [{Vnn}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
141 |
+
print(string)
|
142 |
+
conditions.append(Vnn + Wot > T)
|
143 |
+
|
144 |
+
if W + Vnn + Wot > T and verbose:
|
145 |
+
string = f"W [{W}] + Vnn [{Vnn}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
146 |
+
print(string)
|
147 |
+
print()
|
148 |
+
conditions.append(W + Vnn + Wot > T)
|
149 |
+
|
150 |
+
|
151 |
+
|
152 |
+
# OT Conditions
|
153 |
+
if W + Vot + Wdt > T and verbose:
|
154 |
+
string = f"W [{W}] + Vot [{Vot}] + Wdt [{Wdt}] > T [{T}]\tSATISFIED"
|
155 |
+
print(string)
|
156 |
+
conditions.append(W + Vot + Wdt > T)
|
157 |
+
|
158 |
+
if W + Vot + Wjj > T and verbose:
|
159 |
+
string = f"W [{W}] + Vot [{Vot}] + Wjj [{Wjj}] > T [{T}]\tSATISFIED"
|
160 |
+
print(string)
|
161 |
+
conditions.append(W + Vot + Wjj > T)
|
162 |
+
|
163 |
+
if W + Vot + Wnn > T and verbose:
|
164 |
+
string = f"W [{W}] + Vot [{Vot}] + Wnn [{Wnn}] > T [{T}]\tSATISFIED"
|
165 |
+
print(string)
|
166 |
+
conditions.append(W + Vot + Wnn > T)
|
167 |
+
|
168 |
+
if W + Vot + Wot > T and verbose:
|
169 |
+
string = f"W [{W}] + Vot [{Vot}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
170 |
+
print(string)
|
171 |
+
conditions.append(W + Vot + Wot > T)
|
172 |
+
|
173 |
+
check = np.sum(conditions) == len(conditions)
|
174 |
+
if check:
|
175 |
+
print("\nALL INEQUALITIES SATISFIED FOR THE GIVEN PARAMETERS")
|
176 |
+
else:
|
177 |
+
print("\nALL INEQUALITIES ARE NOT SATISFIED")
|
178 |
+
print(conditions)
|
179 |
+
|
180 |
+
return check
|
181 |
+
|
182 |
+
|
183 |
+
|
184 |
+
def pair2sample(left_index, right_index):
|
185 |
+
"""
|
186 |
+
Takes in left index and right index to give the concatenated
|
187 |
+
1-hot vector of both along with bias term -1
|
188 |
+
|
189 |
+
x = [---upper_input_1-hot--- -1 ---lower_input_1-hot---]
|
190 |
+
The id:0 is used for ^ token
|
191 |
+
NN:1 DT:2 JJ:3 OT:4 for their ids
|
192 |
+
"""
|
193 |
+
|
194 |
+
# Create an array of zeros
|
195 |
+
array_left = np.zeros(5)
|
196 |
+
array_right = np.zeros(5)
|
197 |
+
|
198 |
+
# Set the value at the specified index to 1.0, and bias to -1.0
|
199 |
+
array_left[left_index] = 1.0
|
200 |
+
array_right[0] = -1.0
|
201 |
+
array_right[right_index] = 1.0
|
202 |
+
sample = np.concatenate((array_left, array_right))
|
203 |
+
|
204 |
+
return sample
|
205 |
+
|
206 |
+
|
207 |
+
|
208 |
+
def tags2sentence(tags):
|
209 |
+
|
210 |
+
"""
|
211 |
+
This function takes in tag and returns it in a perceptron input format
|
212 |
+
the output is [x(1), x(2), ......., x(T)]
|
213 |
+
where x(i) is a 10-d vector
|
214 |
+
|
215 |
+
Parameters:
|
216 |
+
tags list[int]: The POS tags of the sentence
|
217 |
+
|
218 |
+
Returns:
|
219 |
+
sentence list[list] : This is a sequence input to the model
|
220 |
+
"""
|
221 |
+
|
222 |
+
new_tags = [0] + tags # For the ^ start token
|
223 |
+
sentence = []
|
224 |
+
|
225 |
+
for idx in range(len(new_tags)-1):
|
226 |
+
left_index = new_tags[idx]
|
227 |
+
right_index = new_tags[idx+1]
|
228 |
+
|
229 |
+
sentence.append(pair2sample(left_index, right_index))
|
230 |
+
|
231 |
+
return np.array(sentence)
|
232 |
+
|
233 |
+
|
234 |
+
|
235 |
+
def calculate_grads(x, y, model):
|
236 |
+
"""
|
237 |
+
Calculates Gradient Loss for a sequence <x(1), x(2), ...... , x(T)>
|
238 |
+
|
239 |
+
"""
|
240 |
+
|
241 |
+
Y = y.copy()
|
242 |
+
Y = np.insert(Y, 0, 0.0) # Insert y(0) at the begining
|
243 |
+
|
244 |
+
X = x.copy()
|
245 |
+
# Insert a row of zeros at the top, call it x(0)
|
246 |
+
new_row = np.zeros((1, X.shape[1])) # Array row of all zeros
|
247 |
+
X = np.insert(X, 0, new_row, axis=0)
|
248 |
+
|
249 |
+
H = model.process_seq(sequence=x)
|
250 |
+
|
251 |
+
dh_dp = np.zeros_like(X)
|
252 |
+
# Iterative calculation dh/dp
|
253 |
+
for idx in range(1, len(X)):
|
254 |
+
dh_dp[idx] = X[idx] + model.w*dh_dp[idx-1]
|
255 |
+
|
256 |
+
# Calculation of dJdp
|
257 |
+
dJdp = model.relu_dash((0.5 - Y)*H) * (0.5 - Y)
|
258 |
+
dJdp = dJdp.reshape(dJdp.shape[0],1)
|
259 |
+
dJdp = dJdp*dh_dp
|
260 |
+
dJdp = dJdp[1:].mean(axis=0)
|
261 |
+
|
262 |
+
|
263 |
+
dh_dw = np.zeros_like(H)
|
264 |
+
# Iterative calculation dh/dp
|
265 |
+
for idx in range(1, len(dh_dw)):
|
266 |
+
dh_dw[idx] = H[idx-1] + model.w*dh_dw[idx-1]
|
267 |
+
|
268 |
+
# Calculation of dJdw
|
269 |
+
dJdw = model.relu_dash((0.5 - Y)*H) * (0.5 - Y)
|
270 |
+
dJdw = dJdw*dh_dw
|
271 |
+
dJdw = dJdw[1:].mean()
|
272 |
+
|
273 |
+
return dJdp, dJdw
|
274 |
+
|
275 |
+
|
276 |
+
|
277 |
+
def batch_calculate_grads(model, batch):
|
278 |
+
|
279 |
+
derivatives_p = []
|
280 |
+
derivatives_w = []
|
281 |
+
|
282 |
+
for _, row in batch.iterrows():
|
283 |
+
|
284 |
+
sent_tags = row.chunk_tags
|
285 |
+
y = np.array(sent_tags)
|
286 |
+
|
287 |
+
sent_pos_tags = row.pos_tags
|
288 |
+
x = tags2sentence(sent_pos_tags)
|
289 |
+
|
290 |
+
der_p, der_w = calculate_grads(model=model, x=x, y=y)
|
291 |
+
derivatives_p.append(der_p)
|
292 |
+
derivatives_w.append(der_w)
|
293 |
+
|
294 |
+
derivatives_p = np.array(derivatives_p).mean(axis=0)
|
295 |
+
derivatives_w = np.array(derivatives_w).mean()
|
296 |
+
|
297 |
+
return derivatives_p, derivatives_w
|
298 |
+
|
299 |
+
|
300 |
+
|
301 |
+
|
302 |
+
def train_and_val(df_folds, val_index):
|
303 |
+
"""
|
304 |
+
Returns train fold and val fold
|
305 |
+
Parameters:
|
306 |
+
df_folds :list[Dataframe]: List of dataframes
|
307 |
+
val_index(int): {0, 1, 2, 3, .... ,N-1}
|
308 |
+
Returns:
|
309 |
+
train_df : train dataframe
|
310 |
+
val_df : validation dataframe
|
311 |
+
"""
|
312 |
+
|
313 |
+
train_df, val_df = None, None
|
314 |
+
|
315 |
+
for idx, df in enumerate(df_folds):
|
316 |
+
|
317 |
+
if idx == val_index:
|
318 |
+
val_df = df.copy()
|
319 |
+
else:
|
320 |
+
train_df = pd.concat([train_df, df.copy()], axis=0)
|
321 |
+
|
322 |
+
train_df.reset_index(drop=True, inplace=True)
|
323 |
+
val_df.reset_index(drop=True, inplace=True)
|
324 |
+
|
325 |
+
|
326 |
+
return train_df, val_df
|
327 |
+
|
328 |
+
|
329 |
+
def prepare_folds(data, nof):
|
330 |
+
"""
|
331 |
+
Creates folds from data
|
332 |
+
Parameters:
|
333 |
+
data :pandas Dataframe
|
334 |
+
nof (int): no of folds
|
335 |
+
Returns:
|
336 |
+
df_folds: list[Dataframes]
|
337 |
+
"""
|
338 |
+
# Shuffle the DataFrame rows
|
339 |
+
data_shuffled = data.sample(frac=1, random_state=42).copy()
|
340 |
+
|
341 |
+
# Calculate the number of rows per fold
|
342 |
+
fold_size = len(data) // nof
|
343 |
+
remainder_rows = len(data) % nof
|
344 |
+
|
345 |
+
# Initialize an empty list to store the folds
|
346 |
+
df_folds = []
|
347 |
+
|
348 |
+
# Split the shuffled DataFrame into folds
|
349 |
+
start_index = 0
|
350 |
+
for fold_index in range(5):
|
351 |
+
|
352 |
+
# Calculate the end index for the fold
|
353 |
+
end_index = start_index + fold_size + (1 if fold_index < remainder_rows else 0)
|
354 |
+
|
355 |
+
# Append the fold to the list of folds
|
356 |
+
df_folds.append(data_shuffled.iloc[start_index:end_index].reset_index(drop=True))
|
357 |
+
|
358 |
+
# Update the start index for the next fold
|
359 |
+
start_index = end_index
|
360 |
+
|
361 |
+
return df_folds
|
362 |
+
|
363 |
+
|
364 |
+
|
365 |
+
def process_CVresults(CVresults_dict, summarize=True):
|
366 |
+
"""
|
367 |
+
ABOUT
|
368 |
+
Processes CV results
|
369 |
+
CVresults[key] = [best_val_loss, best_val_acc, best_val_sequence_acc, best_val_epoch, best_params(array)]
|
370 |
+
"""
|
371 |
+
folds = len(CVresults_dict)
|
372 |
+
val_loss, val_acc, seq_acc = 0, 0, 0
|
373 |
+
P, W= 0.0, 0.0
|
374 |
+
val_acc_list =[]
|
375 |
+
val_seq_acc_list =[]
|
376 |
+
for key, val in CVresults_dict.items():
|
377 |
+
|
378 |
+
val_loss += val[0]
|
379 |
+
|
380 |
+
val_acc += val[1]
|
381 |
+
val_acc_list.append(val[1])
|
382 |
+
|
383 |
+
seq_acc += val[2]
|
384 |
+
val_seq_acc_list.append(val[2])
|
385 |
+
|
386 |
+
P = P + val[4][0]
|
387 |
+
W = W + val[4][1]
|
388 |
+
|
389 |
+
val_loss = val_loss/folds
|
390 |
+
val_acc = np.round(val_acc/folds, 4)
|
391 |
+
seq_acc = np.round(seq_acc/folds, 4)
|
392 |
+
P = P/folds
|
393 |
+
W = W/folds
|
394 |
+
|
395 |
+
if summarize:
|
396 |
+
print(f"BEST VALIDATION ACCURACY : {np.round(np.max(val_acc_list), 4)}")
|
397 |
+
print(f"BEST VALIDATION SEQUENCE ACCURACY : {np.round(np.max(val_seq_acc_list), 4)}")
|
398 |
+
print()
|
399 |
+
print(f"AVERAGE VALIDATION ACCURACY : {val_acc}")
|
400 |
+
print(f"AVERAGE VALIDATION SEQUENCE ACCURACY : {seq_acc}")
|
401 |
+
|
402 |
+
|
403 |
+
return P, W
|
PRNN_utilsSigmoid.py
ADDED
@@ -0,0 +1,407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import pandas as pd
|
3 |
+
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
|
7 |
+
|
8 |
+
def check_all_conditions(Vcap, Vdt, Vjj, Vnn, Vot, Wdt, Wjj, Wnn, Wot, W, T):
|
9 |
+
|
10 |
+
"""
|
11 |
+
Checks RNN Perceptron Conditions
|
12 |
+
"""
|
13 |
+
|
14 |
+
conditions = []
|
15 |
+
|
16 |
+
# Vcap conditions
|
17 |
+
conditions.append(Vcap + Wdt > T)
|
18 |
+
conditions.append(Vcap + Wjj > T)
|
19 |
+
conditions.append(Vcap + Wnn > T)
|
20 |
+
conditions.append(Vcap + Wot > T)
|
21 |
+
|
22 |
+
# Vdt conditions1
|
23 |
+
conditions.append(Vdt + Wdt > T)
|
24 |
+
conditions.append(Vdt + Wjj < T)
|
25 |
+
conditions.append(Vdt + Wnn < T)
|
26 |
+
conditions.append(Vdt + Wot > T)
|
27 |
+
# Vdt conditions2
|
28 |
+
conditions.append(W + Vdt + Wdt > T)
|
29 |
+
conditions.append(W + Vdt + Wjj < T)
|
30 |
+
conditions.append(W + Vdt + Wnn < T)
|
31 |
+
conditions.append(W + Vdt + Wot > T)
|
32 |
+
|
33 |
+
# Vjj conditions 1
|
34 |
+
conditions.append(Vjj + Wdt > T)
|
35 |
+
conditions.append(Vjj + Wjj < T)
|
36 |
+
conditions.append(Vjj + Wnn < T)
|
37 |
+
conditions.append(Vjj + Wot > T)
|
38 |
+
# Vjj conditions 2
|
39 |
+
conditions.append(W + Vjj + Wdt > T)
|
40 |
+
conditions.append(W + Vjj + Wjj < T)
|
41 |
+
conditions.append(W + Vjj + Wnn < T)
|
42 |
+
conditions.append(W + Vjj + Wot > T)
|
43 |
+
|
44 |
+
#Vnn conditions1
|
45 |
+
conditions.append(Vnn + Wdt > T)
|
46 |
+
conditions.append(Vnn + Wjj < T)
|
47 |
+
conditions.append(Vnn + Wnn < T)
|
48 |
+
conditions.append(Vnn + Wot > T)
|
49 |
+
#Vnn conditions2
|
50 |
+
conditions.append(W + Vnn + Wdt > T)
|
51 |
+
conditions.append(W + Vnn + Wjj < T)
|
52 |
+
conditions.append(W + Vnn + Wnn < T)
|
53 |
+
conditions.append(W + Vnn + Wot > T)
|
54 |
+
|
55 |
+
conditions.append(W + Vot + Wdt > T)
|
56 |
+
conditions.append(W + Vot + Wjj > T)
|
57 |
+
conditions.append(W + Vot + Wnn > T)
|
58 |
+
conditions.append(W + Vot + Wot > T)
|
59 |
+
|
60 |
+
if np.sum(conditions) == len(conditions):
|
61 |
+
print("ALL INEQUALITIES SATISFIED FOR THE GIVEN PARAMETERS")
|
62 |
+
|
63 |
+
return conditions
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
def check_conditions(Vcap, Vdt, Vjj, Vnn, Vot, Wdt, Wjj, Wnn, Wot, W, T, verbose=False):
|
68 |
+
|
69 |
+
"""
|
70 |
+
Checks RNN Perceptron Conditions
|
71 |
+
"""
|
72 |
+
conditions = []
|
73 |
+
|
74 |
+
# CAP[^] conditions
|
75 |
+
if Vcap + Wdt > T and verbose:
|
76 |
+
string = f"Vcap [{Vcap}] + Wdt [{Wdt}] > T [{T}]\t\tSATISFIED"
|
77 |
+
print(string)
|
78 |
+
conditions.append(Vcap + Wdt > T)
|
79 |
+
|
80 |
+
if Vcap + Wjj > T and verbose:
|
81 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wjj}] > T [{T}]\t\tSATISFIED"
|
82 |
+
print(string)
|
83 |
+
conditions.append(Vcap + Wjj > T)
|
84 |
+
|
85 |
+
if Vcap + Wnn > T and verbose:
|
86 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wnn}] > T [{T}]\t\tSATISFIED"
|
87 |
+
print(string)
|
88 |
+
conditions.append(Vcap + Wnn > T)
|
89 |
+
|
90 |
+
if Vcap + Wot > T and verbose:
|
91 |
+
string = f"Vcap [{Vcap}] + Wjj [{Wot}] > T [{T}]\t\tSATISFIED"
|
92 |
+
print(string)
|
93 |
+
print()
|
94 |
+
conditions.append(Vcap + Wot > T)
|
95 |
+
|
96 |
+
|
97 |
+
|
98 |
+
# DT Conditions
|
99 |
+
if W + Vdt + Wjj < T and verbose:
|
100 |
+
string = f"W [{W}] + Vdt [{Vdt}] + Wjj [{Wjj}] < T [{T}]\tSATISFIED"
|
101 |
+
print(string)
|
102 |
+
conditions.append(W + Vdt + Wjj < T)
|
103 |
+
|
104 |
+
if W + Vdt + Wnn < T and verbose:
|
105 |
+
string = f"W [{W}] + Vdt [{Vdt}] + Wnn [{Wnn}] < T [{T}]\tSATISFIED"
|
106 |
+
print(string)
|
107 |
+
print()
|
108 |
+
conditions.append(W + Vdt + Wnn < T)
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
|
113 |
+
# JJ Consitions
|
114 |
+
if Vjj + Wjj < T and verbose:
|
115 |
+
string = f"Vjj [{Vjj}] + Wjj [{Wjj}] < T [{T}]\t\tSATISFIED"
|
116 |
+
print(string)
|
117 |
+
conditions.append(Vjj + Wjj < T)
|
118 |
+
|
119 |
+
if Vjj + Wnn < T and verbose:
|
120 |
+
string = f"Vjj [{Vjj}] + Wnn [{Wnn}] < T [{T}]\t\tSATISFIED"
|
121 |
+
print(string)
|
122 |
+
conditions.append(Vjj + Wnn < T)
|
123 |
+
|
124 |
+
if W + Vjj + Wjj < T and verbose:
|
125 |
+
string = f"W [{W}] + Vjj [{Vjj}] + Wjj [{Wjj}] < T [{T}]\tSATISFIED"
|
126 |
+
print(string)
|
127 |
+
conditions.append(W + Vjj + Wjj < T)
|
128 |
+
|
129 |
+
if W + Vjj + Wnn < T and verbose:
|
130 |
+
string = f"W [{W}] + Vjj [{Vjj}] + Wnn [{Wnn}] < T [{T}]\tSATISFIED"
|
131 |
+
print(string)
|
132 |
+
print()
|
133 |
+
conditions.append(W + Vjj + Wnn < T)
|
134 |
+
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
# NN Consitions
|
139 |
+
if Vnn + Wot > T and verbose:
|
140 |
+
string = f"Vnn [{Vnn}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
141 |
+
print(string)
|
142 |
+
conditions.append(Vnn + Wot > T)
|
143 |
+
|
144 |
+
if W + Vnn + Wot > T and verbose:
|
145 |
+
string = f"W [{W}] + Vnn [{Vnn}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
146 |
+
print(string)
|
147 |
+
print()
|
148 |
+
conditions.append(W + Vnn + Wot > T)
|
149 |
+
|
150 |
+
|
151 |
+
|
152 |
+
# OT Conditions
|
153 |
+
if W + Vot + Wdt > T and verbose:
|
154 |
+
string = f"W [{W}] + Vot [{Vot}] + Wdt [{Wdt}] > T [{T}]\tSATISFIED"
|
155 |
+
print(string)
|
156 |
+
conditions.append(W + Vot + Wdt > T)
|
157 |
+
|
158 |
+
if W + Vot + Wjj > T and verbose:
|
159 |
+
string = f"W [{W}] + Vot [{Vot}] + Wjj [{Wjj}] > T [{T}]\tSATISFIED"
|
160 |
+
print(string)
|
161 |
+
conditions.append(W + Vot + Wjj > T)
|
162 |
+
|
163 |
+
if W + Vot + Wnn > T and verbose:
|
164 |
+
string = f"W [{W}] + Vot [{Vot}] + Wnn [{Wnn}] > T [{T}]\tSATISFIED"
|
165 |
+
print(string)
|
166 |
+
conditions.append(W + Vot + Wnn > T)
|
167 |
+
|
168 |
+
if W + Vot + Wot > T and verbose:
|
169 |
+
string = f"W [{W}] + Vot [{Vot}] + Wot [{Wot}] > T [{T}]\tSATISFIED"
|
170 |
+
print(string)
|
171 |
+
conditions.append(W + Vot + Wot > T)
|
172 |
+
|
173 |
+
check = np.sum(conditions) == len(conditions)
|
174 |
+
if check:
|
175 |
+
print("\nALL INEQUALITIES SATISFIED FOR THE GIVEN PARAMETERS")
|
176 |
+
else:
|
177 |
+
print("\nALL INEQUALITIES ARE NOT SATISFIED")
|
178 |
+
print(conditions)
|
179 |
+
|
180 |
+
return check
|
181 |
+
|
182 |
+
|
183 |
+
|
184 |
+
def pair2sample(left_index, right_index):
|
185 |
+
"""
|
186 |
+
Takes in left index and right index to give the concatenated
|
187 |
+
1-hot vector of both along with bias term -1
|
188 |
+
|
189 |
+
x = [---upper_input_1-hot--- -1 ---lower_input_1-hot---]
|
190 |
+
The id:0 is used for ^ token
|
191 |
+
NN:1 DT:2 JJ:3 OT:4 for their ids
|
192 |
+
"""
|
193 |
+
|
194 |
+
# Create an array of zeros
|
195 |
+
array_left = np.zeros(5)
|
196 |
+
array_right = np.zeros(5)
|
197 |
+
|
198 |
+
# Set the value at the specified index to 1.0, and bias to -1.0
|
199 |
+
array_left[left_index] = 1.0
|
200 |
+
array_right[0] = -1.0
|
201 |
+
array_right[right_index] = 1.0
|
202 |
+
sample = np.concatenate((array_left, array_right))
|
203 |
+
|
204 |
+
return sample
|
205 |
+
|
206 |
+
|
207 |
+
|
208 |
+
def tags2sentence(tags):
|
209 |
+
|
210 |
+
"""
|
211 |
+
This function takes in tag and returns it in a perceptron input format
|
212 |
+
the output is [x(1), x(2), ......., x(T)]
|
213 |
+
where x(i) is a 10-d vector
|
214 |
+
|
215 |
+
Parameters:
|
216 |
+
tags list[int]: The POS tags of the sentence
|
217 |
+
|
218 |
+
Returns:
|
219 |
+
sentence list[list] : This is a sequence input to the model
|
220 |
+
"""
|
221 |
+
|
222 |
+
new_tags = [0] + tags # For the ^ start token
|
223 |
+
sentence = []
|
224 |
+
|
225 |
+
for idx in range(len(new_tags)-1):
|
226 |
+
left_index = new_tags[idx]
|
227 |
+
right_index = new_tags[idx+1]
|
228 |
+
|
229 |
+
sentence.append(pair2sample(left_index, right_index))
|
230 |
+
|
231 |
+
return np.array(sentence)
|
232 |
+
|
233 |
+
|
234 |
+
|
235 |
+
def calculate_grads(x, y, model):
|
236 |
+
"""
|
237 |
+
Calculates Gradient Loss for a sequence <x(1), x(2), ...... , x(T)>
|
238 |
+
|
239 |
+
"""
|
240 |
+
|
241 |
+
Y = y.copy()
|
242 |
+
Y = np.insert(Y, 0, 0.0) # Insert y(0) at the begining
|
243 |
+
|
244 |
+
X = x.copy()
|
245 |
+
# Insert a row of zeros at the top, call it x(0)
|
246 |
+
new_row = np.zeros((1, X.shape[1])) # Array row of all zeros
|
247 |
+
X = np.insert(X, 0, new_row, axis=0)
|
248 |
+
|
249 |
+
C, H = model.process_seq(sequence=x)
|
250 |
+
|
251 |
+
dh_dp = np.zeros_like(X)
|
252 |
+
dc_dp = np.zeros_like(X)
|
253 |
+
# Iterative calculation dh/dp and dc/dp
|
254 |
+
for idx in range(1, len(X)):
|
255 |
+
dc_dp[idx] = X[idx] + model.w*dc_dp[idx-1]
|
256 |
+
dh_dp[idx] = model.sigmoid_dash(C[idx])*dc_dp[idx]
|
257 |
+
|
258 |
+
# Calculation of dJdp
|
259 |
+
dJdp = (H[1:]-Y[1:])/(H[1:]*(1-H[1:]))
|
260 |
+
dJdp = dJdp.reshape(dJdp.shape[0],1)
|
261 |
+
dJdp = dJdp*dh_dp[1:]
|
262 |
+
dJdp = dJdp.mean(axis=0)
|
263 |
+
|
264 |
+
|
265 |
+
dh_dw = np.zeros_like(H)
|
266 |
+
dc_dw = np.zeros_like(H)
|
267 |
+
# Iterative calculation dh/dw
|
268 |
+
for idx in range(1, len(dh_dw)):
|
269 |
+
dc_dw[idx] = H[idx-1] + model.w*dh_dw[idx-1]
|
270 |
+
dh_dw[idx] = model.sigmoid_dash(C[idx])
|
271 |
+
|
272 |
+
# Calculation of dJdw
|
273 |
+
dJdw = (H[1:]-Y[1:])/(H[1:]*(1-H[1:]))
|
274 |
+
dJdw = dJdw*dh_dw[1:]
|
275 |
+
dJdw = dJdw.mean()
|
276 |
+
|
277 |
+
return dJdp, dJdw
|
278 |
+
|
279 |
+
|
280 |
+
|
281 |
+
def batch_calculate_grads(model, batch):
|
282 |
+
|
283 |
+
derivatives_p = []
|
284 |
+
derivatives_w = []
|
285 |
+
|
286 |
+
for _, row in batch.iterrows():
|
287 |
+
|
288 |
+
sent_tags = row.chunk_tags
|
289 |
+
y = np.array(sent_tags)
|
290 |
+
|
291 |
+
sent_pos_tags = row.pos_tags
|
292 |
+
x = tags2sentence(sent_pos_tags)
|
293 |
+
|
294 |
+
der_p, der_w = calculate_grads(model=model, x=x, y=y)
|
295 |
+
derivatives_p.append(der_p)
|
296 |
+
derivatives_w.append(der_w)
|
297 |
+
|
298 |
+
derivatives_p = np.array(derivatives_p).mean(axis=0)
|
299 |
+
derivatives_w = np.array(derivatives_w).mean()
|
300 |
+
|
301 |
+
return derivatives_p, derivatives_w
|
302 |
+
|
303 |
+
|
304 |
+
|
305 |
+
|
306 |
+
def train_and_val(df_folds, val_index):
|
307 |
+
"""
|
308 |
+
Returns train fold and val fold
|
309 |
+
Parameters:
|
310 |
+
df_folds :list[Dataframe]: List of dataframes
|
311 |
+
val_index(int): {0, 1, 2, 3, .... ,N-1}
|
312 |
+
Returns:
|
313 |
+
train_df : train dataframe
|
314 |
+
val_df : validation dataframe
|
315 |
+
"""
|
316 |
+
|
317 |
+
train_df, val_df = None, None
|
318 |
+
|
319 |
+
for idx, df in enumerate(df_folds):
|
320 |
+
|
321 |
+
if idx == val_index:
|
322 |
+
val_df = df.copy()
|
323 |
+
else:
|
324 |
+
train_df = pd.concat([train_df, df.copy()], axis=0)
|
325 |
+
|
326 |
+
train_df.reset_index(drop=True, inplace=True)
|
327 |
+
val_df.reset_index(drop=True, inplace=True)
|
328 |
+
|
329 |
+
|
330 |
+
return train_df, val_df
|
331 |
+
|
332 |
+
|
333 |
+
def prepare_folds(data, nof):
|
334 |
+
"""
|
335 |
+
Creates folds from data
|
336 |
+
Parameters:
|
337 |
+
data :pandas Dataframe
|
338 |
+
nof (int): no of folds
|
339 |
+
Returns:
|
340 |
+
df_folds: list[Dataframes]
|
341 |
+
"""
|
342 |
+
# Shuffle the DataFrame rows
|
343 |
+
data_shuffled = data.sample(frac=1, random_state=42).copy()
|
344 |
+
|
345 |
+
# Calculate the number of rows per fold
|
346 |
+
fold_size = len(data) // nof
|
347 |
+
remainder_rows = len(data) % nof
|
348 |
+
|
349 |
+
# Initialize an empty list to store the folds
|
350 |
+
df_folds = []
|
351 |
+
|
352 |
+
# Split the shuffled DataFrame into folds
|
353 |
+
start_index = 0
|
354 |
+
for fold_index in range(5):
|
355 |
+
|
356 |
+
# Calculate the end index for the fold
|
357 |
+
end_index = start_index + fold_size + (1 if fold_index < remainder_rows else 0)
|
358 |
+
|
359 |
+
# Append the fold to the list of folds
|
360 |
+
df_folds.append(data_shuffled.iloc[start_index:end_index].reset_index(drop=True))
|
361 |
+
|
362 |
+
# Update the start index for the next fold
|
363 |
+
start_index = end_index
|
364 |
+
|
365 |
+
return df_folds
|
366 |
+
|
367 |
+
|
368 |
+
|
369 |
+
def process_CVresults(CVresults_dict, summarize=True):
|
370 |
+
"""
|
371 |
+
ABOUT
|
372 |
+
Processes CV results
|
373 |
+
CVresults[key] = [best_val_loss, best_val_acc, best_val_sequence_acc, best_val_epoch, best_params(array)]
|
374 |
+
"""
|
375 |
+
folds = len(CVresults_dict)
|
376 |
+
val_loss, val_acc, seq_acc = 0, 0, 0
|
377 |
+
P, W= 0.0, 0.0
|
378 |
+
val_acc_list =[]
|
379 |
+
val_seq_acc_list =[]
|
380 |
+
for key, val in CVresults_dict.items():
|
381 |
+
|
382 |
+
val_loss += val[0]
|
383 |
+
|
384 |
+
val_acc += val[1]
|
385 |
+
val_acc_list.append(val[1])
|
386 |
+
|
387 |
+
seq_acc += val[2]
|
388 |
+
val_seq_acc_list.append(val[2])
|
389 |
+
|
390 |
+
P = P + val[4][0]
|
391 |
+
W = W + val[4][1]
|
392 |
+
|
393 |
+
val_loss = val_loss/folds
|
394 |
+
val_acc = np.round(val_acc/folds, 4)
|
395 |
+
seq_acc = np.round(seq_acc/folds, 4)
|
396 |
+
P = P/folds
|
397 |
+
W = W/folds
|
398 |
+
|
399 |
+
if summarize:
|
400 |
+
print(f"BEST VALIDATION ACCURACY : {np.round(np.max(val_acc_list), 4)}")
|
401 |
+
print(f"BEST VALIDATION SEQUENCE ACCURACY : {np.round(np.max(val_seq_acc_list), 4)}")
|
402 |
+
print()
|
403 |
+
print(f"AVERAGE VALIDATION ACCURACY : {val_acc}")
|
404 |
+
print(f"AVERAGE VALIDATION SEQUENCE ACCURACY : {seq_acc}")
|
405 |
+
|
406 |
+
|
407 |
+
return P, W
|