haliax 1.4.dev346__tar.gz → 1.4.dev348__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.
- {haliax-1.4.dev346 → haliax-1.4.dev348}/PKG-INFO +1 -1
- haliax-1.4.dev348/src/haliax/__about__.py +1 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/__init__.py +2 -1
- haliax-1.4.dev348/src/haliax/nn/linear.py +261 -0
- haliax-1.4.dev346/src/haliax/__about__.py +0 -1
- haliax-1.4.dev346/src/haliax/nn/linear.py +0 -126
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.coveragerc +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.flake8 +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.github/workflows/publish_dev.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.github/workflows/run_pre_commit.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.github/workflows/run_quick_levanter_tests.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.github/workflows/run_tests.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.gitignore +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.pre-commit-config.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/.readthedocs.yaml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/CONTRIBUTING.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/LICENSE +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/README.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/api.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/broadcasting.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/cheatsheet.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/css/material.css +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/css/mkdocstrings.css +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/faq.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/data_parallel_mesh.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/data_parallel_mesh_replicated.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_1d.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_1d_zero.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d_batch_partitioned.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d_data_replicated.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d_data_replicated_mlp_partitioned.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d_intermediate_fully_partitioned.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/figures/device_mesh_2d_zero.png +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/fp8.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/index.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/indexing.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/matmul.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/nn.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/partitioning.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/rearrange.ipynb +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/rearrange.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/requirements.txt +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/scan.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/state-dict.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/tutorial.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/docs/vmap.md +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/mkdocs.yml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/pyproject.toml +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/__init__.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/__init__.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/compile_utils.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/dot.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/einsum.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/fp8.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/parsing.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/rearrange.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/scan.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/state_dict.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/_src/util.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/axis.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/core.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/debug.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/hof.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/jax_utils.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/activations.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/attention.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/conv.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/dropout.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/embedding.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/loss.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/mlp.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/normalization.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/pool.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/nn/scan.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/ops.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/partitioning.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/quantization.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/random.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/specialized_fns.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/state_dict.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/tree_util.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/types.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/util.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/src/haliax/wrap.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/core_test.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_attention.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_axis.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_conv.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_debug.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_dot.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_einsum.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_fp8.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_hof.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_int8.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_nn.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_ops.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_parsing.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_partitioning.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_pool.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_random.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_rearrange.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_scan.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_specialized_fns.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_state_dict.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_tree_util.py +0 -0
- {haliax-1.4.dev346 → haliax-1.4.dev348}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haliax
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.dev348
|
|
4
4
|
Summary: Named Tensors for Legible Deep Learning in JAX
|
|
5
5
|
Project-URL: Homepage, https://github.com/stanford-crfm/haliax
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/stanford-crfm/haliax/issues/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.4.dev348"
|
|
@@ -33,7 +33,7 @@ from .activations import (
|
|
|
33
33
|
from .conv import Conv, ConvTranspose
|
|
34
34
|
from .dropout import Dropout, dropout
|
|
35
35
|
from .embedding import Embedding
|
|
36
|
-
from .linear import Linear
|
|
36
|
+
from .linear import Linear, MoELinear
|
|
37
37
|
from .loss import binary_cross_entropy_loss, cross_entropy_loss, cross_entropy_loss_and_log_normalizers, reduce_loss
|
|
38
38
|
from .mlp import MLP
|
|
39
39
|
from .normalization import LayerNorm, RmsNorm, log_softmax, logsumexp, softmax, standardize
|
|
@@ -83,6 +83,7 @@ __all__ = [
|
|
|
83
83
|
"dropout",
|
|
84
84
|
"LayerNorm",
|
|
85
85
|
"Linear",
|
|
86
|
+
"MoELinear",
|
|
86
87
|
"Embedding",
|
|
87
88
|
"RmsNorm",
|
|
88
89
|
"Stacked",
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import math
|
|
3
|
+
from functools import partial
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import equinox as eqx
|
|
7
|
+
import jax
|
|
8
|
+
import jax.numpy as jnp
|
|
9
|
+
from jax.experimental.pallas.ops.tpu.megablox import gmm
|
|
10
|
+
from jax.experimental.shard_map import shard_map
|
|
11
|
+
from jax.random import PRNGKey
|
|
12
|
+
|
|
13
|
+
import haliax as hax
|
|
14
|
+
|
|
15
|
+
from .._src.state_dict import Mod, ModuleWithStateDictSerialization
|
|
16
|
+
from ..axis import Axis, AxisSpec
|
|
17
|
+
from ..core import NamedArray
|
|
18
|
+
from ..jax_utils import named_call
|
|
19
|
+
from ..partitioning import ResourceAxis
|
|
20
|
+
from ..quantization import DotGeneralOp
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Linear(ModuleWithStateDictSerialization):
|
|
24
|
+
"""A named Linear layer. This module allows you to specify multiple named axes for both input
|
|
25
|
+
and output, which is occasionally useful."""
|
|
26
|
+
|
|
27
|
+
weight: NamedArray
|
|
28
|
+
bias: Optional[NamedArray]
|
|
29
|
+
|
|
30
|
+
In: AxisSpec = eqx.static_field()
|
|
31
|
+
Out: AxisSpec = eqx.static_field()
|
|
32
|
+
dot_general: DotGeneralOp = eqx.field(default_factory=DotGeneralOp.default)
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def init(
|
|
36
|
+
In: AxisSpec,
|
|
37
|
+
Out: AxisSpec,
|
|
38
|
+
*,
|
|
39
|
+
key: PRNGKey,
|
|
40
|
+
use_bias: bool = True,
|
|
41
|
+
out_first: bool = True,
|
|
42
|
+
dot_general: Optional[DotGeneralOp] = None,
|
|
43
|
+
init_scale: float = 1.0,
|
|
44
|
+
) -> "Linear":
|
|
45
|
+
"""
|
|
46
|
+
Args:
|
|
47
|
+
In: AxisSpec: The input axis spec
|
|
48
|
+
Out: AxisSpec: The output axis spec
|
|
49
|
+
key: PRNGKeyArray: The PRNG key to use for initialization
|
|
50
|
+
use_bias: bool: Whether to use a bias term
|
|
51
|
+
out_first: bool: Whether to put output axes first in the weight matrix. out_first is how PyTorch does it.
|
|
52
|
+
dot_general: Callable: The dot_general function to use. Defaults to jax.lax.dot_general.
|
|
53
|
+
init_scale: float: The scale to use for initialization. We scale init by 1/sqrt(Input.size)*init_scale
|
|
54
|
+
"""
|
|
55
|
+
joint_spec = hax.concat_axis_specs(Out, In) if out_first else hax.concat_axis_specs(In, Out)
|
|
56
|
+
input_size = hax.axis_size(In)
|
|
57
|
+
weight = hax.random.truncated_normal(key, joint_spec, -3, 3) * (init_scale / math.sqrt(input_size))
|
|
58
|
+
bias = hax.zeros(Out) if use_bias else None
|
|
59
|
+
|
|
60
|
+
if dot_general is None:
|
|
61
|
+
dot_general = DotGeneralOp.default()
|
|
62
|
+
|
|
63
|
+
return Linear(weight, bias, In, Out, dot_general=dot_general)
|
|
64
|
+
|
|
65
|
+
@named_call
|
|
66
|
+
def __call__(self, inputs, *, key: Optional[PRNGKey] = None):
|
|
67
|
+
"""
|
|
68
|
+
Args:
|
|
69
|
+
inputs (NamedArray): Input array
|
|
70
|
+
key: Not used, but there for compat with other modules
|
|
71
|
+
"""
|
|
72
|
+
del key
|
|
73
|
+
q = inputs.dot(self.weight, axis=self.In, dot_general=self.dot_general)
|
|
74
|
+
q = hax.auto_sharded(q)
|
|
75
|
+
|
|
76
|
+
if self.bias is not None:
|
|
77
|
+
q = q + self.bias
|
|
78
|
+
q = hax.auto_sharded(q)
|
|
79
|
+
|
|
80
|
+
return q
|
|
81
|
+
|
|
82
|
+
def flatten_for_export(self: Mod) -> Mod:
|
|
83
|
+
if isinstance(self.Out, hax.Axis) and isinstance(self.In, hax.Axis):
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
weight = self.weight
|
|
87
|
+
bias = self.bias
|
|
88
|
+
|
|
89
|
+
new_Out = hax.flatten_axes(self.Out, "__OUT__")
|
|
90
|
+
new_In = hax.flatten_axes(self.In, "__IN__")
|
|
91
|
+
|
|
92
|
+
if weight is not None and weight.array is not None:
|
|
93
|
+
out_first = self._out_first
|
|
94
|
+
weight = weight.flatten_axes(self.Out, new_Out).flatten_axes(self.In, new_In)
|
|
95
|
+
|
|
96
|
+
if out_first:
|
|
97
|
+
weight = weight.rearrange((..., "__OUT__", "__IN__"))
|
|
98
|
+
else:
|
|
99
|
+
weight = weight.rearrange((..., "__IN__", "__OUT__"))
|
|
100
|
+
|
|
101
|
+
if isinstance(bias, NamedArray):
|
|
102
|
+
bias = bias.flatten_axes(self.Out, new_Out)
|
|
103
|
+
|
|
104
|
+
return dataclasses.replace(self, weight=weight, bias=bias, In=new_In, Out=new_Out)
|
|
105
|
+
|
|
106
|
+
def unflatten_from_export(self: Mod, template: Mod) -> Mod:
|
|
107
|
+
weight = self.weight
|
|
108
|
+
bias = self.bias
|
|
109
|
+
|
|
110
|
+
if (template.In, template.Out) == (self.In, self.Out):
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
if weight.array is not None:
|
|
114
|
+
weight = weight.unflatten_axis("__OUT__", template.Out).unflatten_axis("__IN__", template.In)
|
|
115
|
+
weight = weight.rearrange(template.weight.axes)
|
|
116
|
+
|
|
117
|
+
if isinstance(bias, NamedArray):
|
|
118
|
+
bias = bias.unflatten_axis("__OUT__", template.Out)
|
|
119
|
+
bias = bias.rearrange(template.bias.axes)
|
|
120
|
+
|
|
121
|
+
return dataclasses.replace(template, weight=weight, bias=bias)
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def _out_first(self):
|
|
125
|
+
"""
|
|
126
|
+
Returns: bool: Whether the output axes are first in the weight matrix
|
|
127
|
+
"""
|
|
128
|
+
# We do it this way because of scan layers
|
|
129
|
+
if isinstance(self.Out, hax.Axis):
|
|
130
|
+
return self.weight.axes[-1] != self.Out
|
|
131
|
+
else:
|
|
132
|
+
return self.weight.axes[-len(self.Out) :] != self.Out
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class MoELinear(eqx.Module):
|
|
136
|
+
"""A named Linear layer for MoE. This module allows you to specify multiple named axes for both input
|
|
137
|
+
and output, which is occasionally useful."""
|
|
138
|
+
|
|
139
|
+
weight: NamedArray
|
|
140
|
+
bias: Optional[NamedArray]
|
|
141
|
+
|
|
142
|
+
Experts: AxisSpec = eqx.static_field()
|
|
143
|
+
In: Axis = eqx.static_field()
|
|
144
|
+
Out: Axis = eqx.static_field()
|
|
145
|
+
dot_general: DotGeneralOp = eqx.field(default_factory=DotGeneralOp.default)
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def init(
|
|
149
|
+
Experts: Axis,
|
|
150
|
+
In: Axis,
|
|
151
|
+
Out: Axis,
|
|
152
|
+
*,
|
|
153
|
+
key: PRNGKey,
|
|
154
|
+
use_bias: bool = True,
|
|
155
|
+
out_first: bool = False,
|
|
156
|
+
init_scale: float = 1.0,
|
|
157
|
+
) -> "MoELinear":
|
|
158
|
+
"""
|
|
159
|
+
Args:
|
|
160
|
+
Experts: Axis: The expert axis
|
|
161
|
+
In: Axis: The input axis
|
|
162
|
+
Out: Axis: The output axis
|
|
163
|
+
key: PRNGKeyArray: The PRNG key to use for initialization
|
|
164
|
+
use_bias: bool: Whether to use a bias term
|
|
165
|
+
out_first: bool: Whether to put output axes first in the weight matrix. out_first is how PyTorch does it.
|
|
166
|
+
dot_general: Callable: The dot_general function to use. Defaults to jax.lax.dot_general. For fp8 or int8
|
|
167
|
+
init_scale: float: The scale to use for initialization. We scale init by 1/sqrt(Input.size)*init_scale
|
|
168
|
+
"""
|
|
169
|
+
joint_spec = hax.concat_axis_specs(Out, In) if out_first else hax.concat_axis_specs(In, Out)
|
|
170
|
+
joint_spec = hax.concat_axis_specs(Experts, joint_spec)
|
|
171
|
+
input_size = hax.axis_size(In)
|
|
172
|
+
weight = hax.random.truncated_normal(key, joint_spec, -3, 3) * (init_scale / math.sqrt(input_size))
|
|
173
|
+
bias = hax.zeros(Out) if use_bias else None
|
|
174
|
+
|
|
175
|
+
return MoELinear(weight, bias, Experts, In, Out)
|
|
176
|
+
|
|
177
|
+
@named_call
|
|
178
|
+
def __call__(self, inputs, group_sizes, *, key: Optional[PRNGKey] = None):
|
|
179
|
+
"""
|
|
180
|
+
Args:
|
|
181
|
+
inputs (NamedArray): Input array (Batch, In)
|
|
182
|
+
group_sizes (NamedArray): MoE expert sizes (Experts)
|
|
183
|
+
key: Not used, but there for compat with other modules
|
|
184
|
+
"""
|
|
185
|
+
del key
|
|
186
|
+
|
|
187
|
+
inputs = inputs.rearrange((..., self.In))
|
|
188
|
+
out_axes = hax.replace_axis(inputs.axes, self.In, self.Out)
|
|
189
|
+
|
|
190
|
+
q = _gmm(
|
|
191
|
+
inputs,
|
|
192
|
+
self.weight,
|
|
193
|
+
group_sizes,
|
|
194
|
+
out_axes,
|
|
195
|
+
ar=hax.partitioning.physical_axis_name(self.In) == ResourceAxis.MODEL,
|
|
196
|
+
) # gmm((B, D), (E, D, d)) -> (B, d)
|
|
197
|
+
q = hax.auto_sharded(q)
|
|
198
|
+
|
|
199
|
+
if self.bias is not None:
|
|
200
|
+
q = q + self.bias
|
|
201
|
+
q = hax.auto_sharded(q)
|
|
202
|
+
|
|
203
|
+
return q
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def out_first(self):
|
|
207
|
+
"""
|
|
208
|
+
Returns: bool: Whether the output axes are first in the weight matrix
|
|
209
|
+
"""
|
|
210
|
+
# We do it this way because of scan layers
|
|
211
|
+
if isinstance(self.Out, hax.Axis):
|
|
212
|
+
return self.weight.axes[-1] != self.Out
|
|
213
|
+
else:
|
|
214
|
+
return self.weight.axes[-len(self.Out) :] != self.Out
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _gmm(lhs, rhs, group_sizes, out_axes, sharded=False, ar=False):
|
|
218
|
+
if sharded:
|
|
219
|
+
gmm_fn = gmm_sharded
|
|
220
|
+
else:
|
|
221
|
+
gmm_fn = shard_map(
|
|
222
|
+
partial(gmm_sharded, ar=ar),
|
|
223
|
+
mesh=hax.partitioning._get_mesh(),
|
|
224
|
+
in_specs=(
|
|
225
|
+
hax.partitioning.pspec_for_axis(lhs.axes),
|
|
226
|
+
hax.partitioning.pspec_for_axis(rhs.axes),
|
|
227
|
+
hax.partitioning.pspec_for_axis(group_sizes.axes),
|
|
228
|
+
),
|
|
229
|
+
out_specs=hax.partitioning.pspec_for_axis(out_axes),
|
|
230
|
+
check_rep=False,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
out = gmm_fn(lhs.array, rhs.array, group_sizes.array)
|
|
234
|
+
|
|
235
|
+
return hax.NamedArray(out, axes=out_axes)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def gmm_sharded(lhs_: jnp.ndarray, rhs_: jnp.ndarray, group_sizes_: jnp.ndarray, ar: bool = False) -> jnp.ndarray:
|
|
239
|
+
hs_shape = lhs_.shape
|
|
240
|
+
if hs_shape[0] % 512:
|
|
241
|
+
pad_length = 512 - hs_shape[0] % 512
|
|
242
|
+
lhs_ = jax.lax.pad(lhs_, 0.0, [(0, pad_length, 0), (0, 0, 0)])
|
|
243
|
+
|
|
244
|
+
tile_size = (512, 1024, 1024) # (m, k, n)
|
|
245
|
+
m, k, n = lhs_.shape[0], lhs_.shape[1], rhs_.shape[2]
|
|
246
|
+
out = gmm(
|
|
247
|
+
lhs_,
|
|
248
|
+
rhs_,
|
|
249
|
+
group_sizes_,
|
|
250
|
+
preferred_element_type=lhs_.dtype,
|
|
251
|
+
tiling=(min(m, tile_size[0]), min(k, tile_size[1]), min(n, tile_size[2])),
|
|
252
|
+
# interpret=True,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
if ar:
|
|
256
|
+
out = jax.lax.psum(out, ResourceAxis.MODEL)
|
|
257
|
+
|
|
258
|
+
if hs_shape[0] % 512:
|
|
259
|
+
out = out[: hs_shape[0]]
|
|
260
|
+
|
|
261
|
+
return out
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.4.dev346"
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
import math
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
import equinox as eqx
|
|
6
|
-
from jax.random import PRNGKey
|
|
7
|
-
|
|
8
|
-
import haliax as hax
|
|
9
|
-
|
|
10
|
-
from .._src.state_dict import Mod, ModuleWithStateDictSerialization
|
|
11
|
-
from ..axis import AxisSpec
|
|
12
|
-
from ..core import NamedArray
|
|
13
|
-
from ..jax_utils import named_call
|
|
14
|
-
from ..quantization import DotGeneralOp
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Linear(ModuleWithStateDictSerialization):
|
|
18
|
-
"""A named Linear layer. This module allows you to specify multiple named axes for both input
|
|
19
|
-
and output, which is occasionally useful."""
|
|
20
|
-
|
|
21
|
-
weight: NamedArray
|
|
22
|
-
bias: Optional[NamedArray]
|
|
23
|
-
|
|
24
|
-
In: AxisSpec = eqx.static_field()
|
|
25
|
-
Out: AxisSpec = eqx.static_field()
|
|
26
|
-
dot_general: DotGeneralOp = eqx.field(default_factory=DotGeneralOp.default)
|
|
27
|
-
|
|
28
|
-
@staticmethod
|
|
29
|
-
def init(
|
|
30
|
-
In: AxisSpec,
|
|
31
|
-
Out: AxisSpec,
|
|
32
|
-
*,
|
|
33
|
-
key: PRNGKey,
|
|
34
|
-
use_bias: bool = True,
|
|
35
|
-
out_first: bool = True,
|
|
36
|
-
dot_general: Optional[DotGeneralOp] = None,
|
|
37
|
-
init_scale: float = 1.0,
|
|
38
|
-
) -> "Linear":
|
|
39
|
-
"""
|
|
40
|
-
Args:
|
|
41
|
-
In: AxisSpec: The input axis spec
|
|
42
|
-
Out: AxisSpec: The output axis spec
|
|
43
|
-
key: PRNGKeyArray: The PRNG key to use for initialization
|
|
44
|
-
use_bias: bool: Whether to use a bias term
|
|
45
|
-
out_first: bool: Whether to put output axes first in the weight matrix. out_first is how PyTorch does it.
|
|
46
|
-
dot_general: Callable: The dot_general function to use. Defaults to jax.lax.dot_general.
|
|
47
|
-
init_scale: float: The scale to use for initialization. We scale init by 1/sqrt(Input.size)*init_scale
|
|
48
|
-
"""
|
|
49
|
-
joint_spec = hax.concat_axis_specs(Out, In) if out_first else hax.concat_axis_specs(In, Out)
|
|
50
|
-
input_size = hax.axis_size(In)
|
|
51
|
-
weight = hax.random.truncated_normal(key, joint_spec, -3, 3) * (init_scale / math.sqrt(input_size))
|
|
52
|
-
bias = hax.zeros(Out) if use_bias else None
|
|
53
|
-
|
|
54
|
-
if dot_general is None:
|
|
55
|
-
dot_general = DotGeneralOp.default()
|
|
56
|
-
|
|
57
|
-
return Linear(weight, bias, In, Out, dot_general=dot_general)
|
|
58
|
-
|
|
59
|
-
@named_call
|
|
60
|
-
def __call__(self, inputs, *, key: Optional[PRNGKey] = None):
|
|
61
|
-
"""
|
|
62
|
-
Args:
|
|
63
|
-
inputs (NamedArray): Input array
|
|
64
|
-
key: Not used, but there for compat with other modules
|
|
65
|
-
"""
|
|
66
|
-
del key
|
|
67
|
-
q = inputs.dot(self.weight, axis=self.In, dot_general=self.dot_general)
|
|
68
|
-
q = hax.auto_sharded(q)
|
|
69
|
-
|
|
70
|
-
if self.bias is not None:
|
|
71
|
-
q = q + self.bias
|
|
72
|
-
q = hax.auto_sharded(q)
|
|
73
|
-
|
|
74
|
-
return q
|
|
75
|
-
|
|
76
|
-
def flatten_for_export(self: Mod) -> Mod:
|
|
77
|
-
if isinstance(self.Out, hax.Axis) and isinstance(self.In, hax.Axis):
|
|
78
|
-
return self
|
|
79
|
-
|
|
80
|
-
weight = self.weight
|
|
81
|
-
bias = self.bias
|
|
82
|
-
|
|
83
|
-
new_Out = hax.flatten_axes(self.Out, "__OUT__")
|
|
84
|
-
new_In = hax.flatten_axes(self.In, "__IN__")
|
|
85
|
-
|
|
86
|
-
if weight is not None and weight.array is not None:
|
|
87
|
-
out_first = self._out_first
|
|
88
|
-
weight = weight.flatten_axes(self.Out, new_Out).flatten_axes(self.In, new_In)
|
|
89
|
-
|
|
90
|
-
if out_first:
|
|
91
|
-
weight = weight.rearrange((..., "__OUT__", "__IN__"))
|
|
92
|
-
else:
|
|
93
|
-
weight = weight.rearrange((..., "__IN__", "__OUT__"))
|
|
94
|
-
|
|
95
|
-
if isinstance(bias, NamedArray):
|
|
96
|
-
bias = bias.flatten_axes(self.Out, new_Out)
|
|
97
|
-
|
|
98
|
-
return dataclasses.replace(self, weight=weight, bias=bias, In=new_In, Out=new_Out)
|
|
99
|
-
|
|
100
|
-
def unflatten_from_export(self: Mod, template: Mod) -> Mod:
|
|
101
|
-
weight = self.weight
|
|
102
|
-
bias = self.bias
|
|
103
|
-
|
|
104
|
-
if (template.In, template.Out) == (self.In, self.Out):
|
|
105
|
-
return self
|
|
106
|
-
|
|
107
|
-
if weight.array is not None:
|
|
108
|
-
weight = weight.unflatten_axis("__OUT__", template.Out).unflatten_axis("__IN__", template.In)
|
|
109
|
-
weight = weight.rearrange(template.weight.axes)
|
|
110
|
-
|
|
111
|
-
if isinstance(bias, NamedArray):
|
|
112
|
-
bias = bias.unflatten_axis("__OUT__", template.Out)
|
|
113
|
-
bias = bias.rearrange(template.bias.axes)
|
|
114
|
-
|
|
115
|
-
return dataclasses.replace(template, weight=weight, bias=bias)
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
def _out_first(self):
|
|
119
|
-
"""
|
|
120
|
-
Returns: bool: Whether the output axes are first in the weight matrix
|
|
121
|
-
"""
|
|
122
|
-
# We do it this way because of scan layers
|
|
123
|
-
if isinstance(self.Out, hax.Axis):
|
|
124
|
-
return self.weight.axes[-1] != self.Out
|
|
125
|
-
else:
|
|
126
|
-
return self.weight.axes[-len(self.Out) :] != self.Out
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|