mlc-llm 模型请求跟踪

0lvr5msh  于 2个月前  发布在  其他
关注(0)|答案(4)|浏览(26)

这是一个指向 Model Request Tracking Board 的固定问题。

uoifb46i

uoifb46i1#

我对添加一个新模型很感兴趣,但是在看到 tutorial 之后,我发现自己感到困惑和不确定如何开始。关于教程,我有以下几个问题:

  1. 教程中提到 "这几乎是直接翻译",那么为什么只选择了几个参数?还有其他参数,如 n_positionsresid_pdrop ,为什么没有包含它们?或者为什么有些参数直接传递给 kwargs: Dict[str, Any] = dataclasses.field(default_factory=dict) 而没有指定它们的数据类型?

  2. nn.module 的内部结构似乎与教程中的 GPT2Attention 不同。原始实现与宽松版本之间存在显著差异。这是否意味着只要结果一致,实现就可以接受?

  3. 关于 GPT 模型中的函数,有些是存在的,有些则不是。例如,modeling_gpt2.py 中的 class GPT2DoubleHeadsModel(GPT2PreTrainedModel) 没有实现。这是为什么?本质上,哪些模块需要实现,哪些不需要?

  4. 我很难找到在哪里在 export_to_tvm()jit() 中指定 debug=True 的位置。你能告诉我位置吗?

  5. 关于参数,验证阶段中使用的参数是如何选择的?它们似乎没有被传递进来。

作为一个对 LLM-MLC 新手,我很抱歉提出了这么多问题,希望你不介意。

txu3uszq

txu3uszq2#

你好@tlopex,感谢你的问题!

  1. 这是否意味着只要结果一致,实现就可以接受?
    这在很大程度上是正确的,只要考虑到一些性能。

  2. 还有一些其他参数,如n_positions、resid_pdrop,为什么没有包含它们?
    根据问题2的答案,这些参数中的一部分不需要获得一致的结果。在这种情况下,resid_pdrop用于dropout,仅在训练过程中使用——因为我们只考虑mlc-llm中的推理,所以不需要它。对于n_positions,我们在mlc-llm中用context_window_size替换它,以便相同的参数在所有模型之间共享相同的名称。

  3. 从本质上讲,哪些模块需要实现,哪些不需要?
    通常,我们希望实现具有Transformer模型和线性头的模块——因为我们的目标是自回归生成。在这种情况下,它是GPT2LMHeadModel,而对于llama,它是LlamaForCausalLMtransformers中的doc字符串可能对每个模块的功能有所帮助(例如,这里是GPT2LMHeadModel)。

  4. 我很难找到在哪里在export_to_tvm()和jit()中指定debug=True的位置。你能告诉我位置吗?
    抱歉我打错了;应该是export_tvm()而不是export_to_tvm()。只需指定export_tvm(debug=True)jit(debug=True)即可,除了其他参数之外。

  5. 关于参数,验证阶段中使用的参数是如何选择的?它们似乎没有传递进来。
    这是正确的,不是config.json中的所有参数都被使用。

3npbholx

3npbholx3#

感谢CharlieFRuan之前的优秀回答,确实让我学到了很多,也让我开始了。
然而,我今天还是遇到了一些问题:

  1. 我发现教程中的代码不是最新版本的,我想可能需要跟上最新版本?
  2. 我已经编写了QwenAttention,但我发现在验证时,需要输入一个tir.var类型的attn_spec。但是,在查看文档后,我最初使用了tir.Var并遇到了一个错误。

然后我使用了spec.Int,它告诉我TypeError: __init__() takes 1 positional argument but 2 were given,只是不知道如何解决它。
以下是我的validate.py和我的QwenAttention的一部分。

