pytinytensor 0.1.2__tar.gz → 0.1.3__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.
- {pytinytensor-0.1.2/pytinytensor.egg-info → pytinytensor-0.1.3}/PKG-INFO +1 -1
- {pytinytensor-0.1.2 → pytinytensor-0.1.3/pytinytensor.egg-info}/PKG-INFO +1 -1
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/pytinytensor.egg-info/SOURCES.txt +1 -22
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/setup.py +1 -1
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/nn/activations.py +1 -0
- pytinytensor-0.1.3/tinytensor/nn/dropout.py +23 -0
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/nn/modules.py +8 -7
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/optim/optimizer.py +13 -6
- pytinytensor-0.1.2/tinytensor/nn/activations.py +0 -36
- pytinytensor-0.1.2/tinytensor/nn/modules.py +0 -63
- pytinytensor-0.1.2/tinytensor/optim/optimizer.py +0 -72
- pytinytensor-0.1.2/tinytensor/setup.py +0 -81
- pytinytensor-0.1.2/tinytensor/tinytensor/__init__.py +0 -0
- pytinytensor-0.1.2/tinytensor/tinytensor/backends/__init__.py +0 -0
- pytinytensor-0.1.2/tinytensor/tinytensor/backends/cpu_numpy.py +0 -0
- pytinytensor-0.1.2/tinytensor/tinytensor/config.py +0 -20
- pytinytensor-0.1.2/tinytensor/tinytensor/core/__init__.py +0 -0
- pytinytensor-0.1.2/tinytensor/tinytensor/core/autograd.py +0 -22
- pytinytensor-0.1.2/tinytensor/tinytensor/core/ops.py +0 -1
- pytinytensor-0.1.2/tinytensor/tinytensor/core/tensor.py +0 -288
- pytinytensor-0.1.2/tinytensor/tinytensor/data/__init__.py +0 -5
- pytinytensor-0.1.2/tinytensor/tinytensor/data/dataloader.py +0 -41
- pytinytensor-0.1.2/tinytensor/tinytensor/data/dataset.py +0 -19
- pytinytensor-0.1.2/tinytensor/tinytensor/nn/__init__.py +0 -0
- pytinytensor-0.1.2/tinytensor/tinytensor/nn/linear.py +0 -18
- pytinytensor-0.1.2/tinytensor/tinytensor/nn/losses.py +0 -12
- pytinytensor-0.1.2/tinytensor/tinytensor/optim/__init__.py +0 -11
- pytinytensor-0.1.2/tinytensor/utils/__init__.py +0 -4
- pytinytensor-0.1.2/tinytensor/utils/bar.py +0 -26
- pytinytensor-0.1.2/tinytensor/utils/early_stopping.py +0 -64
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/LICENSE +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/README.md +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/pyproject.toml +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/pytinytensor.egg-info/dependency_links.txt +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/pytinytensor.egg-info/requires.txt +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/pytinytensor.egg-info/top_level.txt +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/setup.cfg +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_autograd.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_data.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_losses.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_nn.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_optim.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tests/test_tensor_math.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/__init__.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/backends/__init__.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/backends/cpu_numpy.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/backends/cuda_binding.cpp +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/backends/cuda_gpu.cu +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/backends/cuda_gpu.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/config.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/core/__init__.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/core/autograd.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/core/ops.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/core/tensor.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/data/__init__.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/data/dataloader.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/data/dataset.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/nn/__init__.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/nn/linear.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/nn/losses.py +0 -0
- {pytinytensor-0.1.2 → pytinytensor-0.1.3}/tinytensor/optim/__init__.py +0 -0
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/utils/__init__.py +0 -0
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/utils/bar.py +0 -0
- {pytinytensor-0.1.2/tinytensor → pytinytensor-0.1.3}/tinytensor/utils/early_stopping.py +0 -0
|
@@ -15,7 +15,6 @@ tests/test_optim.py
|
|
|
15
15
|
tests/test_tensor_math.py
|
|
16
16
|
tinytensor/__init__.py
|
|
17
17
|
tinytensor/config.py
|
|
18
|
-
tinytensor/setup.py
|
|
19
18
|
tinytensor/backends/__init__.py
|
|
20
19
|
tinytensor/backends/cpu_numpy.py
|
|
21
20
|
tinytensor/backends/cuda_binding.cpp
|
|
@@ -30,32 +29,12 @@ tinytensor/data/dataloader.py
|
|
|
30
29
|
tinytensor/data/dataset.py
|
|
31
30
|
tinytensor/nn/__init__.py
|
|
32
31
|
tinytensor/nn/activations.py
|
|
32
|
+
tinytensor/nn/dropout.py
|
|
33
33
|
tinytensor/nn/linear.py
|
|
34
34
|
tinytensor/nn/losses.py
|
|
35
35
|
tinytensor/nn/modules.py
|
|
36
36
|
tinytensor/optim/__init__.py
|
|
37
37
|
tinytensor/optim/optimizer.py
|
|
38
|
-
tinytensor/tinytensor/__init__.py
|
|
39
|
-
tinytensor/tinytensor/config.py
|
|
40
|
-
tinytensor/tinytensor/backends/__init__.py
|
|
41
|
-
tinytensor/tinytensor/backends/cpu_numpy.py
|
|
42
|
-
tinytensor/tinytensor/core/__init__.py
|
|
43
|
-
tinytensor/tinytensor/core/autograd.py
|
|
44
|
-
tinytensor/tinytensor/core/ops.py
|
|
45
|
-
tinytensor/tinytensor/core/tensor.py
|
|
46
|
-
tinytensor/tinytensor/data/__init__.py
|
|
47
|
-
tinytensor/tinytensor/data/dataloader.py
|
|
48
|
-
tinytensor/tinytensor/data/dataset.py
|
|
49
|
-
tinytensor/tinytensor/nn/__init__.py
|
|
50
|
-
tinytensor/tinytensor/nn/activations.py
|
|
51
|
-
tinytensor/tinytensor/nn/linear.py
|
|
52
|
-
tinytensor/tinytensor/nn/losses.py
|
|
53
|
-
tinytensor/tinytensor/nn/modules.py
|
|
54
|
-
tinytensor/tinytensor/optim/__init__.py
|
|
55
|
-
tinytensor/tinytensor/optim/optimizer.py
|
|
56
|
-
tinytensor/tinytensor/utils/__init__.py
|
|
57
|
-
tinytensor/tinytensor/utils/bar.py
|
|
58
|
-
tinytensor/tinytensor/utils/early_stopping.py
|
|
59
38
|
tinytensor/utils/__init__.py
|
|
60
39
|
tinytensor/utils/bar.py
|
|
61
40
|
tinytensor/utils/early_stopping.py
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#функция дропаута это короче нужно чтоб вырубать нейроны во время обучения чтоб остальные нейроны обучились хорошо тоже
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from tinytensor.nn.modules import Module
|
|
5
|
+
from tinytensor.core.tensor import Tensor
|
|
6
|
+
|
|
7
|
+
class Dropout(Module):
|
|
8
|
+
def __init__(self, p=0.5):
|
|
9
|
+
super().__init__()
|
|
10
|
+
# p это вероятност типа 0.5 это половина нейронов вырубается
|
|
11
|
+
self.p = p
|
|
12
|
+
|
|
13
|
+
def forward(self, x):
|
|
14
|
+
# если не обучаемся то скип
|
|
15
|
+
if not self.training or self.p == 0:
|
|
16
|
+
return x
|
|
17
|
+
mask_data = (np.random.rand(*x.data.shape) > self.p) / (1.0 - self.p)
|
|
18
|
+
|
|
19
|
+
#маску в тензор превращаем
|
|
20
|
+
mask = Tensor(mask_data, requires_grad=False)
|
|
21
|
+
|
|
22
|
+
#тк маска состоит из 0 и 1 умножение как раз некоторые нейроны вырубит
|
|
23
|
+
return x * mask
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from tinytensor.core.tensor import Tensor
|
|
2
2
|
import pickle
|
|
3
|
-
|
|
4
3
|
#кароч модуль от которого будут наследоваться все слои
|
|
5
4
|
class Module:
|
|
6
5
|
def __init__(self):
|
|
@@ -8,27 +7,31 @@ class Module:
|
|
|
8
7
|
|
|
9
8
|
def __call__(self, *args, **kwargs):
|
|
10
9
|
return self.forward(*args, **kwargs)
|
|
11
|
-
|
|
12
10
|
#щас это просто заглушка для прямого вызова, а в реале у всех должны быть свои реализации forward, так что это роль не играет
|
|
13
11
|
def forward(self, *args, **kwargs):
|
|
14
12
|
raise NotImplementedError(...)
|
|
15
|
-
|
|
16
13
|
# сохраняет обучаемые веса, и если в модуле есть еще какие то модули то он их тоже открывает
|
|
17
14
|
def parameters(self):
|
|
18
15
|
params = []
|
|
19
16
|
for atr in self.__dict__.values():
|
|
20
17
|
if isinstance(atr, Tensor) and atr.requires_grad == True:
|
|
21
18
|
params.append(atr)
|
|
22
|
-
|
|
23
19
|
elif isinstance(atr, Module):
|
|
24
20
|
params.extend(atr.parameters())
|
|
25
21
|
return params
|
|
26
|
-
|
|
27
22
|
#обнуляет градиенты
|
|
28
23
|
def zero_grad(self):
|
|
29
24
|
for atr in self.parameters():
|
|
30
25
|
atr.grad = None
|
|
31
26
|
|
|
27
|
+
def train(self, mode=True):
|
|
28
|
+
self.training = mode
|
|
29
|
+
for atr in self.__dict__.values():
|
|
30
|
+
if isinstance(atr, Module):
|
|
31
|
+
atr.train(mode)
|
|
32
|
+
return self
|
|
33
|
+
def eval(self):
|
|
34
|
+
return self.train(False)
|
|
32
35
|
def state_dict(self):
|
|
33
36
|
#вытащим все веса параметров
|
|
34
37
|
sdict = {}
|
|
@@ -41,7 +44,6 @@ class Module:
|
|
|
41
44
|
for name, param in self._get_named_params().items():
|
|
42
45
|
if name in sdict:
|
|
43
46
|
param.data = sdict[name]
|
|
44
|
-
|
|
45
47
|
def _get_named_params(self, prefix=""):
|
|
46
48
|
named = {}
|
|
47
49
|
for attr_name, attr in self.__dict__.items():
|
|
@@ -56,7 +58,6 @@ class Module:
|
|
|
56
58
|
def save(self,filepath):
|
|
57
59
|
with open(filepath, "wb") as f:
|
|
58
60
|
pickle.dump(self.state_dict(), f)
|
|
59
|
-
|
|
60
61
|
# загрузка весов обратно
|
|
61
62
|
def load(self, filepath):
|
|
62
63
|
with open(filepath, "rb") as f:
|
|
@@ -17,27 +17,30 @@ class Optimizer:
|
|
|
17
17
|
# SGD
|
|
18
18
|
# w = w - lr*dw
|
|
19
19
|
class SGD(Optimizer):
|
|
20
|
-
def __init__(self, parameters, lr = 0.01, momentum = 0.0):
|
|
20
|
+
def __init__(self, parameters, lr = 0.01, momentum = 0.0, weight_decay = 0.0):
|
|
21
21
|
super().__init__(parameters)
|
|
22
22
|
self.lr = lr
|
|
23
23
|
self.momentum = momentum
|
|
24
|
+
self.weight_decay = weight_decay
|
|
24
25
|
# буфера
|
|
25
26
|
self.velocities = [np.zeros_like(p.data) for p in self.parameters] if momentum > 0 else None
|
|
26
27
|
|
|
27
28
|
def step(self):
|
|
28
|
-
for i,p in enumerate(self.parameters):
|
|
29
|
+
for i, p in enumerate(self.parameters):
|
|
29
30
|
if p.grad is None:
|
|
30
31
|
continue
|
|
31
|
-
grad = p.grad
|
|
32
|
+
grad = p.grad
|
|
33
|
+
if self.weight_decay != 0:
|
|
34
|
+
grad = grad + self.weight_decay * p.data
|
|
32
35
|
|
|
33
|
-
if self.momentum>0:
|
|
36
|
+
if self.momentum > 0:
|
|
34
37
|
self.velocities[i] = self.momentum * self.velocities[i] + grad
|
|
35
38
|
grad = self.velocities[i]
|
|
39
|
+
|
|
36
40
|
# шаг
|
|
37
41
|
p.data -= self.lr * grad
|
|
38
42
|
|
|
39
43
|
|
|
40
|
-
|
|
41
44
|
#Adamw
|
|
42
45
|
# слишком много формул мне впадлу писать
|
|
43
46
|
class AdamW(Optimizer):
|
|
@@ -69,4 +72,8 @@ class AdamW(Optimizer):
|
|
|
69
72
|
v_hat = self.v[i] / (1.0 - self.beta2 ** self.t)
|
|
70
73
|
# адапт шаг и разделение затухания весов
|
|
71
74
|
denom = np.sqrt(v_hat) + self.eps
|
|
72
|
-
|
|
75
|
+
|
|
76
|
+
if self.weight_decay != 0:
|
|
77
|
+
p.data -= self.lr * self.weight_decay * p.data
|
|
78
|
+
|
|
79
|
+
p.data -= self.lr * (m_hat / denom)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from tinytensor.nn.modules import Module
|
|
2
|
-
|
|
3
|
-
class ReLU(Module):
|
|
4
|
-
def forward(self, x):
|
|
5
|
-
return x.relu()
|
|
6
|
-
|
|
7
|
-
class LeReLU(Module):
|
|
8
|
-
# у нас есть тут альфа
|
|
9
|
-
def __init__(self, alpha=0.01):
|
|
10
|
-
self.alpha = alpha
|
|
11
|
-
|
|
12
|
-
def forward(self, x):
|
|
13
|
-
return x.leaky_relu(alpha=self.alpha)
|
|
14
|
-
|
|
15
|
-
class Sigmod(Module):
|
|
16
|
-
def forward(self, x):
|
|
17
|
-
return x.sigmoid()
|
|
18
|
-
|
|
19
|
-
class Tanh(Module):
|
|
20
|
-
def forward(self, x):
|
|
21
|
-
return x.tanh()
|
|
22
|
-
|
|
23
|
-
class GELU(Module):
|
|
24
|
-
def forward(self, x):
|
|
25
|
-
return x.gelu()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# ToDo:
|
|
31
|
-
# ReLU [x]
|
|
32
|
-
# LeReLU [x]
|
|
33
|
-
# Sigmoid [x]
|
|
34
|
-
# Tanh [x]
|
|
35
|
-
# GELU [x]
|
|
36
|
-
# kama soska
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
from tinytensor.core.tensor import Tensor
|
|
2
|
-
import pickle
|
|
3
|
-
|
|
4
|
-
#кароч модуль от которого будут наследоваться все слои
|
|
5
|
-
class Module:
|
|
6
|
-
def __init__(self):
|
|
7
|
-
self.training = True
|
|
8
|
-
|
|
9
|
-
def __call__(self, *args, **kwargs):
|
|
10
|
-
return self.forward(*args, **kwargs)
|
|
11
|
-
|
|
12
|
-
#щас это просто заглушка для прямого вызова, а в реале у всех должны быть свои реализации forward, так что это роль не играет
|
|
13
|
-
def forward(self, *args, **kwargs):
|
|
14
|
-
raise NotImplementedError(...)
|
|
15
|
-
|
|
16
|
-
# сохраняет обучаемые веса, и если в модуле есть еще какие то модули то он их тоже открывает
|
|
17
|
-
def parameters(self):
|
|
18
|
-
params = []
|
|
19
|
-
for atr in self.__dict__.values():
|
|
20
|
-
if isinstance(atr, Tensor) and atr.requires_grad == True:
|
|
21
|
-
params.append(atr)
|
|
22
|
-
|
|
23
|
-
elif isinstance(atr, Module):
|
|
24
|
-
params.extend(atr.parameters())
|
|
25
|
-
return params
|
|
26
|
-
|
|
27
|
-
#обнуляет градиенты
|
|
28
|
-
def zero_grad(self):
|
|
29
|
-
for atr in self.parameters():
|
|
30
|
-
atr.grad = None
|
|
31
|
-
|
|
32
|
-
def state_dict(self):
|
|
33
|
-
#вытащим все веса параметров
|
|
34
|
-
sdict = {}
|
|
35
|
-
for name, param in self._get_named_params().items():
|
|
36
|
-
sdict[name] = param.data
|
|
37
|
-
|
|
38
|
-
def load_state_dict(self, sdict):
|
|
39
|
-
#запихиваем обратно
|
|
40
|
-
for name, param in self._get_named_params().items():
|
|
41
|
-
if name in sdict:
|
|
42
|
-
param.data = sdict[name]
|
|
43
|
-
|
|
44
|
-
def _get_named_params(self, prefix=""):
|
|
45
|
-
named = {}
|
|
46
|
-
for attr_name, attr in self.__dict__.items():
|
|
47
|
-
key = f"{prefix}.{attr_name}" if prefix else attr_name
|
|
48
|
-
if isinstance(attr, Tensor):
|
|
49
|
-
named[key] = attr
|
|
50
|
-
elif isinstance(attr, Module):
|
|
51
|
-
named.update(attr._get_named_params(prefix=key))
|
|
52
|
-
return named
|
|
53
|
-
|
|
54
|
-
#сохранение модели
|
|
55
|
-
def save(self,filepath):
|
|
56
|
-
with open(filepath, "wb") as f:
|
|
57
|
-
pickle.dump(self.state_dict(), f)
|
|
58
|
-
|
|
59
|
-
# загрузка весов обратно
|
|
60
|
-
def load(self, filepath):
|
|
61
|
-
with open(filepath, "wb") as f:
|
|
62
|
-
sd = pickle.load(f)
|
|
63
|
-
self.load_state_dict(sd)
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# я допил свой чай, теперь хочу еще но мне лень вставать
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
class Optimizer:
|
|
5
|
-
def __init__ (self, parameters):
|
|
6
|
-
# в лист если через генератор model параметры выдано
|
|
7
|
-
self.parameters = list(parameters)
|
|
8
|
-
|
|
9
|
-
def step(self):
|
|
10
|
-
#у каждого свой
|
|
11
|
-
raise NotImplementedError
|
|
12
|
-
|
|
13
|
-
def zero_grad(self):
|
|
14
|
-
for p in self.parameters:
|
|
15
|
-
p.grad = None
|
|
16
|
-
|
|
17
|
-
# SGD
|
|
18
|
-
# w = w - lr*dw
|
|
19
|
-
class SGD(Optimizer):
|
|
20
|
-
def __init__(self, parameters, lr = 0.01, momentum = 0.0):
|
|
21
|
-
super().__init__(parameters)
|
|
22
|
-
self.lr = lr
|
|
23
|
-
self.momentum = momentum
|
|
24
|
-
# буфера
|
|
25
|
-
self.velocities = [np.zeros_like(p.data) for p in self.parameters] if momentum > 0 else None
|
|
26
|
-
|
|
27
|
-
def step(self):
|
|
28
|
-
for i,p in enumerate(self.parameters):
|
|
29
|
-
if p.grad is None:
|
|
30
|
-
continue
|
|
31
|
-
grad = p.grad
|
|
32
|
-
|
|
33
|
-
if self.momentum>0:
|
|
34
|
-
self.velocities[i] = self.momentum * self.velocities[i] + grad
|
|
35
|
-
grad = self.velocities[i]
|
|
36
|
-
# шаг
|
|
37
|
-
p.data -= self.lr * grad
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
#Adamw
|
|
42
|
-
# слишком много формул мне впадлу писать
|
|
43
|
-
class AdamW(Optimizer):
|
|
44
|
-
def __init__(self, parameters, lr=0.001, betas=(0.9, 0.999), eps=1e-8, weight_decay=0.01):
|
|
45
|
-
super().__init__(parameters)
|
|
46
|
-
self.lr = lr
|
|
47
|
-
self.beta1, self.beta2 = betas
|
|
48
|
-
self.eps = eps
|
|
49
|
-
self.weight_decay = weight_decay
|
|
50
|
-
|
|
51
|
-
self.t = 0
|
|
52
|
-
|
|
53
|
-
self.m = [np.zeros_like(p.data) for p in self.parameters]
|
|
54
|
-
self.v = [np.zeros_like(p.data) for p in self.parameters]
|
|
55
|
-
|
|
56
|
-
def step(self):
|
|
57
|
-
self.t += 1
|
|
58
|
-
|
|
59
|
-
for i, p in enumerate(self.parameters):
|
|
60
|
-
if p.grad is None:
|
|
61
|
-
continue
|
|
62
|
-
|
|
63
|
-
grad = p.grad
|
|
64
|
-
# обновка m и v мометы
|
|
65
|
-
self.m[i] = self.beta1 * self.m[i] + (1.0 - self.beta1) * grad
|
|
66
|
-
self.v[i] = self.beta2 * self.v[i] + (1.0 - self.beta2) * (grad ** 2)
|
|
67
|
-
# корекция баяса
|
|
68
|
-
m_hat = self.m[i] / (1.0 - self.beta1 ** self.t)
|
|
69
|
-
v_hat = self.v[i] / (1.0 - self.beta2 ** self.t)
|
|
70
|
-
# адапт шаг и разделение затухания весов
|
|
71
|
-
denom = np.sqrt(v_hat) + self.eps
|
|
72
|
-
p.data -= self.lr * (m_hat / denom + self.weight_decay * p.data)
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import subprocess
|
|
3
|
-
import pybind11
|
|
4
|
-
from setuptools import setup, find_packages, Extension
|
|
5
|
-
from setuptools.command.build_ext import build_ext
|
|
6
|
-
|
|
7
|
-
def check_cuda():
|
|
8
|
-
try:
|
|
9
|
-
subprocess.check_output(["nvcc", "--version"])
|
|
10
|
-
return True
|
|
11
|
-
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
12
|
-
return False
|
|
13
|
-
|
|
14
|
-
class CUDABuildExt(build_ext):
|
|
15
|
-
def build_extensions(self):
|
|
16
|
-
self.compiler.src_extensions.append('.cu')
|
|
17
|
-
original_compile = self.compiler._compile
|
|
18
|
-
|
|
19
|
-
def custom_compile(obj, src, ext, cc_args, extra_postargs, pp_opts):
|
|
20
|
-
# extra_postargs может приходить как список или словарь — обрабатываем оба случая
|
|
21
|
-
if isinstance(extra_postargs, dict):
|
|
22
|
-
gcc_postargs = extra_postargs.get('gcc', [])
|
|
23
|
-
nvcc_postargs = extra_postargs.get('nvcc', [])
|
|
24
|
-
else:
|
|
25
|
-
gcc_postargs = extra_postargs or []
|
|
26
|
-
nvcc_postargs = []
|
|
27
|
-
|
|
28
|
-
if os.path.splitext(src)[1] == '.cu':
|
|
29
|
-
# nvcc собирает .cu файл
|
|
30
|
-
inc_flags = [f"-I{inc}" for inc in self.compiler.include_dirs]
|
|
31
|
-
cmd = ['nvcc', '-c', src, '-o', obj] + inc_flags + nvcc_postargs
|
|
32
|
-
self.spawn(cmd)
|
|
33
|
-
else:
|
|
34
|
-
# g++ собирает .cpp файл (с pybind11)
|
|
35
|
-
original_compile(obj, src, ext, cc_args, gcc_postargs, pp_opts)
|
|
36
|
-
|
|
37
|
-
self.compiler._compile = custom_compile
|
|
38
|
-
super().build_extensions()
|
|
39
|
-
|
|
40
|
-
ext_modules = []
|
|
41
|
-
|
|
42
|
-
if check_cuda():
|
|
43
|
-
cuda_module = Extension(
|
|
44
|
-
'tinytensor.cuda_ops',
|
|
45
|
-
sources=[
|
|
46
|
-
'tinytensor/backends/cuda_gpu.cu', # Компилируется nvcc
|
|
47
|
-
'tinytensor/backends/cuda_binding.cpp' # Компилируется g++
|
|
48
|
-
],
|
|
49
|
-
include_dirs=[
|
|
50
|
-
pybind11.get_include(),
|
|
51
|
-
'/usr/local/cuda/include',
|
|
52
|
-
os.path.expanduser('~/.local/include')
|
|
53
|
-
],
|
|
54
|
-
library_dirs=['/usr/local/cuda/lib64'],
|
|
55
|
-
libraries=['cudart', 'cublas'],
|
|
56
|
-
extra_compile_args={
|
|
57
|
-
'gcc': ['-O3', '-fPIC', '-std=c++17'],
|
|
58
|
-
'nvcc': ['-O3', '-Xcompiler', '-fPIC']
|
|
59
|
-
}
|
|
60
|
-
)
|
|
61
|
-
ext_modules.append(cuda_module)
|
|
62
|
-
print("🔥 CUDA найдена! Собираем cuBLAS бэкенд...")
|
|
63
|
-
else:
|
|
64
|
-
print("⚠️ CUDA не найдена. Сборка продолжится на CPU (NumPy).")
|
|
65
|
-
|
|
66
|
-
setup(
|
|
67
|
-
name="tinytensor",
|
|
68
|
-
version="0.1.0",
|
|
69
|
-
description="мини ИИ фреймворк от IbrokimN ( github/IbrokhimN )",
|
|
70
|
-
packages=find_packages(include=["tinytensor", "tinytensor.*"]),
|
|
71
|
-
ext_modules=ext_modules,
|
|
72
|
-
cmdclass={'build_ext': CUDABuildExt},
|
|
73
|
-
install_requires=[
|
|
74
|
-
"numpy>=1.23",
|
|
75
|
-
"pybind11>=2.10",
|
|
76
|
-
],
|
|
77
|
-
extras_require={
|
|
78
|
-
"dev": ["pytest>=7.0"],
|
|
79
|
-
},
|
|
80
|
-
python_requires=">=3.9",
|
|
81
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
import numpy as np
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@dataclass
|
|
6
|
-
class Config:
|
|
7
|
-
# базовый сид будет 67
|
|
8
|
-
seed: int = 67
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
config = Config()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def set_seed(seed: int):
|
|
15
|
-
# автоматически устанавливаем сид для воспроизведения и тд
|
|
16
|
-
config.seed = seed
|
|
17
|
-
np.random.seed(seed)
|
|
18
|
-
|
|
19
|
-
# ну все при импорте будет устанавливаться
|
|
20
|
-
np.random.seed(config.seed)
|
|
File without changes
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def backward(target_tensor):
|
|
5
|
-
# эт я вообще сделал чтоб файл не пустовал, но это архитектура micrograd как у Андрея Карпатова,
|
|
6
|
-
# если кто то шарит за нормальный движок autograd, то PRните
|
|
7
|
-
topo = []
|
|
8
|
-
visited = set()
|
|
9
|
-
|
|
10
|
-
def build_topo(v):
|
|
11
|
-
if v not in visited:
|
|
12
|
-
visited.add(v)
|
|
13
|
-
for child in v._prev:
|
|
14
|
-
build_topo(child)
|
|
15
|
-
topo.append(v)
|
|
16
|
-
|
|
17
|
-
build_topo(target_tensor)
|
|
18
|
-
|
|
19
|
-
target_tensor.grad = np.ones_like(target_tensor.data, dtype=np.float32)
|
|
20
|
-
|
|
21
|
-
for v in reversed(topo):
|
|
22
|
-
v._backward()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# пока что побудет пустым
|
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from tinytensor.core.autograd import backward as run_backward
|
|
4
|
-
|
|
5
|
-
#чекаем ес можно на cuda матричные умножения сделать
|
|
6
|
-
try:
|
|
7
|
-
from tinytensor import cuda_ops
|
|
8
|
-
HAS_CUDA = True
|
|
9
|
-
except ImportError:
|
|
10
|
-
HAS_CUDA = False
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def _unbroadcast(grad, target):
|
|
14
|
-
while grad.ndim > len(target):
|
|
15
|
-
grad = grad.sum(axis=0)
|
|
16
|
-
|
|
17
|
-
for i, dim in enumerate(target):
|
|
18
|
-
if dim == 1:
|
|
19
|
-
grad = grad.sum(axis=i, keepdims=True)
|
|
20
|
-
return grad
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# этот мир жесток
|
|
24
|
-
class Tensor:
|
|
25
|
-
def __init__(self, data, requires_grad=False, device="cpu"):
|
|
26
|
-
# кароч проверка если нампай массив то оставляем а если нет то делаем нампаем
|
|
27
|
-
if isinstance(data, np.ndarray):
|
|
28
|
-
self.data = data.astype(np.float32)
|
|
29
|
-
else:
|
|
30
|
-
self.data = np.array(data, dtype=np.float32)
|
|
31
|
-
|
|
32
|
-
self.grad = None
|
|
33
|
-
self._backward = lambda: None
|
|
34
|
-
self._prev = set()
|
|
35
|
-
self.requires_grad = requires_grad
|
|
36
|
-
self.device = device
|
|
37
|
-
|
|
38
|
-
def to(self, device):
|
|
39
|
-
# перекидываем тензор на cuda или cpu
|
|
40
|
-
self.device = device
|
|
41
|
-
return self
|
|
42
|
-
|
|
43
|
-
def __repr__(self):
|
|
44
|
-
return f"tensor({self.data}, device='{self.device}', requires_grad={self.requires_grad})"
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def shape(self):
|
|
48
|
-
return self.data.shape
|
|
49
|
-
|
|
50
|
-
# сложение
|
|
51
|
-
def __add__(self, other):
|
|
52
|
-
other = other if isinstance(other, Tensor) else Tensor(other, device=self.device)
|
|
53
|
-
out = Tensor(
|
|
54
|
-
self.data + other.data,
|
|
55
|
-
requires_grad=self.requires_grad or other.requires_grad,
|
|
56
|
-
device=self.device,
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
if out.requires_grad:
|
|
60
|
-
out._prev = {self, other}
|
|
61
|
-
|
|
62
|
-
def _backward():
|
|
63
|
-
if self.requires_grad:
|
|
64
|
-
if self.grad is None:
|
|
65
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
66
|
-
|
|
67
|
-
grad_self = out.grad * 1.0
|
|
68
|
-
self.grad += _unbroadcast(grad_self, self.data.shape)
|
|
69
|
-
|
|
70
|
-
# градиент для 2 параметра
|
|
71
|
-
if other.requires_grad:
|
|
72
|
-
if other.grad is None:
|
|
73
|
-
other.grad = np.zeros_like(other.data, dtype=np.float32)
|
|
74
|
-
|
|
75
|
-
grad_other = out.grad * 1.0
|
|
76
|
-
other.grad += _unbroadcast(grad_other, other.data.shape)
|
|
77
|
-
|
|
78
|
-
out._backward = _backward
|
|
79
|
-
|
|
80
|
-
return out
|
|
81
|
-
|
|
82
|
-
def __radd__(self, other):
|
|
83
|
-
# эт если пользователь решит написать не Tensor + 5 а 5 + Tensor
|
|
84
|
-
return self + other
|
|
85
|
-
|
|
86
|
-
# умножение
|
|
87
|
-
def __mul__(self, other):
|
|
88
|
-
other = other if isinstance(other, Tensor) else Tensor(other, device=self.device)
|
|
89
|
-
out = Tensor(
|
|
90
|
-
self.data * other.data,
|
|
91
|
-
requires_grad=self.requires_grad or other.requires_grad,
|
|
92
|
-
device=self.device,
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
if out.requires_grad:
|
|
96
|
-
out._prev = {self, other}
|
|
97
|
-
|
|
98
|
-
def _backward():
|
|
99
|
-
if self.requires_grad:
|
|
100
|
-
if self.grad is None:
|
|
101
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
102
|
-
grad_self = out.grad * other.data
|
|
103
|
-
self.grad += _unbroadcast(grad_self, self.data.shape)
|
|
104
|
-
|
|
105
|
-
if other.requires_grad:
|
|
106
|
-
if other.grad is None:
|
|
107
|
-
other.grad = np.zeros_like(other.data, dtype=np.float32)
|
|
108
|
-
grad_other = out.grad * self.data
|
|
109
|
-
other.grad += _unbroadcast(grad_other, other.data.shape)
|
|
110
|
-
|
|
111
|
-
out._backward = _backward
|
|
112
|
-
|
|
113
|
-
return out
|
|
114
|
-
|
|
115
|
-
def __rmul__(self, other):
|
|
116
|
-
return self * other
|
|
117
|
-
|
|
118
|
-
# матричное умножение
|
|
119
|
-
def __matmul__(self, other):
|
|
120
|
-
other = other if isinstance(other, Tensor) else Tensor(other, device=self.device)
|
|
121
|
-
|
|
122
|
-
# если девайс куда и бэкенд собрался то гоним через кублас а если нет то обычный нампай
|
|
123
|
-
if (self.device == "cuda" or other.device == "cuda") and HAS_CUDA:
|
|
124
|
-
res_data = cuda_ops.matmul(self.data, other.data)
|
|
125
|
-
else:
|
|
126
|
-
res_data = np.matmul(self.data, other.data)
|
|
127
|
-
|
|
128
|
-
out = Tensor(
|
|
129
|
-
res_data,
|
|
130
|
-
requires_grad=self.requires_grad or other.requires_grad,
|
|
131
|
-
device=self.device,
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
if out.requires_grad:
|
|
135
|
-
out._prev = {self, other}
|
|
136
|
-
|
|
137
|
-
def _backward():
|
|
138
|
-
if self.requires_grad:
|
|
139
|
-
if self.grad is None:
|
|
140
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
141
|
-
self.grad += np.matmul(out.grad, other.data.T)
|
|
142
|
-
|
|
143
|
-
if other.requires_grad:
|
|
144
|
-
if other.grad is None:
|
|
145
|
-
other.grad = np.zeros_like(other.data, dtype=np.float32)
|
|
146
|
-
other.grad += np.matmul(self.data.T, out.grad)
|
|
147
|
-
|
|
148
|
-
out._backward = _backward
|
|
149
|
-
|
|
150
|
-
return out
|
|
151
|
-
|
|
152
|
-
# вычитание
|
|
153
|
-
def __sub__(self, other):
|
|
154
|
-
return self + (other * -1)
|
|
155
|
-
|
|
156
|
-
def __rsub__(self, other):
|
|
157
|
-
return (self * -1) + other
|
|
158
|
-
|
|
159
|
-
def __pow__(self, power):
|
|
160
|
-
out = Tensor(self.data ** power, requires_grad=self.requires_grad, device=self.device)
|
|
161
|
-
if out.requires_grad:
|
|
162
|
-
out._prev = {self}
|
|
163
|
-
|
|
164
|
-
def _backward():
|
|
165
|
-
if self.requires_grad:
|
|
166
|
-
if self.grad is None:
|
|
167
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
168
|
-
self.grad += out.grad * (power * (self.data ** (power - 1)))
|
|
169
|
-
|
|
170
|
-
out._backward = _backward
|
|
171
|
-
return out
|
|
172
|
-
|
|
173
|
-
def sum(self):
|
|
174
|
-
out = Tensor(self.data.sum(), requires_grad=self.requires_grad, device=self.device)
|
|
175
|
-
if out.requires_grad:
|
|
176
|
-
out._prev = {self}
|
|
177
|
-
|
|
178
|
-
def _backward():
|
|
179
|
-
if self.requires_grad:
|
|
180
|
-
if self.grad is None:
|
|
181
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
182
|
-
self.grad += out.grad * np.ones_like(self.data)
|
|
183
|
-
|
|
184
|
-
out._backward = _backward
|
|
185
|
-
return out
|
|
186
|
-
|
|
187
|
-
def relu(self):
|
|
188
|
-
out = Tensor(
|
|
189
|
-
np.maximum(0, self.data),
|
|
190
|
-
requires_grad=self.requires_grad,
|
|
191
|
-
device=self.device,
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
if out.requires_grad:
|
|
195
|
-
out._prev = {self}
|
|
196
|
-
|
|
197
|
-
def _backward():
|
|
198
|
-
if self.requires_grad:
|
|
199
|
-
if self.grad is None:
|
|
200
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
201
|
-
self.grad += out.grad * (self.data > 0)
|
|
202
|
-
|
|
203
|
-
out._backward = _backward
|
|
204
|
-
|
|
205
|
-
return out
|
|
206
|
-
|
|
207
|
-
def leaky_relu(self, alpha=0.01):
|
|
208
|
-
out_data = np.where(self.data > 0, self.data, self.data * alpha)
|
|
209
|
-
out = Tensor(out_data, requires_grad=self.requires_grad, device=self.device)
|
|
210
|
-
if out.requires_grad:
|
|
211
|
-
out._prev = {self}
|
|
212
|
-
|
|
213
|
-
def _backward():
|
|
214
|
-
if self.requires_grad:
|
|
215
|
-
if self.grad is None:
|
|
216
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
217
|
-
dx = np.where(self.data > 0, 1.0, alpha)
|
|
218
|
-
self.grad += out.grad * dx
|
|
219
|
-
|
|
220
|
-
out._backward = _backward
|
|
221
|
-
return out
|
|
222
|
-
|
|
223
|
-
def sigmoid(self):
|
|
224
|
-
sig = 1.0 / (1.0 + np.exp(-np.clip(self.data, -50, 50)))
|
|
225
|
-
out = Tensor(sig, requires_grad=self.requires_grad, device=self.device)
|
|
226
|
-
if out.requires_grad:
|
|
227
|
-
out._prev = {self}
|
|
228
|
-
|
|
229
|
-
def _backward():
|
|
230
|
-
if self.requires_grad:
|
|
231
|
-
if self.grad is None:
|
|
232
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
233
|
-
self.grad += out.grad * (sig * (1.0 - sig))
|
|
234
|
-
|
|
235
|
-
out._backward = _backward
|
|
236
|
-
return out
|
|
237
|
-
|
|
238
|
-
def tanh(self):
|
|
239
|
-
t = np.tanh(self.data)
|
|
240
|
-
out = Tensor(t, requires_grad=self.requires_grad, device=self.device)
|
|
241
|
-
if out.requires_grad:
|
|
242
|
-
out._prev = {self}
|
|
243
|
-
|
|
244
|
-
def _backward():
|
|
245
|
-
if self.requires_grad:
|
|
246
|
-
if self.grad is None:
|
|
247
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
248
|
-
self.grad += out.grad * (1.0 - t ** 2)
|
|
249
|
-
|
|
250
|
-
out._backward = _backward
|
|
251
|
-
return out
|
|
252
|
-
|
|
253
|
-
def gelu(self):
|
|
254
|
-
x = self.data
|
|
255
|
-
cdf = 0.5 * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * (x ** 3))))
|
|
256
|
-
out = Tensor(x * cdf, requires_grad=self.requires_grad, device=self.device)
|
|
257
|
-
if out.requires_grad:
|
|
258
|
-
out._prev = {self}
|
|
259
|
-
|
|
260
|
-
def _backward():
|
|
261
|
-
if self.requires_grad:
|
|
262
|
-
if self.grad is None:
|
|
263
|
-
self.grad = np.zeros_like(self.data, dtype=np.float32)
|
|
264
|
-
pdf = np.exp(-0.5 * (x ** 2)) / np.sqrt(2.0 * np.pi)
|
|
265
|
-
d_gelu = cdf + x * pdf
|
|
266
|
-
self.grad += out.grad * d_gelu
|
|
267
|
-
|
|
268
|
-
out._backward = _backward
|
|
269
|
-
return out
|
|
270
|
-
|
|
271
|
-
def backward(self):
|
|
272
|
-
run_backward(self)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
# ⣇⣿⠘⣿⣿⣿⡿⡿⣟⣟⢟⢟⢝⠵⡝⣿⡿⢂⣼⣿⣷⣌⠩⡫⡻⣝⠹⢿⣿⣷
|
|
276
|
-
# ⡆⣿⣆⠱⣝⡵⣝⢅⠙⣿⢕⢕⢕⢕⢝⣥⢒⠅⣿⣿⣿⡿⣳⣌⠪⡪⣡⢑⢝⣇
|
|
277
|
-
# ⡆⣿⣿⣦⠹⣳⣳⣕⢅⠈⢗⢕⢕⢕⢕⢕⢈⢆⠟⠋⠉⠁⠉⠉⠁⠈⠼⢐⢕⢽
|
|
278
|
-
# ⡗⢰⣶⣶⣦⣝⢝⢕⢕⠅⡆⢕⢕⢕⢕⢕⣴⠏⣠⡶⠛⡉⡉⡛⢶⣦⡀⠐⣕⢕
|
|
279
|
-
# ⡝⡄⢻⢟⣿⣿⣷⣕⣕⣅⣿⣔⣕⣵⣵⣿⣿⢠⣿⢠⣮⡈⣌⠨⠅⠹⣷⡀⢱⢕
|
|
280
|
-
# ⡝⡵⠟⠈⢀⣀⣀⡀⠉⢿⣿⣿⣿⣿⣿⣿⣿⣼⣿⢈⡋⠴⢿⡟⣡⡇⣿⡇⡀⢕
|
|
281
|
-
# ⡝⠁⣠⣾⠟⡉⡉⡉⠻⣦⣻⣿⣿⣿⣿⣿⣿⣿⣿⣧⠸⣿⣦⣥⣿⡇⡿⣰⢗⢄
|
|
282
|
-
# ⠁⢰⣿⡏⣴⣌⠈⣌⠡⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣬⣉⣉⣁⣄⢖⢕⢕⢕
|
|
283
|
-
# ⡀⢻⣿⡇⢙⠁⠴⢿⡟⣡⡆⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣵⣵⣿
|
|
284
|
-
# ⡻⣄⣻⣿⣌⠘⢿⣷⣥⣿⠇⣿⣿⣿⣿⣿⣿⠛⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
|
|
285
|
-
# ⣷⢄⠻⣿⣟⠿⠦⠍⠉⣡⣾⣿⣿⣿⣿⣿⣿⢸⣿⣦⠙⣿⣿⣿⣿⣿⣿⣿⣿⠟
|
|
286
|
-
# ⡕⡑⣑⣈⣻⢗⢟⢞⢝⣻⣿⣿⣿⣿⣿⣿⣿⠸⣿⠿⠃⣿⣿⣿⣿⣿⣿⡿⠁⣠
|
|
287
|
-
# ⡝⡵⢟⢕⢕⢕⢕⣵⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⠿⠋⣀⣈⠙
|
|
288
|
-
# ⡝⡵⡕⡀⠑⠳⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢉⡠⡲⡫⡪⡪⡣
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from tinytensor.core.tensor import Tensor
|
|
3
|
-
|
|
4
|
-
class DataLoader:
|
|
5
|
-
def __init__(self, dataset, batch_size=32, shuffle=True):
|
|
6
|
-
self.dataset = dataset
|
|
7
|
-
self.batch_size = batch_size
|
|
8
|
-
self.shuffle = shuffle
|
|
9
|
-
|
|
10
|
-
def __len__(self):
|
|
11
|
-
#колво батчей за 1 эпоху
|
|
12
|
-
return (len(self.dataset) + self.batch_size - 1) // self.batch_size
|
|
13
|
-
|
|
14
|
-
def __iter__(self):
|
|
15
|
-
self.indices = np.arange(len(self.dataset))
|
|
16
|
-
|
|
17
|
-
# перемешкиваем если шафл есть
|
|
18
|
-
if self.shuffle:
|
|
19
|
-
np.random.shuffle(self.indices)
|
|
20
|
-
|
|
21
|
-
self.current_idx = 0
|
|
22
|
-
return self
|
|
23
|
-
|
|
24
|
-
def __next__(self):
|
|
25
|
-
# выдает след батч
|
|
26
|
-
# останавливаемся если дошли до конца датасета
|
|
27
|
-
if self.current_idx >= len(self.dataset):
|
|
28
|
-
raise StopIteration
|
|
29
|
-
|
|
30
|
-
batch_indices = self.indices[self.current_idx : self.current_idx + self.batch_size]
|
|
31
|
-
self.current_idx += self.batch_size
|
|
32
|
-
|
|
33
|
-
#cбор
|
|
34
|
-
batch_x, batch_y = [], []
|
|
35
|
-
for i in batch_indices:
|
|
36
|
-
x, y = self.dataset[i]
|
|
37
|
-
batch_x.append(x.data if isinstance(x, Tensor) else x)
|
|
38
|
-
batch_y.append(y.data if isinstance(y, Tensor) else y)
|
|
39
|
-
|
|
40
|
-
# батч в нампай и потом в тензо
|
|
41
|
-
return Tensor(np.array(batch_x)), Tensor(np.array(batch_y))
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#влом коменты ставить тут и так все понятно
|
|
2
|
-
class Dataset:
|
|
3
|
-
def __len__(self):
|
|
4
|
-
raise NotImplementedError
|
|
5
|
-
|
|
6
|
-
def __getitem__(self, idx):
|
|
7
|
-
raise NotImplementedError
|
|
8
|
-
|
|
9
|
-
class TensorDataset(Dataset):
|
|
10
|
-
def __init__(self, x, y):
|
|
11
|
-
assert len(x) == len(y)
|
|
12
|
-
self.x = x
|
|
13
|
-
self.y = y
|
|
14
|
-
|
|
15
|
-
def __len__(self):
|
|
16
|
-
return len(self.x)
|
|
17
|
-
|
|
18
|
-
def __getitem__(self, idx):
|
|
19
|
-
return self.x[idx], self.y[idx]
|
|
File without changes
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from tinytensor.core.tensor import Tensor
|
|
4
|
-
from tinytensor.nn.modules import Module
|
|
5
|
-
|
|
6
|
-
class Linear(Module):
|
|
7
|
-
def __init__(self,in_features, out_features):
|
|
8
|
-
super().__init__()
|
|
9
|
-
std = np.sqrt(2.0 / in_features)
|
|
10
|
-
weightd = np.random.randn(in_features, out_features).astype(np.float32) * std
|
|
11
|
-
self.weight = Tensor(weightd, requires_grad=True)
|
|
12
|
-
|
|
13
|
-
bias_d = np.zeros((1, out_features), dtype=np.float32)
|
|
14
|
-
self.bias = Tensor(bias_d, requires_grad=True)
|
|
15
|
-
|
|
16
|
-
def forward(self, x):
|
|
17
|
-
# кароч обычная формула y = x@w + b
|
|
18
|
-
return (x @ self.weight ) + self.bias
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from tinytensor.nn.modules import Module
|
|
3
|
-
# 1/n * sum((n, i = 1), yi - y`i)^2
|
|
4
|
-
class MSELoss(Module):
|
|
5
|
-
def forward(self, y_pred, y_true):
|
|
6
|
-
diff = y_pred - y_true
|
|
7
|
-
sq_diff = diff ** 2
|
|
8
|
-
return sq_diff.sum() * (1.0/y_pred.data.size)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# мб в будущем добавлю cross entropy loss
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from tinytensor.optim.optimizer import Optimizer, SGD, AdamW
|
|
2
|
-
|
|
3
|
-
__all__ = ["Optimizer", "SGD", "AdamW"]
|
|
4
|
-
|
|
5
|
-
#эт для удобства
|
|
6
|
-
#чтоб можно было писать вот так:
|
|
7
|
-
"""
|
|
8
|
-
from tinytensor.optim import AdamW
|
|
9
|
-
|
|
10
|
-
optimizer = AdamW(model.parameters(), lr=1e-3)
|
|
11
|
-
"""
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def progress_bar(iterable, prefix="", length=30):
|
|
5
|
-
total = len(iterable)
|
|
6
|
-
start_time = time.time()
|
|
7
|
-
for i, item in enumerate(iterable):
|
|
8
|
-
yield item # ИСПРАВЛЕНО: возвращаем элемент, а не модуль time
|
|
9
|
-
percent = (i + 1) / total
|
|
10
|
-
filled = int(length * percent)
|
|
11
|
-
bar = "█" * filled + "-" * (length - filled)
|
|
12
|
-
elapsed = time.time() - start_time
|
|
13
|
-
|
|
14
|
-
print(f"\r{prefix} |{bar}| {percent*100:.1f}% [{elapsed:.1f}s]", end="")
|
|
15
|
-
print()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
#алиас для тех кто привык train_bar писать
|
|
19
|
-
train_bar = progress_bar
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"""
|
|
23
|
-
пользоваться надо крч вот так:
|
|
24
|
-
for epoch in train_bar(range(100), prefix="обучение"):
|
|
25
|
-
...
|
|
26
|
-
"""
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import copy
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class EarlyStopping:
|
|
5
|
-
def __init__(self, model, patience=5, min_delta=0.0, restore_best_weights=True):
|
|
6
|
-
self.model = model
|
|
7
|
-
self.patience = patience
|
|
8
|
-
self.min_delta = min_delta
|
|
9
|
-
self.restore_best_weights = restore_best_weights
|
|
10
|
-
|
|
11
|
-
self.counter = 0
|
|
12
|
-
self.best_loss = None
|
|
13
|
-
self.early_stop = False
|
|
14
|
-
self.best_state_dict = None
|
|
15
|
-
|
|
16
|
-
def __call__(self, val_loss):
|
|
17
|
-
if hasattr(val_loss, "data"):
|
|
18
|
-
val_loss = float(val_loss.data)
|
|
19
|
-
|
|
20
|
-
#если это была первая эпоха
|
|
21
|
-
if self.best_loss is None:
|
|
22
|
-
self.best_loss = val_loss
|
|
23
|
-
self._save_checkpoint()
|
|
24
|
-
|
|
25
|
-
elif val_loss < self.best_loss - self.min_delta:
|
|
26
|
-
self.best_loss = val_loss
|
|
27
|
-
self.counter = 0
|
|
28
|
-
self._save_checkpoint()
|
|
29
|
-
|
|
30
|
-
else:
|
|
31
|
-
self.counter += 1
|
|
32
|
-
if self.counter >= self.patience:
|
|
33
|
-
self.early_stop = True
|
|
34
|
-
if self.restore_best_weights and self.best_state_dict is not None:
|
|
35
|
-
# восстанавливаем лучшие веса
|
|
36
|
-
self.model.load_state_dict(self.best_state_dict)
|
|
37
|
-
|
|
38
|
-
return self.early_stop
|
|
39
|
-
|
|
40
|
-
def _save_checkpoint(self):
|
|
41
|
-
if self.restore_best_weights and hasattr(self.model, "state_dict"):
|
|
42
|
-
self.best_state_dict = copy.deepcopy(self.model.state_dict())
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'''пример кода
|
|
46
|
-
|
|
47
|
-
from tinytensor.utils import EarlyStopping
|
|
48
|
-
|
|
49
|
-
model = MLP()
|
|
50
|
-
early_stopping = EarlyStopping(model, patience=7, min_delta=0.01)
|
|
51
|
-
|
|
52
|
-
for epoch in range(100):
|
|
53
|
-
#обучение
|
|
54
|
-
train_loss = train_one_epoch(model)
|
|
55
|
-
|
|
56
|
-
#валидация
|
|
57
|
-
val_loss = evaluate(model)
|
|
58
|
-
|
|
59
|
-
#проверка остановки
|
|
60
|
-
if early_stopping(val_loss):
|
|
61
|
-
print(f"обучение прекратилось на эпохе {epoch+1}")
|
|
62
|
-
break
|
|
63
|
-
|
|
64
|
-
'''
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|