Spaces:
No application file
No application file
File size: 3,534 Bytes
a43ef41 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | # define batch_first = true dim(input) = (batch_size, sequence_len, input_size)
import numpy as np
class Layer:
def __init__(self, input_size, output_size, hidden_size, learning_rate):
self.input = None
self.output = None
self.input_size = input_size
self.output_size = output_size
self.learning_rate = learning_rate
self.w = np.random.randn(hidden_size, hidden_size)
self.u = np.random.randn(hidden_size, input_size)
self.b = np.zeros((hidden_size, 1))
self.V = np.random.randn(output_size, hidden_size)
self.c = np.zeros((output_size ,1))
self.hidden_size = hidden_size
@staticmethod
def softmax(x):
x_exp = np.exp(x)
return x_exp/(np.sum(x_exp))
@staticmethod
def relu(x):
return np.maximum(0 ,x)
@staticmethod
def softmax_derivative(x):
return x*(1-x)
@staticmethod
def relu_derivative(x):
return np.where(x>0, 1, 0)
def feedforward(self, x_train):
batch_size, seq_len, input_size = x_train.shape
s = np.zeros((self.hidden_size, batch_size))
y = []
s_list = []
for t in range(seq_len):
x_t = x_train[:, t, :]
s = np.tanh(np.dot(self.w, s) + np.dot(self.u, x_t.T) + self.b)
z = np.dot(self.V, s) + self.c
y.append(self.softmax(z).T) # calculate y and reverse to (batch_size, output_size)
s_list.append(s)
# dim(y) = (seq_len, batch_size, output_size) reverse to dim(y) = (batch_size, seq_len, output_size)
return np.stack(y, axis=1), s_list
def backward(self, x_train, y_train, yhat, s_list):
# Gradient descent backward pass
batch_size, seq_len, output_size = y_train.shape
# init gradient
dLdW, dLdU, dLdb = np.zeros_like(self.w), np.zeros_like(self.u), np.zeros_like(self.b)
dLdV, dLdc = np.zeros_like(self.V), np.zeros_like(self.c)
dLds_next = np.zeros_like(s_list[0])
for t in reversed(range(seq_len)):
x_t = x_train[:, t, :].T # (batch, input)
s_t = s_list[t] # (hidden, batch)
s_prev = s_list[t - 1] if t > 0 else np.zeros_like(s_t) # (hidden, batch)
dz = (yhat[:, t, :].T - y_train[:, t, :].T) / batch_size # (output, batch)
dLda = np.dot(self.V.T, dz) + dLds_next # (hidden, output)(output, batch) + (hidden, batch)
ds = (1 - s_t ** 2) * dLda # (hidden, batch)
dLdV += np.dot(dz, s_t.T) #dim(V) = (output, hidden) so (output, batch)(batch, hidden) = (output, hidden)
dLdc += np.sum(dz, axis=1, keepdims=True) #(output, 1)
dLdU += np.dot(ds, x_t.T) #dim(W) = (hidden, hidden) so (hidden, batch)(batch, input) = (hidden, input)
dLdW += np.dot(ds, s_prev.T) # (hidden, batch)(batch, hidden) = (hidden, hidden)
dLdb += np.sum(ds, axis=1, keepdims=True) # (hidden, 1)
dLds_next = np.dot(self.u.T, ds)
@staticmethod
def compute_loss(yhat, y_true):
loss = np.mean((yhat- y_true) ** 2)
return loss
def train(self, x_train, y_train, epochs=100):
for epoch in range(epochs):
yhat, s_list = self.feedforward(x_train)
loss = self.compute_loss(yhat, y_train)
self.backward(x_train, y_train, yhat, s_list)
if epoch % 10 == 0:
print(f'Epoch {epoch}, Loss: {loss}') |