pytinytensor 0.1.1__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.
Files changed (42) hide show
  1. pytinytensor-0.1.3/LICENSE +21 -0
  2. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/PKG-INFO +3 -1
  3. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/PKG-INFO +3 -1
  4. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/SOURCES.txt +3 -0
  5. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/setup.py +58 -11
  6. pytinytensor-0.1.3/tinytensor/nn/__init__.py +0 -0
  7. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/activations.py +1 -0
  8. pytinytensor-0.1.3/tinytensor/nn/dropout.py +23 -0
  9. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/modules.py +11 -9
  10. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/optim/optimizer.py +13 -6
  11. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/README.md +0 -0
  12. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pyproject.toml +0 -0
  13. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/dependency_links.txt +0 -0
  14. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/requires.txt +0 -0
  15. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/top_level.txt +0 -0
  16. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/setup.cfg +0 -0
  17. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_autograd.py +0 -0
  18. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_data.py +0 -0
  19. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_losses.py +0 -0
  20. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_nn.py +0 -0
  21. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_optim.py +0 -0
  22. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_tensor_math.py +0 -0
  23. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/__init__.py +0 -0
  24. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/__init__.py +0 -0
  25. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cpu_numpy.py +0 -0
  26. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cuda_binding.cpp +0 -0
  27. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cuda_gpu.cu +0 -0
  28. /pytinytensor-0.1.1/tinytensor/core/__init__.py → /pytinytensor-0.1.3/tinytensor/backends/cuda_gpu.py +0 -0
  29. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/config.py +0 -0
  30. {pytinytensor-0.1.1/tinytensor/nn → pytinytensor-0.1.3/tinytensor/core}/__init__.py +0 -0
  31. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/autograd.py +0 -0
  32. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/ops.py +0 -0
  33. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/tensor.py +0 -0
  34. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/__init__.py +0 -0
  35. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/dataloader.py +0 -0
  36. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/dataset.py +0 -0
  37. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/linear.py +0 -0
  38. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/losses.py +0 -0
  39. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/optim/__init__.py +0 -0
  40. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/utils/__init__.py +0 -0
  41. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/utils/bar.py +0 -0
  42. {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/utils/early_stopping.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IbrokhimN
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.
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytinytensor
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: мини ИИ фреймворк от IbrokimN ( github/IbrokhimN )
5
5
  Home-page: https://github.com/IbrokhimN/tinytensor
6
6
  Author: IbrokhimN
7
7
  Requires-Python: >=3.9
8
8
  Description-Content-Type: text/markdown
9
+ License-File: LICENSE
9
10
  Requires-Dist: numpy>=1.23
10
11
  Requires-Dist: pybind11>=2.10
11
12
  Provides-Extra: dev
@@ -14,6 +15,7 @@ Dynamic: author
14
15
  Dynamic: description
15
16
  Dynamic: description-content-type
16
17
  Dynamic: home-page
18
+ Dynamic: license-file
17
19
  Dynamic: provides-extra
18
20
  Dynamic: requires-dist
19
21
  Dynamic: requires-python
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytinytensor
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: мини ИИ фреймворк от IbrokimN ( github/IbrokhimN )
5
5
  Home-page: https://github.com/IbrokhimN/tinytensor
6
6
  Author: IbrokhimN
7
7
  Requires-Python: >=3.9
8
8
  Description-Content-Type: text/markdown
9
+ License-File: LICENSE
9
10
  Requires-Dist: numpy>=1.23
10
11
  Requires-Dist: pybind11>=2.10
11
12
  Provides-Extra: dev
@@ -14,6 +15,7 @@ Dynamic: author
14
15
  Dynamic: description
15
16
  Dynamic: description-content-type
16
17
  Dynamic: home-page
18
+ Dynamic: license-file
17
19
  Dynamic: provides-extra
18
20
  Dynamic: requires-dist
19
21
  Dynamic: requires-python
@@ -1,3 +1,4 @@
1
+ LICENSE
1
2
  README.md
2
3
  pyproject.toml
3
4
  setup.py
@@ -18,6 +19,7 @@ tinytensor/backends/__init__.py
18
19
  tinytensor/backends/cpu_numpy.py
19
20
  tinytensor/backends/cuda_binding.cpp
20
21
  tinytensor/backends/cuda_gpu.cu
22
+ tinytensor/backends/cuda_gpu.py
21
23
  tinytensor/core/__init__.py
22
24
  tinytensor/core/autograd.py
23
25
  tinytensor/core/ops.py
@@ -27,6 +29,7 @@ tinytensor/data/dataloader.py
27
29
  tinytensor/data/dataset.py
28
30
  tinytensor/nn/__init__.py
29
31
  tinytensor/nn/activations.py
32
+ tinytensor/nn/dropout.py
30
33
  tinytensor/nn/linear.py
31
34
  tinytensor/nn/losses.py
32
35
  tinytensor/nn/modules.py
@@ -8,19 +8,56 @@ from setuptools.command.build_ext import build_ext
8
8
  long_description = Path(__file__).parent / "README.md"
9
9
  long_description = long_description.read_text(encoding="utf-8") if long_description.exists() else ""
10
10
 
11
+ def find_cuda_lib_dirs():
12
+ candidates = [
13
+ os.environ.get("CUDA_HOME"),
14
+ os.environ.get("CUDA_PATH"),
15
+ "/usr/local/cuda",
16
+ ]
17
+ conda_prefix = os.environ.get("CONDA_PREFIX")
18
+ if conda_prefix:
19
+ candidates.append(conda_prefix)
20
+
21
+ found = []
22
+ for base in candidates:
23
+ if not base:
24
+ continue
25
+ lib_dir = os.path.join(base, "lib64")
26
+ if not os.path.isdir(lib_dir):
27
+ lib_dir = os.path.join(base, "lib")
28
+ has_cudart = any(
29
+ f.startswith("libcudart.so") for f in os.listdir(lib_dir)
30
+ ) if os.path.isdir(lib_dir) else False
31
+ has_cublas = any(
32
+ f.startswith("libcublas.so") for f in os.listdir(lib_dir)
33
+ ) if os.path.isdir(lib_dir) else False
34
+ if has_cudart and has_cublas:
35
+ found.append(lib_dir)
36
+ return found
37
+
38
+
11
39
  def check_cuda():
12
40
  try:
13
41
  subprocess.check_output(["nvcc", "--version"])
14
- return True
15
42
  except (FileNotFoundError, subprocess.CalledProcessError):
16
- return False
43
+ return False, []
44
+
45
+ lib_dirs = find_cuda_lib_dirs()
46
+ if not lib_dirs:
47
+ print("nvcc есть но libcudart/libcublas не найдены рядом. Сборка пойдет на CPU.")
48
+ return False, []
49
+ return True, lib_dirs
50
+
17
51
 
18
52
  class CUDABuildExt(build_ext):
53
+ # если cuda-сборка все равно упадет (например линковка) - не роняем весь pip install,
54
+ # а просто откатываемся на чистый cpu-пакет
19
55
  def build_extensions(self):
20
56
  self.compiler.src_extensions.append('.cu')
21
57
  original_compile = self.compiler._compile
22
58
 
23
59
  def custom_compile(obj, src, ext, cc_args, extra_postargs, pp_opts):
60
+ # extra_postargs может приходить как список или словарь — обрабатываем оба случая
24
61
  if isinstance(extra_postargs, dict):
25
62
  gcc_postargs = extra_postargs.get('gcc', [])
26
63
  nvcc_postargs = extra_postargs.get('nvcc', [])
@@ -29,44 +66,54 @@ class CUDABuildExt(build_ext):
29
66
  nvcc_postargs = []
30
67
 
31
68
  if os.path.splitext(src)[1] == '.cu':
69
+ # nvcc собирает .cu файл
32
70
  inc_flags = [f"-I{inc}" for inc in self.compiler.include_dirs]
33
71
  cmd = ['nvcc', '-c', src, '-o', obj] + inc_flags + nvcc_postargs
34
72
  self.spawn(cmd)
35
73
  else:
74
+ # g++ собирает .cpp файл (с pybind11)
36
75
  original_compile(obj, src, ext, cc_args, gcc_postargs, pp_opts)
37
76
 
38
77
  self.compiler._compile = custom_compile
39
- super().build_extensions()
78
+
79
+ try:
80
+ super().build_extensions()
81
+ except Exception as e:
82
+ print(f"сборка cuda-расширения не удалась ({e}), продолжаем без него (cpu-only).")
83
+ self.extensions = []
40
84
 
41
85
  ext_modules = []
42
86
 
43
- if check_cuda():
87
+ cuda_ok, cuda_lib_dirs = check_cuda()
88
+
89
+ if cuda_ok:
44
90
  cuda_module = Extension(
45
91
  'tinytensor.cuda_ops',
46
92
  sources=[
47
- 'tinytensor/backends/cuda_gpu.cu',
48
- 'tinytensor/backends/cuda_binding.cpp'
93
+ 'tinytensor/backends/cuda_gpu.cu', # nvcc
94
+ 'tinytensor/backends/cuda_binding.cpp' # g++
49
95
  ],
50
96
  include_dirs=[
51
97
  pybind11.get_include(),
52
98
  '/usr/local/cuda/include',
53
99
  os.path.expanduser('~/.local/include')
54
100
  ],
55
- library_dirs=['/usr/local/cuda/lib64'],
101
+ library_dirs=cuda_lib_dirs,
56
102
  libraries=['cudart', 'cublas'],
57
103
  extra_compile_args={
58
104
  'gcc': ['-O3', '-fPIC', '-std=c++17'],
59
105
  'nvcc': ['-O3', '-Xcompiler', '-fPIC']
60
- }
106
+ },
107
+ optional=True,
61
108
  )
