Skip to content

Commit ef34fac

Browse files
committed
feat/fix: QLoRA support and NNX Decoder Sharding Fixes
1 parent cf9b093 commit ef34fac

9 files changed

Lines changed: 331 additions & 77 deletions

File tree

src/dependencies/extra_deps/tpu_post_train_overrides.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ flax==0.12.4
33
fsspec==2026.2.0
44
gcsfs==2026.2.0
55
google-metrax>=0.2.3
6-
optax==0.2.6
6+
jax==0.10.1
7+
optax==0.2.6
8+
qwix==0.1.8

src/dependencies/requirements/generated_requirements/tpu-post-train-requirements.txt

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
# See https://maxtext.readthedocs.io/en/latest/development/update_dependencies.html for details.
33

44
absl-py>=2.4.0
5-
accelerate>=1.13.0
5+
accelerate>=1.14.0
66
aiofiles>=25.1.0
77
aiohappyeyeballs>=2.6.2
88
aiohttp>=3.14.1
99
aiohttp-cors>=0.1.0
1010
aiosignal>=1.4.0
1111
annotated-doc>=0.0.4
1212
annotated-types>=0.7.0
13-
anthropic>=0.109.1
13+
anthropic>=0.112.0
1414
antlr4-python3-runtime>=4.9.3
15-
anyio>=4.13.0
15+
anyio>=4.14.1
1616
apache-tvm-ffi>=0.1.12
1717
appnope>=0.1.4 ; sys_platform == 'darwin'
1818
aqtp>=0.9.0
@@ -24,7 +24,7 @@ astunparse>=1.6.3
2424
attrs>=26.1.0
2525
auditwheel>=6.6.0
2626
black>=25.12.0
27-
blake3>=1.0.8
27+
blake3>=1.0.9
2828
boto>=2.35.0
2929
boto3>=1.34.0
3030
botocore>=1.34.63
@@ -36,8 +36,8 @@ cffi>=2.0.0 ; implementation_name == 'pypy' or platform_python_implementation !=
3636
cfgv>=3.5.0
3737
charset-normalizer>=3.4.7
3838
cheroot>=11.1.2
39-
chex>=0.1.91
40-
click>=8.4.1
39+
chex>=0.1.92
40+
click>=8.4.2
4141
cloud-accelerator-diagnostics>=0.1.1
4242
cloudpickle>=3.1.2
4343
clu>=0.0.12
@@ -47,7 +47,7 @@ colorful>=0.0.0
4747
comm>=0.2.3
4848
compressed-tensors>=0.17.0
4949
contourpy>=1.3.3
50-
cryptography>=48.0.1
50+
cryptography>=49.0.0
5151
cycler>=0.12.1
5252
dataclasses>=0.5
5353
dataclasses-json>=0.0.1
@@ -57,12 +57,12 @@ decorator>=5.3.1
5757
depyf>=0.20.0
5858
dill>=0.4.1
5959
diskcache>=5.6.3
60-
distlib>=0.4.2
60+
distlib>=0.4.3
6161
distro>=1.9.0
6262
dm-tree>=0.1.10
6363
dnspython>=2.0.0
6464
docstring-parser>=0.18.0
65-
drjax>=0.1.4
65+
drjax>=0.2.0
6666
editdistance>=0.8.1
6767
einops>=0.8.2
6868
einshape>=1.0
@@ -71,7 +71,7 @@ entrypoints>=0.4
7171
etils>=1.14.0
7272
execnet>=2.1.2
7373
executing>=2.2.1
74-
fastapi>=0.136.3
74+
fastapi>=0.138.0
7575
fastapi-cli>=0.0.8
7676
fastapi-cloud-cli>=0.1.2
7777
fastar>=0.9.0
@@ -88,28 +88,28 @@ gepa>=0.1.1
8888
gguf>=0.19.0
8989
google-api-core>=2.31.0
9090
google-api-python-client>=2.197.0
91-
google-auth>=2.53.0
91+
google-auth>=2.55.0
9292
google-auth-httplib2>=0.4.0
9393
google-auth-oauthlib>=1.4.0
94-
google-cloud-aiplatform>=1.157.0
94+
google-cloud-aiplatform>=1.158.0
9595
google-cloud-appengine-logging>=1.10.0
9696
google-cloud-audit-log>=0.6.0
97-
google-cloud-bigquery>=3.41.0
97+
google-cloud-bigquery>=3.42.1
9898
google-cloud-core>=2.6.0
9999
google-cloud-logging>=3.16.0
100100
google-cloud-mldiagnostics>=1.0.3
101101
google-cloud-monitoring>=2.31.0
102-
google-cloud-resource-manager>=1.17.0
103-
google-cloud-storage>=3.11.0
102+
google-cloud-resource-manager>=1.18.0
103+
google-cloud-storage>=3.12.0
104104
google-cloud-storage-control>=1.12.0
105105
google-crc32c>=1.8.0
106-
google-genai>=2.8.0
106+
google-genai>=2.10.0
107107
google-metrax>=0.2.3
108108
google-pasta>=0.2.0
109109
google-resumable-media>=2.10.0
110110
google-tunix>=0.1.3
111111
googleapis-common-protos>=1.75.0
112-
grain>=0.2.17
112+
grain>=0.2.18
113113
grpc-google-iam-v1>=0.14.4
114114
grpcio>=1.80.0
115115
grpcio-status>=1.80.0
@@ -124,7 +124,7 @@ httplib2>=0.31.2
124124
httptools>=0.8.0
125125
httpx>=0.28.1
126126
httpx-sse>=0.1.0
127-
huggingface-hub>=1.18.0
127+
huggingface-hub>=1.20.1
128128
humanize>=4.15.0
129129
hypothesis>=6.151.9
130130
identify>=2.6.19
@@ -142,7 +142,7 @@ isort>=8.0.1
142142
jaraco-functools>=4.5.0
143143
jax>=0.10.1
144144
jaxlib>=0.10.1
145-
jaxtyping>=0.3.10
145+
jaxtyping>=0.3.11
146146
jedi>=0.20.0
147147
jinja2>=3.1.6
148148
jiter>=0.15.0
@@ -154,7 +154,7 @@ jupyter-client>=8.9.1
154154
jupyter-core>=5.9.1
155155
jupyterlab-widgets>=3.0.16
156156
kagglehub>=1.0.2
157-
kagglesdk>=0.1.28
157+
kagglesdk>=0.1.30
158158
keras>=3.14.1
159159
kiwisolver>=1.5.0
160160
lark>=1.2.2
@@ -176,14 +176,14 @@ matplotlib-inline>=0.2.2
176176
mccabe>=0.7.0
177177
mcp>=0.9.1
178178
mdurl>=0.1.2
179-
mistral-common>=1.11.3
179+
mistral-common>=1.11.4
180180
ml-collections>=1.1.0
181181
ml-dtypes>=0.5.4
182-
ml-goodput-measurement>=0.0.16
183-
model-hosting-container-standards>=0.1.15
182+
ml-goodput-measurement>=0.2.0
183+
model-hosting-container-standards>=0.1.16
184184
more-itertools>=11.1.0
185185
mpmath>=1.3.0
186-
msgpack>=1.1.2
186+
msgpack>=1.2.1
187187
msgspec>=0.21.1
188188
multidict>=6.7.1
189189
multiprocess>=0.70.19
@@ -200,26 +200,26 @@ numba>=0.65.1
200200
numpy>=2.1.3
201201
numpy-typing-compat>=20251206.2.1
202202
oauthlib>=3.3.1
203-
omegaconf>=2.3.0
204-
openai>=2.41.1
203+
omegaconf>=2.3.1
204+
openai>=2.44.0
205205
openai-harmony>=0.0.8
206206
opencensus>=0.0.1
207207
opencv-python-headless>=4.13.0.90
208-
opentelemetry-api>=1.42.1
209-
opentelemetry-exporter-otlp>=1.42.0
210-
opentelemetry-exporter-otlp-proto-common>=1.42.0
211-
opentelemetry-exporter-otlp-proto-grpc>=1.42.0
212-
opentelemetry-exporter-otlp-proto-http>=1.42.0
208+
opentelemetry-api>=1.43.0
209+
opentelemetry-exporter-otlp>=1.43.0
210+
opentelemetry-exporter-otlp-proto-common>=1.43.0
211+
opentelemetry-exporter-otlp-proto-grpc>=1.43.0
212+
opentelemetry-exporter-otlp-proto-http>=1.43.0
213213
opentelemetry-exporter-prometheus>=0.29b0
214-
opentelemetry-proto>=1.42.0
215-
opentelemetry-sdk>=1.42.1
216-
opentelemetry-semantic-conventions>=0.63b1
214+
opentelemetry-proto>=1.43.0
215+
opentelemetry-sdk>=1.43.0
216+
opentelemetry-semantic-conventions>=0.64b0
217217
opentelemetry-semantic-conventions-ai>=0.4.1
218218
opt-einsum>=3.4.0
219219
optax>=0.2.6
220220
optree>=0.19.1
221221
optype>=0.17.1
222-
orbax-checkpoint>=0.12.0
222+
orbax-checkpoint>=0.12.1
223223
orbax-export>=0.0.8
224224
outlines-core>=0.2.14
225225
packaging>=26.2
@@ -229,7 +229,7 @@ parameterized>=0.9.0
229229
parso>=0.8.7
230230
partial-json-parser>=0.2.1.1.post7
231231
pathspec>=1.1.1
232-
pathwaysutils>=0.1.8
232+
pathwaysutils>=0.1.9
233233
peft>=0.19.1
234234
perfetto>=0.56.0
235235
pexpect>=4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32'
@@ -239,7 +239,7 @@ pluggy>=1.6.0
239239
portpicker>=1.6.0
240240
pre-commit>=4.6.0
241241
prometheus-client>=0.25.0
242-
prometheus-fastapi-instrumentator>=8.0.0
242+
prometheus-fastapi-instrumentator>=8.0.2
243243
promise>=2.3
244244
prompt-toolkit>=3.0.52
245245
propcache>=0.5.2
@@ -266,24 +266,24 @@ pyelftools>=0.32
266266
pyglove>=0.4.5
267267
pygments>=2.20.0
268268
pyink>=25.12.0
269-
pylint>=4.0.5
269+
pylint>=4.0.6
270270
pynvml>=13.0.1
271-
pyopenssl>=26.2.0
271+
pyopenssl>=26.3.0
272272
pyparsing>=3.3.2
273273
pyproject-hooks>=1.2.0
274274
pytest>=8.4.2
275275
pytest-mock>=3.15.1
276276
pytest-xdist>=3.8.0
277277
python-dateutil>=2.9.0.post0
278-
python-discovery>=1.4.0
278+
python-discovery>=1.4.2
279279
python-dotenv>=1.2.2
280280
python-json-logger>=4.1.0
281281
python-multipart>=0.0.18
282282
pytokens>=0.4.1
283283
pytype>=2024.10.11
284284
pyyaml>=6.0.3
285285
pyzmq>=27.1.0
286-
qwix>=0.1.6
286+
qwix>=0.1.8
287287
ray>=2.55.1
288288
referencing>=0.37.0
289289
regex>=2026.5.9
@@ -317,7 +317,7 @@ sniffio>=1.3.1
317317
sortedcontainers>=2.4.0
318318
sse-starlette>=0.1.0
319319
stack-data>=0.6.3
320-
starlette>=1.2.1
320+
starlette>=1.3.1
321321
supervisor>=4.3.0
322322
sympy>=1.14.0
323323
tabulate>=0.10.0
@@ -343,9 +343,9 @@ torchax>=0.0.11
343343
torchvision==0.26.0+cpu
344344
tornado>=6.5.7
345345
tpu-info>=0.7.1
346-
tqdm>=4.68.2
346+
tqdm>=4.68.3
347347
traitlets>=5.15.1
348-
transformers>=5.11.0
348+
transformers>=5.12.1
349349
treescope>=0.1.10
350350
triton>=3.6.0 ; sys_platform == 'linux'
351351
typeguard>=2.13.3
@@ -357,7 +357,7 @@ uritemplate>=4.2.0
357357
urllib3>=2.7.0
358358
uvicorn>=0.49.0
359359
uvloop>=0.22.1
360-
virtualenv>=21.4.2
360+
virtualenv>=21.5.1
361361
wadler-lindig>=0.1.7
362362
watchfiles>=1.2.0
363363
wcwidth>=0.8.1
@@ -366,10 +366,10 @@ werkzeug>=3.1.8
366366
wheel>=0.47.0
367367
widgetsnbextension>=4.0.15
368368
win32-setctime>=1.2.0 ; sys_platform == 'win32'
369-
wrapt>=2.2.1
370-
xgrammar>=0.2.1
369+
wrapt>=2.2.2
370+
xgrammar>=0.2.2
371371
xprof>=2.22.3
372-
xxhash>=3.7.0
372+
xxhash>=3.7.1
373373
yapf>=0.43.0
374374
yarl>=1.24.2
375375
zipp>=4.1.0

