pytensorforge 0.1.0__py3-none-any.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.
- cli.py +604 -0
- pytensorforge-0.1.0.dist-info/METADATA +103 -0
- pytensorforge-0.1.0.dist-info/RECORD +146 -0
- pytensorforge-0.1.0.dist-info/WHEEL +5 -0
- pytensorforge-0.1.0.dist-info/entry_points.txt +2 -0
- pytensorforge-0.1.0.dist-info/top_level.txt +2 -0
- src/__init__.py +0 -0
- src/activations/Activation.py +4 -0
- src/activations/ELU.py +11 -0
- src/activations/GELU.py +6 -0
- src/activations/ReLU.py +27 -0
- src/activations/SELU.py +14 -0
- src/activations/Sigmoid.py +27 -0
- src/activations/Softmax.py +84 -0
- src/activations/Tanh.py +29 -0
- src/activations/__init__.py +17 -0
- src/config.py +120 -0
- src/core/Matrix.py +3 -0
- src/core/Scalar.py +18 -0
- src/core/Tensor.py +866 -0
- src/core/Vector.py +31 -0
- src/core/__init__.py +0 -0
- src/data/__init__.py +0 -0
- src/data/chat_dataset.py +188 -0
- src/data/corpus.py +104 -0
- src/data/document_stream.py +178 -0
- src/data/parallel_encode.py +86 -0
- src/data/prefetch.py +62 -0
- src/data/shard_builder.py +119 -0
- src/data/shard_writer.py +81 -0
- src/data/sharded_dataset.py +112 -0
- src/data/streaming_dataset.py +132 -0
- src/data/validation.py +212 -0
- src/inference/__init__.py +0 -0
- src/inference/chat_template.py +384 -0
- src/inference/config.py +48 -0
- src/inference/engine.py +241 -0
- src/inference/export.py +133 -0
- src/inference/kv_cache.py +65 -0
- src/inference/runtime.py +161 -0
- src/inference/sampling.py +42 -0
- src/inference/scheduler.py +473 -0
- src/inference/text.py +67 -0
- src/initializers/Constant.py +9 -0
- src/initializers/GlorotNormal.py +15 -0
- src/initializers/GlorotUniform.py +26 -0
- src/initializers/HeNormal.py +15 -0
- src/initializers/HeUniform.py +14 -0
- src/initializers/Initializer.py +4 -0
- src/initializers/LecunNormal.py +16 -0
- src/initializers/LecunUniform.py +14 -0
- src/initializers/Ones.py +6 -0
- src/initializers/Orthogonal.py +14 -0
- src/initializers/RandomNormal.py +14 -0
- src/initializers/RandomUniform.py +14 -0
- src/initializers/Zeros.py +8 -0
- src/initializers/__init__.py +17 -0
- src/loss/CategoricalCrossEntropy.py +9 -0
- src/loss/CrossEntropyLoss.py +34 -0
- src/loss/CrossEntropyWithLogitsLoss.py +59 -0
- src/loss/Hinge.py +5 -0
- src/loss/Huber.py +22 -0
- src/loss/Loss.py +6 -0
- src/loss/MSE.py +7 -0
- src/loss/MSELoss.py +10 -0
- src/loss/SparseCategoricalCrossEntropy.py +15 -0
- src/loss/__init__.py +18 -0
- src/loss/bce.py +34 -0
- src/loss/mae.py +16 -0
- src/math/__init__.py +0 -0
- src/math/clip.py +37 -0
- src/math/exp.py +27 -0
- src/math/log.py +25 -0
- src/math/sigmoid.py +5 -0
- src/models/__init__.py +0 -0
- src/models/embedding/Embedding.py +65 -0
- src/models/embedding/__init__.py +0 -0
- src/models/gpt/__init__.py +0 -0
- src/models/gpt/attention.py +158 -0
- src/models/gpt/block.py +74 -0
- src/models/gpt/config.py +103 -0
- src/models/gpt/context.py +44 -0
- src/models/gpt/model.py +165 -0
- src/models/gpt/recompute.py +35 -0
- src/models/gpt/rope.py +84 -0
- src/models/regression/Linear.py +51 -0
- src/models/regression/Logistic.py +36 -0
- src/models/regression/__init__.py +0 -0
- src/models/seq/Sequential.py +297 -0
- src/models/seq/__init__.py +0 -0
- src/models/svm/__init__.py +0 -0
- src/models/tokenizer/BPETokenizer.py +228 -0
- src/models/tokenizer/__init__.py +0 -0
- src/models/transformers/Dropout.py +35 -0
- src/models/transformers/LastToken.py +10 -0
- src/models/transformers/LayerNorm.py +54 -0
- src/models/transformers/Linear.py +18 -0
- src/models/transformers/MultiHeadAttention.py +130 -0
- src/models/transformers/TransformerBlock.py +79 -0
- src/models/transformers/__init__.py +0 -0
- src/neural/Dense.py +58 -0
- src/neural/LSTM.py +167 -0
- src/neural/Layer.py +72 -0
- src/neural/Parameter.py +30 -0
- src/neural/RNN.py +83 -0
- src/neural/__init__.py +0 -0
- src/ops/__init__.py +0 -0
- src/ops/stack.py +40 -0
- src/optimizers/Adagrad.py +31 -0
- src/optimizers/Adam.py +98 -0
- src/optimizers/AdamW.py +84 -0
- src/optimizers/Batch.py +11 -0
- src/optimizers/Nesterov.py +35 -0
- src/optimizers/Optimizer.py +18 -0
- src/optimizers/RMSProp.py +35 -0
- src/optimizers/SGD.py +30 -0
- src/optimizers/SGDMomentum.py +28 -0
- src/optimizers/__init__.py +9 -0
- src/scaling/StandardScaler.py +15 -0
- src/scaling/__init__.py +0 -0
- src/serialization/__init__.py +0 -0
- src/serialization/checkpoint.py +58 -0
- src/serialization/modelio.py +132 -0
- src/serving/__init__.py +0 -0
- src/serving/app.py +792 -0
- src/serving/config.py +216 -0
- src/serving/errors.py +51 -0
- src/serving/http.py +599 -0
- src/serving/metrics.py +293 -0
- src/serving/model_server.py +287 -0
- src/serving/protocol.py +377 -0
- src/serving/security.py +200 -0
- src/serving/server.py +121 -0
- src/tokenization/__init__.py +0 -0
- src/tokenization/base.py +75 -0
- src/tokenization/bpe.py +190 -0
- src/tokenization/bytebpe.py +476 -0
- src/tokenization/registry.py +28 -0
- src/training/__init__.py +0 -0
- src/training/checkpoint_manager.py +101 -0
- src/training/experiment.py +71 -0
- src/training/losses.py +42 -0
- src/training/precision.py +141 -0
- src/training/profiler.py +38 -0
- src/training/scheduler.py +50 -0
- src/training/trainer.py +594 -0
src/training/losses.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from src.core.Tensor import Tensor
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def masked_cross_entropy(logits, targets, mask):
|
|
7
|
+
data = logits.data
|
|
8
|
+
targets = np.asarray(targets, dtype=np.int64).reshape(-1)
|
|
9
|
+
weights = np.asarray(mask, dtype=np.float32).reshape(-1)
|
|
10
|
+
|
|
11
|
+
if data.ndim != 2 or data.shape[0] != targets.shape[0] or weights.shape[0] != targets.shape[0]:
|
|
12
|
+
raise ValueError("masked_cross_entropy expects logits (N, V), targets (N,) and mask (N,)")
|
|
13
|
+
|
|
14
|
+
count = float(weights.sum())
|
|
15
|
+
denom = max(count, 1.0)
|
|
16
|
+
|
|
17
|
+
shifted = data - data.max(axis=1, keepdims=True)
|
|
18
|
+
log_norm = np.log(np.exp(shifted).sum(axis=1))
|
|
19
|
+
rows = np.arange(targets.shape[0])
|
|
20
|
+
nll = log_norm - shifted[rows, targets]
|
|
21
|
+
|
|
22
|
+
out = Tensor(np.float32(float(np.dot(nll, weights)) / denom), requires_grad=logits.requires_grad,
|
|
23
|
+
parents=(logits,), op="MaskedCrossEntropy")
|
|
24
|
+
out.token_count = count
|
|
25
|
+
|
|
26
|
+
def _backward():
|
|
27
|
+
if not logits.requires_grad:
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
active = np.nonzero(weights)[0]
|
|
31
|
+
|
|
32
|
+
if active.size == 0:
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
probs = np.exp(shifted[active] - log_norm[active, None])
|
|
36
|
+
probs[np.arange(active.size), targets[active]] -= 1.0
|
|
37
|
+
probs *= (weights[active] * (float(out.grad) / denom))[:, None]
|
|
38
|
+
logits.grad[active] += probs
|
|
39
|
+
|
|
40
|
+
out._backward = _backward
|
|
41
|
+
|
|
42
|
+
return out
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from src.core.Tensor import set_matmul_policy
|
|
6
|
+
|
|
7
|
+
PRECISIONS = ("fp32", "bf16", "fp16")
|
|
8
|
+
LOSS_SCALING = ("auto", "dynamic", "none")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def round_bf16(x):
|
|
12
|
+
x = np.ascontiguousarray(x, dtype=np.float32)
|
|
13
|
+
bits = x.view(np.uint32)
|
|
14
|
+
finite = (bits & np.uint32(0x7F800000)) != np.uint32(0x7F800000)
|
|
15
|
+
lsb = (bits >> np.uint32(16)) & np.uint32(1)
|
|
16
|
+
rounded = (bits + np.uint32(0x7FFF) + lsb) & np.uint32(0xFFFF0000)
|
|
17
|
+
is_nan = ~finite & ((bits & np.uint32(0x007FFFFF)) != np.uint32(0))
|
|
18
|
+
special = (bits & np.uint32(0xFFFF0000)) | np.where(is_nan, np.uint32(0x00400000), np.uint32(0))
|
|
19
|
+
return np.where(finite, rounded, special).astype(np.uint32).view(np.float32)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def round_fp16(x):
|
|
23
|
+
with np.errstate(over="ignore"):
|
|
24
|
+
return np.asarray(x, dtype=np.float32).astype(np.float16).astype(np.float32)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
ROUNDERS = {"bf16": round_bf16, "fp16": round_fp16}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class autocast:
|
|
31
|
+
|
|
32
|
+
def __init__(self, precision):
|
|
33
|
+
if precision not in PRECISIONS:
|
|
34
|
+
raise ValueError(f"unknown precision '{precision}'; choose one of {PRECISIONS}")
|
|
35
|
+
|
|
36
|
+
self.precision = precision
|
|
37
|
+
self._previous = None
|
|
38
|
+
|
|
39
|
+
def __enter__(self):
|
|
40
|
+
self._previous = set_matmul_policy(ROUNDERS.get(self.precision))
|
|
41
|
+
return self
|
|
42
|
+
|
|
43
|
+
def __exit__(self, *exc):
|
|
44
|
+
set_matmul_policy(self._previous)
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class GradScaler:
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
enabled=True,
|
|
53
|
+
init_scale=65536.0,
|
|
54
|
+
growth_factor=2.0,
|
|
55
|
+
backoff_factor=0.5,
|
|
56
|
+
growth_interval=2000,
|
|
57
|
+
min_scale=1.0,
|
|
58
|
+
max_scale=2.0 ** 24,
|
|
59
|
+
):
|
|
60
|
+
if init_scale <= 0 or growth_factor <= 1 or not 0 < backoff_factor < 1 or growth_interval < 1:
|
|
61
|
+
raise ValueError("invalid loss scaler settings")
|
|
62
|
+
|
|
63
|
+
self.enabled = bool(enabled)
|
|
64
|
+
self.scale = float(init_scale) if enabled else 1.0
|
|
65
|
+
self.growth_factor = float(growth_factor)
|
|
66
|
+
self.backoff_factor = float(backoff_factor)
|
|
67
|
+
self.growth_interval = int(growth_interval)
|
|
68
|
+
self.min_scale = float(min_scale)
|
|
69
|
+
self.max_scale = float(max_scale)
|
|
70
|
+
self.good_steps = 0
|
|
71
|
+
self.skipped_steps = 0
|
|
72
|
+
|
|
73
|
+
def loss_multiplier(self):
|
|
74
|
+
return self.scale if self.enabled else 1.0
|
|
75
|
+
|
|
76
|
+
def grads_finite(self, params):
|
|
77
|
+
for p in params:
|
|
78
|
+
if p.requires_grad and p._grad is not None and not np.isfinite(p._grad).all():
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
def unscale_and_check(self, params):
|
|
84
|
+
if not self.enabled:
|
|
85
|
+
return True
|
|
86
|
+
|
|
87
|
+
if not self.grads_finite(params):
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
inv = 1.0 / self.scale
|
|
91
|
+
|
|
92
|
+
for p in params:
|
|
93
|
+
if p.requires_grad and p._grad is not None:
|
|
94
|
+
p._grad *= inv
|
|
95
|
+
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
def update(self, found_overflow):
|
|
99
|
+
if not self.enabled:
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
if found_overflow:
|
|
103
|
+
self.skipped_steps += 1
|
|
104
|
+
self.good_steps = 0
|
|
105
|
+
self.scale = max(self.min_scale, self.scale * self.backoff_factor)
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
self.good_steps += 1
|
|
109
|
+
|
|
110
|
+
if self.good_steps >= self.growth_interval:
|
|
111
|
+
self.good_steps = 0
|
|
112
|
+
self.scale = min(self.max_scale, self.scale * self.growth_factor)
|
|
113
|
+
|
|
114
|
+
def state_dict(self):
|
|
115
|
+
return {
|
|
116
|
+
"enabled": self.enabled,
|
|
117
|
+
"scale": self.scale,
|
|
118
|
+
"good_steps": self.good_steps,
|
|
119
|
+
"skipped_steps": self.skipped_steps,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def load_state_dict(self, state):
|
|
123
|
+
if bool(state.get("enabled", False)) != self.enabled:
|
|
124
|
+
raise ValueError("checkpoint loss-scaling mode does not match this run")
|
|
125
|
+
|
|
126
|
+
self.scale = float(state["scale"])
|
|
127
|
+
self.good_steps = int(state["good_steps"])
|
|
128
|
+
self.skipped_steps = int(state["skipped_steps"])
|
|
129
|
+
|
|
130
|
+
if not math.isfinite(self.scale) or self.scale <= 0:
|
|
131
|
+
raise ValueError("checkpoint carries an invalid loss scale")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def resolve_loss_scaling(precision, loss_scaling):
|
|
135
|
+
if loss_scaling not in LOSS_SCALING:
|
|
136
|
+
raise ValueError(f"unknown loss_scaling '{loss_scaling}'; choose one of {LOSS_SCALING}")
|
|
137
|
+
|
|
138
|
+
if loss_scaling == "auto":
|
|
139
|
+
return precision == "fp16"
|
|
140
|
+
|
|
141
|
+
return loss_scaling == "dynamic"
|
src/training/profiler.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Profiler:
|
|
6
|
+
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.totals = defaultdict(float)
|
|
9
|
+
self.window = defaultdict(float)
|
|
10
|
+
|
|
11
|
+
def add(self, name, seconds):
|
|
12
|
+
self.totals[name] += seconds
|
|
13
|
+
self.window[name] += seconds
|
|
14
|
+
|
|
15
|
+
def section(self, name):
|
|
16
|
+
return _Section(self, name)
|
|
17
|
+
|
|
18
|
+
def take_window(self):
|
|
19
|
+
snapshot = dict(self.window)
|
|
20
|
+
self.window.clear()
|
|
21
|
+
return snapshot
|
|
22
|
+
|
|
23
|
+
def summary(self):
|
|
24
|
+
total = sum(self.totals.values()) or 1.0
|
|
25
|
+
return {k: {"seconds": v, "share": v / total} for k, v in sorted(self.totals.items())}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _Section:
|
|
29
|
+
|
|
30
|
+
def __init__(self, profiler, name):
|
|
31
|
+
self.profiler = profiler
|
|
32
|
+
self.name = name
|
|
33
|
+
|
|
34
|
+
def __enter__(self):
|
|
35
|
+
self.start = time.perf_counter()
|
|
36
|
+
|
|
37
|
+
def __exit__(self, *exc):
|
|
38
|
+
self.profiler.add(self.name, time.perf_counter() - self.start)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class LRScheduler:
|
|
5
|
+
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
base_lr,
|
|
9
|
+
warmup_steps=0,
|
|
10
|
+
decay="cosine",
|
|
11
|
+
total_steps=None,
|
|
12
|
+
min_lr=0.0,
|
|
13
|
+
):
|
|
14
|
+
if decay not in ("cosine", "linear", "constant"):
|
|
15
|
+
raise ValueError(f"unknown decay '{decay}'")
|
|
16
|
+
|
|
17
|
+
self.base_lr = base_lr
|
|
18
|
+
self.warmup_steps = warmup_steps
|
|
19
|
+
self.decay = decay
|
|
20
|
+
self.total_steps = total_steps
|
|
21
|
+
self.min_lr = min_lr
|
|
22
|
+
self.step_count = 0
|
|
23
|
+
|
|
24
|
+
def get_lr(self, step):
|
|
25
|
+
if self.warmup_steps and step < self.warmup_steps:
|
|
26
|
+
return self.base_lr * (step + 1) / self.warmup_steps
|
|
27
|
+
|
|
28
|
+
if self.decay == "constant" or not self.total_steps:
|
|
29
|
+
return self.base_lr
|
|
30
|
+
|
|
31
|
+
span = max(1, self.total_steps - self.warmup_steps)
|
|
32
|
+
progress = (step - self.warmup_steps) / span
|
|
33
|
+
progress = min(max(progress, 0.0), 1.0)
|
|
34
|
+
|
|
35
|
+
if self.decay == "linear":
|
|
36
|
+
return self.base_lr + (self.min_lr - self.base_lr) * progress
|
|
37
|
+
|
|
38
|
+
cosine = 0.5 * (1 + math.cos(math.pi * progress))
|
|
39
|
+
return self.min_lr + (self.base_lr - self.min_lr) * cosine
|
|
40
|
+
|
|
41
|
+
def step(self):
|
|
42
|
+
lr = self.get_lr(self.step_count)
|
|
43
|
+
self.step_count += 1
|
|
44
|
+
return lr
|
|
45
|
+
|
|
46
|
+
def state_dict(self):
|
|
47
|
+
return {"step_count": self.step_count}
|
|
48
|
+
|
|
49
|
+
def load_state_dict(self, state):
|
|
50
|
+
self.step_count = state["step_count"]
|