62
109
  ext_modules.append(cuda_module)
63
- print("CUDA найдена! Собираем cuBLAS бэкенд...")
110
+ print("cublas")
64
111
  else:
65
- print("CUDA не найдена. Сборка продолжится на CPU (NumPy).")
112
+ print("cpu")
66
113
 
67
114
  setup(
68
115
  name="pytinytensor",
69
- version="0.1.1",
116
+ version="0.1.3",
70
117
  description="мини ИИ фреймворк от IbrokimN ( github/IbrokhimN )",
71
118
  long_description=long_description,
72
119
  long_description_content_type="text/markdown",
File without changes
@@ -7,6 +7,7 @@ class ReLU(Module):
7
7
  class LeReLU(Module):
8
8
  # у нас есть тут альфа
9
9
  def __init__(self, alpha=0.01):
10
+ super().__init__()
10
11
  self.alpha = alpha
11
12
 
12
13
  def forward(self, x):
@@ -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,39 +7,43 @@ 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 = {}
35
38
  for name, param in self._get_named_params().items():
36
39
  sdict[name] = param.data
40
+ return sdict
37
41
 
38
42
  def load_state_dict(self, sdict):
39
43
  #запихиваем обратно
40
44
  for name, param in self._get_named_params().items():
41
45
  if name in sdict:
42
46
  param.data = sdict[name]
43
-
44
47
  def _get_named_params(self, prefix=""):
45
48
  named = {}
46
49
  for attr_name, attr in self.__dict__.items():
@@ -55,9 +58,8 @@ class Module:
55
58
  def save(self,filepath):
56
59
  with open(filepath, "wb") as f:
57
60
  pickle.dump(self.state_dict(), f)
58
-
59
61
  # загрузка весов обратно
60
62
  def load(self, filepath):
61
- with open(filepath, "wb") as f:
63
+ with open(filepath, "rb") as f:
62
64
  sd = pickle.load(f)
63
- self.load_state_dict(sd)
65
+ self.load_state_dict(sd)
@@ -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
- p.data -= self.lr * (m_hat / denom + self.weight_decay * p.data)
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)
File without changes
File without changes