vivek9 commited on
Commit
5e22f01
1 Parent(s): 25c4113

Upload 4 files

Browse files
Files changed (4) hide show
  1. PRNN.py +271 -0
  2. PRNNSigmoid.py +287 -0
  3. PRNN_utils.py +403 -0
  4. 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