LLamafactory API部署与使用异步方式 API 调用优化大模型推理效率

news2024/12/27 8:56:26

文章目录

    • 背景介绍
      • 第三方大模型API
    • 介绍
    • LLamafactory 部署API
    • 大模型 API 调用工具类
    • 项目开源

背景介绍

第三方大模型API

目前,市面上有许多第三方大模型 API 服务提供商,通过 API 接口向用户提供多样化的服务。这些平台不仅能提供更多类别和类型的模型选择,还因其用户规模较大,能够以更低的成本从原厂获得服务,再将其转售给用户。此外,这些服务商还支持一些海外 API 服务,例如 ChatGPT 等,为用户提供了更加广泛的选择。

  • https://www.gptapi.us/register?aff=9xEy

比如上述网站以 API 接口的形式对外提供的服务,比官方的 API 要便宜。

装包:

pip install langchain langchain_openai

运行下述代码,完成上述网站的注册后,并填上述网站的 api_key 便可通过 python API 调用,就会收到 gpt-4o-mini 大模型的响应。

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini", 
    base_url="https://www.gptapi.us/v1/",
    api_key="sk-xxx", # 在这里填入你的密钥
    )
res = llm.invoke("你是谁?请你简要做一下,自我介绍?")
print(res)

介绍

在部署垂直领域模型时,我们通常会对开源大模型进行微调,并获得相应的 LoRA 权重。在接下来的部分,我将介绍如何使用 LLamafactory 将微调后的 LoRA 模型部署为 API 服务。

在 Python 中调用 API 服务时,如果采用同步方式进行请求,往往会导致请求速度较慢。因为同步方式需要在接收到上一条请求的响应后,才能发起下一条请求。

为了解决这一问题,我将为大家介绍如何通过异步请求的方式,在短时间内发送大量请求,从而提升 API 调用效率。

LLamafactory 部署API

关于 LLamafactory 的下载与微调模型,点击查看我的这篇博客:Qwen2.5-7B-Instruct 模型微调与vllm部署详细流程实战.https://blog.csdn.net/sjxgghg/article/details/144016723

vllm_api.yaml 的文件内容如下:

model_name_or_path: qwen/Qwen2.5-7B-Instruct
adapter_name_or_path: ../saves/qwen2.5-7B/ner_epoch5/
template: qwen
finetuning_type: lora
infer_backend: vllm
vllm_enforce_eager: true

# llamafactory-cli chat lora_vllm.yaml
# llamafactory-cli webchat lora_vllm.yaml
# API_PORT=8000 llamafactory-cli api lora_vllm.yaml

使用下述命令便可把大模型以 API 部署的方式,部署到8000端口:

API_PORT=8000 llamafactory-cli api vllm_api.yaml

在这里插入图片描述

LangChain 的 invoke 方法是常用的调用方式,但该方法并不支持异步操作。如果读者想了解同步与异步在速度上的差距,可以自行尝试使用一个 for 循环调用 invoke 方法,并对比其性能表现。

import os
from langchain_openai import ChatOpenAI
client = ChatOpenAI(
    model="gpt-3.5-turbo", 
    api_key="{}".format(os.environ.get("API_KEY", "0")),
    base_url="http://localhost:{}/v1".format(os.environ.get("API_PORT", 8000)),
)

res = llm.invoke("你是谁?请你简要做一下,自我介绍?")
print(res)

在这里插入图片描述

在项目文件夹下,新建一个 .env 文件, 其中 API_KEY 的值便是API接口调用的 API_KEY。

API_KEY=sk-12345678

LLamafactory 通过API部署的大模型地址是: http://localhost:8000/v1
API_KEY 是.env 文件中 API_KEY:sk-12345678

大模型 API 调用工具类

使用异步协程加快 API 的调用速度,可以参考我们前面的这篇文章:大模型 API 异步调用优化:高效并发与令牌池设计实践.https://blog.csdn.net/sjxgghg/article/details/143858730

我们在前面一篇文章的基础上,对异步类再封装了一下。

装包:

