-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathembedding.py
75 lines (55 loc) · 2.65 KB
/
embedding.py
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
from typing import Literal
import numpy as np
import neunet
from neunet.autograd import Tensor
from neunet.nn.modules import Module
from neunet.nn.parameter import Parameter
class _EmbeddingTensor(Tensor): # tensor for static backpropagation
def __init__(self, data, args, op, device):
super().__init__(data, args, op, device=device)
def grad_fn(X: np.ndarray, weight: Tensor, grad):
axis = list(range(len(X.shape)))
axis[-1], axis[-2] = axis[-2], axis[-1]
weight_grad = weight.xp.matmul(X.transpose(*axis), grad)
weight.apply_grad(weight_grad)
self.grad_fn = grad_fn
# class Embedding(Module):
# def __init__(self, num_embeddings: int, embedding_dim: int, device: str="cpu"):
# self.num_embeddings = num_embeddings
# self.embedding_dim = embedding_dim
# # stdv = 1. / self.xp.sqrt(embedding_dim)
# # self.weight = Tensor(self.xp.random.uniform(-stdv, stdv, (num_embeddings, embedding_dim)), dtype=self.xp.float32)
# self.weight = Parameter(
# neunet.tensor(np.random.randn(num_embeddings, embedding_dim), dtype=np.float32)
# ) # Torch's initialization
# self.to(device)
# def one_hot(self, X):
# O = self.xp.zeros((X.size, self.num_embeddings), dtype=self.weight.dtype)
# O[self.xp.arange(X.size), X.reshape(1, -1)] = 1
# return O.reshape(*X.shape, self.num_embeddings)
# def forward(self, X: Tensor) -> Tensor:
# if not isinstance(X, Tensor):
# raise TypeError("Input must be a tensor")
# if X.device != self.device:
# raise ValueError("Tensors must be on the same device")
# X_one_hot = self.one_hot(X if isinstance(X, self.xp.ndarray) else X.data)
# return _EmbeddingTensor(
# self.xp.dot(X_one_hot, self.weight.data),
# (X_one_hot, self.weight),
# "Embedding",
# device=self.device,
# )
# def __call__(self, X):
# return self.forward(X)
class Embedding(Module): # layer with dynamic backpropagation
def __init__(self, num_embeddings: int, embedding_dim: int, device: Literal["cpu", "cuda"] = "cpu"):
self.num_embeddings = num_embeddings
self.embedding_dim = embedding_dim
self.weight = Parameter(
neunet.tensor(np.random.randn(num_embeddings, embedding_dim), dtype=np.float32)
)
self.to(device)
def forward(self, X: Tensor) -> Tensor:
return self.weight[X.data.astype(np.int32)]
def __call__(self, X):
return self.forward(X)