config_dict = {
    "hidden_size": 768,
    "num_hidden_layers": 12,
    "num_attention_heads": 12,
    "intermediate_size": 3072,
    "vocab_size": 50257,
    "rotary_pct": 0.25,
    "rotary_emb_base": 10000,
    "kv_channels": 128,
    "layer_norm_epsilon": 1e-05,
    "context_window_size": 1024
}
qwen_config = QWenConfig(**config_dict)
qwen_attn = QWenAttention(qwen_config)
attn_spec = {
    "forward": {
        "hidden_states": spec.Tensor([1, 2, qwen_config.hidden_size], dtype="float32"),
        "attention_mask": spec.Tensor([1, 1, 2, 2], dtype="float32"),
        "total_seq_len": tir.Var("total_seq_len", dtype=int)
    }
}

mod, named_params = qwen_attn.export_tvm(spec=attn_spec,debug=True)

for name, param in named_params:
    print(name, param.shape, param.dtype)
class QWenAttention(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.rope_theta = config.rotary_emb_base
        self.hidden_size = config.hidden_size
        self.num_attention_heads = config.num_attention_heads
        self.head_dim = self.hidden_size // self.num_attention_heads
        self.query_key_value = nn.Linear(
            in_features=self.hidden_size,
            out_features=3 * self.num_attention_heads * self.head_dim,
            bias=True,
        )
        self.dense = nn.Linear(
            self.num_attention_heads * self.head_dim, self.hidden_size, bias=True
        )
        # Cache for keys and values
        self.k_cache = nn.KVCache(config.context_window_size, [self.num_attention_heads, self.head_dim])
        self.v_cache = nn.KVCache(config.context_window_size, [self.num_attention_heads, self.head_dim])

    def forward(
            self,
            hidden_states: Tensor,
            attention_mask: Tensor,
            total_seq_len: tir.Var
    ):
        batch_size, seq_len, _ = hidden_states.shape
        assert batch_size == 1, "Only support batch size 1 at this moment."

        # Compute query, key, and value
        qkv = self.query_key_value(hidden_states)
        qkv = op.reshape(qkv, (batch_size, seq_len, 3 * self.num_attention_heads, self.head_dim))
        q, k, v = op_ext.llama_rope(
            qkv, total_seq_len, self.rope_theta, self.num_attention_heads, self.num_attention_heads
        )

        # Update cache
        self.k_cache.append(op.squeeze(k, axis=0))
        self.v_cache.append(op.squeeze(v, axis=0))
        k = self.k_cache.view(total_seq_len)
        v = self.v_cache.view(total_seq_len)

        output = op_ext.attention(q, k, v, attention_mask)
        attn_output = self.dense(output)

        return attn_output

此外,似乎documentation中下面的函数(如tvm.tir.IntImm)的解释还没有更新,而且它们的顺序是反的。

  1. hf_attn = hf_model.transformer.h[5].attn中的5是什么意思,为什么选择了第五层?

  1. 如果按照mlc_y = torch_attn["forward"](x, mask)设置并输入tir.Var,我会有点困惑该如何设置。
    抱歉再次有很多问题,希望得到您的回答。
qhhrdooz

qhhrdooz4#

  1. 对不起,回复晚了。请继续提问,这对其他想学习工作流的人也有帮助。

  2. 我发现教程中的代码不是最新版本,我可能需要使用最新版本吗?
    是的,请使用最新版本。仓库可能会不断更新,但主要概念和过程应该基本相同。否则,我们会更新教程。

  3. attn_spec中需要输入tir.var类型。
    也许可以尝试使用"total_seq_len": int而不是"total_seq_len": tir.Var("total_seq_len", dtype=int)

  4. hf_attn = hf_model.transformer.h[5].attn中的5是什么意思,为什么选择第五层?
    5确实是第五层。没有特定的原因选择这一层,我们只是想用单一层来演示验证过程。任何层都可以。

  5. 如果我按照mlc_y = torch_attn["forward"](x, mask)和输入tir.Var的方式设置,有点困惑。
    直接传递整数应该可以,例如mlc_y = torch_attn["forward"](x, mask, 2)
    如果还有其他问题,请告诉我!

相关问题