THUDM / GLM-4

GLM-4 series: Open Multilingual Multimodal Chat LMs | 开源多语言多模态对话模型
Apache License 2.0
4.83k stars 398 forks source link

TensorRT-LLM的支持在计划中吗 #132

Closed HLSS-Hen closed 3 months ago

HLSS-Hen commented 4 months ago

从GLM到chatGLM3都提供了TensorRT-LLM的支持,请问这代模型是否会继续提供

zRzRzRzRzRzRzR commented 4 months ago

目前直接用GLM-3的转换GLM-4的就行了吧

HLSS-Hen commented 4 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

zRzRzRzRzRzRzR commented 4 months ago

不能直接一个字不改,,还是要参考我们的demo的,stop id 有三个哈

HLSS-Hen commented 4 months ago

这里三个stop_id是为什么;对于TensorRT-LLM,在推理的时候,SamplingConfig 只接受一个 int 类型的 end_id,或者提供stop_words_list

在我的简单尝试中,在三个stop id选一个给到SamplingConfig.end_id的情况下,对比GLM-4和GLM-4V,前者要输入 <|user|>(15336)可以正常工作,而后者输入 <|endoftext|> (151329)可以正常工作。

即,如果只把 <|endoftext|> (151329) 给到 end_id,GLM-4无法正确停下,GLM-4V可以。

在给了 end_id=151329 情况下:

 array([[[151329], [     1]],
        [[151336], [     1]],
        [[151338], [     1]]], dtype=int32)
zRzRzRzRzRzRzR commented 4 months ago

如果只能写一个,都用<|user|> 这个问题我已经放到排期了,之后会处理,感谢你的耐心尝试

diaoyechao commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

HLSS-Hen commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

可以,但是tensorrt-llm不支持多模态。

diaoyechao commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

可以,但是tensorrt-llm不支持多模态。

没太明白,glm-4v-9b不就是多模态的模型吗?

HLSS-Hen commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

可以,但是tensorrt-llm不支持多模态。

没太明白,glm-4v-9b不就是多模态的模型吗?

