| 14 | |
| 15 | |
| 16 | class GRU: |
| 17 | def __init__(self, Mi, Mo, activation): |
| 18 | self.Mi = Mi |
| 19 | self.Mo = Mo |
| 20 | self.f = activation |
| 21 | |
| 22 | # numpy init |
| 23 | Wxr = init_weight(Mi, Mo) |
| 24 | Whr = init_weight(Mo, Mo) |
| 25 | br = np.zeros(Mo) |
| 26 | Wxz = init_weight(Mi, Mo) |
| 27 | Whz = init_weight(Mo, Mo) |
| 28 | bz = np.zeros(Mo) |
| 29 | Wxh = init_weight(Mi, Mo) |
| 30 | Whh = init_weight(Mo, Mo) |
| 31 | bh = np.zeros(Mo) |
| 32 | h0 = np.zeros(Mo) |
| 33 | |
| 34 | # theano vars |
| 35 | self.Wxr = theano.shared(Wxr) |
| 36 | self.Whr = theano.shared(Whr) |
| 37 | self.br = theano.shared(br) |
| 38 | self.Wxz = theano.shared(Wxz) |
| 39 | self.Whz = theano.shared(Whz) |
| 40 | self.bz = theano.shared(bz) |
| 41 | self.Wxh = theano.shared(Wxh) |
| 42 | self.Whh = theano.shared(Whh) |
| 43 | self.bh = theano.shared(bh) |
| 44 | self.h0 = theano.shared(h0) |
| 45 | self.params = [self.Wxr, self.Whr, self.br, self.Wxz, self.Whz, self.bz, self.Wxh, self.Whh, self.bh, self.h0] |
| 46 | |
| 47 | def recurrence(self, x_t, h_t1): |
| 48 | r = T.nnet.sigmoid(x_t.dot(self.Wxr) + h_t1.dot(self.Whr) + self.br) |
| 49 | z = T.nnet.sigmoid(x_t.dot(self.Wxz) + h_t1.dot(self.Whz) + self.bz) |
| 50 | hhat = self.f(x_t.dot(self.Wxh) + (r * h_t1).dot(self.Whh) + self.bh) |
| 51 | h = (1 - z) * h_t1 + z * hhat |
| 52 | return h |
| 53 | |
| 54 | def output(self, x): |
| 55 | # input X should be a matrix (2-D) |
| 56 | # rows index time |
| 57 | h, _ = theano.scan( |
| 58 | fn=self.recurrence, |
| 59 | sequences=x, |
| 60 | outputs_info=[self.h0], |
| 61 | n_steps=x.shape[0], |
| 62 | ) |
| 63 | return h |