[AI]如何让语言模型LLMs流式输出:HuggingFace Transformers实现

这篇具有很好参考价值的文章主要介绍了[AI]如何让语言模型LLMs流式输出:HuggingFace Transformers实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

HugginFace Transforms是一个非常方便的库,集成了非常多SOTA的模型,包含:LLAMA, GPT, ChatGLM Moss,等。目前基本上主流的方案都是基于HugginFace Transforms这个框架实现的。以前如果要流式输出需要自己去改模型底层的推理逻辑。

如ChatGLM,自己实现的流式输出如下:

#chatglm-6bmodel/modeling_chatglm.py
@torch.no_grad()
    def stream_chat(self, tokenizer, query: str, history: List[Tuple[str, str]] = None, max_length: int = 2048,
                    do_sample=True, top_p=0.7, temperature=0.95, logits_processor=None, **kwargs):
        if history is None:
            history = []
        if logits_processor is None:
            logits_processor = LogitsProcessorList()
        logits_processor.append(InvalidScoreLogitsProcessor())
        gen_kwargs = {"max_length": max_length, "do_sample": do_sample, "top_p": top_p,
                      "temperature": temperature, "logits_processor": logits_processor, **kwargs}
        if not history:
            prompt = query
        else:
            prompt = ""
            for i, (old_query, response) in enumerate(history):
                prompt += "[Round {}]\n问:{}\n答:{}\n".format(i, old_query, response)
            prompt += "[Round {}]\n问:{}\n答:".format(len(history), query)
        inputs = tokenizer([prompt], return_tensors="pt")
        inputs = inputs.to(self.device)
        for outputs in self.stream_generate(**inputs, **gen_kwargs):
            outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):]
            response = tokenizer.decode(outputs)
            response = self.process_response(response)
            new_history = history + [(query, response)]
            yield response, new_history

    @torch.no_grad()
    def stream_generate(
            self,
            input_ids,
            generation_config: Optional[GenerationConfig] = None,
            logits_processor: Optional[LogitsProcessorList] = None,
            stopping_criteria: Optional[StoppingCriteriaList] = None,
            prefix_allowed_tokens_fn: Optional[Callable[[int, torch.Tensor], List[int]]] = None,
            **kwargs,
    ):
        batch_size, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1]

        if generation_config is None:
            generation_config = self.generation_config
        generation_config = copy.deepcopy(generation_config)
        model_kwargs = generation_config.update(**kwargs)
        bos_token_id, eos_token_id = generation_config.bos_token_id, generation_config.eos_token_id

        if isinstance(eos_token_id, int):
            eos_token_id = [eos_token_id]

        has_default_max_length = kwargs.get("max_length") is None and generation_config.max_length is not None
        if has_default_max_length and generation_config.max_new_tokens is None:
            warnings.warn(
                f"Using `max_length`'s default ({generation_config.max_length}) to control the generation length. "
                "This behaviour is deprecated and will be removed from the config in v5 of Transformers -- we"
                " recommend using `max_new_tokens` to control the maximum length of the generation.",
                UserWarning,
            )
        elif generation_config.max_new_tokens is not None:
            generation_config.max_length = generation_config.max_new_tokens + input_ids_seq_length
            if not has_default_max_length:
                logger.warn(
                    f"Both `max_new_tokens` (={generation_config.max_new_tokens}) and `max_length`(="
                    f"{generation_config.max_length}) seem to have been set. `max_new_tokens` will take precedence. "
                    "Please refer to the documentation for more information. "
                    "(https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)",
                    UserWarning,
                )

        if input_ids_seq_length >= generation_config.max_length:
            input_ids_string = "decoder_input_ids" if self.config.is_encoder_decoder else "input_ids"
            logger.warning(
                f"Input length of {input_ids_string} is {input_ids_seq_length}, but `max_length` is set to"
                f" {generation_config.max_length}. This can lead to unexpected behavior. You should consider"
                " increasing `max_new_tokens`."
            )

        # 2. Set generation parameters if not already defined
        logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()
        stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()

        logits_processor = self._get_logits_processor(
            generation_config=generation_config,
            input_ids_seq_length=input_ids_seq_length,
            encoder_input_ids=input_ids,
            prefix_allowed_tokens_fn=prefix_allowed_tokens_fn,
            logits_processor=logits_processor,
        )

        stopping_criteria = self._get_stopping_criteria(
            generation_config=generation_config, stopping_criteria=stopping_criteria
        )
        logits_warper = self._get_logits_warper(generation_config)

        unfinished_sequences = input_ids.new(input_ids.shape[0]).fill_(1)
        scores = None
        while True:
            model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs)
            # forward pass to get next token
            outputs = self(
                **model_inputs,
                return_dict=True,
                output_attentions=False,
                output_hidden_states=False,
            )

            next_token_logits = outputs.logits[:, -1, :]

            # pre-process distribution
            next_token_scores = logits_processor(input_ids, next_token_logits)
            next_token_scores = logits_warper(input_ids, next_token_scores)

            # sample
            probs = nn.functional.softmax(next_token_scores, dim=-1)
            if generation_config.do_sample:
                next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1)
            else:
                next_tokens = torch.argmax(probs, dim=-1)

            # update generated ids, model inputs, and length for next step
            input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)
            model_kwargs = self._update_model_kwargs_for_generation(
                outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder
            )
            unfinished_sequences = unfinished_sequences.mul((sum(next_tokens != i for i in eos_token_id)).long())

            # stop when each sentence is finished, or if we exceed the maximum length
            if unfinished_sequences.max() == 0 or stopping_criteria(input_ids, scores):
                break
            yield input_ids

