当前位置: 代码网 > 服务器>软件设计>开源 > 阿里通义千问:本地部署Qwen1.5开源大模型

阿里通义千问:本地部署Qwen1.5开源大模型

2024年08月03日 开源 我要评论
通义千问为阿里云研发的大语言系列模型。千问模型基于Transformer架构,在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍、代码等。同时,在预训练模型的基础之上,使用对齐机制打造了模型的chat版本。

一、qwen1.5介绍

        通义千问为阿里云研发的大语言系列模型。千问模型基于transformer架构,在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍、代码等。同时,在预训练模型的基础之上,使用对齐机制打造了模型的chat版本。

开源模型序列

模型

介绍

模型下载

qwen1.5-110b-chat

通义千问1.5对外开源的110b规模参数量的经过人类指令对齐的chat模型。

魔搭社区

qwen1.5-72b-chat通义千问1.5对外开源的72b规模参数量的经过人类指令对齐的chat模型。魔搭社区
qwen1.5-32b-chat通义千问1.5对外开源的32b规模参数量的经过人类指令对齐的chat模型魔搭社区
qwen1.5-14b-chat通义千问1.5对外开源的14b规模参数量的经过人类指令对齐的chat模型。魔搭社区
qwen1.5-7b-chat通义千问1.5对外开源的7b规模参数量是经过人类指令对齐的chat模型。魔搭社区
qwen1.5-4b-chat通义千问1.5对外开源的4b规模参数量是经过人类指令对齐的chat模型。魔搭社区
qwen1.5-0.5b-chat通义千问1.5对外开源的0.5b规模参数量的经过人类指令对齐的chat模型。魔搭社区

二、本地部署qwen1.5

        由于资源问题,本机只能使用cpu运行qwen1.5_4b_chat,所以本次操作基于上述条件执行。

3.1 下载模型文件

      

可以hugging face hub 下载模型,如果从 huggingface 下载比较慢,也可以从 modelscope 中下载:

#从modelscope下载模型
git clone https://www.modelscope.cn/qwen/qwen1.5-4b-chat.git

3.2 安装依赖

        可以通过 conda 创建python环境安装依赖。

# vi requirements.txt

# basic requirements

fastapi>=0.110.0
uvicorn>=0.29.0
pydantic>=2.7.0
tiktoken>=0.6.0
sse-starlette>=2.0.0

transformers>=4.37.0
torch>=2.1.0
sentencepiece>=0.2.0
sentence-transformers>=2.4.0
accelerate


#安装依赖
pip install requirements.txt

        安装过程可能重新网络问题,无法下载相关文件,可以重复执行多次;也可以去pypi下载相关whl文件,离线安装。

3.2 编码实现

        通用python编码实现部署模型和提供restful api服务。

# 文件名:api-server-llm.py

# -*- coding: utf-8 -*-
# this is a sample python script.

import argparse
import datetime
import uuid
from threading import thread
import os

from typing import list, optional
from pydantic import basemodel
# press shift+f10 to execute it or replace it with your code.
# press double shift to search everywhere for classes, files, tool windows, actions, and settings.
import uvicorn
from fastapi import fastapi, request, response
from fastapi.responses import jsonresponse
from sse_starlette.sse import eventsourceresponse
from transformers import autotokenizer, automodelforcausallm, textiteratorstreamer
from utils import num_tokens_from_string


# 声明api
app = fastapi(default_timeout=1000 * 60 * 10)


# chat消息
class chatmessage(basemodel):
    # 角色
    role: str = none
    # chat内容
    content: str = none


# chat请求信息
class chatrequest(basemodel):
    # 对话信息
    messages: list[chatmessage]
    # 模型平台
    platform: str = none
    # 具体模型名称
    model: str = none
    # 客户端id
    clientid: str = none
    stream: optional[bool] = false


# 当前对话的模型输出内容
class chatresponsechoice(basemodel):
    # 模型推理终止的原因
    finishreason: str
    # 消息内容
    messages: chatmessage


# tokens 统计数据
class responseusage(basemodel):
    # 模型输入的 tokens 数量
    outputtokens: int
    # 用户输入的 tokens 数量
    inputtokens: int


# chat返回信息
class chatresponse(basemodel):
    clientid: str = none
    usage: responseusage
    choices: list[chatresponsechoice]


# 统一异常处理
@app.exception_handler(exception)
async def all_exceptions_handler(request: request, exc: exception):
    """
    处理所有异常
    """
    return jsonresponse(
        status_code=500,
        content={
            "msg": str(exc)
        }
    )


# 自定义中间件
@app.middleware("http")
async def unified_interception(request: request, call_next):
    # 在这里编写你的拦截逻辑
    # 例如,检查请求的header或参数
    # 如果不满足条件,可以直接返回响应,不再调用后续的路由处理
    token = request.headers.get("authorization")

    # if token is none:
    #     return jsonresponse({"message": "missing authorization"}, status_code=401)

    # 如果满足条件,则继续调用后续的路由处理
    response = await call_next(request)

    # 在这里编写你的响应处理逻辑
    # 例如,添加或修改响应头

    # 返回最终的响应
    return response


# 监控
@app.get("/api/models")
async def models():
    # 构造返回数据
    response = {
        "model": model_name
    }
    return jsonresponse(response, status_code=200)