src/maxtext/configs/post_train/sft.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ lora:
2727
lora_rank: 0
2828
lora_alpha: 0.0
2929
lora_module_path: ""
30+
# For QLoRA, set lora_weight_qtype (e.g., "nf4") and optionally lora_tile_size.
31+
lora_weight_qtype: null
32+
lora_tile_size: null
3033
# Optional path to LoRA weights to load before training. Ignored if the current run is resumed.
3134
lora_restore_path: ""
3235

src/maxtext/configs/types.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,9 +1338,19 @@ class LoRA(BaseModel):
13381338
lora_module_path: str = Field(
13391339
"",
13401340
description=(
1341-
"Regex identifying target modules for LoRA, e.g." " '.*q_einsum|.*kv_einsum|.*gate_proj|.*down_proj|.*up_proj'."
1341+
"Regex identifying target NNX modules for LoRA. "
1342+
"Example for standard models: 'decoder/layers/.*(self_attention/(query|out)|mlp/(wi_0|wo))'. "
1343+
"Example for MoE: 'decoder/scanned_blocks/layers.*/.*(MoeBlock_0|shared_experts)/(wi_0|wo)'."
13421344
),
13431345
)
1346+
lora_weight_qtype: str | None = Field(
1347+
None,
1348+
description=("Optional quantization type for QLoRA (e.g., 'nf4'). If set, QLoRA is applied."),
1349+
)
1350+
lora_tile_size: NonNegativeInt | None = Field(
1351+
None,
1352+
description=("Tile size for block-wise quantization. Typically 32 or 64."),
1353+
)
13441354
lora_restore_path: PathStr = Field(
13451355
"",
13461356
description=("Optional path to LoRA weights to load before training. Ignored if the current run is resumed."),

src/maxtext/layers/nnx_decoders.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@
6666
simple_layer,
6767
)
6868
from maxtext.multimodal import utils as mm_utils
69-
from maxtext.utils import max_logging, max_utils, maxtext_utils, sharding
70-
from maxtext.utils.maxtext_utils_nnx import nnx_ensure_scan_leading_axis
69+
from maxtext.utils import max_logging, max_utils, maxtext_utils, maxtext_utils_nnx, sharding
7170
from maxtext.utils.sharding import create_sharding
7271
from maxtext.layers.pipeline import create_nnx_pipeline
7372