HuggingFace Transformers实现

hugging face也注意到这个需求,在v4.30.1加入了两个流式输出的接口:

  • TextStreamer: 能够在stdout中流式输出结果
  • TextIteratorStreamer:能够在自定义loop中进行操作

详细介绍如下

TextStreamer

Text generation strategiesWe’re on a journey to advance and democratize artificial intelligence through open source and open science.https://huggingface.co/docs/transformers/main/generation_strategies

The generate() supports streaming, through its streamer input. The streamer input is compatible any instance from a class that has the following methods: put() and end(). Internally, put() is used to push new tokens and end() is used to flag the end of text generation.

The API for the streamer classes is still under development and may change in the future.

In practice, you can craft your own streaming class for all sorts of purposes! We also have basic streaming classes ready for you to use. For example, you can use the TextStreamer class to stream the output of generate() into your screen, one word at a time:

from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer

tok = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")
inputs = tok(["An increasing sequence: one,"], return_tensors="pt")
streamer = TextStreamer(tok)

# Despite returning the usual output, the streamer will also print the generated text to stdout.
_ = model.generate(**inputs, streamer=streamer, max_new_tokens=20)

 TextIteratorStreamer

Utilities for GenerationWe’re on a journey to advance and democratize artificial intelligence through open source and open science.https://huggingface.co/docs/transformers/main/en/internal/generation_utils#transformers.TextStreamer

Streamer that stores print-ready text in a queue, to be used by a downstream application as an iterator. This is useful for applications that benefit from acessing the generated text in a non-blocking way (e.g. in an interactive Gradio demo).

from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
from threading import Thread

tok = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")
inputs = tok(["An increasing sequence: one,"], return_tensors="pt")
streamer = TextIteratorStreamer(tok)

# Run the generation in a separate thread, so that we can fetch the generated text in a non-blocking way.
generation_kwargs = dict(inputs, streamer=streamer, max_new_tokens=20)
thread = Thread(target=model.generate, kwargs=generation_kwargs)
thread.start()
generated_text = ""
for new_text in streamer:
    generated_text += new_text
generated_text

ChatGLM流式回复Demo 

以下是使用chatGLM6B加上TextIteratorStreamerTextStreamer的一个简单的cli demo文章来源地址https://www.toymoban.com/news/detail-595869.html

import os
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer, AutoModel
from transformers import TextIteratorStreamer
from threading import Thread

tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).half().cuda()
model = model.eval()

# 建构显示对话
def build_prompt(history):
    prompt = "欢迎使用 ChatGLM-6B 模型,输入内容即可进行对话,clear 清空对话历史,stop 终止程序"
    for query, response in history:
        prompt += f"\n\n用户:{query}"
        prompt += f"\n\nChatGLM-6B:{response}"
    return prompt

# 维护多轮历史
def build_history(history, query, response, index):
    history[index] = [query, response]
    return history

if __name__ == "__main__":
     # TextIteratorStreamer实现
    streamer = TextIteratorStreamer(tokenizer)
    history = []
    turn_count = 0
    while True:
        query = input("\n用户:")
        if query.strip() == "stop":
            break
        if query.strip() == "clear":
            history = []
            turn_count = 0
            os.system(clear_command)
            print("欢迎使用 ChatGLM-6B 模型,输入内容即可进行对话,clear 清空对话历史,stop 终止程序")
            continue
        
        history.append([query, ""])
        
        inputs = tokenizer([query], return_tensors="pt").to('cuda')
        generation_kwargs = dict(inputs, streamer=streamer, max_new_tokens=512)
        thread = Thread(target=model.generate, kwargs=generation_kwargs)
        thread.start()
        generated_text = ""
        count = 0
        # 流式输出
        for new_text in streamer:
            generated_text += new_text
            history = build_history(history, query, generated_text, turn_count)
            count += 1
            if count % 8 == 0:
                os.system("clear")
                print(build_prompt(history), flush=True)
        os.system("clear")
        print(build_prompt(history), flush=True)
        turn_count += 1
    
    # TextStreamer实现
    # streamer = TextStreamer(tokenizer)
    # _ = model.generate(**inputs, streamer=streamer, max_new_tokens=512)

