如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)

如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)

  • 如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)
    • 模型地址
    • 模型下载
    • 模型部署
      • 指定显卡运行
      • app.py
    • 运行环境
      • requirements
    • 调用接口
      • 代码调用
    • 结语

如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)

本文详细介绍了如何在本地服务器上部署大模型(如DeepSeek、Llama3、Qwen等),并通过接口实现外部调用。首先,从HuggingFace或魔搭网站下载模型,使用git lfs和screen确保大文件完整下载;接着,使用FastAPI封装模型推理过程,支持多GPU运行并通过CUDA_VISIBLE_DEVICES指定显卡,提供完整的app.py代码实现模型加载和接口响应;然后,通过conda创建Python 3.10环境并安装依赖,使用nohup后台运行服务;最后,展示如何通过Postman或代码调用接口,发送请求并获取模型生成的文本。本文提供了从模型下载、部署到接口调用的完整流程,适合在本地服务器上运行大模型并实现高效的推理服务。

模型地址

在HuggingFace中搜索对应模型,并选择git clone
比如

git clone https://huggingface.co/deepseek-ai/DeepSeek-V2-Chat

huggingface网站可能会访问超时,因此可以选择国内的魔搭网站,同样登录网站后,搜索对应模型并下载

在这里插入图片描述

git clone https://www.modelscope.cn/deepseek-ai/DeepSeek-V2-Lite-Chat.git

模型下载

由于模型比较大,所以需要用git lfs install

如果是下载70B或者更大的模型,可能git clone还是会遗漏一些文件,所以推荐使用Screen在后台下载

创建conda环境后,使用conda install -c conda-forge screen安装screen

为 screen 会话指定一个名称,可以使用 -S 参数:

screen -S mysession

暂时离开当前 screen 会话(但保持会话在后台运行)

Ctrl + A,然后按 D

重新连接到之前创建的 screen 会话,可以使用以下命令:

screen -r mysession

screen相当于启动了一个新的终端,与其他的终端互不影响,其中的工作都在后台运行

在screen中运行 git clone命令即可

如果出现文件遗漏,可以使用sh脚本指定文件下载,比如指定三个文件进行下载的download_files.sh

#!/bin/bash

# 目标 URL 和文件名的前缀
BASE_URL="https://www.modelscope.cn/models/LLM-Research/Llama-3.3-70B-Instruct/resolve/master"
FILES=(
    "model-00028-of-00030.safetensors"
    "model-00029-of-00030.safetensors"
    "model-00030-of-00030.safetensors"
)

# 循环下载文件
for FILE in "${FILES[@]}"; do
    echo "开始下载 $FILE ..."
    curl -O "$BASE_URL/$FILE"  # 使用 curl 下载文件
    if [ $? -eq 0 ]; then
        echo "$FILE 下载成功"
    else
        echo "$FILE 下载失败"
    fi
done

echo "所有文件下载完毕!"

在终端中运行脚本:

./download_files.sh
  • ./ 表示当前目录,确保系统知道从当前目录查找脚本。

模型部署

模型下载后,本地就有了完整的模型仓库

在这里插入图片描述
接下来就要进行模型的部署,采用fastapi进行模型部署,使用下列代码作为app.py

指定显卡运行

如果你有多张显卡,并且想指定使用第4和第5张GPU运行,可以在环境变量中设置仅4,5 GPU可见,此时第4变为0 第5变为1

if "DeepSeek" in MODEL_PATH_OR_NAME:
    os.environ['CUDA_VISIBLE_DEVICES'] = '4'
else:
    os.environ['CUDA_VISIBLE_DEVICES'] = '4,5'

然后加载模型时设置device_map="auto"

model = AutoModelForCausalLM.from_pretrained(MODEL_PATH_OR_NAME, torch_dtype=torch.float16, device_map="auto")

app.py

import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import torch
import torch.nn as nn
# Initialize FastAPI app
app = FastAPI()

MODEL_PATH_OR_NAME = "/yourpath/DeepSeek-V2-Lite-Chat"

# Set CUDA devices for visibility
if "DeepSeek" in MODEL_PATH_OR_NAME:
    os.environ['CUDA_VISIBLE_DEVICES'] = '4'
else:
    os.environ['CUDA_VISIBLE_DEVICES'] = '4,5'
device = torch.device('cuda:0')  # Using GPU 2

# Declare global variables for model and tokenizer
model = None
tokenizer = None

