tensorstudio 0.1.1__cp313-cp313-win_amd64.whl
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.
- tensorstudio/_C.cp313-win_amd64.pyd +0 -0
- tensorstudio/_C.pyi +81 -0
- tensorstudio/__init__.py +24 -0
- tensorstudio/_version.py +5 -0
- tensorstudio/autograd.py +15 -0
- tensorstudio/data/__init__.py +8 -0
- tensorstudio/data/dataloader.py +38 -0
- tensorstudio/data/dataset.py +34 -0
- tensorstudio/errors.py +19 -0
- tensorstudio/nn/__init__.py +22 -0
- tensorstudio/nn/functional.py +25 -0
- tensorstudio/nn/losses.py +18 -0
- tensorstudio/nn/modules.py +150 -0
- tensorstudio/ops.py +97 -0
- tensorstudio/optim/__init__.py +8 -0
- tensorstudio/optim/adam.py +53 -0
- tensorstudio/optim/sgd.py +31 -0
- tensorstudio/py.typed +1 -0
- tensorstudio/serialization.py +34 -0
- tensorstudio/tensor.py +69 -0
- tensorstudio/typing.py +12 -0
- tensorstudio-0.1.1.dist-info/METADATA +188 -0
- tensorstudio-0.1.1.dist-info/RECORD +25 -0
- tensorstudio-0.1.1.dist-info/WHEEL +5 -0
- tensorstudio-0.1.1.dist-info/licenses/LICENSE +21 -0
|
Binary file
|
tensorstudio/_C.pyi
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
class Tensor:
|
|
8
|
+
requires_grad: bool
|
|
9
|
+
grad: Tensor | None
|
|
10
|
+
shape: tuple[int, ...]
|
|
11
|
+
dtype: str
|
|
12
|
+
ndim: int
|
|
13
|
+
size: int
|
|
14
|
+
T: Tensor
|
|
15
|
+
def numpy(self) -> np.ndarray: ...
|
|
16
|
+
def tolist(self) -> Any: ...
|
|
17
|
+
def item(self) -> Any: ...
|
|
18
|
+
def reshape(self, *shape: Any) -> Tensor: ...
|
|
19
|
+
def flatten(self) -> Tensor: ...
|
|
20
|
+
def transpose(self) -> Tensor: ...
|
|
21
|
+
def sum(self) -> Tensor: ...
|
|
22
|
+
def mean(self) -> Tensor: ...
|
|
23
|
+
def relu(self) -> Tensor: ...
|
|
24
|
+
def sigmoid(self) -> Tensor: ...
|
|
25
|
+
def tanh(self) -> Tensor: ...
|
|
26
|
+
def exp(self) -> Tensor: ...
|
|
27
|
+
def log(self) -> Tensor: ...
|
|
28
|
+
def backward(self, gradient: Tensor | None = None) -> None: ...
|
|
29
|
+
def zero_grad(self) -> None: ...
|
|
30
|
+
def _assign(self, other: Tensor) -> None: ...
|
|
31
|
+
def _add_scaled_(self, other: Tensor, scale: float) -> None: ...
|
|
32
|
+
def __add__(self, other: Any) -> Tensor: ...
|
|
33
|
+
def __radd__(self, other: Any) -> Tensor: ...
|
|
34
|
+
def __sub__(self, other: Any) -> Tensor: ...
|
|
35
|
+
def __rsub__(self, other: Any) -> Tensor: ...
|
|
36
|
+
def __mul__(self, other: Any) -> Tensor: ...
|
|
37
|
+
def __rmul__(self, other: Any) -> Tensor: ...
|
|
38
|
+
def __truediv__(self, other: Any) -> Tensor: ...
|
|
39
|
+
def __rtruediv__(self, other: Any) -> Tensor: ...
|
|
40
|
+
def __neg__(self) -> Tensor: ...
|
|
41
|
+
def __pow__(self, exponent: float) -> Tensor: ...
|
|
42
|
+
def __matmul__(self, other: Any) -> Tensor: ...
|
|
43
|
+
def __rmatmul__(self, other: Any) -> Tensor: ...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TensorStudioError(RuntimeError): ...
|
|
47
|
+
class ShapeError(TensorStudioError): ...
|
|
48
|
+
class DTypeError(TensorStudioError): ...
|
|
49
|
+
class DeviceError(TensorStudioError): ...
|
|
50
|
+
class AutogradError(TensorStudioError): ...
|
|
51
|
+
|
|
52
|
+
def tensor(data: Any, dtype: str | None = None, requires_grad: bool = False) -> Tensor: ...
|
|
53
|
+
def from_numpy(array: np.ndarray, requires_grad: bool = False) -> Tensor: ...
|
|
54
|
+
def zeros(shape: Any, dtype: str = "float32") -> Tensor: ...
|
|
55
|
+
def ones(shape: Any, dtype: str = "float32") -> Tensor: ...
|
|
56
|
+
def full(shape: Any, fill_value: float, dtype: str = "float32") -> Tensor: ...
|
|
57
|
+
def randn(shape: Any, dtype: str = "float32", seed: int | None = None) -> Tensor: ...
|
|
58
|
+
def arange(
|
|
59
|
+
start: float,
|
|
60
|
+
stop: float | None = None,
|
|
61
|
+
step: float = 1,
|
|
62
|
+
dtype: str = "float32",
|
|
63
|
+
) -> Tensor: ...
|
|
64
|
+
def add(left: Tensor, right: Any) -> Tensor: ...
|
|
65
|
+
def sub(left: Tensor, right: Any) -> Tensor: ...
|
|
66
|
+
def mul(left: Tensor, right: Any) -> Tensor: ...
|
|
67
|
+
def div(left: Tensor, right: Any) -> Tensor: ...
|
|
68
|
+
def neg(input: Tensor) -> Tensor: ...
|
|
69
|
+
def pow(input: Tensor, exponent: float) -> Tensor: ...
|
|
70
|
+
def matmul(left: Tensor, right: Any) -> Tensor: ...
|
|
71
|
+
def sum(input: Tensor) -> Tensor: ...
|
|
72
|
+
def mean(input: Tensor) -> Tensor: ...
|
|
73
|
+
def relu(input: Tensor) -> Tensor: ...
|
|
74
|
+
def sigmoid(input: Tensor) -> Tensor: ...
|
|
75
|
+
def tanh(input: Tensor) -> Tensor: ...
|
|
76
|
+
def exp(input: Tensor) -> Tensor: ...
|
|
77
|
+
def log(input: Tensor) -> Tensor: ...
|
|
78
|
+
def reshape(input: Tensor, shape: Any) -> Tensor: ...
|
|
79
|
+
def flatten(input: Tensor) -> Tensor: ...
|
|
80
|
+
def transpose(input: Tensor) -> Tensor: ...
|
|
81
|
+
def backward(output: Tensor, gradient: Tensor | None = None) -> None: ...
|
tensorstudio/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""TensorStudio public Python API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from . import nn, optim
|
|
6
|
+
from ._version import __version__
|
|
7
|
+
from .serialization import load, save
|
|
8
|
+
from .tensor import Tensor, arange, from_numpy, full, ones, randn, tensor, zeros
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Tensor",
|
|
12
|
+
"__version__",
|
|
13
|
+
"arange",
|
|
14
|
+
"from_numpy",
|
|
15
|
+
"full",
|
|
16
|
+
"load",
|
|
17
|
+
"nn",
|
|
18
|
+
"ones",
|
|
19
|
+
"optim",
|
|
20
|
+
"randn",
|
|
21
|
+
"save",
|
|
22
|
+
"tensor",
|
|
23
|
+
"zeros",
|
|
24
|
+
]
|
tensorstudio/_version.py
ADDED
tensorstudio/autograd.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Autograd helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from . import _C
|
|
6
|
+
from .tensor import Tensor
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def backward(output: Tensor, gradient: Tensor | None = None) -> None:
|
|
10
|
+
"""Run reverse-mode automatic differentiation from an output tensor."""
|
|
11
|
+
|
|
12
|
+
_C.backward(output, gradient)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = ["backward"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Minimal deterministic dataloader."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import random
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from .dataset import Dataset
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DataLoader:
|
|
13
|
+
"""Iterate over a dataset in Python batches."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
dataset: Dataset,
|
|
18
|
+
batch_size: int = 1,
|
|
19
|
+
shuffle: bool = False,
|
|
20
|
+
seed: int | None = None,
|
|
21
|
+
) -> None:
|
|
22
|
+
if batch_size <= 0:
|
|
23
|
+
raise ValueError("batch_size must be positive")
|
|
24
|
+
self.dataset = dataset
|
|
25
|
+
self.batch_size = batch_size
|
|
26
|
+
self.shuffle = shuffle
|
|
27
|
+
self.seed = seed
|
|
28
|
+
|
|
29
|
+
def __iter__(self) -> Iterator[list[Any]]:
|
|
30
|
+
indices = list(range(len(self.dataset)))
|
|
31
|
+
if self.shuffle:
|
|
32
|
+
rng = random.Random(self.seed)
|
|
33
|
+
rng.shuffle(indices)
|
|
34
|
+
for start in range(0, len(indices), self.batch_size):
|
|
35
|
+
yield [self.dataset[index] for index in indices[start : start + self.batch_size]]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["DataLoader"]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Dataset abstractions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Protocol
|
|
6
|
+
|
|
7
|
+
from tensorstudio.tensor import Tensor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Dataset(Protocol):
|
|
11
|
+
def __len__(self) -> int: ...
|
|
12
|
+
|
|
13
|
+
def __getitem__(self, index: int) -> object: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TensorDataset:
|
|
17
|
+
"""Dataset wrapping tensors with matching leading dimension."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, *tensors: Tensor) -> None:
|
|
20
|
+
if not tensors:
|
|
21
|
+
raise ValueError("TensorDataset requires at least one tensor")
|
|
22
|
+
leading = tensors[0].shape[0]
|
|
23
|
+
if any(tensor.shape[0] != leading for tensor in tensors):
|
|
24
|
+
raise ValueError("all tensors must have the same leading dimension")
|
|
25
|
+
self.tensors = tensors
|
|
26
|
+
|
|
27
|
+
def __len__(self) -> int:
|
|
28
|
+
return self.tensors[0].shape[0]
|
|
29
|
+
|
|
30
|
+
def __getitem__(self, index: int) -> tuple[object, ...]:
|
|
31
|
+
return tuple(tensor.tolist()[index] for tensor in self.tensors)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ["Dataset", "TensorDataset"]
|
tensorstudio/errors.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""TensorStudio exception aliases."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from . import _C
|
|
6
|
+
|
|
7
|
+
TensorStudioError = _C.TensorStudioError
|
|
8
|
+
ShapeError = _C.ShapeError
|
|
9
|
+
DTypeError = _C.DTypeError
|
|
10
|
+
DeviceError = _C.DeviceError
|
|
11
|
+
AutogradError = _C.AutogradError
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AutogradError",
|
|
15
|
+
"DTypeError",
|
|
16
|
+
"DeviceError",
|
|
17
|
+
"ShapeError",
|
|
18
|
+
"TensorStudioError",
|
|
19
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Neural network modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .functional import mse_loss, relu, sigmoid, tanh
|
|
6
|
+
from .losses import MSELoss
|
|
7
|
+
from .modules import Linear, Module, Parameter, ReLU, Sequential, Sigmoid, Tanh
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"Linear",
|
|
11
|
+
"MSELoss",
|
|
12
|
+
"Module",
|
|
13
|
+
"Parameter",
|
|
14
|
+
"ReLU",
|
|
15
|
+
"Sequential",
|
|
16
|
+
"Sigmoid",
|
|
17
|
+
"Tanh",
|
|
18
|
+
"mse_loss",
|
|
19
|
+
"relu",
|
|
20
|
+
"sigmoid",
|
|
21
|
+
"tanh",
|
|
22
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Functional neural network operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from tensorstudio.tensor import Tensor
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def relu(input: Tensor) -> Tensor:
|
|
9
|
+
return input.relu()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def sigmoid(input: Tensor) -> Tensor:
|
|
13
|
+
return input.sigmoid()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def tanh(input: Tensor) -> Tensor:
|
|
17
|
+
return input.tanh()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def mse_loss(input: Tensor, target: Tensor) -> Tensor:
|
|
21
|
+
diff = input - target
|
|
22
|
+
return (diff * diff).mean()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ["mse_loss", "relu", "sigmoid", "tanh"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Loss modules."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from tensorstudio.tensor import Tensor
|
|
6
|
+
|
|
7
|
+
from . import functional as F
|
|
8
|
+
from .modules import Module
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MSELoss(Module):
|
|
12
|
+
"""Mean squared error loss."""
|
|
13
|
+
|
|
14
|
+
def forward(self, input: Tensor, target: Tensor) -> Tensor:
|
|
15
|
+
return F.mse_loss(input, target)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["MSELoss"]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Small neural network module system built on TensorStudio tensors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
from typing import Any, cast
|
|
8
|
+
|
|
9
|
+
from tensorstudio.tensor import Tensor, randn, tensor, zeros
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Parameter:
|
|
13
|
+
"""Factory class that creates tensors with ``requires_grad=True``."""
|
|
14
|
+
|
|
15
|
+
def __new__(cls, data: Any, dtype: str | None = None) -> Tensor: # type: ignore[misc]
|
|
16
|
+
if isinstance(data, Tensor):
|
|
17
|
+
data.requires_grad = True
|
|
18
|
+
return data
|
|
19
|
+
return tensor(data, dtype=dtype, requires_grad=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Module:
|
|
23
|
+
"""Base class for Python-level neural network modules."""
|
|
24
|
+
|
|
25
|
+
training: bool
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self.training = True
|
|
29
|
+
|
|
30
|
+
def forward(self, *args: Any, **kwargs: Any) -> Any:
|
|
31
|
+
raise NotImplementedError
|
|
32
|
+
|
|
33
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
34
|
+
return self.forward(*args, **kwargs)
|
|
35
|
+
|
|
36
|
+
def parameters(self) -> list[Tensor]:
|
|
37
|
+
seen: set[int] = set()
|
|
38
|
+
return list(self._iter_parameters(seen))
|
|
39
|
+
|
|
40
|
+
def zero_grad(self) -> None:
|
|
41
|
+
for parameter in self.parameters():
|
|
42
|
+
parameter.zero_grad()
|
|
43
|
+
|
|
44
|
+
def train(self) -> Module:
|
|
45
|
+
self.training = True
|
|
46
|
+
for module in self._children():
|
|
47
|
+
module.train()
|
|
48
|
+
return self
|
|
49
|
+
|
|
50
|
+
def eval(self) -> Module:
|
|
51
|
+
self.training = False
|
|
52
|
+
for module in self._children():
|
|
53
|
+
module.eval()
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def _children(self) -> Iterator[Module]:
|
|
57
|
+
for value in self.__dict__.values():
|
|
58
|
+
yield from self._modules_from_value(value)
|
|
59
|
+
|
|
60
|
+
def _iter_parameters(self, seen: set[int]) -> Iterator[Tensor]:
|
|
61
|
+
for value in self.__dict__.values():
|
|
62
|
+
yield from self._parameters_from_value(value, seen)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def _parameters_from_value(cls, value: Any, seen: set[int]) -> Iterator[Tensor]:
|
|
66
|
+
if isinstance(value, Tensor):
|
|
67
|
+
marker = id(value)
|
|
68
|
+
if value.requires_grad and marker not in seen:
|
|
69
|
+
seen.add(marker)
|
|
70
|
+
yield value
|
|
71
|
+
elif isinstance(value, Module):
|
|
72
|
+
yield from value._iter_parameters(seen)
|
|
73
|
+
elif isinstance(value, dict):
|
|
74
|
+
for item in value.values():
|
|
75
|
+
yield from cls._parameters_from_value(item, seen)
|
|
76
|
+
elif isinstance(value, (list, tuple)):
|
|
77
|
+
for item in value:
|
|
78
|
+
yield from cls._parameters_from_value(item, seen)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def _modules_from_value(cls, value: Any) -> Iterator[Module]:
|
|
82
|
+
if isinstance(value, Module):
|
|
83
|
+
yield value
|
|
84
|
+
elif isinstance(value, dict):
|
|
85
|
+
for item in value.values():
|
|
86
|
+
yield from cls._modules_from_value(item)
|
|
87
|
+
elif isinstance(value, (list, tuple)):
|
|
88
|
+
for item in value:
|
|
89
|
+
yield from cls._modules_from_value(item)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class Linear(Module):
|
|
93
|
+
"""Fully connected layer with shape ``input @ weight.T + bias``."""
|
|
94
|
+
|
|
95
|
+
def __init__(self, in_features: int, out_features: int, bias: bool = True) -> None:
|
|
96
|
+
super().__init__()
|
|
97
|
+
if in_features <= 0 or out_features <= 0:
|
|
98
|
+
raise ValueError("in_features and out_features must be positive")
|
|
99
|
+
scale = 1.0 / math.sqrt(in_features)
|
|
100
|
+
self.in_features = in_features
|
|
101
|
+
self.out_features = out_features
|
|
102
|
+
self.weight = cast(Tensor, Parameter(randn((out_features, in_features), seed=42) * scale))
|
|
103
|
+
self.bias = cast(Tensor, Parameter(zeros((out_features,)))) if bias else None
|
|
104
|
+
|
|
105
|
+
def forward(self, input: Tensor) -> Tensor:
|
|
106
|
+
output = input @ self.weight.T
|
|
107
|
+
if self.bias is not None:
|
|
108
|
+
output = output + self.bias
|
|
109
|
+
return output
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Sequential(Module):
|
|
113
|
+
"""A simple ordered container of modules."""
|
|
114
|
+
|
|
115
|
+
def __init__(self, *modules: Module) -> None:
|
|
116
|
+
super().__init__()
|
|
117
|
+
self.modules = list(modules)
|
|
118
|
+
|
|
119
|
+
def forward(self, input: Tensor) -> Tensor:
|
|
120
|
+
output = input
|
|
121
|
+
for module in self.modules:
|
|
122
|
+
output = module(output)
|
|
123
|
+
return output
|
|
124
|
+
|
|
125
|
+
def __iter__(self) -> Iterator[Module]:
|
|
126
|
+
return iter(self.modules)
|
|
127
|
+
|
|
128
|
+
def __len__(self) -> int:
|
|
129
|
+
return len(self.modules)
|
|
130
|
+
|
|
131
|
+
def __getitem__(self, index: int) -> Module:
|
|
132
|
+
return self.modules[index]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ReLU(Module):
|
|
136
|
+
def forward(self, input: Tensor) -> Tensor:
|
|
137
|
+
return input.relu()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class Sigmoid(Module):
|
|
141
|
+
def forward(self, input: Tensor) -> Tensor:
|
|
142
|
+
return input.sigmoid()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class Tanh(Module):
|
|
146
|
+
def forward(self, input: Tensor) -> Tensor:
|
|
147
|
+
return input.tanh()
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
__all__ = ["Linear", "Module", "Parameter", "ReLU", "Sequential", "Sigmoid", "Tanh"]
|
tensorstudio/ops.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Functional tensor operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from . import _C
|
|
8
|
+
from .tensor import Tensor
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add(left: Tensor, right: Any) -> Tensor:
|
|
12
|
+
return _C.add(left, right)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def sub(left: Tensor, right: Any) -> Tensor:
|
|
16
|
+
return _C.sub(left, right)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def mul(left: Tensor, right: Any) -> Tensor:
|
|
20
|
+
return _C.mul(left, right)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def div(left: Tensor, right: Any) -> Tensor:
|
|
24
|
+
return _C.div(left, right)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def neg(input: Tensor) -> Tensor:
|
|
28
|
+
return _C.neg(input)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def pow(input: Tensor, exponent: float) -> Tensor:
|
|
32
|
+
return _C.pow(input, exponent)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def matmul(left: Tensor, right: Any) -> Tensor:
|
|
36
|
+
return _C.matmul(left, right)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def sum(input: Tensor) -> Tensor: # noqa: A001
|
|
40
|
+
return _C.sum(input)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def mean(input: Tensor) -> Tensor:
|
|
44
|
+
return _C.mean(input)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def relu(input: Tensor) -> Tensor:
|
|
48
|
+
return _C.relu(input)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def sigmoid(input: Tensor) -> Tensor:
|
|
52
|
+
return _C.sigmoid(input)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def tanh(input: Tensor) -> Tensor:
|
|
56
|
+
return _C.tanh(input)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def exp(input: Tensor) -> Tensor:
|
|
60
|
+
return _C.exp(input)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def log(input: Tensor) -> Tensor:
|
|
64
|
+
return _C.log(input)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def reshape(input: Tensor, shape: int | tuple[int, ...] | list[int]) -> Tensor:
|
|
68
|
+
return _C.reshape(input, shape)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def flatten(input: Tensor) -> Tensor:
|
|
72
|
+
return _C.flatten(input)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def transpose(input: Tensor) -> Tensor:
|
|
76
|
+
return _C.transpose(input)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
__all__ = [
|
|
80
|
+
"add",
|
|
81
|
+
"div",
|
|
82
|
+
"exp",
|
|
83
|
+
"flatten",
|
|
84
|
+
"log",
|
|
85
|
+
"matmul",
|
|
86
|
+
"mean",
|
|
87
|
+
"mul",
|
|
88
|
+
"neg",
|
|
89
|
+
"pow",
|
|
90
|
+
"relu",
|
|
91
|
+
"reshape",
|
|
92
|
+
"sigmoid",
|
|
93
|
+
"sub",
|
|
94
|
+
"sum",
|
|
95
|
+
"tanh",
|
|
96
|
+
"transpose",
|
|
97
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Adam optimizer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
|
|
7
|
+
from tensorstudio.tensor import Tensor, zeros
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Adam:
|
|
11
|
+
"""Adam optimizer with bias correction."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self,
|
|
15
|
+
params: Iterable[Tensor],
|
|
16
|
+
lr: float = 0.001,
|
|
17
|
+
betas: tuple[float, float] = (0.9, 0.999),
|
|
18
|
+
eps: float = 1e-8,
|
|
19
|
+
) -> None:
|
|
20
|
+
if lr <= 0:
|
|
21
|
+
raise ValueError("lr must be positive")
|
|
22
|
+
beta1, beta2 = betas
|
|
23
|
+
if not 0 <= beta1 < 1 or not 0 <= beta2 < 1:
|
|
24
|
+
raise ValueError("betas must be in [0, 1)")
|
|
25
|
+
if eps <= 0:
|
|
26
|
+
raise ValueError("eps must be positive")
|
|
27
|
+
self.params = list(params)
|
|
28
|
+
self.lr = lr
|
|
29
|
+
self.beta1 = beta1
|
|
30
|
+
self.beta2 = beta2
|
|
31
|
+
self.eps = eps
|
|
32
|
+
self.t = 0
|
|
33
|
+
self._m = [zeros(parameter.shape, dtype=parameter.dtype) for parameter in self.params]
|
|
34
|
+
self._v = [zeros(parameter.shape, dtype=parameter.dtype) for parameter in self.params]
|
|
35
|
+
|
|
36
|
+
def zero_grad(self) -> None:
|
|
37
|
+
for parameter in self.params:
|
|
38
|
+
parameter.zero_grad()
|
|
39
|
+
|
|
40
|
+
def step(self) -> None:
|
|
41
|
+
self.t += 1
|
|
42
|
+
for index, parameter in enumerate(self.params):
|
|
43
|
+
grad = parameter.grad
|
|
44
|
+
if grad is None:
|
|
45
|
+
continue
|
|
46
|
+
self._m[index] = self._m[index] * self.beta1 + grad * (1.0 - self.beta1)
|
|
47
|
+
self._v[index] = self._v[index] * self.beta2 + (grad * grad) * (1.0 - self.beta2)
|
|
48
|
+
m_hat = self._m[index] / (1.0 - self.beta1**self.t)
|
|
49
|
+
v_hat = self._v[index] / (1.0 - self.beta2**self.t)
|
|
50
|
+
parameter._assign(parameter - self.lr * m_hat / ((v_hat**0.5) + self.eps))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
__all__ = ["Adam"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Stochastic gradient descent optimizer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
|
|
7
|
+
from tensorstudio.tensor import Tensor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SGD:
|
|
11
|
+
"""Basic SGD optimizer."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, params: Iterable[Tensor], lr: float = 0.01) -> None:
|
|
14
|
+
if lr <= 0:
|
|
15
|
+
raise ValueError("lr must be positive")
|
|
16
|
+
self.params = list(params)
|
|
17
|
+
self.lr = lr
|
|
18
|
+
|
|
19
|
+
def zero_grad(self) -> None:
|
|
20
|
+
for parameter in self.params:
|
|
21
|
+
parameter.zero_grad()
|
|
22
|
+
|
|
23
|
+
def step(self) -> None:
|
|
24
|
+
for parameter in self.params:
|
|
25
|
+
grad = parameter.grad
|
|
26
|
+
if grad is None:
|
|
27
|
+
continue
|
|
28
|
+
parameter._assign(parameter - grad * self.lr)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = ["SGD"]
|
tensorstudio/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Serialization helpers.
|
|
2
|
+
|
|
3
|
+
TensorStudio v0.1.x uses pickle for internal object roundtrips. Loading pickle
|
|
4
|
+
data from untrusted sources is unsafe because pickle can execute arbitrary code
|
|
5
|
+
during deserialization.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import pickle
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from .typing import PathLikeStr
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def save(obj: Any, path: PathLikeStr) -> None:
|
|
18
|
+
"""Serialize a TensorStudio object to a file with pickle."""
|
|
19
|
+
|
|
20
|
+
with Path(path).open("wb") as file:
|
|
21
|
+
pickle.dump(obj, file, protocol=pickle.HIGHEST_PROTOCOL)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load(path: PathLikeStr) -> Any:
|
|
25
|
+
"""Load a TensorStudio object from a pickle file.
|
|
26
|
+
|
|
27
|
+
Only load files you created or otherwise trust.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
with Path(path).open("rb") as file:
|
|
31
|
+
return pickle.load(file) # noqa: S301
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ["load", "save"]
|
tensorstudio/tensor.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Tensor creation helpers and the public Tensor class."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from . import _C
|
|
10
|
+
|
|
11
|
+
Tensor = _C.Tensor
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def tensor(data: Any, dtype: str | None = None, requires_grad: bool = False) -> Tensor:
|
|
15
|
+
"""Create a Tensor from Python numeric data or a NumPy array."""
|
|
16
|
+
|
|
17
|
+
return _C.tensor(data, dtype, requires_grad)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def from_numpy(array: np.ndarray, requires_grad: bool = False) -> Tensor:
|
|
21
|
+
"""Create a Tensor copy from a NumPy array."""
|
|
22
|
+
|
|
23
|
+
return _C.from_numpy(np.asarray(array), requires_grad)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def zeros(shape: int | tuple[int, ...] | list[int], dtype: str = "float32") -> Tensor:
|
|
27
|
+
"""Create a tensor filled with zeros."""
|
|
28
|
+
|
|
29
|
+
return _C.zeros(shape, dtype)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def ones(shape: int | tuple[int, ...] | list[int], dtype: str = "float32") -> Tensor:
|
|
33
|
+
"""Create a tensor filled with ones."""
|
|
34
|
+
|
|
35
|
+
return _C.ones(shape, dtype)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def full(
|
|
39
|
+
shape: int | tuple[int, ...] | list[int],
|
|
40
|
+
fill_value: float,
|
|
41
|
+
dtype: str = "float32",
|
|
42
|
+
) -> Tensor:
|
|
43
|
+
"""Create a tensor filled with a scalar value."""
|
|
44
|
+
|
|
45
|
+
return _C.full(shape, fill_value, dtype)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def randn(
|
|
49
|
+
shape: int | tuple[int, ...] | list[int],
|
|
50
|
+
dtype: str = "float32",
|
|
51
|
+
seed: int | None = None,
|
|
52
|
+
) -> Tensor:
|
|
53
|
+
"""Create a tensor with normally distributed pseudo-random values."""
|
|
54
|
+
|
|
55
|
+
return _C.randn(shape, dtype, seed)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def arange(
|
|
59
|
+
start: float,
|
|
60
|
+
stop: float | None = None,
|
|
61
|
+
step: float = 1,
|
|
62
|
+
dtype: str = "float32",
|
|
63
|
+
) -> Tensor:
|
|
64
|
+
"""Create a 1D tensor with evenly spaced values."""
|
|
65
|
+
|
|
66
|
+
return _C.arange(start, stop, step, dtype)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = ["Tensor", "arange", "from_numpy", "full", "ones", "randn", "tensor", "zeros"]
|
tensorstudio/typing.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Typing helpers for TensorStudio."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from os import PathLike
|
|
6
|
+
from typing import TypeAlias
|
|
7
|
+
|
|
8
|
+
ShapeLike: TypeAlias = int | tuple[int, ...] | list[int]
|
|
9
|
+
PathLikeStr: TypeAlias = str | PathLike[str]
|
|
10
|
+
DTypeLike: TypeAlias = str | None
|
|
11
|
+
|
|
12
|
+
__all__ = ["DTypeLike", "PathLikeStr", "ShapeLike"]
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: tensorstudio
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: TensorStudio is a compact C++ tensor and autograd engine with a Python API for learning, experimentation, and lightweight ML workloads.
|
|
5
|
+
Keywords: tensor,autograd,machine-learning,cpp,pybind11
|
|
6
|
+
Author: TensorStudio contributors
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 TensorStudio contributors
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Classifier: Development Status :: 3 - Alpha
|
|
30
|
+
Classifier: Intended Audience :: Developers
|
|
31
|
+
Classifier: Intended Audience :: Education
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Programming Language :: C++
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
40
|
+
Project-URL: Homepage, https://github.com/tensorstudio/tensorstudio
|
|
41
|
+
Project-URL: Repository, https://github.com/tensorstudio/tensorstudio
|
|
42
|
+
Project-URL: Issues, https://github.com/tensorstudio/tensorstudio/issues
|
|
43
|
+
Requires-Python: >=3.10
|
|
44
|
+
Requires-Dist: numpy>=1.24
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
48
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
49
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
50
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
51
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
52
|
+
Requires-Dist: cibuildwheel>=2.19; extra == "dev"
|
|
53
|
+
Requires-Dist: pre-commit>=3.7; extra == "dev"
|
|
54
|
+
Provides-Extra: docs
|
|
55
|
+
Requires-Dist: mkdocs>=1.6; extra == "docs"
|
|
56
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
57
|
+
Description-Content-Type: text/markdown
|
|
58
|
+
|
|
59
|
+
# TensorStudio
|
|
60
|
+
|
|
61
|
+
[](https://github.com/tensorstudio/tensorstudio/actions/workflows/ci.yml)
|
|
62
|
+
[](https://github.com/tensorstudio/tensorstudio/actions/workflows/wheels.yml)
|
|
63
|
+
[](https://pypi.org/project/tensorstudio/)
|
|
64
|
+
|
|
65
|
+
TensorStudio is a compact C++ tensor and autograd engine with a Python API for
|
|
66
|
+
learning, experimentation, and lightweight ML workloads.
|
|
67
|
+
|
|
68
|
+
TensorStudio is experimental v0.1.1 software. It is CPU-only, eager-only, and
|
|
69
|
+
intentionally small enough to read and modify.
|
|
70
|
+
|
|
71
|
+
## Install
|
|
72
|
+
|
|
73
|
+
From a source checkout:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m pip install -U pip
|
|
77
|
+
python -m pip install -e ".[dev]"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Build source and wheel distributions:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python -m build
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Quickstart
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import tensorstudio as ts
|
|
90
|
+
|
|
91
|
+
x = ts.tensor([[1.0, 2.0], [3.0, 4.0]])
|
|
92
|
+
y = ts.ones((2, 2))
|
|
93
|
+
|
|
94
|
+
print((x + y).tolist())
|
|
95
|
+
print((x @ y).numpy())
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Autograd
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import tensorstudio as ts
|
|
102
|
+
|
|
103
|
+
x = ts.tensor([1.0, 2.0, 3.0], requires_grad=True)
|
|
104
|
+
loss = ((x * x).sum())
|
|
105
|
+
loss.backward()
|
|
106
|
+
|
|
107
|
+
print(x.grad.tolist()) # [2.0, 4.0, 6.0]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Neural Networks
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
import tensorstudio as ts
|
|
114
|
+
from tensorstudio import nn, optim
|
|
115
|
+
|
|
116
|
+
model = nn.Sequential(nn.Linear(1, 8), nn.Tanh(), nn.Linear(8, 1))
|
|
117
|
+
optimizer = optim.SGD(model.parameters(), lr=0.05)
|
|
118
|
+
criterion = nn.MSELoss()
|
|
119
|
+
|
|
120
|
+
x = ts.tensor([[0.0], [1.0], [2.0], [3.0]])
|
|
121
|
+
y = ts.tensor([[1.0], [3.0], [5.0], [7.0]])
|
|
122
|
+
|
|
123
|
+
for _ in range(50):
|
|
124
|
+
optimizer.zero_grad()
|
|
125
|
+
loss = criterion(model(x), y)
|
|
126
|
+
loss.backward()
|
|
127
|
+
optimizer.step()
|
|
128
|
+
|
|
129
|
+
print(loss.item())
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
python -m pip install -e ".[dev]"
|
|
136
|
+
pytest
|
|
137
|
+
ruff check .
|
|
138
|
+
mypy python/tensorstudio
|
|
139
|
+
python -m build
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The native extension is built with CMake, pybind11, scikit-build-core, and C++20.
|
|
143
|
+
|
|
144
|
+
## Documentation
|
|
145
|
+
|
|
146
|
+
The documentation lives in `docs/` and is configured with MkDocs:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
python -m pip install -e ".[docs]"
|
|
150
|
+
mkdocs serve
|
|
151
|
+
mkdocs build
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The docs cover tensor semantics, broadcasting, NumPy interop, autograd, neural
|
|
155
|
+
network modules, training loops, CPU backend details, benchmarks, development,
|
|
156
|
+
publishing, and the project roadmap.
|
|
157
|
+
|
|
158
|
+
## Publishing
|
|
159
|
+
|
|
160
|
+
Releases are intended to be built by GitHub Actions. The publish workflow uses
|
|
161
|
+
PyPI trusted publishing through `pypa/gh-action-pypi-publish`; do not commit PyPI
|
|
162
|
+
API tokens.
|
|
163
|
+
|
|
164
|
+
## Current Limitations
|
|
165
|
+
|
|
166
|
+
- CPU backend only
|
|
167
|
+
- Eager execution only
|
|
168
|
+
- No CUDA kernels or mixed precision
|
|
169
|
+
- No graph compiler or distributed training
|
|
170
|
+
- Limited dtype casting and no advanced indexing
|
|
171
|
+
- No sparse tensors
|
|
172
|
+
- Pickle serialization is for trusted TensorStudio objects only
|
|
173
|
+
|
|
174
|
+
## Roadmap
|
|
175
|
+
|
|
176
|
+
- CUDA backend
|
|
177
|
+
- Graph/JIT mode
|
|
178
|
+
- Convolution ops
|
|
179
|
+
- Dataset utilities
|
|
180
|
+
- Model zoo examples
|
|
181
|
+
- ONNX import/export
|
|
182
|
+
- Improved memory allocator
|
|
183
|
+
- SIMD kernels
|
|
184
|
+
- Multithreaded ops
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
TensorStudio is licensed under the MIT License.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
tensorstudio/__init__.py,sha256=Y9DQ2Qf9VTvYJV9ppc_ZLudUgBkWBlNUtLAX4k6Ve5I,467
|
|
2
|
+
tensorstudio/_C.cp313-win_amd64.pyd,sha256=GRjcAGsvbx9sKCCQYWxrsu-lLQUPUx7Mtln1wLt3fSk,408576
|
|
3
|
+
tensorstudio/_C.pyi,sha256=rLsHKXD7tP9yxyUS5n3YQmZADbjaZT3t_fjV7IBFhws,3223
|
|
4
|
+
tensorstudio/_version.py,sha256=J-qSORFK7QMCuBXuRQYvSNcMYGsG28v_KPc392hVSiQ,78
|
|
5
|
+
tensorstudio/autograd.py,sha256=OzmQjn1A3sY8Z_DhJkEu-ujSXsZsPU2PE1B1r6XQdw0,328
|
|
6
|
+
tensorstudio/data/__init__.py,sha256=srpO6wZIkx0r0PJ0PA9w1cyFZJbIs1BshAUYhaK2Cxg,206
|
|
7
|
+
tensorstudio/data/dataloader.py,sha256=GzDwT-1mx1r2EFNpKa7wR30T6dEXBo7U1cx45HbYDck,1051
|
|
8
|
+
tensorstudio/data/dataset.py,sha256=w6eINnpqhgoZb5rlHCQUH5F5oSOmS1RLl0FMaJA6qh4,985
|
|
9
|
+
tensorstudio/errors.py,sha256=v_jnvS8_F2nwHQLkHMcVQKs-FE6DbSnY0yIGopYwpeA,385
|
|
10
|
+
tensorstudio/nn/__init__.py,sha256=Ks_XjkOjFXQyaHh3Vppwpa5y9jzM7BU77Viz_Fwyx3g,438
|
|
11
|
+
tensorstudio/nn/functional.py,sha256=3NYsG5QSfdUGLM5FKBy_TOqhCgkpunrHc3n3dQ0FJN0,501
|
|
12
|
+
tensorstudio/nn/losses.py,sha256=AcBPesUamqvnKyMc7aeTKUEbnr8raYYo3zaal7pci0o,363
|
|
13
|
+
tensorstudio/nn/modules.py,sha256=DK8Ch6-HCHC0oeYrx8W0e_1-qxPw0jpqbANmcCMTmTw,4849
|
|
14
|
+
tensorstudio/ops.py,sha256=REw0fFmex9Dpw4aPRBUa75Vz_9t-qRo9mT5bL5EAu5s,1725
|
|
15
|
+
tensorstudio/optim/__init__.py,sha256=U_Yg_xESI0UAf_VlzgJtnZK-l5ek4pWy_susR49zK5E,134
|
|
16
|
+
tensorstudio/optim/adam.py,sha256=MjwghneGTXLQfJjM2Ic4_beGMNX3OVRfLRpuw7qIfxU,1784
|
|
17
|
+
tensorstudio/optim/sgd.py,sha256=vAAxZM4nheGi7QVymtuoj_p3C8VexDW63_bFK3Oafxs,778
|
|
18
|
+
tensorstudio/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
19
|
+
tensorstudio/serialization.py,sha256=g3sPMgEXLQh-foHxLqPhVHXV2KRn9Sk5AZB1vwtND9s,870
|
|
20
|
+
tensorstudio/tensor.py,sha256=7_6Zd1vOT_Qs8nUmmDRATwlbDk7ljE-tJ7ppOORB82I,1763
|
|
21
|
+
tensorstudio/typing.py,sha256=G6jA3AjaV8PSJG-N-88wSJG0YI7toUG7i3yWM_3XL5k,331
|
|
22
|
+
tensorstudio-0.1.1.dist-info/METADATA,sha256=neuxU2yIu4SgJytDepjYqSUxNPif5WtR7eMdFaYYyoU,5901
|
|
23
|
+
tensorstudio-0.1.1.dist-info/WHEEL,sha256=wCnCdPo_X0QGrRMO_ctMhdhFetNHQp7_-JalWW02tjE,105
|
|
24
|
+
tensorstudio-0.1.1.dist-info/licenses/LICENSE,sha256=4IIKD3q9NiDUwBZ1k1ly4lDgV7z8U-698jfW0_kHRG4,1103
|
|
25
|
+
tensorstudio-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TensorStudio contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|