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.
- pytinytensor-0.1.3/LICENSE +21 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/PKG-INFO +3 -1
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/PKG-INFO +3 -1
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/SOURCES.txt +3 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/setup.py +58 -11
- pytinytensor-0.1.3/tinytensor/nn/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/activations.py +1 -0
- pytinytensor-0.1.3/tinytensor/nn/dropout.py +23 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/modules.py +11 -9
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/optim/optimizer.py +13 -6
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/README.md +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pyproject.toml +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/dependency_links.txt +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/requires.txt +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/pytinytensor.egg-info/top_level.txt +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/setup.cfg +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_autograd.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_data.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_losses.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_nn.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_optim.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tests/test_tensor_math.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cpu_numpy.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cuda_binding.cpp +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/backends/cuda_gpu.cu +0 -0
- /pytinytensor-0.1.1/tinytensor/core/__init__.py → /pytinytensor-0.1.3/tinytensor/backends/cuda_gpu.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/config.py +0 -0
- {pytinytensor-0.1.1/tinytensor/nn → pytinytensor-0.1.3/tinytensor/core}/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/autograd.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/ops.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/core/tensor.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/dataloader.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/data/dataset.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/linear.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/nn/losses.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/optim/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/utils/__init__.py +0 -0
- {pytinytensor-0.1.1 → pytinytensor-0.1.3}/tinytensor/utils/bar.py +0 -0
- {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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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("
|
|
110
|
+
print("cublas")
|
|
64
111
|
else:
|
|
65
|
-
print("
|
|
112
|
+
print("cpu")
|
|
66
113
|
|
|
67
114
|
setup(
|
|
68
115
|
name="pytinytensor",
|
|
69
|
-
version="0.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
|
|
@@ -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, "
|
|
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
|
-
|
|
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
|
|
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
|