glm-4v-9b模型多一个输入images:torch.Tensor,如果不为空则通过视觉骨干(EVA2CLIPModel)将其编码后嵌入,这部分是tensorrt-llm不支持的。

    def forward(
            self,
            input_ids: torch.LongTensor = None,
            images: torch.Tensor = None,
            position_ids: Optional[torch.Tensor] = None,
            attention_mask: Optional[torch.BoolTensor] = None,
            full_attention_mask: Optional[torch.BoolTensor] = None,
            past_key_values: Optional[Tuple[Tuple[torch.Tensor, torch.Tensor], ...]] = None,
            inputs_embeds: Optional[torch.Tensor] = None,
            use_cache: Optional[bool] = None,
            output_hidden_states: Optional[bool] = None,
            return_dict: Optional[bool] = None,
    ) -> Union[Tuple, BaseModelOutputWithPast]:
        """take care of image_encode, position_ids and (attention_mask = None is fine)"""

        # generate mode with past_key_values. the image features are already mapped
        if past_key_values is None:
            # not allow for inputs_embeds, because we want to process image feature
            assert input_ids is not None and inputs_embeds is None, f"{input_ids} {inputs_embeds}"
            if not is_empty(images):  # multi-modality
                image_size: int = self.config.vision_config['image_size']
                patch_size: int = self.config.vision_config['patch_size']
                num_patches = (image_size // patch_size // 2) ** 2
                assert len(input_ids) == len(images), f"{len(input_ids)} {len(images)}"
                inputs_embeds = self.embedding(input_ids)

                images = images.to(dtype=inputs_embeds.dtype)
                images_features = self.vision(images)

                if position_ids is None:
                    position_ids = self.get_position_ids(input_ids, device=inputs_embeds.device)
                new_input_embeds, new_position_ids = [], []

                for i in range(len(input_ids)):
                    input_id = input_ids[i].tolist()
                    boi_token_pos, eoi_token_pos = input_id.index(self.config.boi_token_id), input_id.index(
                        self.config.eoi_token_id)
                    assert eoi_token_pos - boi_token_pos == 2
                    new_input_embeds.append(torch.cat(
                        (inputs_embeds[i, :boi_token_pos], images_features[i].to(inputs_embeds.device),
                         inputs_embeds[i, eoi_token_pos + 1:])))
                    new_position_ids.append(torch.cat(
                        (position_ids[i, :boi_token_pos + 1], position_ids[i, boi_token_pos + 1].repeat(num_patches),
                         position_ids[i, eoi_token_pos:])
                    ))
                inputs_embeds = torch.stack(new_input_embeds, dim=0)
                position_ids = torch.stack(new_position_ids, dim=0)
diaoyechao commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

可以,但是tensorrt-llm不支持多模态。

没太明白,glm-4v-9b不就是多模态的模型吗?

glm-4v-9b模型多一个输入images:torch.Tensor,如果不为空则通过视觉骨干(EVA2CLIPModel)将其编码后嵌入,这部分是tensorrt-llm不支持的。

    def forward(
            self,
            input_ids: torch.LongTensor = None,
            images: torch.Tensor = None,
            position_ids: Optional[torch.Tensor] = None,
            attention_mask: Optional[torch.BoolTensor] = None,
            full_attention_mask: Optional[torch.BoolTensor] = None,
            past_key_values: Optional[Tuple[Tuple[torch.Tensor, torch.Tensor], ...]] = None,
            inputs_embeds: Optional[torch.Tensor] = None,
            use_cache: Optional[bool] = None,
            output_hidden_states: Optional[bool] = None,
            return_dict: Optional[bool] = None,
    ) -> Union[Tuple, BaseModelOutputWithPast]:
        """take care of image_encode, position_ids and (attention_mask = None is fine)"""

        # generate mode with past_key_values. the image features are already mapped
        if past_key_values is None:
            # not allow for inputs_embeds, because we want to process image feature
            assert input_ids is not None and inputs_embeds is None, f"{input_ids} {inputs_embeds}"
            if not is_empty(images):  # multi-modality
                image_size: int = self.config.vision_config['image_size']
                patch_size: int = self.config.vision_config['patch_size']
                num_patches = (image_size // patch_size // 2) ** 2
                assert len(input_ids) == len(images), f"{len(input_ids)} {len(images)}"
                inputs_embeds = self.embedding(input_ids)

                images = images.to(dtype=inputs_embeds.dtype)
                images_features = self.vision(images)

                if position_ids is None:
                    position_ids = self.get_position_ids(input_ids, device=inputs_embeds.device)
                new_input_embeds, new_position_ids = [], []

                for i in range(len(input_ids)):
                    input_id = input_ids[i].tolist()
                    boi_token_pos, eoi_token_pos = input_id.index(self.config.boi_token_id), input_id.index(
                        self.config.eoi_token_id)
                    assert eoi_token_pos - boi_token_pos == 2
                    new_input_embeds.append(torch.cat(
                        (inputs_embeds[i, :boi_token_pos], images_features[i].to(inputs_embeds.device),
                         inputs_embeds[i, eoi_token_pos + 1:])))
                    new_position_ids.append(torch.cat(
                        (position_ids[i, :boi_token_pos + 1], position_ids[i, boi_token_pos + 1].repeat(num_patches),
                         position_ids[i, eoi_token_pos:])
                    ))
                inputs_embeds = torch.stack(new_input_embeds, dim=0)
                position_ids = torch.stack(new_position_ids, dim=0)

意思是只转换了LLM的部分?那转换后还能正常使用吗?

HLSS-Hen commented 3 months ago

@zRzRzRzRzRzRzR 谢谢,用上--chatglm_version chatglm3后,转换、构建成功。 现有的trtllm(r0.10.0),SamplingConfig.end_idint形,而GLM4 MODEL.chat()里面用的 eos_token_id 有三个: [tokenizer.eos_token_id, tokenizer.convert_tokens_to_ids("<|user|>"), tokenizer.convert_tokens_to_ids("<|observation|>")]。 实测 glm-4-9b-chat 要用 <|user|>(151336) 才给到end_id才可以。或者把三个同时给 stop_words_list,最终多生成出一个 <|user|>(151336) 要截去。而在glm-4v-9b 并不需要,直接给eos_token_id(151329)就行。

glm-4v-9b可以转换吗?

可以,但是tensorrt-llm不支持多模态。

没太明白,glm-4v-9b不就是多模态的模型吗?

glm-4v-9b模型多一个输入images:torch.Tensor,如果不为空则通过视觉骨干(EVA2CLIPModel)将其编码后嵌入,这部分是tensorrt-llm不支持的。

    def forward(
            self,
            input_ids: torch.LongTensor = None,
            images: torch.Tensor = None,
            position_ids: Optional[torch.Tensor] = None,
            attention_mask: Optional[torch.BoolTensor] = None,
            full_attention_mask: Optional[torch.BoolTensor] = None,
            past_key_values: Optional[Tuple[Tuple[torch.Tensor, torch.Tensor], ...]] = None,
            inputs_embeds: Optional[torch.Tensor] = None,
            use_cache: Optional[bool] = None,
            output_hidden_states: Optional[bool] = None,
            return_dict: Optional[bool] = None,
    ) -> Union[Tuple, BaseModelOutputWithPast]:
        """take care of image_encode, position_ids and (attention_mask = None is fine)"""

        # generate mode with past_key_values. the image features are already mapped
        if past_key_values is None:
            # not allow for inputs_embeds, because we want to process image feature
            assert input_ids is not None and inputs_embeds is None, f"{input_ids} {inputs_embeds}"
            if not is_empty(images):  # multi-modality
                image_size: int = self.config.vision_config['image_size']
                patch_size: int = self.config.vision_config['patch_size']
                num_patches = (image_size // patch_size // 2) ** 2
                assert len(input_ids) == len(images), f"{len(input_ids)} {len(images)}"
                inputs_embeds = self.embedding(input_ids)

                images = images.to(dtype=inputs_embeds.dtype)
                images_features = self.vision(images)

                if position_ids is None:
                    position_ids = self.get_position_ids(input_ids, device=inputs_embeds.device)
                new_input_embeds, new_position_ids = [], []

                for i in range(len(input_ids)):
                    input_id = input_ids[i].tolist()
                    boi_token_pos, eoi_token_pos = input_id.index(self.config.boi_token_id), input_id.index(
                        self.config.eoi_token_id)
                    assert eoi_token_pos - boi_token_pos == 2
                    new_input_embeds.append(torch.cat(
                        (inputs_embeds[i, :boi_token_pos], images_features[i].to(inputs_embeds.device),
                         inputs_embeds[i, eoi_token_pos + 1:])))
                    new_position_ids.append(torch.cat(
                        (position_ids[i, :boi_token_pos + 1], position_ids[i, boi_token_pos + 1].repeat(num_patches),
                         position_ids[i, eoi_token_pos:])
                    ))
                inputs_embeds = torch.stack(new_input_embeds, dim=0)
                position_ids = torch.stack(new_position_ids, dim=0)

意思是只转换了LLM的部分?那转换后还能正常使用吗?

无法接受图片输入,其他应该正常。

zRzRzRzRzRzRzR commented 3 months ago

trt-llm只支持我们的chat模型,视觉模型还没有支持

15929482853 commented 3 months ago

@HLSS-Hen 你好,请问你有没有尝试glm4用trt-llm进行awq量化,我这边量化之后推理结果为乱码

HLSS-Hen commented 3 months ago

@15929482853 我这里实测没有太大问题,你可能没有正确使用tokenizer或者提供了错误的采样参数。

一些细节: tensorrt-llm: v0.10.0 5800x3d, 128GB RAM, 3090

mamba create -n temp python=3.10
mamba activate temp
cd TENSORT_LLM_PATH
pip install -r examples/chatglm/requirements.txt
examples/quantization/install_requirements.sh
pip install "cython<3.0.0" wheel && pip install pyyaml==5.4.1 --no-build-isolation
pip install -r requirements.txt

魔改下部分package代码:

然后执行量化和构建

python examples/quantization/quantize.py --model_dir /WORKSPACE/hf_ckpt/glm-4-9b-chat/ --dtype float16 --qformat int4_awq --output_dir /WORKSPACE/trt_ckpt/glm-4-9b-chat-awq --batch_size 8
trtllm-build --checkpoint_dir /WORKSPACE/trt_ckpt/glm-4-9b-chat-awq/ --gemm_plugin float16 --output_dir /WORKSPACE/trt_engines/glm-4-9b-chat-awq

简单测试:

from transformers import AutoTokenizer
import torch

tokenizer = AutoTokenizer.from_pretrained("/WORKSPACE/hf_ckpt/glm-4-9b-chat", trust_remote_code=True)

import tensorrt_llm
runner = tensorrt_llm.runtime.ModelRunnerCpp.from_dir("/WORKSPACE/trt_engines/glm-4-9b-chat-awq/")

history = [
        {'role': 'system', 'content': '一些提示词。。。'}, 
        # 可选,few shots
]

conversation = history.copy()
conversation.append({"role": "user", "content": "用户输入"})

inputs = tokenizer.apply_chat_template(conversation,
                                       add_generation_prompt=True,
                                       tokenize=True,
                                       return_tensors="pt",
                                       return_dict=True
                                       )

inputs = inputs.to("cuda")

with torch.no_grad():
    outputs = runner.generate([inputs["input_ids"][0]],
                    max_new_tokens=128,
                    end_id=151336, # 参考上面的讨论
                    pad_id=151329,
                    temperature=0,
                    top_p=0,
                    num_beams=1,
                    output_sequence_lengths=True,
                    return_dict=True,
                    exclude_input_in_output=True
                    )

print(tokenizer.decode(outputs["output_ids"][0,0][inputs["input_ids"].shape[1]:outputs["sequence_lengths"][0]]))
15929482853 commented 3 months ago

@15929482853 我这里实测没有太大问题,你可能没有正确使用tokenizer或者提供了错误的采样参数。

一些细节: tensorrt-llm: v0.10.0 5800x3d, 128GB RAM, 3090

mamba create -n temp python=3.10
mamba activate temp
cd TENSORT_LLM_PATH
pip install -r examples/chatglm/requirements.txt
examples/quantization/install_requirements.sh
pip install "cython<3.0.0" wheel && pip install pyyaml==5.4.1 --no-build-isolation
pip install -r requirements.txt

魔改下部分package代码:

  • site-packages/modelopt/torch/export/model_config_export.py > export_tensorrt_llm_checkpoint model=model -> model=model.cpu() 24G显存是真的会爆的
  • site-packages/tensorrt_llm/models/chatglm/model.py > ChatGLMForCausalLM > check_config config.set_if_not_exist('chatglm_version', 'chatglm3') -> config.chatglm_version = "chatglm3" 强制套用chatglm3相关代码

然后执行量化和构建

python examples/quantization/quantize.py --model_dir /WORKSPACE/hf_ckpt/glm-4-9b-chat/ --dtype float16 --qformat int4_awq --output_dir /WORKSPACE/trt_ckpt/glm-4-9b-chat-awq --batch_size 8
trtllm-build --checkpoint_dir /WORKSPACE/trt_ckpt/glm-4-9b-chat-awq/ --gemm_plugin float16 --output_dir /WORKSPACE/trt_engines/glm-4-9b-chat-awq

简单测试:

from transformers import AutoTokenizer
import torch

tokenizer = AutoTokenizer.from_pretrained("/WORKSPACE/hf_ckpt/glm-4-9b-chat", trust_remote_code=True)

import tensorrt_llm
runner = tensorrt_llm.runtime.ModelRunnerCpp.from_dir("/WORKSPACE/trt_engines/glm-4-9b-chat-awq/")

history = [
        {'role': 'system', 'content': '一些提示词。。。'}, 
        # 可选,few shots
]

conversation = history.copy()
conversation.append({"role": "user", "content": "用户输入"})

inputs = tokenizer.apply_chat_template(conversation,
                                       add_generation_prompt=True,
                                       tokenize=True,
                                       return_tensors="pt",
                                       return_dict=True
                                       )

inputs = inputs.to("cuda")

with torch.no_grad():
    outputs = runner.generate([inputs["input_ids"][0]],
                    max_new_tokens=128,
                    end_id=151336, # 参考上面的讨论
                    pad_id=151329,
                    temperature=0,
                    top_p=0,
                    num_beams=1,
                    output_sequence_lengths=True,
                    return_dict=True,
                    exclude_input_in_output=True
                    )

print(tokenizer.decode(outputs["output_ids"][0,0][inputs["input_ids"].shape[1]:outputs["sequence_lengths"][0]]))

看了一下,我们的流程是一样的,我这块没什么问题。 唯一的不同是我是用的trt-llm版本是0.9.0,不知道这个有没有影响,我准备使用和你一样的环境再尝试一下,感谢回复!

scdotbox commented 3 months ago

如果把 glm-4v-9b 拆成 2个部分,一个是前面的 vit,获得 image embedding,然后把 images:torch.Tensor 合并到 input_ids 模块,可以复用 chat 模型吗?这样是不是可以直接使用 trtllm 的 glm4 ?

HLSS-Hen commented 3 months ago

@scdotbox 不可行,图像的嵌入,不是嵌入为inputs_ids,而是1602 x 4096的特征,同时需要特殊的位置编码。 虽然官方Torch源码里面可以通过传入 position_idsinputs_embeds或者传入past_key_values,实现将图像嵌入操作分离。但是tensorrt_llm那里不支持,可以等tensorrt_llm那里支持。 trt-llm v0.10.0已经引入 CogVLM ;CogGLM2也在issue被请求加入,GLM-4V或许要在CogVLM2之后。