# Use startup and shutdown events for model loading and unloading
@app.on_event("startup")
async def startup():
    global model, tokenizer
    print("Loading model and tokenizer...")
    if "DeepSeek" in MODEL_PATH_OR_NAME:
        tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH_OR_NAME, trust_remote_code=True)
        model = AutoModelForCausalLM.from_pretrained(MODEL_PATH_OR_NAME, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map="auto").cuda()
        model.generation_config = GenerationConfig.from_pretrained(MODEL_PATH_OR_NAME)
        model.generation_config.pad_token_id = model.generation_config.eos_token_id
    else:
        tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH_OR_NAME, use_fast=False)
        tokenizer.pad_token_id = tokenizer.eos_token_id  # 假设eos_token_id就是合适的填充词元标识
        model = AutoModelForCausalLM.from_pretrained(MODEL_PATH_OR_NAME, torch_dtype=torch.float16, device_map="auto")

    print("Model loaded successfully!")

@app.on_event("shutdown")
async def shutdown():
    global model, tokenizer
    print("Shutting down the model...")
    del model
    del tokenizer

# Define request model using Pydantic
class ChatCompletionRequest(BaseModel):
    model: str
    messages: list
    temperature: float = 0
    max_tokens: int = 256
    top_p: float = 1
    stop: list = None  # Ensure stop is a list or None

# Define response model
class ChatCompletionResponse(BaseModel):
    choices: list

# Define the /generate route
@app.post("/generate", response_model=ChatCompletionResponse)
async def generate_response(request: ChatCompletionRequest):
                # Get user prompt (last message)
    prompt = request.messages[-1]["content"]
    print('INPUT :'+prompt+'\n')
    if "DeepSeek" in MODEL_PATH_OR_NAME:
        try:
            messages = [
                {"role": "user", "content": prompt}
            ]
            input_tensor = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")
            outputs = model.generate(input_tensor.to(device), max_new_tokens=100)

            result = tokenizer.decode(outputs[0][input_tensor.shape[1]:], skip_special_tokens=True)
            print('OUTPUT :'+result)
            return ChatCompletionResponse(
                choices=[{
                    "message": {"role": "assistant", "content": result},
                    "finish_reason": "stop"
                }]
            )

        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))
    else:
        try:
            # Tokenize the input text (with padding and truncation to ensure consistency)
            input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)

            # Optionally, get eos_token_id for stopping criteria
            eos_token_id = tokenizer.eos_token_id if tokenizer.eos_token_id else None
            attention_mask = torch.ones(input_ids.shape,dtype=torch.long,device=device)
            # Generate the response using the model
            output = model.generate(
                input_ids,
                num_beams=1,  # Use greedy decoding
                num_return_sequences=1,
                early_stopping=True,
                do_sample=False,
                max_length=(getattr(request, 'max_tokens', 50) + len(input_ids[0])),  # 默认 max_tokens=50
                top_p=getattr(request, 'top_p', 0.9),  # 默认 top_p=0.9
                temperature=getattr(request, 'temperature', 0.9),  # 默认 temperature=1.0
                repetition_penalty=getattr(request, 'repetition_penalty', 1.2),  # 默认 repetition_penalty=1.2
                eos_token_id=eos_token_id,  # Use eos_token_id for stopping
                attention_mask=attention_mask,
                pad_token_id=eos_token_id
            )


            # Decode the generated text (skip special tokens)
            generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

            # Strip the prompt (remove the input part from the output)
            output_tokens = output[0][len(input_ids[0]):]  # Remove input tokens from output tokens
            generated_text = tokenizer.decode(output_tokens, skip_special_tokens=True)
            print('OUTPUT:'+generated_text)
            # Return the generated text in the expected format
            return ChatCompletionResponse(
                choices=[{
                    "message": {"role": "assistant", "content": generated_text.strip()},
                    "finish_reason": "stop"
                }]
            )

        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))


