Files
wehub-resource-sync 770d92cb1f
Lint / lint (push) Has been cancelled
Build Docs / Deploy Docs (push) Has been cancelled
Windows CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:23:58 +08:00

123 lines
4.6 KiB
Python

"""Implementation for Gemma2 architecture."""
import dataclasses
from tvm.relax.frontend import nn
from tvm.relax.frontend.nn import Tensor, op
from mlc_llm.model.gemma.gemma_model import (
GemmaAttention,
GemmaConfig,
GemmaForCausalLM,
GemmaMLP,
GemmaModel,
)
from mlc_llm.nn import PagedKVCache
from mlc_llm.support import logging
from mlc_llm.support import tensor_parallel as tp
logger = logging.getLogger(__name__)
@dataclasses.dataclass
class Gemma2Config(GemmaConfig):
"""Configuration of the Gemma2 model, in addition to the Gemma model"""
# NOTE: We ignore attn_logit_softcapping in the gemma2 implementation for now.
# The Gemma 2 team observed minor differences when soft-capping is removed during inference,
# according to https://huggingface.co/blog/gemma2.
# The soft-capping is also not supported by HuggingFace transformers `Gemma2SdpaAttention`.
attn_logit_softcapping: float = None
final_logit_softcapping: float = None
query_pre_attn_scalar: int = None
sliding_window: int = None
def __post_init__(self):
super().__post_init__()
# NOTE: override the context window size with the Gemma2 sliding window size,
# as the sliding window attention every other layer is yet to be supported.
self.context_window_size = self.sliding_window
class Gemma2Attention(GemmaAttention):
def __init__(self, config: Gemma2Config):
super().__init__(config)
self.scaling_factor = (config.head_dim / config.query_pre_attn_scalar) ** 0.5
class Gemma2DecoderLayer(nn.Module):
def __init__(self, config: Gemma2Config):
rms_norm_eps = config.rms_norm_eps
self.self_attn = Gemma2Attention(config)
self.mlp = GemmaMLP(config)
# Gemma RMSNorm adds 1 to the weights. It is already fused in the loader
self.input_layernorm = nn.RMSNorm(config.hidden_size, -1, rms_norm_eps, bias=False)
self.post_attention_layernorm = nn.RMSNorm(config.hidden_size, -1, rms_norm_eps, bias=False)
self.pre_feedforward_layernorm = nn.RMSNorm(
config.hidden_size, -1, rms_norm_eps, bias=False
)
self.post_feedforward_layernorm = nn.RMSNorm(
config.hidden_size, -1, rms_norm_eps, bias=False
)
def _set_tp():
def _set(layer, hint):
layer.weight.attrs["shard_strategy"] = hint
hd = config.head_dim
q = self.self_attn.num_q_heads * hd
k = self.self_attn.num_kv_heads * hd
v = self.self_attn.num_kv_heads * hd
i = self.mlp.intermediate_size
_set(
self.self_attn.qkv_proj,
tp.ShardSingleDim("_shard_qkv", segs=[q, k, v], dim=0),
)
_set(self.self_attn.o_proj, tp.ShardSingleDim("_shard_o", dim=1))
_set(
self.mlp.gate_up_proj,
tp.ShardSingleDim("_shard_mlp_up", segs=[i, i], dim=0),
)
_set(self.mlp.down_proj, tp.ShardSingleDim("_shard_mlp_down", dim=1))
self.tensor_parallel_shards = config.tensor_parallel_shards
_set_tp()
def forward(self, hidden_states: Tensor, paged_kv_cache: PagedKVCache, layer_id: int):
out = self.self_attn(self.input_layernorm(hidden_states), paged_kv_cache, layer_id)
out = self._apply_post_matmul_norm(out, norm=self.post_attention_layernorm)
hidden_states = out + hidden_states
out = self.pre_feedforward_layernorm(hidden_states)
out = self.mlp(out)
out = self._apply_post_matmul_norm(out, norm=self.post_feedforward_layernorm)
hidden_states = out + hidden_states
return hidden_states
def _apply_post_matmul_norm(self, out: Tensor, norm: nn.Tensor):
if self.tensor_parallel_shards > 1:
return norm(op.ccl_allreduce(out, "sum"))
return norm(out)
class Gemma2Model(GemmaModel):
def __init__(self, config: Gemma2Config):
super().__init__(config)
self.layers = nn.ModuleList(
[Gemma2DecoderLayer(config) for _ in range(config.num_hidden_layers)]
)
class Gemma2ForCausalLM(GemmaForCausalLM):
def __init__(self, config: Gemma2Config):
super().__init__(config)
self.model = Gemma2Model(config)
self.final_logit_softcapping = config.final_logit_softcapping
def get_logits(self, hidden_states: Tensor):
logits = super().get_logits(hidden_states)
if self.final_logit_softcapping is not None:
logits = op.tanh(logits / self.final_logit_softcapping) * self.final_logit_softcapping
return logits