Spaces:
Sleeping
Sleeping
import numpy as np | |
from PRNN_utils import tags2sentence, check_conditions | |
class PRNN(): | |
def __init__(self, seed=18): | |
np.random.seed(seed) # Set the seed | |
self.params = np.random.normal(0, 1, size=10) | |
self.w = np.random.normal(0, 1, size=1) | |
def step(self, x): | |
out = (x>0.0).astype('float') | |
return out | |
def relu(self, x): | |
return np.maximum(x, 0.0) | |
def relu_dash(self, x): | |
return np.where(x > 0.0, 1.0, 0.0) | |
def forward(self, x, h): | |
''' | |
Process x(t) and h(t-1) ie Single pass of RNN | |
Parameters: | |
x:np.array = [-upper_input_1-hot- -1 -lower_input_1-hot-] | |
h:float {0,1} | |
Returns: | |
out(float): Sigmoid(params_trans x(t) + w h(t-1)) | |
''' | |
h_t = np.dot(self.params, x) + self.w*h # p_trans x(t) + w h(t-1) | |
return h_t | |
def process_seq(self, sequence, h_0=0.0): | |
""" | |
Process the whole sequence | |
Parameters: | |
sequence List[List] | |
Returns: | |
list of hidden states | |
""" | |
hidden_states = [h_0] | |
h_tminus1 = h_0 | |
# Sequentially process the | |
for x_t in sequence: | |
h_t = self.forward(x=x_t, h=h_tminus1) | |
hidden_states.append(h_t[0]) # Just extract the numerical value | |
h_tminus1 = h_t | |
out = np.array(hidden_states).reshape(-1) | |
return out | |
def predict_tags(self, sequence): | |
'''' | |
Predict Tags {0,1} using step function | |
The op is [[y_cap(1), y_cap(2), .... y_cap(T)]] | |
Each y_cap(i) is either 0 or 1 | |
''' | |
out = self.process_seq(sequence) | |
out = self.step(out).reshape(-1)[1:] | |
return out | |
def process_batch(self, batch): | |
""" | |
Processes a batch of sequences throught the model(rnn) | |
Parameters: | |
batch (dtaframe) : containint the field <pos_tags> | |
Oututput | |
outputs list[numpy_array] : Output of each sequence through RNN, hidden state | |
""" | |
outputs = [] | |
for _, row in batch.iterrows(): | |
x = tags2sentence(row.pos_tags) | |
out = self.process_seq(x) | |
out = out.reshape(-1) | |
outputs.append(out) | |
return outputs | |
def view_params(self): | |
''' | |
prints perceptron parameters along with names | |
''' | |
print("PERCEPTRON PARAMETERS") | |
print(f"Vcap : {self.params[0]}" , end = ' | ') | |
print(f"Vnn : {self.params[1]}" , end = ' | ') | |
print(f"Vdt : {self.params[2]}" , end = ' | ') | |
print(f"Vjj : {self.params[3]}" , end = ' | ') | |
print(f"Vot : {self.params[4]}" ) | |
print(f"T [Theta] : {self.params[5]}" , end = ' | ') | |
print(f"Wnn : {self.params[6]}" , end = ' | ') | |
print(f"Wdt : {self.params[7]}" , end = ' | ') | |
print(f"Wjj : {self.params[8]}" , end = ' | ') | |
print(f"Wot : {self.params[9]}") | |
print(f"W : {self.w[0]}") | |
def set_perfect_params(self): | |
''' | |
Params are of the form | |
params = [Vcap, Vnn, Vdt, Vjj, Vot, [T]Theta, Wnn, Wdt, Wjj, Wot] | |
''' | |
print("RESETTING TO PERFECT PARAMETERS \n") | |
self.params = np.array([1.5, .3, .1, .2, 2.5, 1.2, .3, 1.3, .2, 2.0]) | |
self.w[0] = 0.1 | |
self.view_params() | |
def gradient_descent_step(self, grad_p, grad_w, lr=0.05): | |
''' | |
Updates the self. parama and self.w according to the fradient descent rule | |
Parameters: | |
grad_p : numpy array (10,) | |
grad_w : sigle float | |
''' | |
self.params = self.params - lr*grad_p | |
self.w = self.w - lr*grad_w | |
def batch_hinge_loss(self, batch): | |
""" | |
Processes a batch of sequences and calculates the ReLU loss | |
Parameters: | |
batch (dtaframe) : containint the field <pos_tags> and <chunk_tags> | |
Oututput | |
Total Loss Relu | |
""" | |
total_loss = 0 | |
for _, row in batch.iterrows(): | |
sent_pos_tags = row.pos_tags | |
X = tags2sentence(sent_pos_tags) | |
H = self.process_seq(X)[1:] # Exclude h(0) | |
sent_tags = row.chunk_tags | |
Y = np.array(sent_tags) | |
loss = self.relu((.5-Y)*H) # J(t) = ReLU((0.5-y(t))*h(t)) | |
loss = loss.mean() | |
total_loss += loss | |
total_loss = total_loss/len(batch) | |
return total_loss | |
def batch_accuracy(self, batch): | |
correct = 0 # Predictions that match | |
total = 0 # Total predictions | |
for _, row in batch.iterrows(): | |
sent_pos_tags = row.pos_tags | |
x = tags2sentence(sent_pos_tags) | |
sent_tags = row.chunk_tags | |
y_target = np.array(sent_tags) | |
y_pred = self.predict_tags(x) | |
correct += np.sum(y_pred == y_target) | |
total += len(y_pred) | |
acc = (correct/total)*100 # Accuracy in percentage | |
return acc | |
def batch_sentence_accuracy(self, batch): | |
match = 0 | |
for _, row in batch.iterrows(): | |
sent_pos_tags = row.pos_tags | |
x = tags2sentence(sent_pos_tags) | |
sent_tags = row.chunk_tags | |
y_target = np.array(sent_tags) | |
y_pred = self.predict_tags(x) | |
if np.array_equal(y_pred, y_target): | |
match +=1 | |
sent_acc = (match/len(batch))*100 | |
return sent_acc | |
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): | |
self.params[0] = Vcap | |
self.params[1] = Vnn | |
self.params[2] = Vdt | |
self.params[3] = Vjj | |
self.params[4] = Vot | |
self.params[5] = T | |
self.params[6] = Wnn | |
self.params[7] = Wdt | |
self.params[8] = Wjj | |
self.params[9] = Wot | |
self.w[0] = W | |
def does_RNN_satisfy_conditions(self): | |
""" | |
Checks whether the RNN satisfies the inequality conditions | |
""" | |
check_conditions(Vcap = np.round(self.params[0],4), | |
Vnn = np.round(self.params[1],4), | |
Vdt = np.round(self.params[2],4), | |
Vjj = np.round(self.params[3],4), | |
Vot = np.round(self.params[4],4), | |
T = np.round(self.params[5],4), | |
Wnn = np.round(self.params[6],4), | |
Wdt = np.round(self.params[7],4), | |
Wjj = np.round(self.params[8],4), | |
Wot = np.round(self.params[9],4), | |
W = np.round(self.w[0],4), verbose=True) | |