model: Support Hybrid Mamba2 NemotronHForCausalLM (nvidia/NVIDIA-Nemotron-Nano-9B-v2) (#10909)
Signed-off-by: Netanel Haber <nhaber@nvidia.com>
This commit is contained in:
@@ -15,6 +15,9 @@ limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from sglang.srt.configs.mamba_utils import Mamba2CacheParams
|
||||
from sglang.srt.layers.attention.nsa import index_buf_accessor
|
||||
from sglang.srt.layers.attention.nsa.quant_k_cache import quantize_k_cache
|
||||
from sglang.srt.torch_memory_saver_adapter import TorchMemorySaverAdapter
|
||||
@@ -109,17 +112,38 @@ class ReqToTokenPool:
|
||||
|
||||
|
||||
class MambaPool:
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class State:
|
||||
conv: torch.Tensor
|
||||
temporal: torch.Tensor
|
||||
|
||||
def at_layer_idx(self, layer: int):
|
||||
return type(self)(**{k: v[layer] for k, v in vars(self).items()})
|
||||
|
||||
def mem_usage_bytes(self):
|
||||
return sum(get_tensor_size_bytes(t) for t in vars(self).values())
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class SpeculativeState(State):
|
||||
intermediate_ssm: torch.Tensor
|
||||
intermediate_conv_window: torch.Tensor
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
size: int,
|
||||
conv_dtype: torch.dtype,
|
||||
ssm_dtype: torch.dtype,
|
||||
num_mamba_layers: int,
|
||||
conv_state_shape: Tuple[int, int],
|
||||
temporal_state_shape: Tuple[int, int],
|
||||
cache_params: "Mamba2CacheParams",
|
||||
device: str,
|
||||
speculative_num_draft_tokens: Optional[int] = None,
|
||||
):
|
||||
conv_state_shape = cache_params.shape.conv
|
||||
temporal_state_shape = cache_params.shape.temporal
|
||||
conv_dtype = cache_params.dtype.conv
|
||||
ssm_dtype = cache_params.dtype.temporal
|
||||
num_mamba_layers = len(cache_params.layers)
|
||||
|
||||
# assume conv_state = (dim, state_len)
|
||||
assert conv_state_shape[0] > conv_state_shape[1]
|
||||
conv_state = torch.zeros(
|
||||
size=(num_mamba_layers, size + 1) + conv_state_shape,
|
||||
dtype=conv_dtype,
|
||||
@@ -158,11 +182,11 @@ class MambaPool:
|
||||
dtype=conv_dtype,
|
||||
device="cuda",
|
||||
)
|
||||
self.mamba_cache = (
|
||||
conv_state,
|
||||
temporal_state,
|
||||
intermediate_ssm_state_cache,
|
||||
intermediate_conv_window_cache,
|
||||
self.mamba_cache = self.SpeculativeState(
|
||||
conv=conv_state,
|
||||
temporal=temporal_state,
|
||||
intermediate_ssm=intermediate_ssm_state_cache,
|
||||
intermediate_conv_window=intermediate_conv_window_cache,
|
||||
)
|
||||
logger.info(
|
||||
f"Mamba Cache is allocated. "
|
||||
@@ -172,7 +196,7 @@ class MambaPool:
|
||||
f"intermediate_conv_window_cache size: {get_tensor_size_bytes(intermediate_conv_window_cache) / GB:.2f}GB "
|
||||
)
|
||||
else:
|
||||
self.mamba_cache = (conv_state, temporal_state)
|
||||
self.mamba_cache = self.State(conv=conv_state, temporal=temporal_state)
|
||||
logger.info(
|
||||
f"Mamba Cache is allocated. "
|
||||
f"conv_state size: {get_tensor_size_bytes(conv_state) / GB:.2f}GB, "
|
||||
@@ -180,16 +204,14 @@ class MambaPool:
|
||||
)
|
||||
self.size = size
|
||||
self.free_slots = list(range(size))
|
||||
self.mem_usage = self.get_mamba_size() / GB
|
||||
self.mem_usage = self.mamba_cache.mem_usage_bytes() / GB
|
||||
|
||||
def get_mamba_params_all_layers(self):
|
||||
return [self.mamba_cache[i] for i in range(len(self.mamba_cache))]
|
||||
def get_speculative_mamba2_params_all_layers(self) -> SpeculativeState:
|
||||
assert isinstance(self.mamba_cache, self.SpeculativeState)
|
||||
return self.mamba_cache
|
||||
|
||||
def get_mamba_params(self, layer_id: int):
|
||||
return [self.mamba_cache[i][layer_id] for i in range(len(self.mamba_cache))]
|
||||
|
||||
def get_mamba_size(self):
|
||||
return sum(get_tensor_size_bytes(t) for t in self.mamba_cache)
|
||||
def mamba2_layer_cache(self, layer_id: int):
|
||||
return self.mamba_cache.at_layer_idx(layer_id)
|
||||
|
||||
def available_size(self):
|
||||
return len(self.free_slots)
|
||||
@@ -208,7 +230,9 @@ class MambaPool:
|
||||
self.free_slots.append(free_index)
|
||||
else:
|
||||
self.free_slots.extend(free_index)
|
||||
self.mamba_cache[0][:, free_index] = self.mamba_cache[1][:, free_index] = 0
|
||||
self.mamba_cache.conv[:, free_index] = self.mamba_cache.temporal[
|
||||
:, free_index
|
||||
] = 0
|
||||
|
||||
def clear(self):
|
||||
self.free_slots = list(range(self.size))
|
||||
@@ -219,16 +243,13 @@ class HybridReqToTokenPool(ReqToTokenPool):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
size: int,
|
||||
max_context_len: int,
|
||||
device: str,
|
||||
enable_memory_saver: bool,
|
||||
conv_dtype: torch.dtype,
|
||||
ssm_dtype: torch.dtype,
|
||||
mamba_layers: List[int],
|
||||
conv_state_shape: Tuple[int, int],
|
||||
temporal_state_shape: Tuple[int, int],
|
||||
speculative_num_draft_tokens: int,
|
||||
cache_params: "Mamba2CacheParams",
|
||||
speculative_num_draft_tokens: int = None,
|
||||
):
|
||||
super().__init__(
|
||||
size=size,
|
||||
@@ -238,16 +259,12 @@ class HybridReqToTokenPool(ReqToTokenPool):
|
||||
)
|
||||
|
||||
self.mamba_pool = MambaPool(
|
||||
size,
|
||||
conv_dtype,
|
||||
ssm_dtype,
|
||||
len(mamba_layers),
|
||||
conv_state_shape,
|
||||
temporal_state_shape,
|
||||
device,
|
||||
speculative_num_draft_tokens,
|
||||
size=size,
|
||||
cache_params=cache_params,
|
||||
device=device,
|
||||
speculative_num_draft_tokens=speculative_num_draft_tokens,
|
||||
)
|
||||
self.mamba_map = {layer_id: i for i, layer_id in enumerate(mamba_layers)}
|
||||
self.mamba_map = {layer_id: i for i, layer_id in enumerate(cache_params.layers)}
|
||||
|
||||
self.device = device
|
||||
self.req_index_to_mamba_index_mapping: torch.Tensor = torch.zeros(
|
||||
@@ -287,12 +304,12 @@ class HybridReqToTokenPool(ReqToTokenPool):
|
||||
def get_mamba_indices(self, req_indices: torch.Tensor) -> torch.Tensor:
|
||||
return self.req_index_to_mamba_index_mapping[req_indices]
|
||||
|
||||
def get_mamba_params(self, layer_id: int):
|
||||
def mamba2_layer_cache(self, layer_id: int):
|
||||
assert layer_id in self.mamba_map
|
||||
return self.mamba_pool.get_mamba_params(self.mamba_map[layer_id])
|
||||
return self.mamba_pool.mamba2_layer_cache(self.mamba_map[layer_id])
|
||||
|
||||
def get_mamba_params_all_layers(self):
|
||||
return self.mamba_pool.get_mamba_params_all_layers()
|
||||
def get_speculative_mamba2_params_all_layers(self) -> MambaPool.SpeculativeState:
|
||||
return self.mamba_pool.get_speculative_mamba2_params_all_layers()
|
||||
|
||||
# For chunk prefill, we can not free mamba cache, we need use it in the future
|
||||
def free(self, free_index: Union[int, List[int]], free_mamba_cache: bool = True):
|
||||
|
||||
Reference in New Issue
Block a user