# Health check route
@app.get("/")
async def health_check():
    return {"status": "ok", "message": "Text Generation API is running!"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("app:app", host="0.0.0.0", port=8890, reload=True)  # reload=True 用于开发时的热重载

运行环境

运行app.py前需要安装环境依赖

首先
conda 创建环境:

conda create -n llmapi python=3.10 -y
conda activate llmapi

安装以下依赖,保存为requirements,txt

requirements

accelerate==1.1.1
annotated-types==0.7.0
anyio==4.6.2.post1
certifi==2024.8.30
charset-normalizer==3.4.0
click==8.1.7
exceptiongroup==1.2.2
fastapi==0.115.5
filelock==3.16.1
fsspec==2024.10.0
gputil==1.4.0
h11==0.14.0
huggingface-hub==0.26.3
idna==3.10
jinja2==3.1.4
markupsafe==3.0.2
mpmath==1.3.0
# networkx==3.2.1
numpy==2.0.2
nvidia-cublas-cu12==12.4.5.8
nvidia-cuda-cupti-cu12==12.4.127
nvidia-cuda-nvrtc-cu12==12.4.127
nvidia-cuda-runtime-cu12==12.4.127
nvidia-cudnn-cu12==9.1.0.70
nvidia-cufft-cu12==11.2.1.3
nvidia-curand-cu12==10.3.5.147
nvidia-cusolver-cu12==11.6.1.9
nvidia-cusparse-cu12==12.3.1.170
nvidia-nccl-cu12==2.21.5
nvidia-nvjitlink-cu12==12.4.127
nvidia-nvtx-cu12==12.4.127
packaging==24.2
pillow==11.0.0
protobuf==5.29.0
psutil==6.1.0
pydantic==2.10.2
pydantic-core==2.27.1
pyyaml==6.0.2
regex==2024.11.6
requests==2.32.3
safetensors==0.4.5
sentencepiece==0.2.0
sniffio==1.3.1
starlette==0.41.3
sympy==1.13.1
tokenizers==0.20.3
torch==2.5.1
torchaudio==2.5.1
torchvision==0.20.1
tqdm==4.67.1
transformers==4.46.3
triton==3.1.0
typing-extensions==4.12.2
urllib3==2.2.3
uvicorn==0.32.1

运行下列命令安装:

pip install -r requirements,txt

然后运行下列命令启动app.py ,这个命令会在后台启动app.py,并且输出日志在app.log 文件内

nohup python app.py > app.log 2>&1 &

调用接口

查看日志模型是否成功启动:

在这里插入图片描述

然后使用Post请求对应接口

{
            "model": "deep seek", 
            "messages": [{"role": "user", "content": "AI是什么意思?"}],
            "temperature": 0.9,
            "max_tokens": 100,
            "repetition_penalty": 1.2, 
            "top_p": 0.9,
            "stop": ["\n"] 
        }   

使用PostMan测试结果:

在这里插入图片描述

代码调用

 import requests
 import json

 # Define the FastAPI URL
 url = "http://YourIPAddress:YourPort/generate"
 prompt = '你是什么模型?'
 # Define the request payload (data)
 data = {
     "model": "ModelName",  # Example model name (change according to your setup)
     "messages": [{'role': 'user', 'content': prompt}],
     "temperature": 0.7,
     "max_tokens": 100,
     "top_p": 1.0,
     "frequency_penalty": 0.0,
     "presence_penalty": 0.0,
     "stop": []  # Ensure 'stop' is an empty list
 }
 response = ''
 # Send a POST request to the FastAPI endpoint
 response_data = requests.post(url, json=data)

 # Check the response
 if response_data.status_code == 200:
     # print("Response received successfully:")
     # print(json.dumps(response.json(), indent=4))
     result = response_data.json()
     # 从响应中获取生成的文本
     response = str(result['choices'][0]['message']['content']).strip()
 else:
     print(f"Request failed with status code {response_data.status_code}")
     print(response_data.text)
 return response

结语

至此,大模型的本地部署和接口调用就介绍完了

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vmware-ubuntu22.04配置虚拟机win10,重新上网成功

打开问题显示 Hardware配置 Options配置 最后的Advanced,第一次用了BIOS,然后启动中有更新,然后关闭,再用UEFI启动

GDPU Android移动应用 重点习题集

目录 程序填空 ppt摘选 题目摘选 “就这两页ppt,你还背不了吗” “。。。” 打开ppt后 “Sorry咯,还真背不了😜” 更新日志 考后的更新日志 没想到重点勾了一堆,还愣是没考到其中的内容,翻了一下,原…

运行.Net 7 Zr.Admin项目(后端)

1.下载Zr.Admin代码压缩包 https://codeload.github.com/izhaorui/Zr.Admin.NET/zip/refs/heads/main 2.打开项目 我这里装的是VS2022社区版 进入根目录,双击ZRAdmin.sln打开项目 3.安装.net7运行时 我当时下载的代码版本是.net7的 点击安装 点击安装&#xff0…

代码随想录算法训练营第3天(链表1)| 203.移除链表元素 707.设计链表 206.反转链表

一、203.移除链表元素 题目:203. 移除链表元素 - 力扣(LeetCode) 视频:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili 讲解:代码随想录 注意: 针对头结点和非头结点的…

2024年总结及2025年目标之关键字【稳进】

1. 感受 时光荏苒,都731天(2年时间)下来了,从第一年的【坚持】,到第二年的【提速】,定目标,现在回头看,还是那句话【事非经过不知难】,那又怎么样呢,再难不是…

qt QLabel QPushButton 控件重写paintEvent后 控件消失

qt 继承自PushButton控件的类 重写paintEvent后 控件消失 解决办法,在paintevent结尾加上这条语句:QPushButton::paintEvent(event); void MyButton::paintEvent(QPaintEvent *event) {QPushButton::paintEvent(event); } 这里QPushButton不能写成Q…

苹果手机(IOS系统)出现安全延迟进行中如何关闭?

苹果手机(IOS系统)出现安全延迟进行中如何关闭? 一、设置二、隐私与安全性三、失窃设备保护关闭 一、设置 二、隐私与安全性 三、失窃设备保护关闭

ELK的搭建

ELK elk:elasticsearch logstatsh kibana统一日志收集系统 elasticsearch:分布式的全文索引引擎点非关系型数据库,存储所有的日志信息,主和从,最少需要2台 logstatsh:动态的从各种指定的数据源,获取数据…

从CentOS到龙蜥:企业级Linux迁移实践记录(龙蜥开局)

引言: 在我们之前的文章中,我们详细探讨了从CentOS迁移到龙蜥操作系统的基本过程和考虑因素。今天,我们将继续这个系列,重点关注龙蜥系统的实际应用——特别是常用软件的安装和配置。 龙蜥操作系统(OpenAnolis&#…

【AI自动化渗透】大模型支持的自动化渗透测试,看蚂蚁和浙大的

参考文章: https://mp.weixin.qq.com/s/WTaO54zRxtNMHaiI1tfdGw 最近,美国西北大学,浙江大学,蚂蚁集团的一些专家学者联手发表了一篇论文,介绍了一个PentestAgent的方案,实现了渗透测试自动化。 01 技术方案 图的字…

探秘block原理

01 概述 在iOS开发中,block大家用的都很熟悉了,是iOS开发中闭包的一种实现方式,可以对一段代码逻辑进行封装,使其可以像数据一样被传递、存储、调用,并且可以保存相关的上下文状态。 很多block原理性的文章都比较老&am…

【Java】-- 利用 jar 命令将配置文件添加到 jar 中

目录 1、准备 2、目标 3、步骤 3.1、安装 jdk 3.2、添加配置文件 3.3、校验 1、准备 java 环境hadoop-core-1.2.1.jar 和 core-site.xml 2、目标 将 core-site.xml 添加到 hadoop-core-1.2.1.jar 中。 3、步骤 3.1、安装 jdk 3.2、添加配置文件 jar -cvf hadoop-core-…

概率论与数理统计总复习

复习课本:中科大使用的教辅《概率论和数理统计》缪柏其、张伟平版本 目录 0.部分积分公式 1.容斥原理 2.条件概率 3.全概率公式 4.贝叶斯公式 5.独立性 6.伯努利分布(两点分布) 7.二项分布 8.帕斯卡分布(负二项分布&am…

阿里mod_asr3.0集成webrtc静音算法

alibabacloud-nls-cpp-sdk-master 先到阿里官网下载nls库的源代码,编译生成对应的库文件和头文件。 我编译的放到了以下目录。 /home/jp/2025/alibabacloud-nls-cpp-sdk-master/build/install/NlsSdk3.X_LINUX/include/ /home/jp/2025/alibabacloud-nls-cpp-sdk-…

机器人碳钢去毛刺,用大扭去毛刺主轴可轻松去除

在碳钢精密加工的最后阶段,去除毛刺是确保产品质量的关键步骤。面对碳钢这种硬度较高的材料,采用大扭矩的SycoTec去毛刺主轴,成为了行业内的高效解决方案。SycoTec作为精密加工领域的领军品牌,其生产的高速电主轴以其卓越的性能&a…

iOS 逆向学习 - Inter-Process Communication:进程间通信

iOS 逆向学习 - Inter-Process Communication:进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…

音视频入门基础:RTP专题(1)——RTP官方文档下载

一、引言 实时传输协议(Real-time Transport Protocol,简写RTP)是一个网络传输协议,由IETF的多媒体传输工作小组1996年在《RFC 1889》中公布的。 RTP作为因特网标准在《RFC 3550》有详细说明。而《RFC 3551》详细描述了使用最小…

qt-C++笔记之自定义继承类初始化时涉及到parents的初始化

qt-C笔记之自定义继承类初始化时涉及到parents的初始化 code review! 参考笔记 1.qt-C笔记之父类窗口、父类控件、对象树的关系 2.qt-C笔记之继承自 QWidget和继承自QObject 并通过 getWidget() 显示窗口或控件时的区别和原理 3.qt-C笔记之自定义类继承自 QObject 与 QWidget …

《图解HTTP》 学习日记

1.了解WEB以及网络基础 1.1使用HTTP协议访问WEB web页面显示:根据web浏览器地址栏中输入指定的URL,web浏览器从web服务端获取文件资源(resource)等信息,从而显示出web页面 1.2网络基础TCP/IP 通常使用的网络(包括 互联网)是在tcp/ip协议族的基础上运作的&#xf…

VSCODE使用Echarts组件库(不是vue)

第一步打开Echarts官网 Examples - Apache ECharts 第二步随便点击一个图形点击我圈的按钮 第三步