Skip to content

Commit 43b3194

Browse files
ssfdre38Copilot
andcommitted
load_safetensors: fix tensor names for Gemma 4 multimodal HF checkpoints
Public Gemma 4 checkpoints (e4b/e2b) on HuggingFace wrap the language model under model.language_model.*, not model.* directly. Also the per-layer token embedding is named embed_tokens_per_layer.weight with shape [V, L*D] (not [L,V,D]), requiring a simpler matrix transpose. - LN() prefix: model.layers.N. -> model.language_model.layers.N. - Global tensors: model.embed_tokens.weight -> model.language_model.* - LoadPerLayerEmbd: new name + correct [V, L*D] -> [L*D, V] transpose Tested: 2130 tensors indexed, 42 layers loaded, prompt processing begins (CPU-only inference is slow for 4B BF16 model). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 116a56e commit 43b3194

1 file changed

Lines changed: 18 additions & 17 deletions

File tree

gemma/load_safetensors.cc

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ namespace gcpp {
4040
namespace {
4141

4242
// Returns a HF layer tensor name for layer `i`.
43+
// Gemma 4 multimodal checkpoints nest the LM under model.language_model.
4344
static inline std::string LN(const char* tail, size_t i) {
44-
return "model.layers." + std::to_string(i) + "." + tail;
45+
return "model.language_model.layers." + std::to_string(i) + "." + tail;
4546
}
4647

4748
// Validates that the safetensor entry has the expected element count.
@@ -148,21 +149,24 @@ static void AllocAndReadConcat3(MatPtr& mat, std::vector<MatOwner>& owners,
148149
if (!idx.ReadTensor(*ec, dst)) HWY_ABORT("safetensors: read failed: '%s'", hf_c);
149150
}
150151

151-
// Loads per_layer_token_embd from HF shape [L, V, D] into gemma shape
152-
// [L*D, V] by transposing the [V, D] sub-matrix for each layer.
153-
// HF: data[l*V*D + v*D + d] → gemma row (l*D+d), col v
152+
// Loads per-layer token embedding from HF shape [V, L*D] into gemma shape
153+
// [L*D, V] by transposing (simple matrix transpose of a [V, L*D] matrix).
154+
// HF: hf[v, l*D+d] → gemma row (l*D+d), col v.
154155
static void LoadPerLayerEmbd(MatPtr& mat, std::vector<MatOwner>& owners,
155156
const Allocator& alloc,
156157
const SafetensorsIndex& idx,
157158
size_t num_layers, size_t vocab_size,
158159
size_t embd_dim) {
159-
const char* hf_name = "model.per_layer_token_embd.weight";
160+
// Gemma 4 multimodal: "model.language_model.embed_tokens_per_layer.weight"
161+
// Shape [V, L*D] in HF; gemma stores it as [L*D, V].
162+
const char* hf_name =
163+
"model.language_model.embed_tokens_per_layer.weight";
160164
const SafetensorEntry* e = idx.Find(hf_name);
161165
if (!e) HWY_ABORT("safetensors: '%s' not found", hf_name);
162166
ValidateShape(*e, hf_name, num_layers * vocab_size * embd_dim);
163167

164-
// Read HF [L, V, D] into a temp buffer.
165-
const size_t total_elems = num_layers * vocab_size * embd_dim;
168+
// Read HF [V, L*D] into a temp buffer.
169+
const size_t total_elems = vocab_size * num_layers * embd_dim;
166170
auto tmp = hwy::AllocateAligned<uint16_t>(total_elems); // BF16 = uint16
167171
if (!idx.ReadTensor(*e, tmp.get())) {
168172
HWY_ABORT("safetensors: read failed: '%s'", hf_name);
@@ -173,16 +177,13 @@ static void LoadPerLayerEmbd(MatPtr& mat, std::vector<MatOwner>& owners,
173177
owners.emplace_back();
174178
owners.back().AllocateFor(mat, alloc, MatPadding::kPacked);
175179

176-
// Transpose: gemma[l*D+d, v] = HF[l*V*D + v*D + d]
180+
// Transpose: gemma[l*D+d, v] = HF[v, l*D+d]
177181
uint16_t* dst = static_cast<uint16_t*>(mat.Packed());
178182
const uint16_t* src = tmp.get();
179-
for (size_t l = 0; l < num_layers; ++l) {
180-
for (size_t d = 0; d < embd_dim; ++d) {
181-
const size_t dst_row = l * embd_dim + d;
182-
uint16_t* dst_row_ptr = dst + dst_row * vocab_size;
183-
for (size_t v = 0; v < vocab_size; ++v) {
184-
dst_row_ptr[v] = src[l * vocab_size * embd_dim + v * embd_dim + d];
185-
}
183+
const size_t LD = num_layers * embd_dim;
184+
for (size_t v = 0; v < vocab_size; ++v) {
185+
for (size_t ld = 0; ld < LD; ++ld) {
186+
dst[ld * vocab_size + v] = src[v * LD + ld];
186187
}
187188
}
188189
}
@@ -198,9 +199,9 @@ void WeightsPtrs::LoadFromSafetensors(const std::string& dir,
198199

199200
// ── Global tensors ────────────────────────────────────────────────────────
200201
AllocAndReadDirect(embedder_input_embedding, mat_owners, alloc, idx,
201-
"model.embed_tokens.weight");
202+
"model.language_model.embed_tokens.weight");
202203
AllocAndReadDirect(final_norm_scale, mat_owners, alloc, idx,
203-
"model.norm.weight");
204+
"model.language_model.norm.weight");
204205

205206
if (cfg.per_layer_embd_dim > 0) {
206207
LoadPerLayerEmbd(per_layer_input_embedding, mat_owners, alloc, idx,

0 commit comments

Comments
 (0)