到了这里,关于[AI]如何让语言模型LLMs流式输出:HuggingFace Transformers实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【AI大模型应用开发】【LangChain系列】9. 实用技巧:大模型的流式输出在 OpenAI 和 LangChain 中的使用

    大家好,我是同学小张,日常分享AI知识和实战案例 欢迎 点赞 + 关注 👏, 持续学习 , 持续干货输出 。 +v: jasper_8017 一起交流💬,一起进步💪。 微信公众号也可搜【同学小张】 🙏 本站文章一览: 当大模型的返回文字非常多时,返回完整的结果会耗费比较长的时间。如果

    2024年04月09日
    浏览(21)
  • 16K个大语言模型的进化树;81个在线可玩的AI游戏;AI提示工程的终极指南;音频Transformers课程 | ShowMeAI日报

    👀 日报周刊合集 | 🎡 生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 这张进化图来自于论文 「 On the Origin of LLMs: An Evolutionary Tree and Graph for 15,821 Large Language Models 」,构建了一个包含15821个大型语言模型的进化树和关系图,以便探索不同的大模型之间的关系 ⋙ 论文

    2024年02月16日
    浏览(6)
  • huggingface transformers库中LlamaForCausalLM

    新手入门笔记。 LlamaForCausalLM 的使用示例,这应该是一段推理代码。 参考: Llama2 https://huggingface.co/docs/transformers/v4.32.1/en/model_doc/llama2#transformers.LlamaForCausalLM

    2024年02月09日
    浏览(42)
  • huggingface transformers loadset 导入本地文件

    点击查看 Huggingface详细入门介绍之dataset库 json : 表示导入的本地文件是 json文件

    2024年02月11日
    浏览(16)
  • 使用SSE技术调用OPENAI接口并实现流式输出,用PHP语言实现

    作为AI语言模型服务提供商,OpenAI 提供了一系列的 API 接口,其中大部分需要通过 HTTP 请求访问。对于大量数据的请求,传统的同步请求会导致网络响应变慢,无法满足实时数据处理和分析的需求。因此,为了优化这些接口的调用效率,我们可以利用 SSE(Server Sent Events) 技术来

    2024年02月11日
    浏览(14)
  • 【AI之路】使用huggingface_hub优雅解决huggingface大模型下载问题

    Hugging face 资源很不错,可是国内下载速度很慢,动则GB的大模型,下载很容易超时,经常下载不成功。很是影响玩AI的信心。(有人说用迅雷啊,试试就知道有无奈。) 经过多次测试,终于搞定了下载,即使超时也可以继续下载。真正实现下载无忧!究竟如何实现?且看本文

    2024年02月09日
    浏览(13)
  • LLMs:《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性+设

    LLMs:《A Survey on Evaluation of Large Language Models大型语言模型评估综述》翻译与解读 导读 :该文章首先介绍了人工智能(AI)对机器智能的专注,并探讨了评估AI模型的方法。随后,重点介绍了大语言模型(LLMs)的背景和特点,以及它们在自然语言处理、推理、生成等各类任务中

    2024年02月03日
    浏览(25)
  • 【修改huggingface transformers默认缓存文件夹】

    最近在学习用TensorFlow框架做NLP任务,注意到huggingface中的transforms库非常强大,于是开始学习用它来做相应的任务。刚开始用这个库没多久,感觉确实操作起来既简单又强大,于是打算深入学习。 学习过程中发现,运行程序过程中,下载的模型和数据集是默认放在C盘的用户目

    2024年01月23日
    浏览(19)
  • Huggingface镜像网站下载语言模型方法

    通常通过镜像网站下载https://hf-mirror.com/。 在链接页面有介绍方法,对于不大的模型可以直接下载。这里介绍比较常用且方便的下载方法。 安装(huggingface_hub、hf_transfer安装可以使用-i命令从镜像网站下载) 基本命令(每次打开远程链接都要输入) 下载模型(下载NousResearch

    2024年02月21日
    浏览(24)
  • 语言模型:GPT与HuggingFace的应用

    本文分享自华为云社区《大语言模型底层原理你都知道吗?大语言模型底层架构之二GPT实现》,作者:码上开花_Lancer 。 受到计算机视觉领域采用ImageNet对模型进行一次预训练,使得模型可以通过海量图像充分学习如何提取特征,然后再根据任务目标进行模型微调的范式影响

    2024年02月05日
    浏览(19)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包