Feat/add gemma3 model - #581
Open
zyc107109102 wants to merge 2 commits into
Open
zyc107109102 wants to merge 2 commits into
zyc107109102 wants to merge 2 commits into
Conversation
Gemma-2 is a LLaMA-family architecture with four notable differences, verified against the HF reference implementation: - attention logit soft-capping (scores squashed with tanh(s/cap)*cap before the causal mask/softmax) and final logit soft-capping after the LM head. Soft-capping is added to the framework as an optional AttentionLayer/StaticAttentionImpl parameter (default 0 = disabled, existing models unaffected), mirroring vLLM's logits_soft_cap attention parameter; paged/flash backends reject a non-zero softcap explicitly instead of silently ignoring it. - four RMSNorms per decoder layer with branch-normalize-then-add ordering: implemented as Gemma2DecoderLayer; the TextModel residual contract is preserved so TextModel itself is unchanged. The branch addition is fused with the pre-feedforward norm via InfiniCore's add_rms_norm (math-preserving; measured neutral on MR-V100 for single-batch decode and 2k prefill, kept for the leaner op sequence). - zero-centered RMSNorm weights (checkpoints store w-1) and embedding scaling by sqrt(hidden_size): handled by the _remap_gemma remapper and _get_scale_emb; the tied lm_head uses the unscaled copy, matching HF semantics. - packed prefill computes lm_head logits only for the last token of each request (same as TextCausalLM), keeping the soft-capping passes off the full [S, vocab] tensor. - gelu_pytorch_tanh activation (op::gelu_tanh) and a dedicated head_dim preserved from the checkpoint (256 != hidden/num_heads). Known limitations (documented in code): sliding-window attention is not implemented (correct for seq_len <= sliding_window = 4096, where the local window covers the full causal context), and soft-capping is supported on the STATIC attention backend only. Verified against HF Gemma2ForCausalLM (eager attention, greedy): - gemma-2-2b-it: 36/36 greedy tokens on Iluvatar MR-V100 (bf16), 29/29 on NVIDIA RTX 4060 (bf16); tiny random gemma2 36/36 (fp32). - gemma-2-9b-it (same code path, config-driven): 38/39 on MR-V100 (single bf16 token flip on a 602-token prompt). - softcap effect probe: |logits|max 19.75 capped vs 23.50 uncapped. - no missing/unexpected weight keys; unit tests under test/models/gemma2 pass; scripts/format.py --check passes. Harden against silently-wrong configurations (folded review follow-ups): - attention soft-capping rejects negative values explicitly, both at the config level and in AttentionLayer, instead of silently disabling the feature through the ">0 enables" checks; attention modules default attention_bias to false, matching the HF Gemma2Config default. - warn at load time when the checkpoint context can exceed sliding_window (sliding-window attention is not implemented; correctness holds only up to the window, e.g. gemma-2-2b-it context variants with 8192).
Gemma-3 text (model_type "gemma3_text") shares Gemma-2's four-norm decoder layer, zero-centered RMSNorm weights, embedding scaling, and gelu_pytorch_tanh MLP (the MLP implementation is reused via an alias). Its new capabilities are QK-norm, per-layer-type RoPE frequencies, and alternating sliding-window attention (sliding_window_pattern, default 6 -> 5:1 interleave). - Gemma3Attention: QK-norm on per-head vectors before RoPE (qwen3 pattern); sliding layers use the local RoPE base frequency (rope_local_base_freq) while full layers use rope_theta, via the get_rope explicit overload. - Sliding layers manage the static KV cache directly (mirroring StaticAttentionImpl's layout and update): decode reads only the trailing sliding_window keys; prefill trims the key range to the union of visible keys (keys older than past-window+1 are masked for every query and dropped before the score matmul), applies a window mask built on host in the score dtype (fp32, bf16 or fp16 bit pattern), and relies on causal_softmax_ for the causal part. - Requires the STATIC attention backend for sliding layers (explicit error otherwise); full layers work on any backend. - Top level reuses TextCausalLM unchanged (no logit soft-capping in Gemma-3). - modeling_utils.py: register "gemma3_text" for the shared _remap_gemma (QK-norm weights are also stored w-1) and _get_scale_emb. Verified against HF Gemma3ForCausalLM (eager attention, greedy): - gemma-3-1b-it on Iluvatar MR-V100 (bf16): 24/24 over 3 prompts and a 602-token prompt (past the 512 sliding window) matching 8/8 -- sliding window genuinely exercised; NVIDIA RTX 4060 matches as well. - tiny random gemma3 (window 8, alternating layers, distinct local/global thetas, 32-token prompt > window): 30/30 (fp32). - multi-turn chunked prefill (past>0, seq>1 via prefix cache reuse on a >window prompt): 10/10. - no missing/unexpected weight keys; scripts/format.py --check passes; unit tests under test/models/gemma3 pass. Harden against silently-wrong configurations (folded review follow-ups): - reject rope_scaling explicitly (gemma-3-4b/12b/27b text configs use linear factor 8 on the global attention layers; that is not implemented, so refuse to load rather than silently corrupt long-context RoPE), reject KV-cache quantization on sliding layers (their direct cache writes would be silently truncated in an int8 cache), reject sliding layers without a positive sliding_window, and assert KV-cache capacity before the windowed write (same guard as StaticAttentionImpl). - attention module defaults attention_bias to false, matching the HF Gemma3TextConfig default.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 标题: feat: 支持 gemma2 与 gemma3_text 模型推理
概述
本 PR 以两个 commit 为 InfiniLM 增加两个 Gemma 文本模型家族:
model_type="gemma2"(Gemma-2):LLaMA 家族架构,差异点是注意力/最终 logits 软上限(soft-capping)、每层四个 RMSNorm 的解码层、零中心归一化权重。model_type="gemma3_text"(Gemma-3 文本,如 gemma-3-1b):QK-norm、按层类型区分的 RoPE 频率、交替滑窗注意力(5:1 交错)——其中滑窗 KV cache 是框架此前不具备的能力。顺带引入两个小的、可选的框架能力:
AttentionLayer/StaticAttentionImpl上的可选 softcap 参数(默认0.0f= 关闭,所有现有模型不受影响);全部改动在三个后端上与 HF
transformers(eager attention、贪心解码)做了逐 token 对照:Iluvatar MR-V100(bf16)、NVIDIA RTX 4060(bf16)、CPU(fp32)。两个 commit 均可独立编译并通过各自的单元测试(bisect 友好)。架构说明(Gemma 与 llama 的差异)
Gemma-2(commit 1)
Gemma-2 是 LLaMA 家族架构,有四处差异,均已对照 HF 参考实现逐条验证:
注意力 logit 软上限。 缩放后的分数在因果掩码和 softmax 之前先做
tanh(s/cap) * cap压缩;LM head 之后的最终 logits 做同样处理(所有已发布尺寸均为attn_logit_softcapping=50、final_logit_softcapping=30)。注意力缩放使用1/sqrt(query_pre_attn_scalar)而非1/sqrt(head_dim)。每层四个 RMSNorm,顺序为"分支先归一化再相加":
实现为自定义
Gemma2DecoderLayer;TextModel的 residual 契约(hidden= 尚未加回的分支,residual= 主流)保持不变,因此TextModel本体零改动。分支加法通过 InfiniCore 的add_rms_norm与 pre-feedforward 归一化融合(返回(norm(residual+branch), residual+branch)),替代独立的 add + norm 两步;在 MR-V100 上实测性能中性(batch-1 解码 ITL 22.72 vs 22.76 ms,2k prefill TTFT 720.2 vs 721.1 ms),保留理由是算子序列更精简。零中心 RMSNorm 权重——checkpoint 存储
w - 1,加载期 remapper 统一+1。Embedding 缩放——embedding 输出在加载期乘以
sqrt(hidden_size)(经_get_scale_emb);tied lm_head 用未缩放副本填充,与 HF 语义一致。激活仅实现gelu_pytorch_tanh;head_dim(256)从 checkpoint 保留,不按hidden/num_heads(2304/8 = 288)推导。Gemma-3 文本(commit 2)
复用 Gemma-2 的四范式解码层、权重 remap 与 embedding 缩放(MLP 直接以别名复用)。新能力:
QK-norm:RoPE 之前对逐头向量归一化(qwen3 模式);其权重同样以
w - 1存储,由共享 remapper 处理。按层类型区分的 RoPE。
layer_types按sliding_window_pattern周期(默认 6 → 5:1)交替sliding_attention/full_attention,与 HF 的生成规则一致((i+1) % pattern == 0→ full)。滑窗层使用rope_local_base_freq(10k),全局层使用rope_theta(1M)。滑窗注意力。 滑窗层直接管理静态 KV cache(cache 布局与更新逻辑对齐
StaticAttentionImpl):min(total, W)个 key——无需掩码;-1e9溢出改用-inf);当past + i - j >= W时 keyj对 queryi不可见。因果部分交给causal_softmax_,其对齐因果语义(valid_len = total - seq + i + 1)与窗口掩码精确复合,chunked prefill(past > 0, seq > 1)同样成立;[bs, seq, heads, dim] → permute → [bs*nkv, ng*seq, dim]),与 static 后端一致。全注意力层委托共享的
AttentionLayer,可在任意后端运行;滑窗层要求 STATIC 后端(显式报错)。Gemma-3 无 logit 软上限,顶层直接复用TextCausalLM,零改动。框架改动:注意力 softcap(commit 1)
softcap 必须作用在分数矩阵与"掩码+softmax"之间——这在注意力后端内部——所以它是
AttentionLayer/StaticAttentionImpl的构造参数(softcap,默认0.0f= 关闭)。设计与 vLLM 一致(logits_soft_cap即注意力后端参数)。现有模型不受影响(默认关闭,无数值与分发路径变化)。不支持的组合一律响亮报错,绝不静默输出错误结果:
如果 maintainer 希望把这部分拆成独立的框架 PR,随时可以拆。
加载路径改动(python/infinilm/modeling_utils.py)
_remap_gemma:对所有零中心归一化权重(input_layernorm、post_attention_layernorm、pre_feedforward_layernorm、post_feedforward_layernorm、self_attn.q_norm、self_attn.k_norm、model.norm)做+1平移;注册到gemma2与gemma3_text。_get_scale_emb:对上述模型类型返回sqrt(hidden_size);tied lm_head 用未缩放的 embedding 副本填充。加固:不支持的配置一律响亮报错
rope_scalingsliding_windowStaticAttentionImpl同一防线)sliding_window < max_position_embeddingsAttentionLayer双重)按 commit 粒度做了 A/B:所有正常路径的输出与不加硬化逐位一致;每条防护都用探针验证过会带着预期信息触发。
局限(代码内与 PR 中均已注明)
seq_len <= sliding_window(所有已发布尺寸均为 4096)时结果正确——此时局部窗口覆盖全部因果上下文。超过后模型按全注意力运行:功能正常、输出连贯,但与 HF 分歧(HF 会对局部层开窗)——加载期警告覆盖此场景。S×S分数矩阵,且每个滑窗层各缓存一份窗口掩码;gemma-3-1b 在 32GB 卡上单块 prefill 实测可用至约 11.7k token,超过约 12k 后以干净的 OOM 失败(是分配报错,绝不是错误结果)。chunked prefill 与更短上下文不受影响。rope_scaling(linear)未实现——见后续工作。TextModel模板(Gemma-2 顶层对齐TextCausalLM的 PP 分段),但本 PR 仅在单卡上实测。验证
所有对照均为贪心解码(do_sample=False),参考实现为 HF
attn_implementation="eager",除注明外均逐 token 一致。小随机模型(fp32,CPU)——覆盖 head_dim ≠ hidden/heads、四范式、
w-1权重、tied embedding、窗口 < 提示长度:真实权重:
其他检查:
|logits|max加帽 19.75 vs 不加帽 23.50;scripts/format.py --check通过;复现方式
后续工作(愿意继续贡献,优先级欢迎反馈)
[past-W+1, past+seq-1]内的 key;截断可去掉绝大部分逐层掩码/分数显存,显著抬高分块 prefill 的长上下文上限。(seq_len, total_len),当前却按滑窗层实例各缓存一份。Closes #<issue 编号>