rnnt.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from tinygrad.tensor import Tensor
  2. from tinygrad.engine.jit import TinyJit
  3. from tinygrad.nn import Linear, Embedding
  4. from tinygrad.helpers import fetch
  5. import numpy as np
  6. from pathlib import Path
  7. class RNNT:
  8. def __init__(self, input_features=240, vocab_size=29, enc_hidden_size=1024, pred_hidden_size=320, joint_hidden_size=512, pre_enc_layers=2, post_enc_layers=3, pred_layers=2, stack_time_factor=2, dropout=0.32):
  9. self.encoder = Encoder(input_features, enc_hidden_size, pre_enc_layers, post_enc_layers, stack_time_factor, dropout)
  10. self.prediction = Prediction(vocab_size, pred_hidden_size, pred_layers, dropout)
  11. self.joint = Joint(vocab_size, pred_hidden_size, enc_hidden_size, joint_hidden_size, dropout)
  12. @TinyJit
  13. def __call__(self, x, y, hc=None):
  14. f, _ = self.encoder(x, None)
  15. g, _ = self.prediction(y, hc, Tensor.ones(1, requires_grad=False))
  16. out = self.joint(f, g)
  17. return out.realize()
  18. def decode(self, x, x_lens):
  19. logits, logit_lens = self.encoder(x, x_lens)
  20. outputs = []
  21. for b in range(logits.shape[0]):
  22. inseq = logits[b, :, :].unsqueeze(1)
  23. logit_len = logit_lens[b]
  24. seq = self._greedy_decode(inseq, int(np.ceil(logit_len.numpy()).item()))
  25. outputs.append(seq)
  26. return outputs
  27. def _greedy_decode(self, logits, logit_len):
  28. hc = Tensor.zeros(self.prediction.rnn.layers, 2, self.prediction.hidden_size, requires_grad=False)
  29. labels = []
  30. label = Tensor.zeros(1, 1, requires_grad=False)
  31. mask = Tensor.zeros(1, requires_grad=False)
  32. for time_idx in range(logit_len):
  33. logit = logits[time_idx, :, :].unsqueeze(0)
  34. not_blank = True
  35. added = 0
  36. while not_blank and added < 30:
  37. if len(labels) > 0:
  38. mask = (mask + 1).clip(0, 1)
  39. label = Tensor([[labels[-1] if labels[-1] <= 28 else labels[-1] - 1]], requires_grad=False) + 1 - 1
  40. jhc = self._pred_joint(Tensor(logit.numpy()), label, hc, mask)
  41. k = jhc[0, 0, :29].argmax(axis=0).numpy()
  42. not_blank = k != 28
  43. if not_blank:
  44. labels.append(k)
  45. hc = jhc[:, :, 29:] + 1 - 1
  46. added += 1
  47. return labels
  48. @TinyJit
  49. def _pred_joint(self, logit, label, hc, mask):
  50. g, hc = self.prediction(label, hc, mask)
  51. j = self.joint(logit, g)[0]
  52. j = j.pad(((0, 1), (0, 1), (0, 0)))
  53. out = j.cat(hc, dim=2)
  54. return out.realize()
  55. def load_from_pretrained(self):
  56. fn = Path(__file__).parents[1] / "weights/rnnt.pt"
  57. fetch("https://zenodo.org/record/3662521/files/DistributedDataParallel_1576581068.9962234-epoch-100.pt?download=1", fn)
  58. import torch
  59. with open(fn, "rb") as f:
  60. state_dict = torch.load(f, map_location="cpu")["state_dict"]
  61. # encoder
  62. for i in range(2):
  63. self.encoder.pre_rnn.cells[i].weights_ih.assign(state_dict[f"encoder.pre_rnn.lstm.weight_ih_l{i}"].numpy())
  64. self.encoder.pre_rnn.cells[i].weights_hh.assign(state_dict[f"encoder.pre_rnn.lstm.weight_hh_l{i}"].numpy())
  65. self.encoder.pre_rnn.cells[i].bias_ih.assign(state_dict[f"encoder.pre_rnn.lstm.bias_ih_l{i}"].numpy())
  66. self.encoder.pre_rnn.cells[i].bias_hh.assign(state_dict[f"encoder.pre_rnn.lstm.bias_hh_l{i}"].numpy())
  67. for i in range(3):
  68. self.encoder.post_rnn.cells[i].weights_ih.assign(state_dict[f"encoder.post_rnn.lstm.weight_ih_l{i}"].numpy())
  69. self.encoder.post_rnn.cells[i].weights_hh.assign(state_dict[f"encoder.post_rnn.lstm.weight_hh_l{i}"].numpy())
  70. self.encoder.post_rnn.cells[i].bias_ih.assign(state_dict[f"encoder.post_rnn.lstm.bias_ih_l{i}"].numpy())
  71. self.encoder.post_rnn.cells[i].bias_hh.assign(state_dict[f"encoder.post_rnn.lstm.bias_hh_l{i}"].numpy())
  72. # prediction
  73. self.prediction.emb.weight.assign(state_dict["prediction.embed.weight"].numpy())
  74. for i in range(2):
  75. self.prediction.rnn.cells[i].weights_ih.assign(state_dict[f"prediction.dec_rnn.lstm.weight_ih_l{i}"].numpy())
  76. self.prediction.rnn.cells[i].weights_hh.assign(state_dict[f"prediction.dec_rnn.lstm.weight_hh_l{i}"].numpy())
  77. self.prediction.rnn.cells[i].bias_ih.assign(state_dict[f"prediction.dec_rnn.lstm.bias_ih_l{i}"].numpy())
  78. self.prediction.rnn.cells[i].bias_hh.assign(state_dict[f"prediction.dec_rnn.lstm.bias_hh_l{i}"].numpy())
  79. # joint
  80. self.joint.l1.weight.assign(state_dict["joint_net.0.weight"].numpy())
  81. self.joint.l1.bias.assign(state_dict["joint_net.0.bias"].numpy())
  82. self.joint.l2.weight.assign(state_dict["joint_net.3.weight"].numpy())
  83. self.joint.l2.bias.assign(state_dict["joint_net.3.bias"].numpy())
  84. class LSTMCell:
  85. def __init__(self, input_size, hidden_size, dropout):
  86. self.dropout = dropout
  87. self.weights_ih = Tensor.uniform(hidden_size * 4, input_size)
  88. self.bias_ih = Tensor.uniform(hidden_size * 4)
  89. self.weights_hh = Tensor.uniform(hidden_size * 4, hidden_size)
  90. self.bias_hh = Tensor.uniform(hidden_size * 4)
  91. def __call__(self, x, hc):
  92. gates = x.linear(self.weights_ih.T, self.bias_ih) + hc[:x.shape[0]].linear(self.weights_hh.T, self.bias_hh)
  93. i, f, g, o = gates.chunk(4, 1)
  94. i, f, g, o = i.sigmoid(), f.sigmoid(), g.tanh(), o.sigmoid()
  95. c = (f * hc[x.shape[0]:]) + (i * g)
  96. h = (o * c.tanh()).dropout(self.dropout)
  97. return Tensor.cat(h, c).realize()
  98. class LSTM:
  99. def __init__(self, input_size, hidden_size, layers, dropout):
  100. self.input_size = input_size
  101. self.hidden_size = hidden_size
  102. self.layers = layers
  103. self.cells = [LSTMCell(input_size, hidden_size, dropout) if i == 0 else LSTMCell(hidden_size, hidden_size, dropout if i != layers - 1 else 0) for i in range(layers)]
  104. def __call__(self, x, hc):
  105. @TinyJit
  106. def _do_step(x_, hc_):
  107. return self.do_step(x_, hc_)
  108. if hc is None:
  109. hc = Tensor.zeros(self.layers, 2 * x.shape[1], self.hidden_size, requires_grad=False)
  110. output = None
  111. for t in range(x.shape[0]):
  112. hc = _do_step(x[t] + 1 - 1, hc) # TODO: why do we need to do this?
  113. if output is None:
  114. output = hc[-1:, :x.shape[1]]
  115. else:
  116. output = output.cat(hc[-1:, :x.shape[1]], dim=0).realize()
  117. return output, hc
  118. def do_step(self, x, hc):
  119. new_hc = [x]
  120. for i, cell in enumerate(self.cells):
  121. new_hc.append(cell(new_hc[i][:x.shape[0]], hc[i]))
  122. return Tensor.stack(*new_hc[1:]).realize()
  123. class StackTime:
  124. def __init__(self, factor):
  125. self.factor = factor
  126. def __call__(self, x, x_lens):
  127. x = x.pad(((0, (-x.shape[0]) % self.factor), (0, 0), (0, 0)))
  128. x = x.reshape(x.shape[0] // self.factor, x.shape[1], x.shape[2] * self.factor)
  129. return x, x_lens / self.factor if x_lens is not None else None
  130. class Encoder:
  131. def __init__(self, input_size, hidden_size, pre_layers, post_layers, stack_time_factor, dropout):
  132. self.pre_rnn = LSTM(input_size, hidden_size, pre_layers, dropout)
  133. self.stack_time = StackTime(stack_time_factor)
  134. self.post_rnn = LSTM(stack_time_factor * hidden_size, hidden_size, post_layers, dropout)
  135. def __call__(self, x, x_lens):
  136. x, _ = self.pre_rnn(x, None)
  137. x, x_lens = self.stack_time(x, x_lens)
  138. x, _ = self.post_rnn(x, None)
  139. return x.transpose(0, 1), x_lens
  140. class Prediction:
  141. def __init__(self, vocab_size, hidden_size, layers, dropout):
  142. self.hidden_size = hidden_size
  143. self.emb = Embedding(vocab_size - 1, hidden_size)
  144. self.rnn = LSTM(hidden_size, hidden_size, layers, dropout)
  145. def __call__(self, x, hc, m):
  146. emb = self.emb(x) * m
  147. x_, hc = self.rnn(emb.transpose(0, 1), hc)
  148. return x_.transpose(0, 1), hc
  149. class Joint:
  150. def __init__(self, vocab_size, pred_hidden_size, enc_hidden_size, joint_hidden_size, dropout):
  151. self.dropout = dropout
  152. self.l1 = Linear(pred_hidden_size + enc_hidden_size, joint_hidden_size)
  153. self.l2 = Linear(joint_hidden_size, vocab_size)
  154. def __call__(self, f, g):
  155. (_, T, H), (B, U, H2) = f.shape, g.shape
  156. f = f.unsqueeze(2).expand(B, T, U, H)
  157. g = g.unsqueeze(1).expand(B, T, U, H2)
  158. inp = f.cat(g, dim=3)
  159. t = self.l1(inp).relu()
  160. t = t.dropout(self.dropout)
  161. return self.l2(t)