pip install langchain tqdm aiolimiter python-dotenv
import os
import random
import asyncio
import pandas as pd
from tqdm import tqdm
from typing import List
from dataclasses import dataclass, field
from aiolimiter import AsyncLimiter
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()


def generate_arithmetic_expression(num: int):
    """
    生成数学计算的公式和结果
    """
    # 定义操作符和数字范围,除法
    operators = ["+", "-", "*"]
    expression = (
        f"{random.randint(1, 100)} {random.choice(operators)} {random.randint(1, 100)}"
    )
    num -= 1
    for _ in range(num):
        expression = f"{expression} {random.choice(operators)} {random.randint(1, 100)}"
    result = eval(expression)
    expression = expression.replace("*", "x")
    return expression, result


@dataclass
class AsyncLLMAPI:
    """
    大模型API的调用类
    """

    base_url: str
    api_key: str  # 每个API的key不一样
    uid: int = 0
    cnt: int = 0  # 统计每个API被调用了多少次
    model: str = "gpt-3.5-turbo"
    llm: ChatOpenAI = field(init=False)  # 自动创建的对象,不需要用户传入
    num_per_second: int = 6  # 限速每秒调用6次

    def __post_init__(self):
        # 初始化 llm 对象
        self.llm = self.create_llm()
        # 创建限速器,每秒最多发出 5 个请求
        self.limiter = AsyncLimiter(self.num_per_second, 1)

    def create_llm(self):
        # 创建 llm 对象
        return ChatOpenAI(
            model=self.model,
            base_url=self.base_url,
            api_key=self.api_key,
        )

    async def __call__(self, text):
        # 异步协程 限速
        self.cnt += 1
        async with self.limiter:
            return await self.llm.agenerate([text])

    @staticmethod
    async def _run_task_with_progress(task, pbar):
        """包装任务以更新进度条"""
        result = await task
        pbar.update(1)
        return result

    @staticmethod
    def async_run(
        llms: List["AsyncLLMAPI"],
        data: List[str],
        keyword: str = "",  # 文件导出名
        output_dir: str = "output",
        chunk_size=500,
    ):

        async def _func(llms, data):
            """
            异步请求处理一小块数据
            """
            results = [llms[i % len(llms)](text) for i, text in enumerate(data)]
            with tqdm(total=len(results)) as pbar:
                results = await asyncio.gather(
                    *[
                        AsyncLLMAPI._run_task_with_progress(task, pbar)
                        for task in results
                    ]
                )
            return results

        idx = 0
        all_df = []
        while idx < len(data):
            file = f"{idx}_{keyword}.csv"
            file_dir = os.path.join(output_dir, file)

            if os.path.exists(file_dir):
                print(f"{file_dir} already exist! Just skip.")
                tmp_df = pd.read_csv(file_dir)
            else:
                tmp_data = data[idx : idx + chunk_size]

                loop = asyncio.get_event_loop()
                tmp_result = loop.run_until_complete(_func(llms=llms, data=tmp_data))
                tmp_result = [item.generations[0][0].text for item in tmp_result]
                tmp_df = pd.DataFrame({"infer": tmp_result})

                # 如果文件夹不存在,则创建
                if not os.path.exists(tmp_folder := os.path.dirname(file_dir)):
                    os.makedirs(tmp_folder)

                tmp_df.to_csv(file_dir, index=False)

            all_df.append(tmp_df)
            idx += chunk_size

        all_df = pd.concat(all_df)
        all_df.to_csv(os.path.join(output_dir, f"all_{keyword}.csv"), index=False)
        return all_df


if __name__ == "__main__":

    # 生成 数学计算数据集

    texts = []
    labels = []

    for _ in range(1000):
        text, label = generate_arithmetic_expression(2)
        texts.append(text)
        labels.append(label)

    llm = AsyncLLMAPI(
        base_url="http://localhost:{}/v1".format(os.environ.get("API_PORT", 8000)),
        api_key="{}".format(os.environ.get("API_KEY", "0")),
    )

    AsyncLLMAPI.async_run(
        [llm], texts, keyword="数学计算", output_dir="output", chunk_size=500
    )

