华为昇腾服务器部署DeepSeek模型实战
在华为的昇腾服务器上部署了DeepSeek R1的模型进行验证测试,记录一下相关的过程。服务器是配置了8块910B3的显卡,每块显卡有64GB显存,根据DeepSeek R1各个模型的参数计算,如果部署R1的Qwen 14B版本,需要1张显卡,如果是32B版本,需要2张,Llama 70B的模型需要4张显卡。如果是R1全参数版本,则需要32张显卡,也就是4台满配的昇腾服务器。这里先选择32B的模型进行部署测试,等之后申请更多的算力资源之后再测试部署全参数版本。另外除了部署32B之外,为了能更好地使用DeepSeek,还部署了一个语义嵌入向量模型Bge-zh和向量数据库Chromadb,用于对文本进行编码,方便构建知识库,以及部署了Open Webui服务,使得用户可以访问Webui的方式来使用DeepSeek。
DeepSeek的部署
首先简单介绍一下DeepSeek模型的一些技术特点,包括了
- 基于Transformer搭建的深度神经网络,可以实现高效的语义理解和文本生成能力。
- 改进的Transformer多头注意力MHA架构,提出了多头潜在注意力MLA,实现对K,V向量的低秩分解,降低了训练和推理中的算力需求。
- 混合专家结构,DeepSeek大模型由多个小型专家网络模型组成,不同的专家网络为不同的场景领域进行优化训练,在接受任务时根据任务类型自动路由到特定的专家网络进行推理,有效节省了对算力的需求。DeepSeek大模型全参数版本由6710亿参数,但推理时只需要用到特定专家网络的370亿参数。
- 强化学习技术,通过在V3大模型上采用改进后的GPRO优化算法以及基于规则的奖励系统进行强化学习,可以有效地训练模型使用长思维链方式来增加其推理思考能力。
- 知识蒸馏技术,把R1大模型生成的预料数据,对其他较小参数量的大模型如LLAMA或阿里通义千问进行知识蒸馏训练,有效提高了这些大模型的性能,实现了在相同参数量技术上对原有性能的提高。
部署过程是,首先要在华为官网下载相应的MindIE镜像,这个网页有产品版本信息-版本说明-MindIE1.0.0开发文档-昇腾社区相关的介绍,在模型库-ModelZoo-昇腾这个网站上选择我们需要的模型,然后会介绍相应的镜像版本。对于DeepSeek-R1-Distill-Qwen系列的模型,对应910显卡的是1.0.0-800I-A2-py311-openeuler24.03-lts这个镜像版本。需要注意的是,这个镜像有ARM64和X86_64两个版本,因为我需要现在本地笔记本电脑下载镜像再上传到服务器,所以需要先在服务器上通过命令uname -m来查看服务器的架构,如果是ARM64的架构,在本地笔记本下载镜像的时候需要在docker pull后面加上--platform=linux/aarch64。
下一步是下载模型的权重文件,我们可以在hf-mirror.com这个网站上找到对应的权重文件,下载到本地。我选择的是DeepSeek-R1-Distill-Qwen-32B的模型。
然后在服务器端我们可以加载镜像运行容器了,例如以下的命令
docker run -it -d --net=host --shm-size=1g --network=llm-network -p 9999:1025 --privileged --name deepseek-qwen-32b --device=/dev/davinci_manager --device=/dev/hisi_hdc --device=/dev/devmm_svm -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro -v /usr/local/sbin:/usr/local/sbin:ro -v /data/models/DeepSeek-R1-Distill-Qwen-32B:/model:rw swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:1.0.0-800I-A2-py311-openeuler24.03-lts bash
容器启动后,我们通过命令登录到容器上,修改Config.json配置文件。
docker exec -it deepseek-qwen-32b bash
chmod 750 /model
vim /usr/local/Ascend/mindie/latest/mindie-service/conf/config.json
修改以下位置
{..."ServerConfig" :{"ipAddress" : "0.0.0.0","allowAllZeroIpListening" : true,"httpsEnabled" : false,...}"BackendConfig" : {"npuDeviceIds" : [[0,1]],"ModelDeployConfig" :{"maxSeqLen" : 8192,"maxInputTokenLen" : 4096,"truncation" : false,"ModelConfig" : [{"modelInstanceType" : "Standard","modelName" : "DeepSeek-R1-Distill-Qwen-32B","modelWeightPath" : "/model","worldSize" : 2,"cpuMemSize" : 5,"npuMemSize" : -1,"backendType" : "atb","trustRemoteCode" : false}]},"ScheduleConfig" :{..."maxIterTimes" : 8192,}}
}
在以上配置中,我设置了模型部署在2张910 NPU卡上,然后调整了maxSeqLen,maxInputTokenLen,maxIterTimes这几个参数。原来的默认值maxSeqLen=2560,maxInputTokenLen=2048,我理解对应的意思上输入Token不能超过2048,然后输出Token不能超过2560-2048=512个,如果要调大输出的token数,也要相应做出调整,但是好像maxIterTimes这个参数也要做相应调整,按照文档意思这是控制一句话的最大长度的。
最后就是启动推理服务,提供服务化API接口给外部应用调用。
cd /usr/local/Ascend/mindie/latest/mindie-service/bin
./mindieservice_daemon
API接口提供了兼容OpenAI的格式,所以服务启动后我们可以调用接口测试一下
curl -X POST "http://127.0.0.1:1025/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{
"model": "DeepSeek-R1-Distill-Qwen-32B",
"max_tokens": 3000,
"stream": false,
"temperature": 0.6,
"messages": [
{"role": "user", "content": "Please describe guangzhou city in about 2000 words"}
]
}'
注意这里设置了Temperature为0.6,以及在Message里面没有设置System Prompt,这是根据官网上的说明来设置的:
- Set the temperature within the range of 0.5-0.7 (0.6 is recommended) to prevent endless repetitions or incoherent outputs.
- Avoid adding a system prompt; all instructions should be contained within the user prompt.
向量嵌入模型的部署
现在要部署一个向量嵌入模型来配合知识库的使用。在MindIE的网站提到了可以适配HuggingFace的Text Embeddings Interface框架,见网页功能介绍-TEI-MindIE开源第三方服务化框架适配开发指南-服务化集成部署-MindIE1.0.0开发文档-昇腾社区
但是这个TEI的接口和OpenAI或或者Ollama的embedding接口不兼容,因为我想部署Open Webui来对接,Open webui无法调用TEI,因此我还不能直接采取部署TEI镜像的方式来启动Embedding服务。
在MindIE镜像的/usr/local/Ascend/atb-models/examples/models目录下,有介绍当前适配的一些模型,其中我们可以找到Bge这个目录,这是对应bge-zh这个embedding模型的。因此我尝试加载这个模型。同样在hf-mirror网站上找到bge-large-zh-v1.5模型的权重并下载,然后启动一个新的容器,如以下命令
docker run -it -d --net=host --shm-size=1g --network=llm-network -p 9998:8088 --privileged --name bge-zh --device=/dev/davinci_manager --device=/dev/hisi_hdc --device=/dev/devmm_svm -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro -v /usr/local/sbin:/usr/local/sbin:ro -v /data/models/bge-base-zh-v1.5:/model:rw swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:1.0.0-800I-A2-py311-openeuler24.03-lts bash
容器启动后,进入容器
docker exec -it bge-zh bash
chmod 750 /model
source /usr/local/Ascend/ascend-toolkit/set_env.sh
下载的模型权重都放置在容器的/model目录下,然后调用模型的脚本文件是放置在容器的/usr/local/Ascend/atb-models/examples/models/embeddings目录下,参考/model/config.json中的model_type的值,用脚本文件目录/usr/local/Ascend/atb-models/examples/models/embeddings/bert的'modeling_bert.py`替换下载模型权重的 `modeling_bert.py'
修改模型权重配置文件/model/config.json,修改_name_or_path的值指向/model,设置auto_map的值,修改后的配置如下:
{"_name_or_path": "/model","auto_map": {"AutoModel": "/model--modeling_bert.BertModel"},...
}
完成后即可在脚本文件目录下运行以下命令来测试
python run.py \embed \--model_name_or_path=/model \--trust_remote_code \--device_type=npu \--device_id=3 \--text='this is a test'
可以看到能成功输出Embedding后的向量。
之后就是增加一个和Ollama兼容的embed接口,这里我采用fastapi来做,新建一个名为embed_api.py文件,内容如下:
import time
from typing import Any, List, Unionimport torch
from transformers.tokenization_utils_base import BatchEncodingfrom atb_llm.utils.log.logging import logger, message_filter
from atb_llm.utils.log.error_code import ErrorCodefrom model_runner import ModelRunner, Argumentsfrom fastapi import FastAPI
from fastapi.encoders import jsonable_encoderimport uvicorn
from pydantic import BaseModelapp = FastAPI()class Runner:def __init__(self, **kwargs: Any) -> None:self.model = ModelRunner(str(kwargs.pop("model_name_or_path", None)),bool(kwargs.pop("trust_remote_code", True)),getattr(torch, kwargs.pop("torch_dtype", "float16")),torch.device(f"{kwargs.pop('device_type', 'cpu')}:{str(kwargs.pop('device_id', 0))}"),str(kwargs.pop("model_type", None)))self.model_name_or_path = self.model.model_name_or_pathself.torch_dtype = self.model.torch_dtypeself.device = self.model.device#self.device = 'npu:4'self.model_type = self.model.model_typeself.config = self.model.configself.tokenizer = self.model.tokenizerself.max_batch_size = kwargs.pop("max_batch_size", 1)self.max_seq_len = kwargs.pop("max_seq_len", self.tokenizer.model_max_length)self.return_tensors = kwargs.pop("return_tensors", "pt")self.tokenizer_args = {"padding": kwargs.pop("padding", "max_length"),"truncation": kwargs.pop("truncation", True),"return_tensors": self.return_tensors,"max_length": self.max_seq_len,}def warm_up(self) -> None:inputs = self.model.generate_inputs(self.tokenizer.model_input_names,self.tokenizer.vocab_size,self.max_batch_size,self.max_seq_len,self.device)encoded_inputs = BatchEncoding(inputs, tensor_type=self.return_tensors)logger.info("---------------begin warm_up---------------")tick = time.perf_counter()model_outputs = self.model.forward(encoded_inputs)torch.nn.functional.normalize(model_outputs[0]).view(-1, ).float().cpu()tock = time.perf_counter()logger.info("---------------end warm_up---------------")logger.info(f"warm time: {(tock - tick) * 1000:.2f} ms")def embed(self, texts: Union[str, List[str], List[List[str]]]) -> torch.Tensor:encoded_inputs = self.model.tokenize(texts, **self.tokenizer_args)logger.info("---------------begin embed---------------")tick = time.perf_counter()embeddings = self.model.embed(encoded_inputs)tock = time.perf_counter()logger.info("---------------end embed---------------")logger.info(f"embed time: {(tock - tick) * 1000:.2f} ms")return embeddingsdef rerank(self, texts: Union[str, List[str], List[List[str]]]) -> torch.Tensor:encoded_inputs = self.model.tokenize(texts, **self.tokenizer_args)logger.info("---------------begin rerank---------------")tick = time.perf_counter()scores = self.model.rerank(encoded_inputs)tock = time.perf_counter()logger.info("---------------end rerank---------------")logger.info(f"rerank time: {(tock - tick) * 1000:.2f} ms")return scoresclass EmbedRequest(BaseModel):model: strinput: Union[str, List[str]]runner = None@app.on_event("startup")
async def startup_event():global runnerrunner = Runner(model_name_or_path='/model', device_type='npu', device_id=4, trust_remote_code=True, model_type='float',torch_dtype='float16',padding='max_length',truncation=True,return_tensors='pt',request='embed')@app.post("/embed")
async def embed_text(request: EmbedRequest):results = runner.embed(request.input)results_list = results.tolist()json_compatible_data = jsonable_encoder(results_list)return {"embeddings": json_compatible_data}if __name__ == "__main__":uvicorn.run("embed_api:app", host="0.0.0.0", port=8088, reload=True, log_level="info")
运行这个文件即可提供和Ollama兼容的embed API服务。
Open Webui的部署
最后可以部署一个Web服务,来提供对Deepseek服务的调用了。
Open WebUI 是一个开源的、功能丰富且用户友好的自托管 AI 平台,支持调用 Ollama 和 OpenAI 兼容的 API来使用大语言模型,并内置了用于检索增强生成(RAG)的推理引擎。
下载ARM64平台的Open webui镜像
docker pull ghcr.io/open-webui/open-webui:main --platform=linux/aarch64
在服务器建立一个open_webui的目录,并新建一个.env配置文件,内容如下
OPENAI_API_BASE_URL='http://deepseek-qwen-32b:1025/v1'
OPENAI_API_KEY=''ENABLE_OLLAMA_API=false
HF_HUB_OFFLINE=1
然后通过命令启动
docker run -d -p 80:8080 --network=llm-network -v /data/open_webui:/app/backend/data -v /data/open_webui/.env:/app/.env --name open-webui ghcr.io/open-webui/open-webui:main
题外话:
因为服务器是在内网,需要通过Nginx转发才能访问Open webui服务,最开始调用Open webui始终有问题,页面加载后显示空白,看了一下浏览器开发者工具的日志,提示是_app目录下的js文件路径不对,看了一下open webui的代码,发现这些路径都是通过href='/_app/xxx.js'这种绝对路径的方式来写的,因此在Nginx下面需要配置一下路径改写。配置后可以成功访问页面,但是在聊天窗口调用Deepseek又出现问题,一直停留在等待回复的状态,看了一下日志,发现很多web socket的链接被关掉了,怀疑是因为Nginx没有配置http 1.1版本导致的,在Nginx中增加以下配置即可。
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
相关文章:
华为昇腾服务器部署DeepSeek模型实战
在华为的昇腾服务器上部署了DeepSeek R1的模型进行验证测试,记录一下相关的过程。服务器是配置了8块910B3的显卡,每块显卡有64GB显存,根据DeepSeek R1各个模型的参数计算,如果部署R1的Qwen 14B版本,需要1张显卡&#x…...
做谷歌SEO需要了解哪些基本概念?
做谷歌SEO时,必须掌握一些基本的概念。首先是关键词。关键词是用户在搜索框里输入的词汇,它们直接影响到你网站的排名。所以,了解用户的搜索习惯、挑选合适的关键词,是每一个SEO优化者必须做的工作。 内容是关键。谷歌非常看重网…...
通过BingAPI爬取Bing半个月内壁纸
通过BingAPI爬取Bing半个月内壁纸 一、前言二、爬虫代码三、代码说明 一、前言 爬取Bing搜索网站首页壁纸的方式主要有两种,第一种为间接爬取,即并不直接对Bing网站发起请求,而是对那些收集汇总了Bing壁纸的网站发起请求,爬取图片…...
springboot021-基于协同过滤算法的个性化音乐推荐系统
💕💕作者: 小九学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
开关电源实战(一)宽范围DC降压模块MP4560
系列文章目录 文章目录 系列文章目录MP4560MP4560 3.8V 至 55V 的宽输入范围可满足各种降压应用 MOSFET只有250mΩ 输出可调0.8V-52V SW:需要低VF肖特基二极管接地,而且要靠近引脚,高压侧开关的输出。 EN:输入使能,拉低到阈值以下关闭芯片,拉高或浮空启动 COMP:Compens…...
【MySQL】我在广州学Mysql 系列——Mysql 日志管理详解
ℹ️大家好,我是练小杰,今天又是新的一周了,又该摆好心态迎接美好的明天了!!!😆 本文主要对Mysql数据库中的日志种类以及基本命令进行讨论!! 回顾:Ǵ…...
《Zookeeper 分布式过程协同技术详解》读书笔记-2
目录 zk的一些内部原理和应用请求,事务和标识读写操作事务标识(zxid) 群首选举Zab协议(ZooKeeper Atomic Broadcast protocol)文件系统和监听通知机制分布式配置中心, 简单Demojava code 集群管理code 分布式锁 zk的一…...
HTML5+CSS多层级ol标签序号样式问题
在CSS中,ol标签用于创建有序列表,而多层级的ol标签可以通过CSS实现不同的序号样式。以下是一些常见的问题和解决方案: 1. 多层级ol的序号格式问题 默认情况下,多层级的ol标签会自动继承父级的序号格式,但有时我们可能…...
网络初始2:网络编程--基于UDP和TCP实现回显器
基础概念 1.发送端与接受端 在通过网络传输信息时,会有两个进程,接收端和发送端。 发送端:数据的发送方进程,即网络通信中的源主机。 接收端:数据的接收方进程,即网路通信中的目的主机。 2.Socet套接字…...
vtkCamera类的Dolly函数作用及相机拉近拉远
录 1. 预备知识 1.1.相机焦点 2. vtkCamera类的Dolly函数作用 3. 附加说明 1. 预备知识 要理解vtkCamera类的Dolly函数作用,就必须先了解vtkCamera类表示的相机的各种属性。 VTK是用vtkCamera类来表示三维渲染场景中的相机。vtkCamera负责把三维场景投影到二维平面,如…...
车载音频架构图详解(精简)
目录 上图是车载音频架构图,对这个图我们进行详细的分析 左边第一层 是 app 常用的类有MediaPlayer和MediaRecorder, AudioTrack和AudioRecorder 第二层 是framework提供给应用的多媒体功能的AP...
Android嵌套滑动造成的滑动冲突原理分析
嵌套滑动造成的滑动冲突原理分析 场景复现: CoordinatorLayout AppBarLayout Vertical RecyclerView Horizontal RecycleView Horizontal RecycleView 是Vertical RecyclerView的一个子view, CoordinatorLayout 实现了AppBarLayout 和 RecyclerView的协调联动…...
计算机专业知识【 轻松理解数据库四大运算:笛卡尔积、选择、投影与连接】
在数据库的世界里,有几个关键的运算操作,就像是神奇的魔法工具,能帮助我们对数据进行各种处理和组合。今天,咱们就来聊聊笛卡尔积运算、选择运算、投影运算和连接运算这四大运算,用超简单的例子让小白也能轻松理解。 …...
使用神经网络对驾驶数据进行道路类型分类
摘要 道路分类,了解我们是在城市、农村地区还是在高速公路上驾驶,可以提高现代驾驶员辅助系统的性能,并有助于了解驾驶习惯。本研究的重点是仅使用车速数据来普遍解决这个问题。已经开发了一种数据记录方法,用于为 On-board Diagn…...
S4D480 S4HANA 基于PDF的表单打印
2022年元旦的笔记草稿 SAP的表单打印从最早的SAPScripts 到后来的SMARTFORM,步入S4时代后由于Fiori的逐渐普及,更适应Web的Adobe Form成了SAP主流output文件格式。 目录 一、 基于PDF表单打印系统架构Interface 接口Form 表单ContextLayout 二、表单接…...
qt QOpenGLTexture详解
1. 概述 QOpenGLTexture 是 Qt5 提供的一个类,用于表示和管理 OpenGL 纹理。它封装了 OpenGL 纹理的创建、分配存储、绑定和设置像素数据等操作,简化了 OpenGL 纹理的使用。 2. 重要函数 构造函数: QOpenGLTexture(const QImage &image,…...
Deepseek-R1推理模型API接入调用指南 ChatGPT Web Midjourney Proxy 开源项目接入Deepseek教程
DeepSeek-R1和OpenAI o1模型都属于推理任务模型,两个模型各有优点:DeepSeek-R1 在后训练阶段大规模使用了强化学习技术,在仅有极少标注数据的情况下,极大提升了模型推理能力。在数学、代码、自然语言推理等任务上,性能…...
蓝耘智算携手DeepSeek,共创AI未来
🌟 各位看官号,我是egoist2023! 🌍 种一棵树最好是十年前,其次是现在! 🚀 今天来学习如何通过蓝耘智算使用DeepSeek R1模型 👍 如果觉得这篇文章有帮助,欢迎您一键三连&a…...
【网络编程】之数据链路层
【网络编程】之数据链路层 数据链路层基本介绍基本功能常见协议 以太网什么是以太网以太网协议帧格式数据链路层的以太网帧报文如何封装/解封装以及分用以太网通信原理传统的以太网与集线器现代以太网与交换机碰撞域的概念 Mac地址基本概念为什么要使用Mac地址而不是使用IP地址…...
EasyExcel 复杂填充
EasyExcel Excel表格中用{}或者{.} 来表示包裹要填充的变量,如果单元格文本中本来就有{、}左右大括号,需要在括号前面使用斜杠转义\{ 、\}。 代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和Excel中被{}包裹的变量名称一致。 …...
FreeRTOS第10篇:系统的“体检医生”——调试与跟踪
文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 引言:嵌入式系统的“健康检查” 想象你是一名医生,面对一位患者(嵌入式系统),他偶尔会“头晕目眩”(任务崩溃)、“心…...
Unreal5从入门到精通之如何在 C++ 中创建 UserWidget
文章目录 前言UUserWidget 子类示例创建我们的 C++ 类的新蓝图子类更改现有蓝图的父类现在我们有了 C++ 基类,下一步做什么?蓝图还是 C++?结论前言 在之前的教程中,我展示了如何在编辑器中创建 UserWidget 蓝图, 在本教程中,我们将创建一个新的基于 C++ 的子类UUserWid…...
【大模型系列】Windows系统上运行大语言模型方式
在Windows系统上运行大语言模型(LLMs)有多种方式,以下是一些具体的方法: GPT4All 简介:GPT4All是一个适用于所有操作系统的LLM框架和聊天机器人应用程序,可以本地运行LLMs,并通过API将其与任何…...
Maven 中的 Artifact 与 GroupId:定义与使用
1. 什么是 Maven 的 Artifact 和 GroupId? 在 Maven 中,Artifact 和 GroupId 是构建和管理项目依赖的核心概念,它们用来唯一标识一个 Maven 项目或库。理解这两个概念对于管理 Maven 项目的依赖关系、构建过程和版本控制至关重要。 Artifac…...
滑动窗口-无重复字符的最长子串
无重复字符的最长子串 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串的长度。输入:字符串 输出:整型变量 思路:两个指针一前一后,最开始都在0位置,然后有值则快指针向右移动一位,判…...
猿大师办公助手:高效、安全、兼容的WebOffice在线办公解决方案
兼容性难题 浏览器插件逐渐被淘汰,依赖插件的传统Office控件难以适配现代浏览器,导致功能受限或完全无法使用。不同浏览器内核之间的兼容性问题,使得企业在选择Office控件时倍感困扰。 功能不完整 部分在线Office方案无法支持复杂的文档处理…...
通过VSCode直接连接使用 GPT的编程助手
GPT的编程助手在VSC上可以直接使用 选择相应的版本都可以正常使用。每个月可以使用40条,超过限制要付费。 如下图对应的4o和claude3.5等模型都可以使用。VSC直接连接即可。 配置步骤如下: 安装VSCODE 直接,官网下载就行 https://code.vis…...
【算法与数据结构】并查集详解+题目
目录 一,什么是并查集 二,并查集的结构 三,并查集的代码实现 1,并查集的大致结构和初始化 2,find操作 3,Union操作 4,优化 小结: 四,并查集的应用场景 省份…...
Java 集合数据处理技巧:使用 Stream API 实现多种操作
在 Java 开发中,对集合数据进行处理是非常常见的需求,例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作,并给出相…...
OSI 参考模型和 TCP/IP 参考模型
数据通信是很复杂的,很难在一个协议中完成所有功能。因此在制定协议时经常采用的思路是将复杂的数据通信功能由若干协议分别完成,然后将这些协议按照一定的方式组织起来。最典型的是采用分层的方式来组织协议,每一层都有一套清晰明确的功能和…...
