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
|