使用异步类,在短时间内向对方服务器,发送大量的请求可能会导致服务器拒绝响应。
由于使用了异步的请求,则必须在所有的请求都完成后才能拿到结果。为了避免程序中途崩溃导致前面的请求的数据丢失,故 使用 chunk_size 对请求的数据进行切分,每完成一块数据的请求则把该块数据保存到csv文件中。

本文使用 generate_arithmetic_expression 生成1000条数学计算式,调用大模型 API 完成计算。

运行效果如下:

原始的 1000 条数据,设置chunk_size为500,故拆分为2块500条,分批进行处理。
在这里插入图片描述

为了避免程序崩垮,分批进行异步推理,若程序崩溃了,可重新运行,程序会从上一次崩溃的点重新运行。(要保证数据集输入的一致!)
在这里插入图片描述

最终的输出文件是 all_数学计算.csv ,它是所有分快csv文件的汇总。

项目开源

https://github.com/JieShenAI/csdn/tree/main/24/11/async_llm_api

在这里插入图片描述

  • vllm_api.yaml 是 llamafactory 的API部署的配置;
  • core.py 是主要代码;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2251566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Leecode】Leecode刷题之路第66天之加一

题目出处 66-加一-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 66-加一-官方解法 方法1&#xff1a;找出最长的后缀9 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&#…

uniapp-vue2引用了vue-inset-loader插件编译小程序报错

报错信息 Error: Vue packages version mismatch: - vue3.2.45 (D:\qjy-myApp\admin-app\node_modules\vue\index.js) - vue-template-compiler2.7.16 (D:\qjy-myApp\admin-app\node_modules\vue-template-compiler\package.json) This may cause things to work incorrectly.…

【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势

文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …

Shell脚本小练习

学习了这么长时间Shell脚本&#xff0c;总得来一次小小的练习吧&#xff0c;那么请看下文&#xff01; 1.用Shell写一个小计算器。 通过read命令获取用户输入的表达式&#xff0c;表达式的格式设定为操作数1 运算符 操作数2&#xff0c;例如53&#xff0c;然后利用设计的脚本…

二,[ACTF2020 新生赛]Include1感谢 Y1ng 师傅供题。

进入靶场后&#xff0c;发现tips可以点击 点击后进入此页面 猜测此为文件包含漏洞,构造payload&#xff0c;并成功得到base64编码后的源码 详解payload&#xff1a; php://filter/readconvert.base64-encode/resourceflag.php 1.php://filter是PHP中的一个流封装协议&#xf…

技术实践 | AI 安全:通过大模型解决高危WEB应用识别问题

一、引言 在日常企业安全能力建设中&#xff0c;收敛企业外网高危资产&#xff0c;以保障公司外部安全是企业安全的重要工作。WEB 高危服务&#xff08;如&#xff1a;管理后台、内部系统等&#xff09;外开是企业所面临的一个重要风险。针对该风险&#xff0c;传统的方式是基…

【Linux】TCP网络编程

目录 V1_Echo_Server V2_Echo_Server多进程版本 V3_Echo_Server多线程版本 V3-1_多线程远程命令执行 V4_Echo_Server线程池版本 V1_Echo_Server TcpServer的上层调用如下&#xff0c;和UdpServer几乎一样&#xff1a; 而在InitServer中&#xff0c;大部分也和UDP那里一样&…

osg、osgearth源码编译(二)

如果比较懒&#xff0c;也可以不看这篇文章&#xff0c;网上应该有很多编译好的库。也可以找我要。 本人还是建议学会编译&#xff0c;因为其他人电脑上编译好的&#xff0c;可能在你的电脑环境上&#xff0c;出现这样那样奇怪的问题&#xff0c;所以&#xff0c;最好还是自己能…

【QGIS入门实战精品教程】4.11:文本型字段转浮点型

《QGIS入门实战精品教程(配套案例数据)》:本专栏以实战案例的形式,深入浅出地介绍了QGIS的基本使用方法,用一个个实例讲解了QGIS基本操作与常见的空间分析方法。订阅专栏,获取专栏内所有文章阅读权限,从私信查收配套实验数据等资料,持续同步更新! 文章目录 一、加载实…

