转换模型 转换词汇表是否支持Mixtral-8x7B OpenMoE Qwen1.5-MoE等MoE模型
使用官方提供的MiniCPM MoE模型的mllm文件和词汇表进行推理结果正常,使用官方工具自己转换得到MiniCPM MoE模型的mllm文件和词汇表进行推理结果也正常,但使用官方工具自己转换得到Qwen1.5-MoE模型的mllm文件和词汇表进行推理得到无意义的字符。感谢!
- 请问您的运行环境是什么?是 X86 / Arm, Linux / Android / Mac
- 请问您使用的 MLLM 版本是 V1 还是 V2?
- 请问您的 Qwen1.5-MoE 的 modeling 文件是怎么书写的?
运行环境为linux 使用的版本为V1 我检查了一下 modeling 文件,发现有一些问题,现在正在参考官方的 modeling 文件进行修改。官方文件是 Python (.py) 形式,所以不能直接使用。请问在将其改写成 .hpp形式 时,有哪些实用的技巧吗?我刚开始学习这方面的知识,所以感觉有点困难,总是容易出错,非常感谢!
- 请问您的运行环境是什么?是 X86 / Arm, Linux / Android / Mac
- 请问您使用的 MLLM 版本是 V1 还是 V2?
- 请问您的 Qwen1.5-MoE 的 modeling 文件是怎么书写的?
- 建议对照着 Py 的 modeling 文件编写,可以和 torch 逐层对精度。
- 如果您不是很依赖于 v1 的功能,如 MoE 的优化。建议用 v2 来写,体验会好不少。
- 建议对照着 Py 的 modeling 文件编写,可以和 torch 逐层对精度。
- 如果您不是很依赖于 v1 的功能,如 MoE 的优化。建议用 v2 来写,体验会好不少。
由于我想要使用edgemoe的功能,使用edgemoe推理Qwen1.5 MoE 所以我仍采用了v1版本进行了代码的编写,编写过程中参照推理的相关文件。由于想要快速完成一个可正常运行的版本,所以暂时省去了MBM的相关代码,按需加载专家。但是经详细对照后,MiniCPM MoE推理结果仍是无意义的字符。
具体改动如下:
mllm-main/examples/demo_qwen_moe_mbm.cpp 与MiniCPM MoE版本类似 改了对应文件的路径和这个语句
QWenMoEConfig config(tokens_limit, "2.7B");
由于省去了MBM相关代码所以setting文件在后续没有使用。configuration文件是参照官方文件写的参数。modeling文件的主要改动如下:
1.专家类增加了共享专家机制,使用norm_topk_prob(官方文件默认为false)判断路由部分是否需要归一化
class Qwen2Moe final : public Module {
public:
Qwen2Moe() = default;
Qwen2Moe(const QWenMoEConfig &config, const QWenMoENameConfig &names, const std::string &base_name) {
...
norm_topk_prob = config.norm_topk_prob;
// 添加共享专家机制
shared_expert = Qwen2MoeMLP(config.hidden_size, config.shared_expert_intermediate_size, names,
base_name + ".shared_expert.");
shared_expert_gate = Linear(config.hidden_size, 1, false, base_name + ".shared_expert_gate");
sigmoid = Sigmoid(base_name + "sigmoid");
}
std::vector<Tensor> Forward(std::vector<Tensor> inputs, std::vector<std::any> args) override {
auto hidden_states = inputs[0];
// 处理batch
...
// ===== 共享专家部分 =====
// 检查共享专家是否已加载
if (!shared_expert.loaded()) {
shared_expert.load();
}
auto shared_expert_output = shared_expert({hidden_states})[0];
auto shared_gate_logits = shared_expert_gate(hidden_states);
// 使用sigmoid激活
shared_gate_logits = sigmoid(shared_gate_logits);
shared_expert_output = shared_expert_output * shared_gate_logits;
// ===== 路由部分 =====
auto scores = gate(hidden_states); // 1, batch*seq, 1, num_experts
scores = softmax(scores);
auto experts_w_i = Tensor::topk(scores, num_experts_per_tok, DIMENSION);
auto expert_weights = experts_w_i[0]; // 1, batch*seq, 1, k
auto expert_indices = experts_w_i[1]; // 1, batch*seq, 1, k
expert_indices = expert_indices.view(-1, 1, 1, -1); // 1, 1, 1, k* batch*seq
// 按照Python版本的归一化逻辑
if (norm_topk_prob) {
expert_weights = expert_weights / expert_weights.sum(DIMENSION); // 1, batch*seq, 1, k
}
expert_weights = expert_weights.view(-1, -1, 1, 1); // 1, k* batch*seq, 1, 1
auto idxs = expert_indices.argsort(); // 1, 1, 1, k* batch*seq
auto tokens_per_expert = expert_indices.bincount();
// ==== 专家推理 ====
auto expert_cache = moe_infer(hidden_states, tokens_per_expert, expert_weights, idxs);
// ==== 合并 ====
expert_cache = expert_cache + shared_expert_output;
return {expert_cache};
}
Tensor moe_infer(Tensor &hidden_states, Tensor &tokens_per_expert, Tensor &expert_weights, Tensor &idxs) {
...
}
...
};
2.decoder类中未使用深度缩放
class Qwen2MoeDecoderLayer final : public Module {
...
std::vector<Tensor> Forward(std::vector<Tensor> inputs, std::vector<std::any> args) override {
auto hidden_states = inputs[0];
// Self Attention
auto residual = hidden_states;
hidden_states = input_layernorm(hidden_states);
hidden_states = self_atten({hidden_states, hidden_states, hidden_states}, args)[0];
hidden_states = residual + hidden_states;
// MLP/MoE
residual = hidden_states;
hidden_states = post_attention_layernorm(hidden_states);
hidden_states = moe({hidden_states}, args)[0];
hidden_states = residual + hidden_states;
return {hidden_states};
}
...
};
3.Qwen2MoeForCausalLM类中也没有使用深度缩放
class Qwen2MoeForCausalLM final : public Module {
...
std::vector<Tensor> Forward(std::vector<Tensor> inputs, std::vector<std::any> args) override {
return do_forward(inputs, args);
}
std::vector<Tensor> do_forward(std::vector<Tensor> inputs, std::vector<std::any>) {
auto x = embedding(inputs[0]);
auto outputs = model({x})[0];
auto last_hidden = outputs.clip({}, {}, {outputs.sequence() - 1, outputs.sequence()}, {});
auto lm_head_tensor = lm_head();
auto logits = Tensor::mm(last_hidden, lm_head_tensor.transpose(Chl::SEQUENCE, Chl::DIMENSION));
return {logits};
}
...
};
请问有什么问题吗?https://github.com/huggingface/transformers/blob/main/src/transformers/models/qwen2_moe/modeling_qwen2_moe.py
这个是官方的modeling文件链接。 如果有需要,我也可以上传相关代码供参考。非常感谢!
cc @yirongjie
cc @yirongjie 你们过去有遇到过这种问题吗?如果遇到过原因是哪些呢?我可以再排查一下