Some checks failed
CI / build-and-test (push) Has been cancelled
- E4B-MarkBase model (42 layers, 4.4GB) loaded successfully - All Phase 1-6 tests passed (model loading, forward pass, vision/audio towers, token generation, performance) - All stress tests passed (5/5 in 127.6s) - Concurrent inference - Memory stress (67.5 tok/s, 0 NaN) - Continuous generation - Batch processing - Long-running stability - Swift Metal inference engine with multimodal support
437 lines
8.3 KiB
Markdown
437 lines
8.3 KiB
Markdown
# Gemma-4 26B 测试结果报告
|
||
|
||
## 测试状态: 需要格式适配 ⚠️
|
||
|
||
**测试时间**: June 19, 2026
|
||
**模型位置**: `/Users/accusys/.cache/huggingface/hub/models--mlx-community--gemma-4-26b-a4b-mxfp4/`
|
||
**模型大小**: 14.8 GB (3 shards)
|
||
|
||
---
|
||
|
||
## 测试结果
|
||
|
||
### 文件检查 ✓
|
||
```
|
||
✓ Config.json: 存在
|
||
✓ Tokenizer.json: 30 MB
|
||
✓ Weights shard 1: 5063 MB
|
||
✓ Weights shard 2: 5075 MB
|
||
✓ Weights shard 3: 4011 MB
|
||
✓ Total: 1283 tensors
|
||
```
|
||
|
||
### 加载尝试 ⚠️
|
||
```
|
||
✓ Engine created
|
||
✓ Found 3 safetensors shards
|
||
✗ Error: unsupportedDtype("Embed tokens not quantized")
|
||
```
|
||
|
||
---
|
||
|
||
## 问题分析
|
||
|
||
### 主要问题
|
||
|
||
**错误**: `Embed tokens not quantized`
|
||
|
||
**原因**: MLX 格式与我们的格式不兼容
|
||
|
||
#### 具体差异
|
||
|
||
**1. 权重命名差异**
|
||
```
|
||
MLX 格式:
|
||
language_model.model.embed_tokens.weight
|
||
language_model.model.layers.0.experts.switch_glu.down_proj.weight
|
||
language_model.model.layers.0.input_layernorm.weight
|
||
|
||
我们的格式:
|
||
embed_tokens.weight
|
||
layers.0.down_proj.weight
|
||
layers.0.input_layernorm.weight
|
||
```
|
||
|
||
**2. Embed tokens 格式**
|
||
```
|
||
MLX 26B:
|
||
embed_tokens.weight: uint32 [262144, 352]
|
||
embed_tokens.scales: uint8 [262144, 88]
|
||
|
||
我们期望:
|
||
embed_tokens.weight: uint32 (quantized)
|
||
embed_tokens.scales: uint32 (BF16 scales)
|
||
embed_tokens.biases: uint32 (BF16 biases)
|
||
```
|
||
|
||
**3. MoE 结构**
|
||
```
|
||
MLX 26B 有 MoE (Mixture of Experts):
|
||
layers.0.experts.switch_glu.down_proj
|
||
layers.0.experts.switch_glu.gate_proj
|
||
layers.0.experts.switch_glu.up_proj
|
||
|
||
我们的代码不支持 MoE 专家路由
|
||
```
|
||
|
||
**4. Config 结构**
|
||
```
|
||
MLX config:
|
||
{
|
||
"text_config": {
|
||
"hidden_size": 2816,
|
||
"num_hidden_layers": ?,
|
||
"enable_moe_block": true,
|
||
...
|
||
}
|
||
}
|
||
|
||
我们期望:
|
||
{
|
||
"hidden_size": 2816,
|
||
"num_hidden_layers": ?,
|
||
...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 详细对比
|
||
|
||
### 模型架构
|
||
|
||
**Gemma-4 26B MLX**:
|
||
```
|
||
Model type: gemma4
|
||
Architecture: Gemma4ForConditionalGeneration
|
||
Hidden size: 2816 (比 12B 的 2560 大)
|
||
Intermediate size: 2112
|
||
MoE blocks: enabled
|
||
Experts: 128 experts per layer (推测)
|
||
```
|
||
|
||
**我们的 E4B-MarkBase**:
|
||
```
|
||
Model type: gemma4
|
||
Architecture: Gemma4ForConditionalGeneration
|
||
Hidden size: 2560
|
||
Intermediate size: 10240
|
||
MoE: disabled (dense layers)
|
||
```
|
||
|
||
### 权重对比
|
||
|
||
| Component | MLX 26B | 我们的 E4B |
|
||
|-----------|---------|------------|
|
||
| Embed tokens | uint32 + uint8 scales | uint32 + BF16 scales/biases |
|
||
| Layers | language_model.model.layers.X | layers.X |
|
||
| MoE | experts.switch_glu | dense MLP |
|
||
| Vision | embed_vision.embedding_projection | vision_tower.X |
|
||
|
||
### 格式差异
|
||
|
||
**量化格式**:
|
||
```
|
||
MLX mxfp4:
|
||
- weight: uint32 (packed 4-bit)
|
||
- scales: uint8 (8-bit)
|
||
- 无 biases
|
||
|
||
我们的标准 4-bit:
|
||
- weight: uint32 (packed, group_size=64)
|
||
- scales: uint32 (BF16)
|
||
- biases: uint32 (BF16)
|
||
```
|
||
|
||
---
|
||
|
||
## 解决方案
|
||
|
||
### 方案 1: 转换模型格式 (推荐)
|
||
|
||
**步骤**:
|
||
|
||
#### 1. 下载并转换
|
||
```python
|
||
from safetensors.torch import load_file, save_file
|
||
import torch
|
||
|
||
# Load MLX model
|
||
mlx_dir = "/Users/accusys/.cache/huggingface/hub/models--mlx-community--gemma-4-26b-a4b-mxfp4"
|
||
weights = {}
|
||
for shard in ["model-00001-of-00003.safetensors", ...]:
|
||
w = load_file(f"{mlx_dir}/{shard}")
|
||
weights.update(w)
|
||
|
||
# Rename weights
|
||
renamed = {}
|
||
for key, tensor in weights.items():
|
||
# Remove language_model.model prefix
|
||
new_key = key.replace("language_model.model.", "")
|
||
renamed[new_key] = tensor
|
||
|
||
# Convert MoE to dense (可选)
|
||
# 或保留 MoE 并实现路由
|
||
|
||
# Convert scales format
|
||
# uint8 → BF16 uint32
|
||
|
||
# Save as single file
|
||
save_file(renamed, "gemma-4-26b-converted.safetensors")
|
||
```
|
||
|
||
#### 2. 创建适配的 config.json
|
||
```json
|
||
{
|
||
"model_type": "gemma4",
|
||
"architectures": ["Gemma4ForConditionalGeneration"],
|
||
"hidden_size": 2816,
|
||
"num_hidden_layers": 42,
|
||
"vocab_size": 262144,
|
||
"quantization_config": {
|
||
"bits": 4,
|
||
"group_size": 64
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. 测试加载
|
||
```bash
|
||
swift run G12BServer /path/to/converted-26b 8080 gemma-26b
|
||
```
|
||
|
||
**优点**:
|
||
- ✓ 可以加载
|
||
- ✓ 性能优化
|
||
- ✓ 与现有代码兼容
|
||
|
||
**缺点**:
|
||
- 需要转换时间
|
||
- MoE 仍需额外实现
|
||
- 需要足够 memory
|
||
|
||
### 方案 2: 适配代码支持 MLX
|
||
|
||
**需要修改**:
|
||
|
||
#### 1. 权重加载
|
||
```swift
|
||
// Sources/G12B/Model.swift
|
||
|
||
// 支持两种命名格式
|
||
let weightName = {
|
||
if tensorName.hasPrefix("language_model.model.") {
|
||
return tensorName.replacing("language_model.model.", with: "")
|
||
}
|
||
return tensorName
|
||
}()
|
||
```
|
||
|
||
#### 2. Scales 格式
|
||
```swift
|
||
// 支持 uint8 scales
|
||
if scalesTensor.dtype == .uint8 {
|
||
// 转换为 BF16
|
||
scales = convertUint8ToBfloat16(scalesTensor)
|
||
}
|
||
```
|
||
|
||
#### 3. MoE 支持
|
||
```swift
|
||
// 新增 MoE 路由实现
|
||
struct MoERouter {
|
||
func route(input: MTLBuffer, experts: [Expert]) -> MTLBuffer {
|
||
// 专家路由逻辑
|
||
}
|
||
}
|
||
|
||
struct Expert {
|
||
let down_proj: QuantizedWeights
|
||
let gate_proj: QuantizedWeights
|
||
let up_proj: QuantizedWeights
|
||
}
|
||
```
|
||
|
||
**优点**:
|
||
- ✓ 直接支持 MLX
|
||
- ✓ 无需转换
|
||
- ✓ 支持更多模型
|
||
|
||
**缺点**:
|
||
- 需要较多代码修改
|
||
- MoE 实现复杂
|
||
- 测试工作量
|
||
|
||
### 方案 3: 下载标准版本
|
||
|
||
**等待官方或社区提供**:
|
||
- 标准 4-bit quantized 格式
|
||
- 无 MoE 或 MoE 已转换
|
||
- 命名符合标准
|
||
|
||
**来源**:
|
||
- HuggingFace 标准量化版本
|
||
- 自行量化官方模型
|
||
- 社区转换版本
|
||
|
||
**优点**:
|
||
- ✓ 无需修改代码
|
||
- ✓ 直接可用
|
||
- ✓ 官方支持
|
||
|
||
**缺点**:
|
||
- 可能不存在
|
||
- 需要等待
|
||
- 需要自己量化
|
||
|
||
---
|
||
|
||
## Memory 需求估算
|
||
|
||
### 26B Memory 分析
|
||
|
||
**权重大小**:
|
||
```
|
||
26B parameters × 0.5 bytes (4-bit) = 13 GB
|
||
Embed tokens (可能未量化): +1 GB
|
||
Vision tower: +0.5 GB
|
||
Total weights: ~14.5 GB
|
||
```
|
||
|
||
**运行时 Memory**:
|
||
```
|
||
Weights: 14.5 GB
|
||
KV Cache (128 context): 0.5 GB
|
||
Activations: 1-2 GB
|
||
Total: ~17 GB
|
||
```
|
||
|
||
**Mac 要求**:
|
||
```
|
||
M3 Pro (36GB): ✓ 充足
|
||
M3 Max (48GB): ✓ 充足
|
||
M4/M5 (64GB+): ✓ 完全充足
|
||
M1/M2 Max (24-32GB): ⚠ 勉强
|
||
```
|
||
|
||
---
|
||
|
||
## 推荐路径
|
||
|
||
### 立即可行
|
||
|
||
**短期 (1-2天)**:
|
||
- 转换现有 MLX 26B 为标准格式
|
||
- 转换 scales uint8 → BF16
|
||
- 重命名权重
|
||
- 测试加载
|
||
|
||
### 长期支持
|
||
|
||
**中期 (1-2周)**:
|
||
- 实现 MLX 格式直接支持
|
||
- 实现 uint8 scales 支持
|
||
- 权重命名自动适配
|
||
|
||
**长期 (1-2月)**:
|
||
- 实现完整 MoE 支持
|
||
- 专家路由优化
|
||
- 分布式 MoE 推理
|
||
|
||
---
|
||
|
||
## 下一步行动
|
||
|
||
### Option A: 快速转换 (推荐)
|
||
|
||
**1. 编写转换脚本** (Python):
|
||
```bash
|
||
python convert_mlx_26b.py \
|
||
--input ~/.cache/huggingface/hub/models--mlx-community--gemma-4-26b-a4b-mxfp4 \
|
||
--output ~/models/gemma-4-26b-standard \
|
||
--rename \
|
||
--convert-scales
|
||
```
|
||
|
||
**2. 测试加载**:
|
||
```bash
|
||
swift test --filter test26BModelLoading
|
||
```
|
||
|
||
**3. 性能测试**:
|
||
```bash
|
||
swift run G12BServer ~/models/gemma-4-26b-standard 8080 gemma-26b
|
||
```
|
||
|
||
### Option B: 代码适配
|
||
|
||
**1. 支持双重命名**:
|
||
```swift
|
||
// 修改 Model.swift 支持两种格式
|
||
```
|
||
|
||
**2. uint8 scales 转换**:
|
||
```swift
|
||
// 在加载时转换格式
|
||
```
|
||
|
||
**3. 测试验证**:
|
||
```bash
|
||
swift test
|
||
```
|
||
|
||
---
|
||
|
||
## 结论
|
||
|
||
**当前状态**: 26B 模型存在但格式不兼容
|
||
|
||
**问题**: MLX 格式 vs 我们的标准格式
|
||
|
||
**解决方案**:
|
||
- ✓ 方案1: 转换格式 (最快)
|
||
- ⚠️ 方案2: 适配代码 (需要工作量)
|
||
- ⏳ 方案3: 等待标准版本 (可能不存在)
|
||
|
||
**推荐**: **方案 1 - 转换格式**
|
||
|
||
**预计时间**: 1-2天完成转换和测试
|
||
|
||
**Memory 要求**: M3 Pro/Max 或更高 (36GB+)
|
||
|
||
---
|
||
|
||
## 附录
|
||
|
||
### MLX 权重列表 (部分)
|
||
|
||
```
|
||
language_model.model.embed_tokens.weight [262144, 352] uint32
|
||
language_model.model.embed_tokens.scales [262144, 88] uint8
|
||
language_model.model.layers.0.experts.switch_glu.down_proj.weight [128, 2816, 88] uint32
|
||
language_model.model.layers.0.experts.switch_glu.down_proj.scales [128, 2816, 22] uint8
|
||
language_model.model.layers.0.input_layernorm.weight [2816] bfloat16
|
||
language_model.model.layers.0.layer_scalar [1] bfloat16
|
||
...
|
||
embed_vision.embedding_projection.weight [...] uint32
|
||
embed_vision.embedding_projection.scales [...] uint8
|
||
```
|
||
|
||
### 需要的转换脚本功能
|
||
|
||
**Python script**:
|
||
1. Load MLX safetensors shards
|
||
2. Rename weights (remove language_model.model prefix)
|
||
3. Convert uint8 scales to BF16
|
||
4. Flatten MoE structure (可选)
|
||
5. Merge into single safetensors
|
||
6. Generate standard config.json
|
||
7. Copy tokenizer files
|
||
|
||
---
|
||
|
||
**报告生成**: June 19, 2026
|
||
**测试结果**: 格式不兼容,需要转换
|
||
**建议**: 转换 MLX 格式为标准格式
|
||
|