【R库包安装】R库包安装总结:conda、CRAN等

【R库包安装】R studio 安装rgdal库/BPST库 R studio 安装rgdal库解决方法 R studio 安装BPST库&#xff08;github&#xff09;解决方法方法1&#xff1a;使用devtools安装方法2&#xff1a;下载安装包直接在Rstudio中安装 参考 基础 R 库包的安装可参见另一博客-【R库包安装】…

探索 IntelliJ IDEA 中 Spring Boot 运行配置

前言 IntelliJ IDEA 作为一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;为 Spring Boot 应用提供了丰富的运行配置选项&#xff0c;定义了如何在 IntelliJ IDEA 中运行 Spring Boot 应用程序&#xff0c;当从主类文件运行应用程序时&#xff0c;IDE 将创建…

Qt支持RKMPP硬解的视频监控系统/性能卓越界面精美/实时性好延迟低/录像存储和回放/云台控制

一、前言 之前做的监控系统&#xff0c;已经实现了在windows上硬解码比如dxva2和d3d11va&#xff0c;后续又增加了linux上的硬解vdpau的支持&#xff0c;这几种方式都是跨系统的硬解实现方案&#xff0c;也是就是如果都是windows系统&#xff0c;无论X86还是ARM都通用&#xf…

全面解读权限控制与RBAC模型在若依中的实现

目录 前言1 权限控制基础概念1.1 权限控制的核心要素1.2 常见权限控制模型 2 RBAC模型详解2.1 RBAC的基本原理2.2 RBAC的优点2.3 RBAC的扩展模型 3 若依框架中的权限管理3.1 菜单管理3.2 角色管理3.3 用户管理 4 若依权限管理的实现流程4.1 创建菜单4.2 创建角色并分配权限4.3 …

qt QGraphicsEllipseItem详解

1、概述 QGraphicsEllipseItem是Qt框架中QGraphicsItem的一个子类&#xff0c;它提供了一个可以添加到QGraphicsScene中的椭圆项。QGraphicsEllipseItem表示一个带有填充和轮廓的椭圆&#xff0c;也可以用于表示椭圆段&#xff08;通过startAngle()和spanAngle()方法&#xff…

SAP SD学习笔记15 - 返品处理流程2 - 参照请求传票(发票)来生成返品传票

上一章讲了返品处理&#xff08;退货处理&#xff09;的流程。 SAP SD学习笔记14 - 返品处理&#xff08;退货处理&#xff09;的流程以及系统实操&#xff0c;比如 返品传票&#xff1b;请求Block标记&#xff1b;收到退货之后的处理&#xff0c;请求传票的登录_sap 销售返品…

在 ASP.NET C# Web API 中实现 Serilog 以增强请求和响应的日志记录

介绍 日志记录是任何 Web 应用程序的关键方面。它有助于调试、性能监控和了解用户交互。在 ASP.NET C# 中&#xff0c;集成 Serilog 作为记录请求和响应&#xff08;包括传入和传出的数据&#xff09;的中间件可以显著提高 Web API 的可观察性和故障排除能力。 在过去的几周里&…

Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档

家政服务系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着人们生活水平的提高&#xff0c;老龄化、少子化等多重因素影响&#xff0c;我国对家政服务人群的需求与日俱增。家政服务行业对我国的就业和社会效益贡献也与日俱增&#…

基于AutoEncode自编码器的端到端无线通信系统matlab误码率仿真

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 自编码器是…

深度学习与持续学习:人工智能的未来与研究方向

文章目录 1. 持续学习与深度学习1.1 深度学习的局限1.2 持续学习的定义 2. 目标与心智2.1 奖励假说2.2 心智的构成 3. 对研究方法的建议3.1 日常写作记录3.2 中立对待流行趋势 1. 持续学习与深度学习 1.1 深度学习的局限 深度学习注重“瞬时学习”&#xff0c;如ChatGPT虽在语…