|
41 | 41 | from maxtext.layers.quantizations import AqtQuantization as Quant |
42 | 42 | from maxtext.models import ( |
43 | 43 | deepseek, |
| 44 | + deepseek4, |
44 | 45 | deepseek_batchsplit, |
45 | 46 | deepseek_batchsplit_fp8, |
46 | 47 | gemma, |
@@ -467,6 +468,10 @@ def get_decoder_layers(self): |
467 | 468 | deepseek.DeepSeekDenseLayerToLinen, |
468 | 469 | deepseek.DeepSeekMoELayerToLinen, |
469 | 470 | ] |
| 471 | + case DecoderBlockType.DEEPSEEK4: |
| 472 | + return ( |
| 473 | + [deepseek4.DeepSeek4ScannableBlockToLinen] if self.config.scan_layers else [deepseek4.DeepSeek4LayerToLinen] |
| 474 | + ) |
470 | 475 | case DecoderBlockType.GEMMA: |
471 | 476 | return [gemma.GemmaDecoderLayerToLinen] |
472 | 477 | case DecoderBlockType.GEMMA2: |
@@ -632,6 +637,7 @@ def get_norm_layer(self, num_features: int): |
632 | 637 | DecoderBlockType.MISTRAL, |
633 | 638 | DecoderBlockType.MIXTRAL, |
634 | 639 | DecoderBlockType.DEEPSEEK, |
| 640 | + DecoderBlockType.DEEPSEEK4, |
635 | 641 | DecoderBlockType.GEMMA, |
636 | 642 | DecoderBlockType.GEMMA2, |
637 | 643 | DecoderBlockType.GEMMA3, |
@@ -1061,6 +1067,17 @@ def __call__( |
1061 | 1067 | previous_chunk, |
1062 | 1068 | slot, |
1063 | 1069 | ) |
| 1070 | + elif cfg.decoder_block == DecoderBlockType.DEEPSEEK4: |
| 1071 | + y = self._apply_deepseek4_scanned_blocks( |
| 1072 | + y, |
| 1073 | + decoder_segment_ids, |
| 1074 | + decoder_positions, |
| 1075 | + deterministic, |
| 1076 | + model_mode, |
| 1077 | + previous_chunk, |
| 1078 | + slot, |
| 1079 | + decoder_input_tokens, |
| 1080 | + ) |
1064 | 1081 | else: |
1065 | 1082 | RemattedBlockLayer = RemattedBlockLayers[0] |
1066 | 1083 | scan_length = int(cfg.num_decoder_layers / cfg.inhomogeneous_layer_cycle_interval) |
@@ -1195,7 +1212,7 @@ def __call__( |
1195 | 1212 | "is_nope_layer": llama4.determine_is_nope_layer(lyr, self.config.nope_layer_interval), |
1196 | 1213 | "is_moe_layer": llama4.determine_is_moe_layer(lyr, self.config.interleave_moe_layer_step), |
1197 | 1214 | } |
1198 | | - if cfg.decoder_block in (DecoderBlockType.QWEN3_NEXT, DecoderBlockType.QWEN3_5): |
| 1215 | + if cfg.decoder_block in (DecoderBlockType.QWEN3_NEXT, DecoderBlockType.QWEN3_5, DecoderBlockType.DEEPSEEK4): |
1199 | 1216 | layer_kwargs = {"layer_idx": lyr} |
1200 | 1217 | kv_cache = None |
1201 | 1218 | if kv_caches is not None: |
@@ -1423,6 +1440,97 @@ def _apply_gemma4_scanned_blocks( |
1423 | 1440 |
|
1424 | 1441 | return y |
1425 | 1442 |
|
| 1443 | + def _apply_deepseek4_scanned_blocks( |
| 1444 | + self, |
| 1445 | + y, |
| 1446 | + decoder_segment_ids, |
| 1447 | + decoder_positions, |
| 1448 | + deterministic, |
| 1449 | + model_mode, |
| 1450 | + previous_chunk, |
| 1451 | + slot, |
| 1452 | + decoder_input_tokens, |
| 1453 | + ): |
| 1454 | + """Applies DeepSeek V4 scanned decoder blocks. |
| 1455 | +
|
| 1456 | + DeepSeek V4 has some number of prefix layers (defined by `first_num_hash_layers`) |
| 1457 | + that use static Hash Routing. The remaining layers alternate `compress_ratio=128` (HCA) |
| 1458 | + and `compress_ratio=4` (CSA) and are evaluated in a single `nn.scan` block. |
| 1459 | +
|
| 1460 | + For DeepSeek4-Flash (43 hidden layers total): |
| 1461 | + - 3 Prefix layers (Indices 0, 1, 2) |
| 1462 | + - 40 Scanned layers: 20 perfectly repeating chunks of [128, 4] |
| 1463 | + """ |
| 1464 | + |
| 1465 | + cfg = self.config |
| 1466 | + mesh = self.mesh |
| 1467 | + |
| 1468 | + broadcast_args = ( |
| 1469 | + decoder_segment_ids, |
| 1470 | + decoder_positions, |
| 1471 | + deterministic, |
| 1472 | + model_mode, |
| 1473 | + slot, |
| 1474 | + previous_chunk, |
| 1475 | + ) |
| 1476 | + |
| 1477 | + layer_call_kwargs = { |
| 1478 | + "previous_chunk": previous_chunk, |
| 1479 | + "slot": slot, |
| 1480 | + "decoder_input_tokens": decoder_input_tokens, |
| 1481 | + } |
| 1482 | + |
| 1483 | + # 1. Prefix Unrolling |
| 1484 | + # These layers use Hash Routing. |
| 1485 | + num_hash_layers = cfg.first_num_hash_layers |
| 1486 | + for layer_idx in range(num_hash_layers): |
| 1487 | + prefix_layer = deepseek4.DeepSeek4LayerToLinen( |
| 1488 | + config=cfg, |
| 1489 | + mesh=mesh, |
| 1490 | + name=f"layers_{layer_idx}", |
| 1491 | + quant=self.quant, |
| 1492 | + model_mode=self.model_mode, |
| 1493 | + layer_idx=layer_idx, |
| 1494 | + ) |
| 1495 | + y, _ = prefix_layer( |
| 1496 | + y, |
| 1497 | + decoder_segment_ids, |
| 1498 | + decoder_positions, |
| 1499 | + deterministic, |
| 1500 | + model_mode, |
| 1501 | + **layer_call_kwargs, |
| 1502 | + ) |
| 1503 | + |
| 1504 | + # 2. Chunked Scanning |
| 1505 | + # The remaining layers perfectly alternate HCA (128) and CSA (4). |
| 1506 | + num_remaining_layers = cfg.num_decoder_layers - num_hash_layers |
| 1507 | + num_full_blocks = num_remaining_layers // 2 |
| 1508 | + |
| 1509 | + if num_full_blocks > 0: |
| 1510 | + ScannableBlockToLinen = deepseek4.DeepSeek4ScannableBlockToLinen |
| 1511 | + policy = self.get_remat_policy() |
| 1512 | + RemattedDeepSeek4Block = self.set_remat_policy([ScannableBlockToLinen], policy)[0] |
| 1513 | + |
| 1514 | + y, _ = nn.scan( |
| 1515 | + RemattedDeepSeek4Block, |
| 1516 | + variable_axes={ |
| 1517 | + "params": cfg.param_scan_axis, |
| 1518 | + "cache": 0, |
| 1519 | + "intermediates": 0, |
| 1520 | + "aqt": 0, |
| 1521 | + "_overwrite_with_gradient": 0, |
| 1522 | + }, |
| 1523 | + split_rngs={"params": True, "dropout": cfg.enable_dropout}, |
| 1524 | + in_axes=(nn.broadcast,) * len(broadcast_args), |
| 1525 | + length=num_full_blocks, |
| 1526 | + metadata_params={ |
| 1527 | + nn.PARTITION_NAME: "layers", |
| 1528 | + "abstract_init": False, |
| 1529 | + }, |
| 1530 | + )(config=cfg, mesh=mesh, quant=self.quant, model_mode=model_mode, name="scanned_blocks",)(y, *broadcast_args) |
| 1531 | + |
| 1532 | + return y |
| 1533 | + |
1426 | 1534 | def _apply_gemma4_small_layers( |
1427 | 1535 | self, |
1428 | 1536 | y, |
|
0 commit comments