# 构造 回复消息对象
def create_chat_response(request_id: str, role: str, content: str, input_tokens: int, output_tokens: int,
                         finish_reason: str):
    now = datetime.datetime.now()  # 获取当前时间
    time = now.strftime("%y-%m-%d %h:%m:%s")  # 格式化时间为字符串
    chat_message = {
        "output": {
            "choices": [{
                "finish_reason": finish_reason,
                "message": {
                    "role": role,
                    "content": content
                }
            }]
        },
        "request_id": request_id,
        "usage": {
            "input_tokens": input_tokens,
            "output_tokens": output_tokens,
            "total_tokens": (input_tokens + output_tokens)
        },
        "time": time
    }
    return chat_message


# 获取流式数据
def predict_stream(generation_kwargs: dict, request_id: str, input_tokens: int):
    thread = thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()
    output_tokens = 0

    for new_text in streamer:
        output_tokens = output_tokens + num_tokens_from_string(str(new_text))
        # 构造返回数据
        yield str(create_chat_response(request_id=request_id, role="assistant", content=new_text,
                                       input_tokens=input_tokens, output_tokens=output_tokens, finish_reason=""))

    yield str(create_chat_response(request_id=request_id, role="assistant", content="", input_tokens=input_tokens,
                                   output_tokens=output_tokens, finish_reason="stop"))


@app.post("/api/v1/chat/completions")
async def completions(request: chatrequest):
    # if model_name != request.model:
    #     return jsonresponse({"msg": "模型异常!"}, status_code=500)

    if len(request.messages) <= 0:
        return jsonresponse({"msg": "消息不能为空!"}, status_code=500)

    # 请求id
    request_id = str(uuid.uuid4())
    # 计算输入tokens
    input_tokens = sum(num_tokens_from_string(message.content) for message in request.messages)

    # 使用自带的聊天模板,格式化对话记录
    text = tokenizer.apply_chat_template(request.messages, tokenize=false, add_generation_prompt=true)
    model_inputs = tokenizer(text, return_tensors="pt").to("cpu")

    if request.stream:
        print("----流式-----")
        # 流式对象

        generation_kwargs = dict(**model_inputs, streamer=streamer, max_new_tokens=4096,
                                 pad_token_id=tokenizer.eos_token_id,
                                 num_beams=1, do_sample=true, top_p=0.8,
                                 temperature=0.3)
        generate = predict_stream(generation_kwargs=generation_kwargs, request_id=request_id, input_tokens=input_tokens)

        return eventsourceresponse(generate, media_type="text/event-stream")

    print("----非流式-----")
    # 非流式
    generated_ids = model.generate(
        model_inputs.input_ids
        , max_new_tokens=512
    )
    generated_ids = [
        output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
    ]

    response = tokenizer.batch_decode(generated_ids, skip_special_tokens=true)[0]
    # 计算输出tokens
    output_tokens = num_tokens_from_string(response)
    # 构造返回数据
    result = create_chat_response(request_id=request_id, role="assistant", content=response, input_tokens=input_tokens,
                                  output_tokens=output_tokens, finish_reason="stop")
    return jsonresponse(result, status_code=200)


if __name__ == '__main__':
    # 定义命令行解析器对象
    parser = argparse.argumentparser(description='大语言模型参数解析器')
    # 添加命令行参数、默认值
    parser.add_argument("--host", type=str, default="0.0.0.0")
    parser.add_argument("--port", type=int, default=8860)
    parser.add_argument("--model_path", type=str, default="")
    parser.add_argument("--model_name", type=str, default="")
    # 从命令行中结构化解析参数
    args = parser.parse_args()

    # 模型路径
    model_path = args.model_path
    model_name = args.model_name

    if len(model_path) <= 0:
        raise exception("大语言模型路径不能为空!")
    # 如果没有传入模型名称,则从路径中获取
    if len(model_name) == 0:
       model_dir, model_name = os.path.split(model_path)

    tokenizer = autotokenizer.from_pretrained(model_path, trust_remote_code=true)

    model = automodelforcausallm.from_pretrained(
        model_path, trust_remote_code=true, device_map='auto'
    ).eval()
    # 流式输出
    streamer = textiteratorstreamer(tokenizer=tokenizer, skip_prompt=true, skip_special_tokens=true)

    # 启动 uvicorn 服务
    uvicorn.run(app, host=args.host, port=args.port)

  工具类:utils.py

import tiktoken


# 计算token数量
def num_tokens_from_string(string: str) -> int:
    encoding = tiktoken.get_encoding('cl100k_base')
    num_tokens = len(encoding.encode(string))
    return num_tokens

3.3 运行服务

# 运行脚本,指定模型路径
python api-server-llm.py --model_path=f:\llm\model\qwen1.5-4b-chat

3.4 使用api访问

      

curl -x post -h "content-type: application/json" 'http://localhost:8860/api/v1/chat/completions' \
-d '{
	"platform": "tongyi", 
	"model": "qwen1.5-4b-chat",  
	"stream":true, 
	"messages":[ 
		{
			"role": "user", 
			"content": "你好,你是谁?" 
		} 
	]
  }'

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com