cogforge-engine 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cogforge_engine-0.1.0/.github/workflows/release.yml +33 -0
- cogforge_engine-0.1.0/.gitignore +12 -0
- cogforge_engine-0.1.0/PKG-INFO +11 -0
- cogforge_engine-0.1.0/README.md +1 -0
- cogforge_engine-0.1.0/cogforge/__init__.py +44 -0
- cogforge_engine-0.1.0/cogforge/app.py +864 -0
- cogforge_engine-0.1.0/pyproject.toml +22 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
deploy:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout Source Code
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.10"
|
|
22
|
+
|
|
23
|
+
- name: Install Build Tools
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
python -m pip install build
|
|
27
|
+
|
|
28
|
+
- name: Build Wheel and Source Tarball
|
|
29
|
+
run: |
|
|
30
|
+
python -m build
|
|
31
|
+
|
|
32
|
+
- name: Publish to PyPI via Trusted Publishing
|
|
33
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cogforge-engine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A custom autograd engine and Transformer block built from scratch.
|
|
5
|
+
Project-URL: Homepage, https://github.com/avikmjd2/cogforge
|
|
6
|
+
Author-email: Avik Majumder <avikmjd2@gmail.com>
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Requires-Dist: numpy>=1.20.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
Intial
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Intial
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
|
|
3
|
+
from .app import (
|
|
4
|
+
Tensor,
|
|
5
|
+
Linear,
|
|
6
|
+
MLP,
|
|
7
|
+
Embedding,
|
|
8
|
+
RNNCell,
|
|
9
|
+
RNN,
|
|
10
|
+
StackedRNN,
|
|
11
|
+
SGD,
|
|
12
|
+
Adam,
|
|
13
|
+
Sequential,
|
|
14
|
+
BatchNorm1D,
|
|
15
|
+
Bridge,
|
|
16
|
+
Attention,
|
|
17
|
+
MultiHeadAttention,
|
|
18
|
+
LayerNorm,
|
|
19
|
+
FeedForward,
|
|
20
|
+
Transformer,
|
|
21
|
+
PositionalEncoding
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"Tensor",
|
|
27
|
+
"Linear",
|
|
28
|
+
"MLP",
|
|
29
|
+
"Embedding",
|
|
30
|
+
"RNNCell",
|
|
31
|
+
"RNN",
|
|
32
|
+
"StackedRNN",
|
|
33
|
+
"SGD",
|
|
34
|
+
"Adam",
|
|
35
|
+
"Sequential",
|
|
36
|
+
"BatchNorm1D",
|
|
37
|
+
"Bridge",
|
|
38
|
+
"Attention",
|
|
39
|
+
"MultiHeadAttention",
|
|
40
|
+
"LayerNorm",
|
|
41
|
+
"FeedForward",
|
|
42
|
+
"Transformer",
|
|
43
|
+
"PositionalEncoding"
|
|
44
|
+
]
|
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
class Tensor:
|
|
4
|
+
def __init__(self, array,children=(),requires_grad = True):
|
|
5
|
+
self.data = np.asarray(array, dtype=float)
|
|
6
|
+
self.shape = self.data.shape
|
|
7
|
+
self.requires_grad = requires_grad
|
|
8
|
+
# if self.requires_grad:
|
|
9
|
+
self.grad = np.zeros(self.shape)
|
|
10
|
+
self._backwards = lambda:None
|
|
11
|
+
self._children = set(children)
|
|
12
|
+
|
|
13
|
+
def __getitem__(self, key):
|
|
14
|
+
out_data = self.data[key]
|
|
15
|
+
|
|
16
|
+
out = Tensor(out_data,children=(self,))
|
|
17
|
+
|
|
18
|
+
def _backward():
|
|
19
|
+
self.grad[key] += out.grad
|
|
20
|
+
|
|
21
|
+
out._backwards = _backward
|
|
22
|
+
|
|
23
|
+
return out
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def __add__(self, other):
|
|
27
|
+
other = other if isinstance(other, Tensor) else Tensor(other)
|
|
28
|
+
out_data = self.data + other.data
|
|
29
|
+
out = Tensor(out_data, (self, other))
|
|
30
|
+
|
|
31
|
+
def _backward():
|
|
32
|
+
if self.shape != out_data.shape:
|
|
33
|
+
axis = tuple(range(out.grad.ndim - self.data.ndim))
|
|
34
|
+
self.grad += np.sum(out.grad, axis=axis).reshape(self.shape)
|
|
35
|
+
else:
|
|
36
|
+
self.grad += out.grad
|
|
37
|
+
|
|
38
|
+
if other.shape != out_data.shape:
|
|
39
|
+
axis = tuple(range(out.grad.ndim - other.data.ndim))
|
|
40
|
+
other.grad += np.sum(out.grad, axis=axis).reshape(other.shape)
|
|
41
|
+
else:
|
|
42
|
+
other.grad += out.grad
|
|
43
|
+
|
|
44
|
+
out._backwards = _backward
|
|
45
|
+
return out
|
|
46
|
+
|
|
47
|
+
def __radd__(self, other):
|
|
48
|
+
return self + other
|
|
49
|
+
|
|
50
|
+
def __neg__(self):
|
|
51
|
+
return self * -1
|
|
52
|
+
|
|
53
|
+
def __sub__(self, other):
|
|
54
|
+
other = other if isinstance(other, Tensor) else Tensor(other)
|
|
55
|
+
return self + (-other)
|
|
56
|
+
|
|
57
|
+
def __rsub__(self, other):
|
|
58
|
+
return (-self) + other
|
|
59
|
+
|
|
60
|
+
def __mul__(self, other):
|
|
61
|
+
other = other if isinstance(other, Tensor) else Tensor(other)
|
|
62
|
+
out_data = self.data * other.data
|
|
63
|
+
|
|
64
|
+
out = Tensor(out_data, children=(self, other))
|
|
65
|
+
|
|
66
|
+
def _backward():
|
|
67
|
+
grad_self = other.data * out.grad
|
|
68
|
+
if self.shape != out_data.shape:
|
|
69
|
+
axis = tuple(range(out.grad.ndim - self.data.ndim))
|
|
70
|
+
grad_self = np.sum(grad_self, axis=axis).reshape(self.shape)
|
|
71
|
+
self.grad += grad_self
|
|
72
|
+
|
|
73
|
+
# gradient w.r.t. other
|
|
74
|
+
grad_other = self.data * out.grad
|
|
75
|
+
if other.shape != out_data.shape:
|
|
76
|
+
axis = tuple(range(out.grad.ndim - other.data.ndim))
|
|
77
|
+
grad_other = np.sum(grad_other, axis=axis).reshape(other.shape)
|
|
78
|
+
other.grad += grad_other
|
|
79
|
+
|
|
80
|
+
out._backwards = _backward
|
|
81
|
+
return out
|
|
82
|
+
|
|
83
|
+
def __rmul__(self, other):
|
|
84
|
+
return self * other
|
|
85
|
+
|
|
86
|
+
# def __matmul__(self, other):
|
|
87
|
+
# out_data = self.data @ other.data
|
|
88
|
+
|
|
89
|
+
# out = Tensor(out_data, children=(self,other))
|
|
90
|
+
|
|
91
|
+
# # def _backward():
|
|
92
|
+
# # self.grad += out.grad @ np.transpose(other.data)
|
|
93
|
+
# # other.grad += np.transpose(self.data) @ out.grad
|
|
94
|
+
|
|
95
|
+
# def _backward():
|
|
96
|
+
# self.grad += out.grad @ np.swapaxes(other.data, -1, -2)
|
|
97
|
+
# other.grad += np.swapaxes(self.data, -1, -2) @ out.grad
|
|
98
|
+
|
|
99
|
+
# out._backwards = _backward
|
|
100
|
+
# return out
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def unbroadcast(grad, shape):
|
|
104
|
+
while grad.ndim > len(shape):
|
|
105
|
+
grad = grad.sum(axis=0)
|
|
106
|
+
for i, s in enumerate(shape):
|
|
107
|
+
if s == 1 and grad.shape[i] != 1:
|
|
108
|
+
grad = grad.sum(axis=i, keepdims=True)
|
|
109
|
+
return grad
|
|
110
|
+
|
|
111
|
+
def __matmul__(self, other):
|
|
112
|
+
out = Tensor(self.data @ other.data, children=(self, other))
|
|
113
|
+
def _backward():
|
|
114
|
+
gs = out.grad @ np.swapaxes(other.data, -1, -2)
|
|
115
|
+
go = np.swapaxes(self.data, -1, -2) @ out.grad
|
|
116
|
+
self.grad += Tensor.unbroadcast(gs, self.data.shape)
|
|
117
|
+
other.grad += Tensor.unbroadcast(go, other.data.shape)
|
|
118
|
+
out._backwards = _backward
|
|
119
|
+
return out
|
|
120
|
+
|
|
121
|
+
def relu(self):
|
|
122
|
+
out_data = np.maximum(0,self.data)
|
|
123
|
+
|
|
124
|
+
out = Tensor(out_data, children=(self,))
|
|
125
|
+
|
|
126
|
+
def _backward():
|
|
127
|
+
mask = out_data > 0
|
|
128
|
+
self.grad+=(mask*out.grad)
|
|
129
|
+
|
|
130
|
+
out._backwards = _backward
|
|
131
|
+
return out
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def view(self,shape):
|
|
135
|
+
curr_shape = self.data.shape
|
|
136
|
+
|
|
137
|
+
if not self.data.flags['C_CONTIGUOUS']:
|
|
138
|
+
arr = np.ascontiguousarray(self.data)
|
|
139
|
+
else:
|
|
140
|
+
arr = self.data
|
|
141
|
+
|
|
142
|
+
out_data = arr.reshape(shape)
|
|
143
|
+
out = Tensor(out_data, children=(self,))
|
|
144
|
+
|
|
145
|
+
def _backward():
|
|
146
|
+
self.grad+=(out.grad.reshape(curr_shape))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
out._backwards = _backward
|
|
150
|
+
return out
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def sigmoid(self):
|
|
156
|
+
out_data = 1 / (1 + np.exp(-self.data))
|
|
157
|
+
out = Tensor(out_data, children=(self,))
|
|
158
|
+
def _backward():
|
|
159
|
+
local_derivative = out_data * (1 - out_data)
|
|
160
|
+
|
|
161
|
+
self.grad += local_derivative * out.grad
|
|
162
|
+
|
|
163
|
+
out._backwards = _backward
|
|
164
|
+
return out
|
|
165
|
+
|
|
166
|
+
def tanh(self):
|
|
167
|
+
out_data = np.tanh(self.data)
|
|
168
|
+
out = Tensor(out_data,children=(self,))
|
|
169
|
+
def _backward():
|
|
170
|
+
dervitive = 1-(out_data*out_data)
|
|
171
|
+
self.grad+=(out.grad*dervitive)
|
|
172
|
+
|
|
173
|
+
out._backwards = _backward
|
|
174
|
+
return out
|
|
175
|
+
|
|
176
|
+
def softmax(self,axis=-1):
|
|
177
|
+
maxVal = np.max(self.data,axis=axis,keepdims=True)
|
|
178
|
+
expVal = np.exp(self.data-maxVal)
|
|
179
|
+
|
|
180
|
+
out_data = expVal/np.sum(expVal,axis=axis,keepdims=True)
|
|
181
|
+
out=Tensor(out_data,(self,))
|
|
182
|
+
|
|
183
|
+
def _backward():
|
|
184
|
+
g = out.grad
|
|
185
|
+
self.grad += out_data * (g - np.sum(g * out_data, axis=axis, keepdims=True))
|
|
186
|
+
|
|
187
|
+
out._backwards = _backward
|
|
188
|
+
return out
|
|
189
|
+
|
|
190
|
+
#optimized for batches
|
|
191
|
+
@classmethod
|
|
192
|
+
def cross_entropy_loss(cls,predictions, targets):
|
|
193
|
+
|
|
194
|
+
probabilities = np.clip(predictions.data, 1e-15, 1 - 1e-15)
|
|
195
|
+
batch_size = predictions.shape[0]
|
|
196
|
+
|
|
197
|
+
loss_data = - np.sum(targets * np.log(probabilities)) / batch_size
|
|
198
|
+
loss = Tensor(loss_data, children=(predictions,))
|
|
199
|
+
|
|
200
|
+
def _backward():
|
|
201
|
+
|
|
202
|
+
# predictions.grad += (predictions.data - targets) / batch_size * loss.grad
|
|
203
|
+
predictions.grad += (-(targets / probabilities)) / batch_size * loss.grad
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
loss._backwards = _backward
|
|
207
|
+
return loss
|
|
208
|
+
|
|
209
|
+
#LEGACY
|
|
210
|
+
def backwards_recursive(self):
|
|
211
|
+
topo = []
|
|
212
|
+
visited = set()
|
|
213
|
+
def topoSort(v):
|
|
214
|
+
if v in visited:
|
|
215
|
+
return
|
|
216
|
+
visited.add(v)
|
|
217
|
+
for edges in v._children:
|
|
218
|
+
topoSort(edges)
|
|
219
|
+
|
|
220
|
+
topo.append(v)
|
|
221
|
+
|
|
222
|
+
topoSort(self)
|
|
223
|
+
|
|
224
|
+
self.grad = np.ones(self.shape)
|
|
225
|
+
|
|
226
|
+
for node in reversed(topo):
|
|
227
|
+
node._backwards()
|
|
228
|
+
|
|
229
|
+
def backwards(self):
|
|
230
|
+
topo = []
|
|
231
|
+
visited = set()
|
|
232
|
+
stack = [(self,False)]
|
|
233
|
+
|
|
234
|
+
while stack:
|
|
235
|
+
node,processed = stack.pop()
|
|
236
|
+
if processed:
|
|
237
|
+
topo.append(node)
|
|
238
|
+
continue
|
|
239
|
+
if node in visited:
|
|
240
|
+
continue
|
|
241
|
+
visited.add(node)
|
|
242
|
+
|
|
243
|
+
stack.append((node,True))
|
|
244
|
+
for child in node._children:
|
|
245
|
+
stack.append((child,False))
|
|
246
|
+
|
|
247
|
+
self.grad = np.ones(self.shape)
|
|
248
|
+
|
|
249
|
+
for node in reversed(topo):
|
|
250
|
+
node._backwards()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def flatten(self):
|
|
254
|
+
batch_size = self.shape[0]
|
|
255
|
+
out_data = self.data.reshape(batch_size, -1)
|
|
256
|
+
|
|
257
|
+
out = Tensor(out_data, children=(self,))
|
|
258
|
+
def _backward():
|
|
259
|
+
self.grad += out.grad.reshape(self.shape)
|
|
260
|
+
|
|
261
|
+
out._backwards = _backward
|
|
262
|
+
return out
|
|
263
|
+
|
|
264
|
+
def flatten_consective(self,num):
|
|
265
|
+
"""THIS ONLY FLATTENS A 3 DIMENSIONAL TENSOR. CAREFULL.
|
|
266
|
+
EXPLECTS (BATCH, CONTEXT, DIMENSION) AS SHAPE"""
|
|
267
|
+
self.flatten_dim = num
|
|
268
|
+
if(len(self.shape)) != 3:
|
|
269
|
+
raise ValueError("THIS FUNCTION ONLY EXPECTS A 3 DIMENSIONAL TENSOR.")
|
|
270
|
+
|
|
271
|
+
B,T,C = self.shape
|
|
272
|
+
|
|
273
|
+
if T % num != 0:
|
|
274
|
+
raise ValueError(f"Time dimension {T} must be cleanly divisible by num {num}")
|
|
275
|
+
|
|
276
|
+
out_data = self.data.reshape(B,T//num,C*num)
|
|
277
|
+
|
|
278
|
+
out = Tensor(out_data, children=(self,))
|
|
279
|
+
|
|
280
|
+
def _backward():
|
|
281
|
+
self.grad += out.grad.reshape(self.shape)
|
|
282
|
+
|
|
283
|
+
out._backwards = _backward
|
|
284
|
+
return out
|
|
285
|
+
|
|
286
|
+
#TODO
|
|
287
|
+
@classmethod
|
|
288
|
+
def cross_entropy_loss_masked(cls, predictions, targets, mask):
|
|
289
|
+
"""
|
|
290
|
+
predictions: (B, V) softmax probs
|
|
291
|
+
targets: (B, V) one-hot
|
|
292
|
+
mask: (B,) 1.0 for real positions, 0.0 for <PAD>
|
|
293
|
+
"""
|
|
294
|
+
probs = np.clip(predictions.data, 1e-15, 1 - 1e-15)
|
|
295
|
+
mask = mask.reshape(-1, 1) # (B, 1)
|
|
296
|
+
n_real = mask.sum()
|
|
297
|
+
n_real = n_real if n_real > 0 else 1.0
|
|
298
|
+
|
|
299
|
+
# only real rows contribute to the loss value
|
|
300
|
+
loss_data = -np.sum(mask * targets * np.log(probs)) / n_real
|
|
301
|
+
loss = cls(loss_data, children=(predictions,))
|
|
302
|
+
|
|
303
|
+
def _backward():
|
|
304
|
+
# grad = (predictions.data - targets) / n_real
|
|
305
|
+
grad = -(targets / probs) / n_real
|
|
306
|
+
grad = grad * mask # <-- padded rows get exactly zero gradient
|
|
307
|
+
predictions.grad += grad * loss.grad
|
|
308
|
+
|
|
309
|
+
loss._backwards = _backward
|
|
310
|
+
return loss
|
|
311
|
+
|
|
312
|
+
#Legacy
|
|
313
|
+
@classmethod
|
|
314
|
+
def softmax_cross_entropy_old(cls, scores, targets):
|
|
315
|
+
z = scores.data
|
|
316
|
+
z = z - z.max(axis=1, keepdims=True) # stability
|
|
317
|
+
e = np.exp(z)
|
|
318
|
+
p = e / e.sum(axis=1, keepdims=True) # softmax, computed privately
|
|
319
|
+
B = scores.shape[0]
|
|
320
|
+
|
|
321
|
+
loss = cls(-np.sum(targets * np.log(np.clip(p, 1e-15, 1.0))) / B, children=(scores,))
|
|
322
|
+
|
|
323
|
+
def _backward():
|
|
324
|
+
scores.grad += (p - targets) / B * loss.grad
|
|
325
|
+
loss._backwards = _backward
|
|
326
|
+
return loss
|
|
327
|
+
|
|
328
|
+
@classmethod
|
|
329
|
+
def softmax_cross_entropy(cls, scores, targets):
|
|
330
|
+
z = scores.data
|
|
331
|
+
z = z - z.max(axis=-1, keepdims=True)
|
|
332
|
+
e = np.exp(z)
|
|
333
|
+
p = e / e.sum(axis=-1, keepdims=True)
|
|
334
|
+
N = np.prod(scores.shape[:-1]) # B for 2D, B*T for 3D
|
|
335
|
+
loss = cls(-np.sum(targets * np.log(np.clip(p, 1e-15, 1.0))) / N, children=(scores,))
|
|
336
|
+
def _backward():
|
|
337
|
+
scores.grad += (p - targets) / N * loss.grad
|
|
338
|
+
loss._backwards = _backward
|
|
339
|
+
return loss
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@classmethod
|
|
343
|
+
def softmax_cross_entropy_masked(cls, scores, targets, mask):
|
|
344
|
+
z = scores.data
|
|
345
|
+
z = z - z.max(axis=1, keepdims=True)
|
|
346
|
+
e = np.exp(z)
|
|
347
|
+
p = e / e.sum(axis=1, keepdims=True)
|
|
348
|
+
|
|
349
|
+
mask = mask.reshape(-1, 1)
|
|
350
|
+
n_real = mask.sum()
|
|
351
|
+
n_real = n_real if n_real > 0 else 1.0
|
|
352
|
+
|
|
353
|
+
loss = cls(-np.sum(mask * targets * np.log(np.clip(p, 1e-15, 1.0))) / n_real, children=(scores,))
|
|
354
|
+
|
|
355
|
+
def _backward():
|
|
356
|
+
grad = (p - targets) / n_real
|
|
357
|
+
grad = grad * mask
|
|
358
|
+
scores.grad += grad * loss.grad
|
|
359
|
+
loss._backwards = _backward
|
|
360
|
+
return loss
|
|
361
|
+
|
|
362
|
+
def transpose(self,axes):
|
|
363
|
+
out = Tensor(np.transpose(self.data,axes=axes),children=(self,))
|
|
364
|
+
inv = np.argsort(axes)
|
|
365
|
+
def _backward():
|
|
366
|
+
self.grad+=np.transpose(out.grad,inv)
|
|
367
|
+
|
|
368
|
+
out._backwards = _backward
|
|
369
|
+
return out
|
|
370
|
+
|
|
371
|
+
def masked_fill(self, mask, value):
|
|
372
|
+
out_data = np.where(mask, value, self.data)
|
|
373
|
+
out = Tensor(out_data, children=(self,))
|
|
374
|
+
def _backward():
|
|
375
|
+
self.grad += np.where(mask, 0.0, 1.0) * out.grad
|
|
376
|
+
out._backwards = _backward
|
|
377
|
+
return out
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
class Linear:
|
|
383
|
+
def __init__(self, nin, nout):
|
|
384
|
+
self.W = Tensor(np.random.randn(nin, nout) * np.sqrt(2.0/nin))
|
|
385
|
+
self.v_W = np.zeros(self.W.shape)
|
|
386
|
+
self.b = Tensor(np.zeros((nout,)))
|
|
387
|
+
self.v_b = np.zeros(self.b.shape)
|
|
388
|
+
|
|
389
|
+
def __call__ (self,x):
|
|
390
|
+
if(x.shape[-1]!=self.W.shape[0]):
|
|
391
|
+
raise TypeError("Dimensions mismatched")
|
|
392
|
+
out = x@self.W + self.b
|
|
393
|
+
return out
|
|
394
|
+
|
|
395
|
+
def parameters(self):
|
|
396
|
+
return [self.W, self.b]
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class MLP:
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def __init__(self, layer_sizes):
|
|
403
|
+
self.layers = []
|
|
404
|
+
for i in range(len(layer_sizes)-1):
|
|
405
|
+
self.layers.append(Linear(layer_sizes[i], layer_sizes[i+1]))
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def __call__(self, x):
|
|
409
|
+
for layer in self.layers[:-1]:
|
|
410
|
+
x = layer(x).relu()
|
|
411
|
+
|
|
412
|
+
out = self.layers[-1](x)
|
|
413
|
+
return out
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def save(self, filename="best_model.npz"):
|
|
417
|
+
weights_dict = {}
|
|
418
|
+
for i, layer in enumerate(self.layers):
|
|
419
|
+
weights_dict[f'W_{i}'] = layer.W.data
|
|
420
|
+
weights_dict[f'b_{i}'] = layer.b.data
|
|
421
|
+
|
|
422
|
+
np.savez_compressed(filename, **weights_dict)
|
|
423
|
+
|
|
424
|
+
def load(self, filename="best_model.npz"):
|
|
425
|
+
with np.load(filename) as data:
|
|
426
|
+
for i, layer in enumerate(self.layers):
|
|
427
|
+
layer.W.data = data[f'W_{i}']
|
|
428
|
+
layer.b.data = data[f'b_{i}']
|
|
429
|
+
print(f"Model loaded successfully from {filename}!")
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class Embedding:
|
|
433
|
+
def __init__(self, vocab_size, embedding_dim):
|
|
434
|
+
self.weights = Tensor(np.random.randn(vocab_size, embedding_dim))
|
|
435
|
+
|
|
436
|
+
def __call__(self, input_indices):
|
|
437
|
+
out_data = self.weights.data[input_indices]
|
|
438
|
+
|
|
439
|
+
out = Tensor(out_data, children=(self.weights,))
|
|
440
|
+
|
|
441
|
+
def _backward():
|
|
442
|
+
np.add.at(self.weights.grad,input_indices,out.grad)
|
|
443
|
+
|
|
444
|
+
out._backwards = _backward
|
|
445
|
+
return out
|
|
446
|
+
|
|
447
|
+
def parameters(self):
|
|
448
|
+
return [self.weights]
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class RNNCell:
|
|
452
|
+
def __init__(self,input_dim, hidden_dim):
|
|
453
|
+
self.i2h = Linear(input_dim,hidden_dim)
|
|
454
|
+
self.h2h = Linear(hidden_dim,hidden_dim)
|
|
455
|
+
|
|
456
|
+
def __call__(self, x,h_prev):
|
|
457
|
+
input_transform = self.i2h(x)
|
|
458
|
+
hidden_transform = self.h2h(h_prev)
|
|
459
|
+
|
|
460
|
+
h_next = Tensor.tanh(input_transform + hidden_transform)
|
|
461
|
+
|
|
462
|
+
return h_next
|
|
463
|
+
|
|
464
|
+
def parameters(self):
|
|
465
|
+
return self.i2h.parameters() + self.h2h.parameters()
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class RNN:
|
|
469
|
+
def __init__(self,input_dim, hidden_dim):
|
|
470
|
+
self.hidden_dim = hidden_dim
|
|
471
|
+
self.cell = RNNCell(input_dim=input_dim,hidden_dim=hidden_dim)
|
|
472
|
+
|
|
473
|
+
def __call__(self,xs,prev_hidden = None):
|
|
474
|
+
"""
|
|
475
|
+
xs: A list of Tensors, each of shape (B, input_dim) — the same
|
|
476
|
+
timestep across all sequences in the batch.
|
|
477
|
+
|
|
478
|
+
Returns: A list of Tensors (hidden states) at every time step,
|
|
479
|
+
each of shape (B, hidden_dim).
|
|
480
|
+
"""
|
|
481
|
+
|
|
482
|
+
if prev_hidden is not None:
|
|
483
|
+
h = prev_hidden
|
|
484
|
+
else:
|
|
485
|
+
B = xs[0].shape[0]
|
|
486
|
+
h = Tensor(np.zeros((B, self.hidden_dim)))
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
hidden_states = []
|
|
490
|
+
|
|
491
|
+
for x in xs:
|
|
492
|
+
h = self.cell(x,h)
|
|
493
|
+
hidden_states.append(h)
|
|
494
|
+
|
|
495
|
+
return hidden_states
|
|
496
|
+
|
|
497
|
+
def parameters(self):
|
|
498
|
+
return self.cell.parameters()
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
class StackedRNN:
|
|
502
|
+
def __init__(self,input_dim,hidden_dim,num_layers):
|
|
503
|
+
self.layers = []
|
|
504
|
+
self.layers.append(RNN(input_dim,hidden_dim))
|
|
505
|
+
|
|
506
|
+
for _ in range(1,num_layers):
|
|
507
|
+
self.layers.append(RNN(input_dim=hidden_dim, hidden_dim=hidden_dim))
|
|
508
|
+
|
|
509
|
+
def __call__(self,xs,prev_hidden = None):
|
|
510
|
+
"""
|
|
511
|
+
xs: A list of Tensors (the initial word embeddings)
|
|
512
|
+
|
|
513
|
+
Returns: A list of Tensors representing the hidden states
|
|
514
|
+
from the very TOP layer.
|
|
515
|
+
"""
|
|
516
|
+
if prev_hidden is not None:
|
|
517
|
+
assert len(prev_hidden) == len(self.layers), \
|
|
518
|
+
f"prev_hidden has {len(prev_hidden)} states but stack has {len(self.layers)} layers"
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
curr = xs
|
|
522
|
+
h_outs = []
|
|
523
|
+
|
|
524
|
+
for i,layer in enumerate(self.layers):
|
|
525
|
+
initial = prev_hidden[i] if prev_hidden is not None else None
|
|
526
|
+
curr = layer(curr,initial)
|
|
527
|
+
|
|
528
|
+
h_outs.append(curr[-1])
|
|
529
|
+
|
|
530
|
+
return curr,h_outs
|
|
531
|
+
|
|
532
|
+
def parameters(self):
|
|
533
|
+
return [p for layer in self.layers for p in layer.parameters()]
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
class SGD:
|
|
537
|
+
def __init__(self,parameters,learning_rate=0.01):
|
|
538
|
+
self.parameters = parameters
|
|
539
|
+
self.lr = learning_rate
|
|
540
|
+
|
|
541
|
+
def clip_grads(self, max_norm=5.0):
|
|
542
|
+
total = np.sqrt(sum(np.sum(p.grad ** 2) for p in self.parameters))
|
|
543
|
+
if total > max_norm:
|
|
544
|
+
scale = max_norm / (total + 1e-6)
|
|
545
|
+
for p in self.parameters:
|
|
546
|
+
p.grad *= scale
|
|
547
|
+
|
|
548
|
+
def step(self):
|
|
549
|
+
for p in self.parameters:
|
|
550
|
+
p.data-=self.lr*(p.grad)
|
|
551
|
+
|
|
552
|
+
def zero_grad(self):
|
|
553
|
+
for p in self.parameters:
|
|
554
|
+
p.grad = np.zeros_like(p.grad)
|
|
555
|
+
|
|
556
|
+
class Sequential:
|
|
557
|
+
def __init__(self,layers):
|
|
558
|
+
self.layers = layers
|
|
559
|
+
|
|
560
|
+
def __call__(self, x):
|
|
561
|
+
for layer in self.layers:
|
|
562
|
+
x = layer(x)
|
|
563
|
+
return x
|
|
564
|
+
|
|
565
|
+
def parameters(self):
|
|
566
|
+
params = []
|
|
567
|
+
for layer in self.layers:
|
|
568
|
+
if hasattr(layer, 'W'): params.append(layer.W)
|
|
569
|
+
if hasattr(layer, 'b'): params.append(layer.b)
|
|
570
|
+
if hasattr(layer, 'gamma'): params.append(layer.gamma)
|
|
571
|
+
if hasattr(layer, 'beta'): params.append(layer.beta)
|
|
572
|
+
#TODO: add rest of parameters
|
|
573
|
+
return params
|
|
574
|
+
|
|
575
|
+
def train(self):
|
|
576
|
+
for layer in self.layers:
|
|
577
|
+
if hasattr(layer, 'training'):
|
|
578
|
+
layer.training = True
|
|
579
|
+
|
|
580
|
+
def test(self):
|
|
581
|
+
for layer in self.layers:
|
|
582
|
+
if hasattr(layer, 'training'):
|
|
583
|
+
layer.training = False
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class BatchNorm1D:
|
|
587
|
+
def __init__(self, dim, eps=1e-5, momentum=0.1):
|
|
588
|
+
self.eps = eps
|
|
589
|
+
self.momentum = momentum
|
|
590
|
+
self.training = True
|
|
591
|
+
|
|
592
|
+
self.gamma = Tensor(np.ones(dim))
|
|
593
|
+
self.beta = Tensor(np.zeros(dim))
|
|
594
|
+
|
|
595
|
+
self.running_mean = np.zeros(dim)
|
|
596
|
+
self.running_var = np.ones(dim)
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def __call__(self,x:Tensor):
|
|
600
|
+
reduce_dims = (0,) if x.data.ndim==2 else (0,1)
|
|
601
|
+
|
|
602
|
+
if self.training:
|
|
603
|
+
mean = x.data.mean(axis=reduce_dims, keepdims=True)
|
|
604
|
+
var = x.data.var(axis=reduce_dims, keepdims=True)
|
|
605
|
+
|
|
606
|
+
self.x_centered = x.data - mean
|
|
607
|
+
self.std_inv = 1.0 / np.sqrt(var + self.eps)
|
|
608
|
+
self.x_hat = self.x_centered * self.std_inv
|
|
609
|
+
|
|
610
|
+
N = np.prod([x.data.shape[d] for d in reduce_dims])
|
|
611
|
+
unbiased_var = var.squeeze() * (N / (N - 1)) if N > 1 else var.squeeze()
|
|
612
|
+
|
|
613
|
+
self.running_mean = (1 - self.momentum) * self.running_mean + self.momentum * mean.squeeze()
|
|
614
|
+
self.running_var = (1 - self.momentum) * self.running_var + self.momentum * unbiased_var
|
|
615
|
+
|
|
616
|
+
else:
|
|
617
|
+
self.x_hat = (x.data-self.running_mean)/np.sqrt(self.running_var + self.eps)
|
|
618
|
+
|
|
619
|
+
out_data = self.gamma.data * self.x_hat + self.beta.data
|
|
620
|
+
|
|
621
|
+
out = Tensor(out_data, children=(x, self.gamma, self.beta))
|
|
622
|
+
|
|
623
|
+
def _backward():
|
|
624
|
+
if not self.training:
|
|
625
|
+
return
|
|
626
|
+
|
|
627
|
+
dout = out.grad
|
|
628
|
+
self.gamma.grad += np.sum(dout * self.x_hat, axis=reduce_dims)
|
|
629
|
+
self.beta.grad += np.sum(dout, axis=reduce_dims)
|
|
630
|
+
|
|
631
|
+
N = np.prod([x.data.shape[d] for d in reduce_dims])
|
|
632
|
+
|
|
633
|
+
dx_hat = dout * self.gamma.data
|
|
634
|
+
dx = (1.0 / N) * self.std_inv * (
|
|
635
|
+
N * dx_hat
|
|
636
|
+
- np.sum(dx_hat, axis=reduce_dims, keepdims=True)
|
|
637
|
+
- self.x_hat * np.sum(dx_hat * self.x_hat, axis=reduce_dims, keepdims=True)
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
x.grad += dx
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
out._backwards = _backward
|
|
644
|
+
|
|
645
|
+
return out
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
class Bridge:
|
|
650
|
+
"""
|
|
651
|
+
Maps encoder final hidden states to decoder initial hidden states.
|
|
652
|
+
Handles asymmetry in:
|
|
653
|
+
- num_layers (encoder count != decoder count)
|
|
654
|
+
- hidden_dim (enc_hidden != dec_hidden)
|
|
655
|
+
Embedding-dim asymmetry needs no bridge: encoder/decoder have
|
|
656
|
+
independent Embeddings and independent first-layer i2h Linears.
|
|
657
|
+
|
|
658
|
+
mode:
|
|
659
|
+
"project" : one learned Linear(enc_H -> dec_H) per decoder layer (general, recommended)
|
|
660
|
+
"tie" : no params; requires enc_H == dec_H. Selects/repeats raw states.
|
|
661
|
+
"""
|
|
662
|
+
def __init__(self, enc_hidden, dec_hidden, enc_layers, dec_layers, mode="project"):
|
|
663
|
+
self.enc_hidden = enc_hidden
|
|
664
|
+
self.dec_hidden = dec_hidden
|
|
665
|
+
self.enc_layers = enc_layers
|
|
666
|
+
self.dec_layers = dec_layers
|
|
667
|
+
self.mode = mode
|
|
668
|
+
|
|
669
|
+
if mode == "tie":
|
|
670
|
+
if enc_hidden != dec_hidden:
|
|
671
|
+
raise ValueError(
|
|
672
|
+
f"mode='tie' needs enc_hidden==dec_hidden, "
|
|
673
|
+
f"got {enc_hidden} vs {dec_hidden}. Use mode='project'."
|
|
674
|
+
)
|
|
675
|
+
self.projections = None
|
|
676
|
+
elif mode == "project":
|
|
677
|
+
# one projection per decoder layer
|
|
678
|
+
self.projections = [Linear(enc_hidden, dec_hidden) for _ in range(dec_layers)]
|
|
679
|
+
else:
|
|
680
|
+
raise ValueError(f"unknown bridge mode: {mode}")
|
|
681
|
+
|
|
682
|
+
def __select(self,enc_hidden):
|
|
683
|
+
"""Pick/pad encoder states to exactly dec_layers, bottom→top aligned at the TOP."""
|
|
684
|
+
n = len(enc_hidden) #enc_hidden is the final layer of each level
|
|
685
|
+
if n == self.dec_layers:
|
|
686
|
+
return enc_hidden
|
|
687
|
+
elif n > self.dec_layers:
|
|
688
|
+
return enc_hidden[-self.dec_layers:]
|
|
689
|
+
else:
|
|
690
|
+
top = enc_hidden[-1]
|
|
691
|
+
return enc_hidden + [top] * (self.dec_layers - n)
|
|
692
|
+
|
|
693
|
+
def __call__(self,enc_hidden):
|
|
694
|
+
final_layers = self.__select(enc_hidden)
|
|
695
|
+
if self.mode=="tie":
|
|
696
|
+
return final_layers
|
|
697
|
+
|
|
698
|
+
return [proj(h) for proj,h in zip(self.projections,final_layers)]
|
|
699
|
+
|
|
700
|
+
def parameters(self):
|
|
701
|
+
if self.projections is None:
|
|
702
|
+
return []
|
|
703
|
+
return [p for proj in self.projections for p in proj.parameters()]
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
class Adam:
|
|
707
|
+
def __init__(self, parameters, lr=1e-3, beta1=0.9, beta2=0.999, eps=1e-8):
|
|
708
|
+
self.parameters = parameters
|
|
709
|
+
self.lr = lr; self.beta1 = beta1; self.beta2 = beta2; self.eps = eps
|
|
710
|
+
self.m = [np.zeros_like(p.data) for p in parameters]
|
|
711
|
+
self.v = [np.zeros_like(p.data) for p in parameters]
|
|
712
|
+
self.t = 0
|
|
713
|
+
|
|
714
|
+
def step(self):
|
|
715
|
+
self.t += 1
|
|
716
|
+
for i, p in enumerate(self.parameters):
|
|
717
|
+
self.m[i] = self.beta1*self.m[i] + (1-self.beta1)*p.grad
|
|
718
|
+
self.v[i] = self.beta2*self.v[i] + (1-self.beta2)*(p.grad**2)
|
|
719
|
+
m_hat = self.m[i] / (1 - self.beta1**self.t)
|
|
720
|
+
v_hat = self.v[i] / (1 - self.beta2**self.t)
|
|
721
|
+
p.data -= self.lr * m_hat / (np.sqrt(v_hat) + self.eps)
|
|
722
|
+
|
|
723
|
+
def zero_grad(self):
|
|
724
|
+
for p in self.parameters:
|
|
725
|
+
p.grad = np.zeros_like(p.grad)
|
|
726
|
+
|
|
727
|
+
def clip_grads(self, max_norm=5.0):
|
|
728
|
+
total = np.sqrt(sum(np.sum(p.grad**2) for p in self.parameters))
|
|
729
|
+
if total > max_norm:
|
|
730
|
+
scale = max_norm / (total + 1e-6)
|
|
731
|
+
for p in self.parameters:
|
|
732
|
+
p.grad *= scale
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
class Attention:
|
|
736
|
+
def __init__(self,dk):
|
|
737
|
+
self.scale = 1.0/np.sqrt(dk)
|
|
738
|
+
|
|
739
|
+
def __call__(self, Q:Tensor,K:Tensor,V:Tensor,mask=None):
|
|
740
|
+
axes = list(range(Q.data.ndim)); axes[-1], axes[-2] = axes[-2], axes[-1]
|
|
741
|
+
scores:Tensor = (Q @ K.transpose(tuple(axes)))*(self.scale)
|
|
742
|
+
|
|
743
|
+
if mask is not None:
|
|
744
|
+
scores = scores.masked_fill(mask,-1e9)
|
|
745
|
+
|
|
746
|
+
intermediate = scores.softmax(axis=-1)
|
|
747
|
+
|
|
748
|
+
return intermediate @ V
|
|
749
|
+
|
|
750
|
+
class MultiHeadAttention:
|
|
751
|
+
def __init__(self,dinp,dmodel, dout,n):
|
|
752
|
+
assert dmodel%n==0
|
|
753
|
+
self.h = n
|
|
754
|
+
self.dk = dmodel//n
|
|
755
|
+
self.q = Linear(dinp,dmodel) #dmodel = dk*h, we will slice it
|
|
756
|
+
self.k = Linear(dinp,dmodel)
|
|
757
|
+
self.v = Linear(dinp,dmodel)
|
|
758
|
+
self.o = Linear(dmodel,dout)
|
|
759
|
+
self.attention = Attention(self.dk)
|
|
760
|
+
|
|
761
|
+
def split(self,x:Tensor):
|
|
762
|
+
B,T,_ = x.data.shape
|
|
763
|
+
return x.view((B,T,self.h,self.dk)).transpose((0,2,1,3)) #(B, h, T, d_k)
|
|
764
|
+
|
|
765
|
+
def merge(self,x:Tensor):
|
|
766
|
+
B, h, T, d_k = x.data.shape
|
|
767
|
+
return x.transpose((0, 2, 1, 3)).view((B, T, h * d_k))
|
|
768
|
+
|
|
769
|
+
def __call__(self, query,key,value,mask=None):
|
|
770
|
+
Q = self.split(self.q(query))
|
|
771
|
+
K = self.split(self.k(key))
|
|
772
|
+
V = self.split(self.v(value))
|
|
773
|
+
out = self.attention(Q=Q,K=K,V=V,mask=mask)
|
|
774
|
+
return self.o(self.merge(out))
|
|
775
|
+
|
|
776
|
+
def parameters(self):
|
|
777
|
+
return (self.q.parameters() + self.k.parameters()
|
|
778
|
+
+ self.v.parameters() + self.o.parameters())
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
class LayerNorm:
|
|
782
|
+
def __init__(self, dim, eps=1e-5):
|
|
783
|
+
self.eps = eps
|
|
784
|
+
self.gamma = Tensor(np.ones(dim))
|
|
785
|
+
self.beta = Tensor(np.zeros(dim))
|
|
786
|
+
|
|
787
|
+
def __call__(self, x):
|
|
788
|
+
mu = x.data.mean(axis=-1, keepdims=True)
|
|
789
|
+
var = x.data.var(axis=-1, keepdims=True)
|
|
790
|
+
std_inv = 1.0 / np.sqrt(var + self.eps)
|
|
791
|
+
x_hat = (x.data - mu) * std_inv
|
|
792
|
+
out_data = self.gamma.data * x_hat + self.beta.data
|
|
793
|
+
out = Tensor(out_data, children=(x, self.gamma, self.beta))
|
|
794
|
+
|
|
795
|
+
D = x.data.shape[-1]
|
|
796
|
+
def _backward():
|
|
797
|
+
dout = out.grad
|
|
798
|
+
axes = tuple(range(dout.ndim - 1))
|
|
799
|
+
self.gamma.grad += np.sum(dout * x_hat, axis=axes)
|
|
800
|
+
self.beta.grad += np.sum(dout, axis=axes)
|
|
801
|
+
dxhat = dout * self.gamma.data
|
|
802
|
+
dx = std_inv / D * (
|
|
803
|
+
D * dxhat
|
|
804
|
+
- np.sum(dxhat, axis=-1, keepdims=True)
|
|
805
|
+
- x_hat * np.sum(dxhat * x_hat, axis=-1, keepdims=True)
|
|
806
|
+
)
|
|
807
|
+
x.grad += dx
|
|
808
|
+
out._backwards = _backward
|
|
809
|
+
return out
|
|
810
|
+
|
|
811
|
+
def parameters(self):
|
|
812
|
+
return [self.gamma, self.beta]
|
|
813
|
+
|
|
814
|
+
class FeedForward:
|
|
815
|
+
def __init__(self,dmodel,dff=None):
|
|
816
|
+
dff = dff if dff is not None else 4 * dmodel
|
|
817
|
+
self.fc1 = Linear(dmodel,dff)
|
|
818
|
+
self.fc2 = Linear(dff,dmodel)
|
|
819
|
+
|
|
820
|
+
def __call__(self, x):
|
|
821
|
+
return self.fc2(self.fc1(x).relu())
|
|
822
|
+
def parameters(self):
|
|
823
|
+
return self.fc1.parameters() + self.fc2.parameters()
|
|
824
|
+
|
|
825
|
+
class Transformer:
|
|
826
|
+
"""The transformer block has no bridge. So demb = dmodel"""
|
|
827
|
+
|
|
828
|
+
def __init__(self, dmodel, n, dff = None):
|
|
829
|
+
self.ln1 = LayerNorm(dmodel)
|
|
830
|
+
self.attn = MultiHeadAttention(dinp=dmodel,dmodel=dmodel,dout=dmodel,n=n)
|
|
831
|
+
self.ln2 = LayerNorm(dmodel)
|
|
832
|
+
self.ff = FeedForward(dmodel=dmodel,dff=dff)
|
|
833
|
+
|
|
834
|
+
def __call__(self,x,mask=None):
|
|
835
|
+
a = self.ln1(x)
|
|
836
|
+
x = x + self.attn(a,a,a,mask=mask)
|
|
837
|
+
f = self.ln2(x)
|
|
838
|
+
x = x+ self.ff(f)
|
|
839
|
+
|
|
840
|
+
return x
|
|
841
|
+
|
|
842
|
+
def parameters(self):
|
|
843
|
+
return (self.ln1.parameters() + self.attn.parameters()
|
|
844
|
+
+ self.ln2.parameters() + self.ff.parameters())
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
class PositionalEncoding:
|
|
848
|
+
def __init__(self,max_len,dmodel):
|
|
849
|
+
pe = np.zeros((max_len,dmodel))
|
|
850
|
+
pos = np.arange(max_len).reshape(-1,1)
|
|
851
|
+
div = np.exp(np.arange(0, dmodel, 2) * (-np.log(10000.0) / dmodel))
|
|
852
|
+
pe[:,0::2] = np.sin(pos*div)
|
|
853
|
+
pe[:,1::2] = np.cos(pos*div)
|
|
854
|
+
self.pe = pe
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
def __call__(self, x):
|
|
858
|
+
T = x.shape[1]
|
|
859
|
+
return x + Tensor(self.pe[:T])
|
|
860
|
+
|
|
861
|
+
def parameters(self):
|
|
862
|
+
return []
|
|
863
|
+
|
|
864
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cogforge-engine"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Avik Majumder", email="avikmjd2@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "A custom autograd engine and Transformer block built from scratch."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"numpy>=1.20.0",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://github.com/avikmjd2/cogforge"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["cogforge"]
|