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/models/gpt/block.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from src.activations import activation_fns
|
|
2
|
+
from src.models.gpt.attention import CausalSelfAttention
|
|
3
|
+
from src.models.transformers.Dropout import Dropout
|
|
4
|
+
from src.models.transformers.LayerNorm import LayerNorm
|
|
5
|
+
from src.neural.Dense import Dense
|
|
6
|
+
from src.neural.Layer import Layer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GPTBlock(Layer):
|
|
10
|
+
|
|
11
|
+
def __init__(self, config, rope=None):
|
|
12
|
+
super().__init__()
|
|
13
|
+
|
|
14
|
+
self.config = config
|
|
15
|
+
|
|
16
|
+
self.norm1 = LayerNorm(config.d_model, eps=config.norm_eps)
|
|
17
|
+
self.attn = CausalSelfAttention(config.d_model, config.n_heads, rope=rope)
|
|
18
|
+
|
|
19
|
+
self.norm2 = LayerNorm(config.d_model, eps=config.norm_eps)
|
|
20
|
+
self.fc1 = Dense(config.ff_dim)
|
|
21
|
+
self.fc2 = Dense(config.d_model)
|
|
22
|
+
|
|
23
|
+
self.dropout = Dropout(config.dropout)
|
|
24
|
+
self.activation = activation_fns[config.activation]
|
|
25
|
+
|
|
26
|
+
def build(self, input_shape):
|
|
27
|
+
self.norm1.build(input_shape)
|
|
28
|
+
self.attn.build(input_shape)
|
|
29
|
+
|
|
30
|
+
self.norm2.build(input_shape)
|
|
31
|
+
self.fc1.build(input_shape)
|
|
32
|
+
|
|
33
|
+
ff_shape = (*input_shape[:-1], self.fc1.units)
|
|
34
|
+
self.fc2.build(ff_shape)
|
|
35
|
+
|
|
36
|
+
self.dropout.build(input_shape)
|
|
37
|
+
|
|
38
|
+
self.built = True
|
|
39
|
+
|
|
40
|
+
def call(self, x, mask=None):
|
|
41
|
+
h = self.norm1.call(x)
|
|
42
|
+
h = self.attn.call(h, mask=mask)
|
|
43
|
+
x = x + self.dropout.call(h)
|
|
44
|
+
|
|
45
|
+
h = self.norm2.call(x)
|
|
46
|
+
h = self.fc2.call(self.activation(self.fc1.call(h)))
|
|
47
|
+
x = x + self.dropout.call(h)
|
|
48
|
+
|
|
49
|
+
return x
|
|
50
|
+
|
|
51
|
+
def parameters(self):
|
|
52
|
+
params = []
|
|
53
|
+
params.extend(self.norm1.parameters())
|
|
54
|
+
params.extend(self.attn.parameters())
|
|
55
|
+
params.extend(self.norm2.parameters())
|
|
56
|
+
params.extend(self.fc1.parameters())
|
|
57
|
+
params.extend(self.fc2.parameters())
|
|
58
|
+
return params
|
|
59
|
+
|
|
60
|
+
def state_dict(self):
|
|
61
|
+
return {
|
|
62
|
+
"norm1": self.norm1.state_dict(),
|
|
63
|
+
"attn": self.attn.state_dict(),
|
|
64
|
+
"norm2": self.norm2.state_dict(),
|
|
65
|
+
"fc1": self.fc1.state_dict(),
|
|
66
|
+
"fc2": self.fc2.state_dict(),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
def load_state_dict(self, state):
|
|
70
|
+
self.norm1.load_state_dict(state["norm1"])
|
|
71
|
+
self.attn.load_state_dict(state["attn"])
|
|
72
|
+
self.norm2.load_state_dict(state["norm2"])
|
|
73
|
+
self.fc1.load_state_dict(state["fc1"])
|
|
74
|
+
self.fc2.load_state_dict(state["fc2"])
|
src/models/gpt/config.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
SUPPORTED_ACTIVATIONS = ("gelu", "relu", "tanh", "sigmoid")
|
|
7
|
+
POSITION_ENCODINGS = ("learned", "rope")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class GPTConfig:
|
|
12
|
+
vocab_size: int
|
|
13
|
+
context_length: int = 1024
|
|
14
|
+
d_model: int = 768
|
|
15
|
+
n_layers: int = 12
|
|
16
|
+
n_heads: int = 12
|
|
17
|
+
ff_dim: int = 3072
|
|
18
|
+
activation: str = "gelu"
|
|
19
|
+
dropout: float = 0.0
|
|
20
|
+
norm_eps: float = 1e-5
|
|
21
|
+
tie_weights: bool = True
|
|
22
|
+
architecture: str = "gpt"
|
|
23
|
+
position_encoding: str = "learned"
|
|
24
|
+
rope_theta: float = 10000.0
|
|
25
|
+
rope_scaling: str = "none"
|
|
26
|
+
rope_scaling_factor: float = 1.0
|
|
27
|
+
trained_context_length: Optional[int] = None
|
|
28
|
+
|
|
29
|
+
def __post_init__(self):
|
|
30
|
+
if self.d_model % self.n_heads != 0:
|
|
31
|
+
raise ValueError("d_model must be divisible by n_heads")
|
|
32
|
+
|
|
33
|
+
if self.activation not in SUPPORTED_ACTIVATIONS:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"unsupported activation '{self.activation}'; choose one of {SUPPORTED_ACTIVATIONS}"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if self.position_encoding not in POSITION_ENCODINGS:
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"unsupported position_encoding '{self.position_encoding}'; choose one of {POSITION_ENCODINGS}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if self.position_encoding == "rope":
|
|
44
|
+
if (self.d_model // self.n_heads) % 2 != 0:
|
|
45
|
+
raise ValueError("rope needs an even head dimension (d_model / n_heads)")
|
|
46
|
+
|
|
47
|
+
if not self.rope_theta > 0:
|
|
48
|
+
raise ValueError("rope_theta must be positive")
|
|
49
|
+
|
|
50
|
+
if self.rope_scaling not in ("none", "linear", "ntk"):
|
|
51
|
+
raise ValueError(f"unknown rope_scaling '{self.rope_scaling}'; choose none, linear or ntk")
|
|
52
|
+
|
|
53
|
+
self.rope_scaling_factor = float(self.rope_scaling_factor)
|
|
54
|
+
|
|
55
|
+
if not self.rope_scaling_factor >= 1.0:
|
|
56
|
+
raise ValueError("rope_scaling_factor must be >= 1")
|
|
57
|
+
|
|
58
|
+
if (self.rope_scaling != "none" or self.trained_context_length is not None) and not self.uses_rope:
|
|
59
|
+
raise ValueError("context extension settings require position_encoding: rope")
|
|
60
|
+
|
|
61
|
+
if self.trained_context_length is not None and self.trained_context_length > self.context_length:
|
|
62
|
+
raise ValueError("trained_context_length cannot exceed context_length")
|
|
63
|
+
|
|
64
|
+
self.rope_theta = float(self.rope_theta)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def head_dim(self):
|
|
68
|
+
return self.d_model // self.n_heads
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def uses_rope(self):
|
|
72
|
+
return self.position_encoding == "rope"
|
|
73
|
+
|
|
74
|
+
def to_dict(self):
|
|
75
|
+
return asdict(self)
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def from_dict(cls, data):
|
|
79
|
+
known = set(cls.__dataclass_fields__.keys())
|
|
80
|
+
return cls(**{k: v for k, v in data.items() if k in known})
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def base_context_length(self):
|
|
84
|
+
return self.trained_context_length or self.context_length
|
|
85
|
+
|
|
86
|
+
def rotary_tables(self):
|
|
87
|
+
from src.models.gpt.rope import rotary_tables
|
|
88
|
+
|
|
89
|
+
return rotary_tables(self.head_dim, self.context_length, self.rope_theta,
|
|
90
|
+
self.rope_scaling, self.rope_scaling_factor)
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def normalized(cls, data):
|
|
94
|
+
return cls.from_dict(data).to_dict()
|
|
95
|
+
|
|
96
|
+
def save(self, path):
|
|
97
|
+
with open(path, "w") as f:
|
|
98
|
+
json.dump(self.to_dict(), f, indent=2, sort_keys=True)
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def load(cls, path):
|
|
102
|
+
with open(path) as f:
|
|
103
|
+
return cls.from_dict(json.load(f))
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from dataclasses import replace
|
|
2
|
+
|
|
3
|
+
EXTENSION_METHODS = ("extrapolate", "linear", "ntk")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def extend_context(config, context_length, method):
|
|
7
|
+
if method not in EXTENSION_METHODS:
|
|
8
|
+
raise ValueError(f"unknown context extension method '{method}'; choose one of {EXTENSION_METHODS}")
|
|
9
|
+
|
|
10
|
+
if not config.uses_rope:
|
|
11
|
+
raise ValueError(
|
|
12
|
+
"context extension needs a rope model; learned positional embeddings have no entries past "
|
|
13
|
+
f"the trained length of {config.context_length}"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
base = config.base_context_length
|
|
17
|
+
context_length = int(context_length)
|
|
18
|
+
|
|
19
|
+
if context_length <= base:
|
|
20
|
+
raise ValueError(f"extended context ({context_length}) must exceed the trained context ({base})")
|
|
21
|
+
|
|
22
|
+
factor = context_length / base
|
|
23
|
+
scaling = "none" if method == "extrapolate" else method
|
|
24
|
+
|
|
25
|
+
return replace(
|
|
26
|
+
config,
|
|
27
|
+
context_length=context_length,
|
|
28
|
+
trained_context_length=base,
|
|
29
|
+
rope_scaling=scaling,
|
|
30
|
+
rope_scaling_factor=1.0 if scaling == "none" else factor,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def describe_context(config):
|
|
35
|
+
if config.trained_context_length is None:
|
|
36
|
+
return {"context_length": config.context_length, "extended": False}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
"context_length": config.context_length,
|
|
40
|
+
"extended": True,
|
|
41
|
+
"trained_context_length": config.trained_context_length,
|
|
42
|
+
"method": "extrapolate" if config.rope_scaling == "none" else config.rope_scaling,
|
|
43
|
+
"factor": config.context_length / config.trained_context_length,
|
|
44
|
+
}
|
src/models/gpt/model.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from src.core.Tensor import Tensor
|
|
4
|
+
from src.models.embedding.Embedding import Embedding
|
|
5
|
+
from src.models.gpt.block import GPTBlock
|
|
6
|
+
from src.models.gpt.recompute import checkpoint
|
|
7
|
+
from src.models.transformers.LayerNorm import LayerNorm
|
|
8
|
+
from src.neural.Dense import Dense
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GPTModel:
|
|
12
|
+
|
|
13
|
+
def __init__(self, config):
|
|
14
|
+
self.config = config
|
|
15
|
+
|
|
16
|
+
self.token_emb = Embedding(config.vocab_size, config.d_model)
|
|
17
|
+
|
|
18
|
+
self.pos_emb = None
|
|
19
|
+
self.rope = None
|
|
20
|
+
|
|
21
|
+
if config.uses_rope:
|
|
22
|
+
self.rope = config.rotary_tables()
|
|
23
|
+
else:
|
|
24
|
+
self.pos_emb = Embedding(config.context_length, config.d_model)
|
|
25
|
+
|
|
26
|
+
self.blocks = [GPTBlock(config, rope=self.rope) for _ in range(config.n_layers)]
|
|
27
|
+
|
|
28
|
+
self.final_norm = LayerNorm(config.d_model, eps=config.norm_eps)
|
|
29
|
+
|
|
30
|
+
self.lm_head = None
|
|
31
|
+
if not config.tie_weights:
|
|
32
|
+
self.lm_head = Dense(config.vocab_size)
|
|
33
|
+
|
|
34
|
+
self.activation_checkpointing = False
|
|
35
|
+
self.training = True
|
|
36
|
+
self._built = False
|
|
37
|
+
|
|
38
|
+
def build(self):
|
|
39
|
+
if self._built:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
self.token_emb.build((None, self.config.context_length))
|
|
43
|
+
|
|
44
|
+
if self.pos_emb is not None:
|
|
45
|
+
self.pos_emb.build((None, self.config.context_length))
|
|
46
|
+
|
|
47
|
+
block_shape = (None, self.config.context_length, self.config.d_model)
|
|
48
|
+
|
|
49
|
+
for block in self.blocks:
|
|
50
|
+
block.build(block_shape)
|
|
51
|
+
|
|
52
|
+
self.final_norm.build(block_shape)
|
|
53
|
+
|
|
54
|
+
if self.lm_head is not None:
|
|
55
|
+
self.lm_head.build(block_shape)
|
|
56
|
+
|
|
57
|
+
self._built = True
|
|
58
|
+
|
|
59
|
+
def forward(self, input_ids):
|
|
60
|
+
if not self._built:
|
|
61
|
+
self.build()
|
|
62
|
+
|
|
63
|
+
batch, seq_len = input_ids.shape
|
|
64
|
+
|
|
65
|
+
if seq_len > self.config.context_length:
|
|
66
|
+
raise ValueError(
|
|
67
|
+
f"sequence length {seq_len} exceeds context_length "
|
|
68
|
+
f"{self.config.context_length}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
x = self.token_emb.call(input_ids)
|
|
72
|
+
|
|
73
|
+
if self.pos_emb is not None:
|
|
74
|
+
positions = Tensor(
|
|
75
|
+
np.tile(np.arange(seq_len, dtype=np.float32), (batch, 1)),
|
|
76
|
+
requires_grad=False,
|
|
77
|
+
)
|
|
78
|
+
x = x + self.pos_emb.call(positions)
|
|
79
|
+
|
|
80
|
+
for block in self.blocks:
|
|
81
|
+
if self.activation_checkpointing:
|
|
82
|
+
x = checkpoint(block.call, x)
|
|
83
|
+
else:
|
|
84
|
+
x = block.call(x)
|
|
85
|
+
|
|
86
|
+
x = self.final_norm.call(x)
|
|
87
|
+
|
|
88
|
+
if self.lm_head is not None:
|
|
89
|
+
logits = self.lm_head.call(x)
|
|
90
|
+
else:
|
|
91
|
+
weight = self.token_emb.weight
|
|
92
|
+
flat = x.reshape(batch * seq_len, self.config.d_model)
|
|
93
|
+
logits = flat @ weight.transpose(1, 0)
|
|
94
|
+
logits = logits.reshape(batch, seq_len, self.config.vocab_size)
|
|
95
|
+
|
|
96
|
+
return logits
|
|
97
|
+
|
|
98
|
+
def __call__(self, input_ids):
|
|
99
|
+
return self.forward(input_ids)
|
|
100
|
+
|
|
101
|
+
def set_training(self, flag):
|
|
102
|
+
previous = self.training
|
|
103
|
+
self.training = bool(flag)
|
|
104
|
+
|
|
105
|
+
for block in self.blocks:
|
|
106
|
+
block.dropout.training = self.training
|
|
107
|
+
|
|
108
|
+
return previous
|
|
109
|
+
|
|
110
|
+
def parameters(self):
|
|
111
|
+
if not self._built:
|
|
112
|
+
self.build()
|
|
113
|
+
|
|
114
|
+
params = []
|
|
115
|
+
params.extend(self.token_emb.parameters())
|
|
116
|
+
|
|
117
|
+
if self.pos_emb is not None:
|
|
118
|
+
params.extend(self.pos_emb.parameters())
|
|
119
|
+
|
|
120
|
+
for block in self.blocks:
|
|
121
|
+
params.extend(block.parameters())
|
|
122
|
+
|
|
123
|
+
params.extend(self.final_norm.parameters())
|
|
124
|
+
|
|
125
|
+
if self.lm_head is not None:
|
|
126
|
+
params.extend(self.lm_head.parameters())
|
|
127
|
+
|
|
128
|
+
return params
|
|
129
|
+
|
|
130
|
+
def num_parameters(self):
|
|
131
|
+
return sum(p.data.size for p in self.parameters())
|
|
132
|
+
|
|
133
|
+
def state_dict(self):
|
|
134
|
+
state = {
|
|
135
|
+
"token_emb": self.token_emb.state_dict(),
|
|
136
|
+
"final_norm": self.final_norm.state_dict(),
|
|
137
|
+
"blocks": [b.state_dict() for b in self.blocks],
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if self.pos_emb is not None:
|
|
141
|
+
state["pos_emb"] = self.pos_emb.state_dict()
|
|
142
|
+
|
|
143
|
+
if self.lm_head is not None:
|
|
144
|
+
state["lm_head"] = self.lm_head.state_dict()
|
|
145
|
+
|
|
146
|
+
return state
|
|
147
|
+
|
|
148
|
+
def load_state_dict(self, state):
|
|
149
|
+
if not self._built:
|
|
150
|
+
self.build()
|
|
151
|
+
|
|
152
|
+
if (self.pos_emb is not None) != ("pos_emb" in state):
|
|
153
|
+
raise ValueError("state does not match the model's position encoding")
|
|
154
|
+
|
|
155
|
+
self.token_emb.load_state_dict(state["token_emb"])
|
|
156
|
+
|
|
157
|
+
if self.pos_emb is not None:
|
|
158
|
+
self.pos_emb.load_state_dict(state["pos_emb"])
|
|
159
|
+
self.final_norm.load_state_dict(state["final_norm"])
|
|
160
|
+
|
|
161
|
+
for block, block_state in zip(self.blocks, state["blocks"]):
|
|
162
|
+
block.load_state_dict(block_state)
|
|
163
|
+
|
|
164
|
+
if self.lm_head is not None and "lm_head" in state:
|
|
165
|
+
self.lm_head.load_state_dict(state["lm_head"])
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from src.core.Tensor import Tensor, grad_enabled, no_grad
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def checkpoint(fn, x):
|
|
7
|
+
if not grad_enabled():
|
|
8
|
+
return fn(x)
|
|
9
|
+
|
|
10
|
+
rng_state = np.random.get_state()
|
|
11
|
+
|
|
12
|
+
with no_grad():
|
|
13
|
+
y_data = fn(Tensor(x.data, requires_grad=False)).data
|
|
14
|
+
|
|
15
|
+
out = Tensor(y_data, requires_grad=True, parents=(x,), op="Checkpoint")
|
|
16
|
+
|
|
17
|
+
def _backward():
|
|
18
|
+
resume_state = np.random.get_state()
|
|
19
|
+
np.random.set_state(rng_state)
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
x_local = Tensor(x.data, requires_grad=True)
|
|
23
|
+
y = fn(x_local)
|
|
24
|
+
finally:
|
|
25
|
+
np.random.set_state(resume_state)
|
|
26
|
+
|
|
27
|
+
y.backward(out.grad, release=True)
|
|
28
|
+
|
|
29
|
+
if x.requires_grad:
|
|
30
|
+
x.grad += x_local.grad
|
|
31
|
+
|
|
32
|
+
out._backward = _backward
|
|
33
|
+
|
|
34
|
+
return out
|
|
35
|
+
|
src/models/gpt/rope.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
ROPE_SCALING = ("none", "linear", "ntk")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def scaled_theta(theta, head_dim, scaling, factor):
|
|
10
|
+
if scaling == "ntk":
|
|
11
|
+
return float(theta) * float(factor) ** (head_dim / (head_dim - 2))
|
|
12
|
+
|
|
13
|
+
return float(theta)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RotaryTables:
|
|
17
|
+
|
|
18
|
+
def __init__(self, head_dim, max_positions, theta=10000.0, scaling="none", factor=1.0):
|
|
19
|
+
if head_dim % 2 != 0:
|
|
20
|
+
raise ValueError("rotary position encoding needs an even head dimension")
|
|
21
|
+
|
|
22
|
+
if scaling not in ROPE_SCALING:
|
|
23
|
+
raise ValueError(f"unknown rope scaling '{scaling}'; choose one of {ROPE_SCALING}")
|
|
24
|
+
|
|
25
|
+
if not factor >= 1.0:
|
|
26
|
+
raise ValueError("rope scaling factor must be >= 1")
|
|
27
|
+
|
|
28
|
+
self.head_dim = head_dim
|
|
29
|
+
self.half = head_dim // 2
|
|
30
|
+
self.scaling = scaling
|
|
31
|
+
self.factor = float(factor)
|
|
32
|
+
self.theta = scaled_theta(theta, head_dim, scaling, factor)
|
|
33
|
+
self.max_positions = int(max_positions)
|
|
34
|
+
|
|
35
|
+
inv_freq = self.theta ** (-np.arange(0, self.half, dtype=np.float64) / self.half)
|
|
36
|
+
positions = np.arange(self.max_positions, dtype=np.float64)
|
|
37
|
+
|
|
38
|
+
if scaling == "linear":
|
|
39
|
+
positions = positions / self.factor
|
|
40
|
+
|
|
41
|
+
angles = positions[:, None] * inv_freq[None, :]
|
|
42
|
+
|
|
43
|
+
self.cos = np.cos(angles).astype(np.float32)
|
|
44
|
+
self.sin = np.sin(angles).astype(np.float32)
|
|
45
|
+
|
|
46
|
+
def tables(self, positions):
|
|
47
|
+
positions = np.asarray(positions, dtype=np.int64)
|
|
48
|
+
|
|
49
|
+
if positions.size and (positions.min() < 0 or positions.max() >= self.max_positions):
|
|
50
|
+
raise ValueError(f"position outside the rotary table (0..{self.max_positions - 1})")
|
|
51
|
+
|
|
52
|
+
return self.cos[positions], self.sin[positions]
|
|
53
|
+
|
|
54
|
+
def rotate(self, x, cos, sin, inverse=False):
|
|
55
|
+
h = self.half
|
|
56
|
+
x1 = x[..., :h]
|
|
57
|
+
x2 = x[..., h:]
|
|
58
|
+
out = np.empty_like(x)
|
|
59
|
+
|
|
60
|
+
if inverse:
|
|
61
|
+
out[..., :h] = x1 * cos + x2 * sin
|
|
62
|
+
out[..., h:] = x2 * cos - x1 * sin
|
|
63
|
+
else:
|
|
64
|
+
out[..., :h] = x1 * cos - x2 * sin
|
|
65
|
+
out[..., h:] = x2 * cos + x1 * sin
|
|
66
|
+
|
|
67
|
+
return out
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
_cache = {}
|
|
71
|
+
_cache_lock = threading.Lock()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def rotary_tables(head_dim, max_positions, theta=10000.0, scaling="none", factor=1.0):
|
|
75
|
+
key = (int(head_dim), int(max_positions), float(theta), scaling, float(factor))
|
|
76
|
+
|
|
77
|
+
with _cache_lock:
|
|
78
|
+
tables = _cache.get(key)
|
|
79
|
+
|
|
80
|
+
if tables is None:
|
|
81
|
+
tables = RotaryTables(head_dim, max_positions, theta, scaling, factor)
|
|
82
|
+
_cache[key] = tables
|
|
83
|
+
|
|
84
|
+
return tables
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from src.core.Tensor import Tensor
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# y = XW + B
|
|
7
|
+
class Linear:
|
|
8
|
+
def __init__(self, weight_shape, bias_shape):
|
|
9
|
+
|
|
10
|
+
self.W = Tensor.random(weight_shape)
|
|
11
|
+
|
|
12
|
+
self.b = Tensor.random(bias_shape)
|
|
13
|
+
|
|
14
|
+
self.dW = Tensor.zeros(weight_shape)
|
|
15
|
+
self.db = Tensor.zeros(bias_shape)
|
|
16
|
+
|
|
17
|
+
self.X = None
|
|
18
|
+
|
|
19
|
+
def normalize(self, X):
|
|
20
|
+
norm = np.linalg.norm(X)
|
|
21
|
+
return X if norm == 0 else X / norm
|
|
22
|
+
|
|
23
|
+
def forward(self, X):
|
|
24
|
+
self.X = X
|
|
25
|
+
return np.dot(X, self.W.data) + self.b.data
|
|
26
|
+
|
|
27
|
+
def grads(self):
|
|
28
|
+
return [self.dW, self.db]
|
|
29
|
+
|
|
30
|
+
def parameters(self):
|
|
31
|
+
return [self.W, self.b]
|
|
32
|
+
|
|
33
|
+
def backward(self, grad_output):
|
|
34
|
+
# L = pred - target
|
|
35
|
+
# u = pred - target
|
|
36
|
+
# L = u
|
|
37
|
+
# dL/du = 1
|
|
38
|
+
# dL/dpred = dL/du * du/dpred
|
|
39
|
+
# du/dpred = 1 - 0 = 1
|
|
40
|
+
# dL/dpred = u = pred - target
|
|
41
|
+
# how do W affect the L?
|
|
42
|
+
# dL/dW = dL/dpred * dpred/dW
|
|
43
|
+
# dpred/dW = X
|
|
44
|
+
# dL/dW = (pred - target) * X
|
|
45
|
+
self.dW.data += grad_output * self.X.data
|
|
46
|
+
self.db.data += grad_output
|
|
47
|
+
return grad_output * self.W.data
|
|
48
|
+
|
|
49
|
+
def update(self, learning_rate):
|
|
50
|
+
self.W.data -= learning_rate * self.dW.data
|
|
51
|
+
self.b.data -= learning_rate * self.db.data
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from src.core.Tensor import Tensor
|
|
4
|
+
from src.math.sigmoid import sigmoid
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Logistic:
|
|
8
|
+
def __init__(self, weight_shape, bias_shape):
|
|
9
|
+
self.X = None
|
|
10
|
+
self.W = Tensor(weight_shape)
|
|
11
|
+
self.W.random()
|
|
12
|
+
|
|
13
|
+
self.b = Tensor(bias_shape)
|
|
14
|
+
self.b.random()
|
|
15
|
+
|
|
16
|
+
self.dW = Tensor(weight_shape)
|
|
17
|
+
self.db = Tensor(bias_shape)
|
|
18
|
+
|
|
19
|
+
def grads(self):
|
|
20
|
+
return [self.dW, self.db]
|
|
21
|
+
|
|
22
|
+
def parameters(self):
|
|
23
|
+
return [self.W, self.b]
|
|
24
|
+
|
|
25
|
+
def forward(self, X):
|
|
26
|
+
self.X = X
|
|
27
|
+
return sigmoid(np.dot(X, self.W.data) + self.b.data)
|
|
28
|
+
|
|
29
|
+
def backward(self, grad_output):
|
|
30
|
+
self.dW.data += grad_output * self.X.data
|
|
31
|
+
self.db.data += grad_output
|
|
32
|
+
return grad_output * self.W.data
|
|
33
|
+
|
|
34
|
+
def update(self, learning_rate):
|
|
35
|
+
self.W.data -= learning_rate * self.dW.data
|
|
36
|
+
self.b.data -= learning_rate * self.db.data
|
|
File without changes
|