@@ -993,6 +992,8 @@ def _extract_matching_state(template, full):
993992
use_kv = kv_caches_stacked is not None
994993

995994
def layer_fn(carry, scanned_vars):
995+
# Ensure metadata rank matches the sliced values
996+
scanned_vars = maxtext_utils_nnx.nnx_remove_scan_axis(scanned_vars, "layers")
996997

997998
# Unpack the sliced variables for THIS layer
998999
if use_kv:
@@ -1065,16 +1066,21 @@ def layer_fn(carry, scanned_vars):
10651066
# inference with vLLM, parameters do not change and we don't need intermediates.
10661067
return current_carry, layers, None
10671068
else:
1068-
params = nnx_ensure_scan_leading_axis(params, length)
1069-
state = nnx_ensure_scan_leading_axis(state, length)
1069+
params = maxtext_utils_nnx.nnx_ensure_scan_leading_axis(params, length)
1070+
state = maxtext_utils_nnx.nnx_ensure_scan_leading_axis(state, length)
10701071

10711072
final_carry, scanned_state = jax.lax.scan(layer_fn_wrapped, x_in, (params, state))
10721073
returned_kv_stacked = None
10731074

1074-
if scan_axis != 0:
1075-
new_params, new_rest = scanned_state.split(nnx.Param, ...)
1076-
new_params = jax.tree.map(lambda x: jnp.moveaxis(x, scan_axis, 0), new_params)
1077-
scanned_state = nnx.merge_state(new_params, new_rest)
1075+
# Ensure metadata rank matches the stacked values
1076+
scanned_state = maxtext_utils_nnx.nnx_add_scan_axis(scanned_state, "layers", 0)
1077+
1078+
if scan_axis != 0:
1079+
new_params, new_rest = scanned_state.split(nnx.Param, ...)
1080+
new_params = maxtext_utils_nnx.nnx_sync_moveaxis(new_params, 0, scan_axis)
1081+
scanned_state = nnx.merge_state(new_params, new_rest)
1082+
1083+
returned_kv_stacked = None
10781084

10791085
if dynamic_graph_init:
10801086
# If graph changed, we need to merge with the new graphdef.

0 commit comments

Comments
 (0)