File size: 9,938 Bytes
cf0f656 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | """Pinned NVIDIA Mamba-2 8B source loader and exact tokenizer.
Execution uses state-spaces/mamba (Apache-2.0). The Megatron key mapping follows
NVIDIA's public checkpoint layout. Source BF16 weights are cast to FP16 for the
native quality reference; this is not native Megatron BF16 parity.
"""
from __future__ import annotations
import argparse
import enum
import gc
import hashlib
import importlib
import json
import platform
import re
from pathlib import Path
import torch
from torch import nn
SOURCE_CHECKPOINT_SHA256 = "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb"
TOKENIZER_SHA256 = "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09"
TOKENIZER_FILENAME = "mt_nlg_plus_multilingual_ja_zh_the_stack_frac_015_256k.model"
MODEL_CONFIG = {
"d_model": 4096, "d_intermediate": 0, "n_layer": 56, "vocab_size": 256000,
"ssm_cfg": {"layer": "Mamba2", "d_state": 128, "d_conv": 4, "expand": 2,
"headdim": 64, "ngroups": 8, "chunk_size": 128,
"rmsnorm": True, "norm_before_gate": False,
"use_mem_eff_path": False},
"rms_norm": True, "residual_in_fp32": False, "fused_add_norm": False,
"pad_vocab_size_multiple": 128, "tie_embeddings": False,
}
_VERIFIED_FILES = {}
class _MegatronModelType(enum.Enum):
# Passive metadata enum from NVIDIA Megatron-LM core_r0.10.0/core/enums.py.
encoder_or_decoder = 1
encoder_and_decoder = 2
retro_encoder = 3
retro_decoder = 4
def sha256_file(path):
digest = hashlib.sha256()
with Path(path).open("rb") as stream:
for chunk in iter(lambda: stream.read(8 * 1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def token_digest(ids):
import numpy as np
return hashlib.sha256(np.asarray(ids, dtype="<i8").tobytes()).hexdigest()
def environment_receipt():
import importlib.metadata
packages = {}
for name in ("torch", "mamba-ssm", "numpy", "triton", "datasets", "sentencepiece"):
try:
packages[name] = importlib.metadata.version(name)
except importlib.metadata.PackageNotFoundError:
packages[name] = None
return {"python": platform.python_version(), "packages": packages,
"cuda_runtime": torch.version.cuda,
"gpu": torch.cuda.get_device_name() if torch.cuda.is_available() else None,
"tf32_matmul": torch.backends.cuda.matmul.allow_tf32}
def gpu_memory_receipt():
if not torch.cuda.is_available():
return None
return {"peak_allocated_bytes": torch.cuda.max_memory_allocated(),
"peak_reserved_bytes": torch.cuda.max_memory_reserved(),
"current_allocated_bytes": torch.cuda.memory_allocated(),
"note": "Native FP16 quality runtime; stored W4 matrices expand to FP16 GPU weights"}
def checkpoint_path(source_dir):
directory = Path(source_dir)
if directory.is_file():
return directory
for relative in ("model_optim_rng.pt", "release/mp_rank_00/model_optim_rng.pt"):
candidate = directory / relative
if candidate.is_file():
return candidate
raise FileNotFoundError(f"NVIDIA checkpoint missing under {directory}")
def normalize_source_key(key):
"""Anchored mapping: decoder.layers.1 must never match layer 10 or 11."""
special = {"embedding.word_embeddings.weight": "backbone.embedding.weight",
"decoder.final_norm.weight": "backbone.norm_f.weight",
"output_layer.weight": "lm_head.weight"}
if key in special:
return special[key]
match = re.fullmatch(r"decoder\.layers\.(\d+)\.(.+)", key)
if match:
return f"backbone.layers.{int(match[1])}.{match[2]}"
# The loader can inspect an already mapped state without changing its keys.
if key.startswith("backbone.") or key == "lm_head.weight":
return key.replace("backbone.embeddings.", "backbone.embedding.", 1)
raise ValueError(f"Unrecognized model tensor key: {key}")
def normalize_source_state(state):
result = {}
for name, value in state.items():
if not isinstance(value, torch.Tensor):
raise TypeError(f"Unexpected non-tensor model entry {name}: {type(value).__name__}")
target = normalize_source_key(name)
if target in result:
raise ValueError(f"Duplicate normalized tensor: {target}")
result[target] = value
return result
def load_source_state(source_dir, expected_sha256=SOURCE_CHECKPOINT_SHA256):
"""Load a pinned official CPU checkpoint without an unrestricted unpickler.
Megatron stores an argparse namespace, a model-kind enum, and NumPy RNG state.
Only those inspected passive metadata types are additionally allowed.
Unexpected pickle globals fail closed. mmap avoids a second disk copy.
"""
path = checkpoint_path(source_dir)
stat = path.stat()
cache_key = (str(path.resolve()), stat.st_size, stat.st_mtime_ns)
digest = _VERIFIED_FILES.get(cache_key)
if digest is None:
digest = sha256_file(path)
_VERIFIED_FILES[cache_key] = digest
if digest != expected_sha256:
raise ValueError(f"Source checkpoint SHA-256 mismatch: {digest}")
import numpy as np
reconstruct = importlib.import_module("numpy.core.multiarray")._reconstruct
allowed = [argparse.Namespace, np.ndarray, np.dtype, type(np.dtype("uint32")),
(reconstruct, "numpy.core.multiarray._reconstruct"),
(_MegatronModelType, "megatron.core.enums.ModelType")]
try:
with torch.serialization.safe_globals(allowed):
checkpoint = torch.load(path, map_location="cpu", mmap=True, weights_only=True)
except Exception as error:
unsafe = torch.serialization.get_unsafe_globals_in_checkpoint(path)
raise RuntimeError(f"Safe checkpoint loading failed; inspect globals {unsafe}") from error
state = checkpoint["model"] if "model" in checkpoint else checkpoint
result = normalize_source_state(state)
del checkpoint
return result
def make_model(config=None, device="meta", dtype=torch.float16):
from mamba_ssm.models.config_mamba import MambaConfig
from mamba_ssm.models.mixer_seq_simple import MambaLMHeadModel
config = json.loads(json.dumps(MODEL_CONFIG if config is None else config))
model = MambaLMHeadModel(MambaConfig(**config), device=device, dtype=dtype)
for block in model.backbone.layers:
block.mixer.use_mem_eff_path = False
expected_group_size = block.mixer.d_ssm // block.mixer.ngroups
if block.mixer.norm.group_size != expected_group_size:
raise RuntimeError("Runtime does not implement grouped gated RMSNorm")
return model.eval().requires_grad_(False)
def load_source_model(source_dir, device="cuda", dtype=torch.float16,
expected_sha256=SOURCE_CHECKPOINT_SHA256):
model = make_model()
state = load_source_state(source_dir, expected_sha256=expected_sha256)
model.load_state_dict(state, strict=True, assign=True)
del state
model = model.to(device=device, dtype=dtype)
if model.backbone.embedding.weight.data_ptr() == model.lm_head.weight.data_ptr():
raise RuntimeError("8B source requires independent embedding and output head")
model._package_receipt = {"format": "original BF16 checkpoint cast to requested dtype",
"source_checkpoint_sha256": expected_sha256,
"parameter_count": sum(p.numel() for p in model.parameters())}
return model.eval().requires_grad_(False)
class SentencePieceTokenizer:
"""NVIDIA GPTSentencePiece token IDs without automatic BOS/EOS insertion."""
def __init__(self, path):
import sentencepiece as spm
path = Path(path)
if path.is_dir():
path = path / TOKENIZER_FILENAME
self.path = path
self.processor = spm.SentencePieceProcessor(model_file=str(path))
self.eos_token_id = self.processor.eos_id()
self.bos_token_id = self.processor.bos_id()
self.pad_token_id = self.processor.pad_id()
self.vocab_size = self.processor.vocab_size()
self.sha256 = sha256_file(path)
if self.sha256 != TOKENIZER_SHA256:
raise ValueError("Tokenizer does not match the pinned original NVIDIA SentencePiece model")
def encode(self, text, add_special_tokens=False):
if add_special_tokens:
raise ValueError("This protocol never inserts BOS/EOS automatically")
return self.processor.encode_as_ids(text)
def decode(self, ids, skip_special_tokens=False):
if isinstance(ids, torch.Tensor):
ids = ids.detach().cpu().tolist()
if skip_special_tokens:
ids = [i for i in ids if i not in (self.eos_token_id, self.bos_token_id, self.pad_token_id)]
return self.processor.decode_ids(ids)
def make_cache(model, max_seqlen, batch_size=1, state_dtype=torch.float16):
"""Native one-token cache: state is rounded to the requested dtype each step."""
from mamba_ssm.utils.generation import InferenceParams
cache = InferenceParams(max_seqlen=max_seqlen, max_batch_size=batch_size)
cache.key_value_memory_dict = model.allocate_inference_cache(
batch_size, max_seqlen, dtype=state_dtype)
return cache
def cache_bytes(cache):
return sum(tensor.numel() * tensor.element_size()
for pair in cache.key_value_memory_dict.values() for tensor in pair)
@torch.inference_mode()
def backbone_tokenwise(model, ids, state_dtype=torch.float16):
cache = make_cache(model, ids.shape[1], ids.shape[0], state_dtype)
result = []
for position in range(ids.shape[1]):
cache.seqlen_offset = position
result.append(model.backbone(ids[:, position:position+1], inference_params=cache))
return torch.cat(result, dim=1), cache
load_model = load_source_model
|