Vishtorch 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.
- vishtorch-0.1.0/PKG-INFO +11 -0
- vishtorch-0.1.0/Vishtorch/__init__.py +3 -0
- vishtorch-0.1.0/Vishtorch/nn.py +131 -0
- vishtorch-0.1.0/Vishtorch/optim.py +14 -0
- vishtorch-0.1.0/Vishtorch/tensor.py +115 -0
- vishtorch-0.1.0/Vishtorch.egg-info/PKG-INFO +11 -0
- vishtorch-0.1.0/Vishtorch.egg-info/SOURCES.txt +10 -0
- vishtorch-0.1.0/Vishtorch.egg-info/dependency_links.txt +1 -0
- vishtorch-0.1.0/Vishtorch.egg-info/requires.txt +1 -0
- vishtorch-0.1.0/Vishtorch.egg-info/top_level.txt +1 -0
- vishtorch-0.1.0/pyproject.toml +21 -0
- vishtorch-0.1.0/setup.cfg +4 -0
vishtorch-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: Vishtorch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A deep learning framework built completely from scratch.
|
|
5
|
+
Author-email: Vish <your_email@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy>=1.20.0
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from Vishtorch.tensor import Tensor
|
|
3
|
+
|
|
4
|
+
class Parameter(Tensor):
|
|
5
|
+
""" A wrapper designating a Tensor as a trainable layer weight or bias """
|
|
6
|
+
def __init__(self, data):
|
|
7
|
+
super().__init__(data, requires_grad=True)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Module:
|
|
11
|
+
""" Base structural Module matching PyTorch tracking layout """
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self._modules = {}
|
|
14
|
+
self._parameters = {}
|
|
15
|
+
|
|
16
|
+
def __setattr__(self, name, value):
|
|
17
|
+
if isinstance(value, Parameter):
|
|
18
|
+
self._parameters[name] = value
|
|
19
|
+
elif isinstance(value, Module):
|
|
20
|
+
self._modules[name] = value
|
|
21
|
+
super().__setattr__(name, value)
|
|
22
|
+
|
|
23
|
+
def parameters(self):
|
|
24
|
+
params = list(self._parameters.values())
|
|
25
|
+
for module in self._modules.values():
|
|
26
|
+
params.extend(module.parameters())
|
|
27
|
+
return params
|
|
28
|
+
|
|
29
|
+
def __call__(self, *args, **kwargs):
|
|
30
|
+
if hasattr(self, 'forward'):
|
|
31
|
+
return self.forward(*args, **kwargs)
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Linear(Module):
|
|
36
|
+
""" Fully connected deep learning dense network layer """
|
|
37
|
+
def __init__(self, in_features, out_features):
|
|
38
|
+
super().__init__()
|
|
39
|
+
# Standard Xavier/He initial weight variance scaling
|
|
40
|
+
bound = 1.0 / np.sqrt(in_features)
|
|
41
|
+
self.weight = Parameter(np.random.uniform(-bound, bound, (in_features, out_features)))
|
|
42
|
+
self.bias = Parameter(np.zeros((1, out_features)))
|
|
43
|
+
|
|
44
|
+
def forward(self, x):
|
|
45
|
+
return x @ self.weight + self.bias
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Sequential(Module):
|
|
49
|
+
""" Structural module pipe container that runs layers consecutively """
|
|
50
|
+
def __init__(self, *layers):
|
|
51
|
+
super().__init__()
|
|
52
|
+
self.layers = list(layers)
|
|
53
|
+
for i, layer in enumerate(self.layers):
|
|
54
|
+
setattr(self, f"layer_{i}", layer)
|
|
55
|
+
|
|
56
|
+
def forward(self, x):
|
|
57
|
+
out = x
|
|
58
|
+
for layer in self.layers:
|
|
59
|
+
out = layer(out)
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ReLU(Module):
|
|
64
|
+
def forward(self, x): return x.relu()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Sigmoid(Module):
|
|
68
|
+
def forward(self, x): return x.sigmoid()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class MSELoss(Module):
|
|
72
|
+
def __call__(self, predictions, targets):
|
|
73
|
+
diff = predictions + (targets.data * -1.0)
|
|
74
|
+
sq_diff = Tensor(diff.data ** 2, requires_grad=predictions.requires_grad, _children=(predictions,))
|
|
75
|
+
|
|
76
|
+
def _backward():
|
|
77
|
+
if predictions.requires_grad:
|
|
78
|
+
N = predictions.data.size
|
|
79
|
+
predictions.grad += out.grad * (2.0 / N) * diff.data
|
|
80
|
+
|
|
81
|
+
out = sq_diff.sum()
|
|
82
|
+
out._backward = _backward
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class BCELoss(Module):
|
|
87
|
+
def __call__(self, predictions, targets):
|
|
88
|
+
p = np.clip(predictions.data, 1e-7, 1.0 - 1e-7)
|
|
89
|
+
t = targets.data
|
|
90
|
+
loss_val = -np.mean(t * np.log(p) + (1.0 - t) * np.log(1.0 - p))
|
|
91
|
+
out = Tensor(loss_val, requires_grad=predictions.requires_grad, _children=(predictions,))
|
|
92
|
+
|
|
93
|
+
def _backward():
|
|
94
|
+
if predictions.requires_grad:
|
|
95
|
+
N = predictions.data.size
|
|
96
|
+
predictions.grad += out.grad * (1.0 / N) * (p - t) / (p * (1.0 - p))
|
|
97
|
+
|
|
98
|
+
out._backward = _backward
|
|
99
|
+
return out
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class SimpleDataset:
|
|
103
|
+
def __init__(self, X, y):
|
|
104
|
+
self.X = np.array(X, dtype=np.float32)
|
|
105
|
+
self.y = np.array(y, dtype=np.float32)
|
|
106
|
+
|
|
107
|
+
def __len__(self): return len(self.X)
|
|
108
|
+
def __getitem__(self, idx): return self.X[idx], self.y[idx]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class DataLoader:
|
|
112
|
+
def __init__(self, dataset, batch_size=2, shuffle=True):
|
|
113
|
+
self.dataset = dataset
|
|
114
|
+
self.batch_size = batch_size
|
|
115
|
+
self.shuffle = shuffle
|
|
116
|
+
|
|
117
|
+
def __iter__(self):
|
|
118
|
+
self.indices = np.arange(len(self.dataset))
|
|
119
|
+
if self.shuffle:
|
|
120
|
+
np.random.shuffle(self.indices)
|
|
121
|
+
self.idx = 0
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
def __next__(self):
|
|
125
|
+
if self.idx >= len(self.dataset):
|
|
126
|
+
raise StopIteration
|
|
127
|
+
batch_idx = self.indices[self.idx : self.idx + self.batch_size]
|
|
128
|
+
self.idx += self.batch_size
|
|
129
|
+
X_batch = [self.dataset[i][0] for i in batch_idx]
|
|
130
|
+
y_batch = [self.dataset[i][1] for i in batch_idx]
|
|
131
|
+
return Tensor(X_batch), Tensor(y_batch)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class SGD:
|
|
2
|
+
""" Stochastic Gradient Descent parameter weights manager """
|
|
3
|
+
def __init__(self, parameters, lr=0.01):
|
|
4
|
+
self.parameters = list(parameters)
|
|
5
|
+
self.lr = lr
|
|
6
|
+
|
|
7
|
+
def zero_grad(self):
|
|
8
|
+
for p in self.parameters:
|
|
9
|
+
if p.grad is not None:
|
|
10
|
+
p.grad.fill(0.0)
|
|
11
|
+
|
|
12
|
+
def step(self):
|
|
13
|
+
for p in self.parameters:
|
|
14
|
+
p.data -= self.lr * p.grad
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
class Tensor:
|
|
4
|
+
""" Core Autograd Tensor engine with multidimensional broadcasting support """
|
|
5
|
+
def __init__(self, data, requires_grad=False, _children=()):
|
|
6
|
+
self.data = np.array(data, dtype=np.float32)
|
|
7
|
+
self.requires_grad = requires_grad
|
|
8
|
+
self.grad = np.zeros_like(self.data) if requires_grad else None
|
|
9
|
+
self._backward = lambda: None
|
|
10
|
+
self._prev = set(_children)
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def shape(self):
|
|
14
|
+
return self.data.shape
|
|
15
|
+
@property
|
|
16
|
+
def ndim(self):
|
|
17
|
+
""" Returns the number of dimensions of the underlying data matrix """
|
|
18
|
+
return self.data.ndim
|
|
19
|
+
|
|
20
|
+
def __repr__(self):
|
|
21
|
+
return f"Tensor(shape={self.shape}, data=\n{self.data})"
|
|
22
|
+
|
|
23
|
+
def __add__(self, other):
|
|
24
|
+
other = other if isinstance(other, Tensor) else Tensor(other)
|
|
25
|
+
out = Tensor(self.data + other.data, requires_grad=self.requires_grad or other.requires_grad, _children=(self, other))
|
|
26
|
+
|
|
27
|
+
def _backward():
|
|
28
|
+
if self.requires_grad:
|
|
29
|
+
grad_self = out.grad
|
|
30
|
+
# Collapse broadcasted dimensions for self
|
|
31
|
+
while grad_self.ndim > self.ndim:
|
|
32
|
+
grad_self = grad_self.sum(axis=0)
|
|
33
|
+
for axis, size in enumerate(self.shape):
|
|
34
|
+
if size == 1:
|
|
35
|
+
grad_self = grad_self.sum(axis=axis, keepdims=True)
|
|
36
|
+
self.grad += grad_self
|
|
37
|
+
|
|
38
|
+
if other.requires_grad:
|
|
39
|
+
grad_other = out.grad
|
|
40
|
+
# Collapse broadcasted dimensions for other
|
|
41
|
+
while grad_other.ndim > other.ndim:
|
|
42
|
+
grad_other = grad_other.sum(axis=0)
|
|
43
|
+
for axis, size in enumerate(other.shape):
|
|
44
|
+
if size == 1:
|
|
45
|
+
grad_other = grad_other.sum(axis=axis, keepdims=True)
|
|
46
|
+
other.grad += grad_other
|
|
47
|
+
|
|
48
|
+
out._backward = _backward
|
|
49
|
+
return out
|
|
50
|
+
|
|
51
|
+
def __radd__(self, other):
|
|
52
|
+
return self.__add__(other)
|
|
53
|
+
|
|
54
|
+
def __matmul__(self, other):
|
|
55
|
+
assert isinstance(other, Tensor), "Matrix multiplication requires another Tensor"
|
|
56
|
+
out = Tensor(self.data @ other.data, requires_grad=self.requires_grad or other.requires_grad, _children=(self, other))
|
|
57
|
+
|
|
58
|
+
def _backward():
|
|
59
|
+
if self.requires_grad:
|
|
60
|
+
self.grad += out.grad @ other.data.T
|
|
61
|
+
if other.requires_grad:
|
|
62
|
+
other.grad += self.data.T @ out.grad
|
|
63
|
+
|
|
64
|
+
out._backward = _backward
|
|
65
|
+
return out
|
|
66
|
+
|
|
67
|
+
def sum(self):
|
|
68
|
+
out = Tensor(np.sum(self.data), requires_grad=self.requires_grad, _children=(self,))
|
|
69
|
+
|
|
70
|
+
def _backward():
|
|
71
|
+
if self.requires_grad:
|
|
72
|
+
self.grad += out.grad * np.ones_like(self.data)
|
|
73
|
+
|
|
74
|
+
out._backward = _backward
|
|
75
|
+
return out
|
|
76
|
+
|
|
77
|
+
def relu(self):
|
|
78
|
+
out = Tensor(np.maximum(0, self.data), requires_grad=self.requires_grad, _children=(self,))
|
|
79
|
+
|
|
80
|
+
def _backward():
|
|
81
|
+
if self.requires_grad:
|
|
82
|
+
self.grad += out.grad * (self.data > 0)
|
|
83
|
+
|
|
84
|
+
out._backward = _backward
|
|
85
|
+
return out
|
|
86
|
+
|
|
87
|
+
def sigmoid(self):
|
|
88
|
+
clipped_data = np.clip(self.data, -500, 500)
|
|
89
|
+
out_data = 1.0 / (1.0 + np.exp(-clipped_data))
|
|
90
|
+
out = Tensor(out_data, requires_grad=self.requires_grad, _children=(self,))
|
|
91
|
+
|
|
92
|
+
def _backward():
|
|
93
|
+
if self.requires_grad:
|
|
94
|
+
self.grad += out.grad * (out.data * (1.0 - out.data))
|
|
95
|
+
|
|
96
|
+
out._backward = _backward
|
|
97
|
+
return out
|
|
98
|
+
|
|
99
|
+
def backward(self):
|
|
100
|
+
""" Dynamically sorts the graph topologially and executes the backward pass """
|
|
101
|
+
topo = []
|
|
102
|
+
visited = set()
|
|
103
|
+
|
|
104
|
+
def build_topo(v):
|
|
105
|
+
if v not in visited:
|
|
106
|
+
visited.add(v)
|
|
107
|
+
for child in v._prev:
|
|
108
|
+
build_topo(child)
|
|
109
|
+
topo.append(v)
|
|
110
|
+
|
|
111
|
+
build_topo(self)
|
|
112
|
+
self.grad = np.ones_like(self.data)
|
|
113
|
+
|
|
114
|
+
for node in reversed(topo):
|
|
115
|
+
node._backward()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: Vishtorch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A deep learning framework built completely from scratch.
|
|
5
|
+
Author-email: Vish <your_email@example.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy>=1.20.0
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
Vishtorch/__init__.py
|
|
3
|
+
Vishtorch/nn.py
|
|
4
|
+
Vishtorch/optim.py
|
|
5
|
+
Vishtorch/tensor.py
|
|
6
|
+
Vishtorch.egg-info/PKG-INFO
|
|
7
|
+
Vishtorch.egg-info/SOURCES.txt
|
|
8
|
+
Vishtorch.egg-info/dependency_links.txt
|
|
9
|
+
Vishtorch.egg-info/requires.txt
|
|
10
|
+
Vishtorch.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
numpy>=1.20.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Vishtorch
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "Vishtorch"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="Vish", email="your_email@example.com" }
|
|
10
|
+
]
|
|
11
|
+
description = "A deep learning framework built completely from scratch."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"numpy>=1.20.0"
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
]
|