从零开始:Windows系统下Qwen2.5大模型的实践教程(三)-windows xpu方案推理加速

201 阅读5分钟

1、环境准备

1.0、环境描述

首先查看自己的显卡为:Intel(R) Arc(TM) Graphics。

显卡配置.png

IPEX-LLM是一个由Intel开发的大模型推理加速库,它可以利用Intel的硬件(如CPU、集成显卡和独立显卡)来加速大语言模型的推理。因此为了使用xpu方案,必须是intel的显卡

1.适用场景
  • 在 Intel 笔记本/工作站运行 7B-13B 模型(如 Llama2, Mistral)。

1.1、驱动安装

1. 下载官方最新的显卡驱动

www.intel.com/content/www…

2. 下载安装 Visual Studio 以便使用其带有 C++ 工作负载的桌面开发来实现其部分包的功能

www.yuque.com/alascanfu/a…

3. 安装 OneAPI Toolkit Installer(依赖第二步Visual Studio的安装)

www.yuque.com/alascanfu/a…

4. 激活 OneAPI 环境

4.1 修改OneAPI安装目录下(第三步中选择的路径,例如:C:\Program Files (x86)\Intel\oneAPI)的setvars.bat文件,来配置Visual Studio环境变量

# 新增的配置
set "VS2022INSTALLDIR=C:\Program Files\Microsoft Visual Studio\2022\Community"

4.2 激活OneAPI环境

  • Win + R 输入 cmd 出现命令行窗口
  • 激活 OneAPI 环境 call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" ,如果需要强制重新激活环境需要在后方追加 --force 命令即可。

激活成功显示如下(出现oneAPI environment initialized):

image.png

1.2、依赖安装

1. 准备conda环境,python版本建议3.10以上

例如:

conda create -n ipex python=3.10 -y
conda activate ipex
2. 其他可能需要的依赖包安装
pip install jupyter matplotlib pandas pillow timm torcheval torchtnt tqdm -i https://pypi.mirrors.ustc.edu.cn/simple/
pip install cjm_pandas_utils cjm_psl_utils cjm_pil_utils cjm_pytorch_utils -i https://pypi.mirrors.ustc.edu.cn/simple/
 
conda install pkg-config libuv
# 如果是非conda环境
pip install pyuv

# 设置环境变量
set IPEX_XPU_ONEDNN_LAYOUT=1
set SYCL_CACHE_PERSISTENT=1
set BIGDL_LLM_XMX_DISABLED=1
3. 安装torch相关的包

参考下面网址进行: intel.github.io/intel-exten…

在网址中根据你的环境选择:

image.png

image.png

# 复制出来环境依赖如下
python -m pip install torch==2.5.1+cxx11.abi torchvision==0.20.1+cxx11.abi torchaudio==2.5.1+cxx11.abi intel-extension-for-pytorch==2.5.10+xpu --extra-index-url https://pytorch-extension.intel.com/release-whl/stable/xpu/cn/
# 以及ipex运行的包及相关依赖
pip install --pre --upgrade ipex-llm[xpu] --extra-index-url https://pytorch-extension.intel.com/release-whl/stable/xpu/cn/
pip install transformers==4.45.2
pip install accelerate==0.34.2
pip install peft==0.11.1
pip install trl
4. 验证torch,在conda环境里输入以下内容
import torch
import intel_extension_for_pytorch as ipex

print(f'PyTorch Version: {torch.__version__}')
print(f'Intel PyTorch Extension Version: {ipex.__version__}')

2、推理部署

2.1、代码

import torch
import os
from flask import Flask
from flask import request
from transformers import AutoTokenizer, AutoModel, Qwen2ForCausalLM, Qwen2Tokenizer, GenerationConfig
from ipex_llm.transformers import AutoModelForCausalLM

# 参数
max_new_tokens: int = 2048  # 生成响应时最大的新token数
temperature: float = 0.6  # 控制生成文本的随机性
top_p: float = 0.9  # 用于概率限制的参数,有助于控制生成文本的多样性
top_k: int = 32  # 控制生成过程中每一步考虑的最可能token的数量
repetition_penalty: float = 1.2  # 用于惩罚重复生成相同token的参数
eos_token_id = [151645, 151643]

app = Flask(__name__)
model_path = "D:\project\llm\Qwen2-7B"
tokenizer = Qwen2Tokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path,
                                             load_in_4bit=True,  # 以4位精度加载
                                             cpu_embedding=True,  # 模型的嵌入层将在CPU上运行
                                             low_cpu_mem_usage=True,  # 降低CPU内存使用
                                             use_cache=True,  # 启用KV缓存(推理过程的中间层缓存)
                                             trust_remote_code=True,  # 信任远程代码
                                             optimize_model=True,
                                             torch_dtype=torch.float16,  # 添加这行
                                             ).to('xpu').eval()


@app.route('/chat', methods=["POST"])
def chat():
    req_json = request.json
    messages = [
        {"role": "system", "content": req_json['systemPrompt']},
        {"role": "user", "content": req_json['userPrompt']}
    ]
    generation_config = GenerationConfig(use_cache=True,
                                         repetition_penalty=repetition_penalty,
                                         do_sample=False,  # 取消采样,使用贪心策略,输出是确定的
                                         stop_strings="}")
    # 设置停止词)
    text = tokenizer.apply_chat_template(messages,
                                         tokenize=False,
                                         add_generation_prompt=True)
    # Generate predicted tokens
    input_ids = tokenizer.encode(text, return_tensors="pt").to('xpu')
    print(input_ids.shape[-1])

    generated_ids = model.generate(input_ids,
                                   max_new_tokens=req_json['maxNewTokens'],
                                   tokenizer=tokenizer,
                                   generation_config=generation_config)
    # 将输入的ids部分截掉
    output_ids = generated_ids[:, input_ids.shape[-1]:]
    output_str = tokenizer.batch_decode(output_ids, skip_special_tokens=True)[0]
    print(output_str)
    return output_str.strip()


@app.route('/chat_qwen', methods=["POST"])
def chat_qwen():
    try:
        # 系统设定和prompt
        req_json = request.json
        prompt = req_json['message']
        print(prompt)
        torch.xpu.empty_cache()  # 清理显存
        # 使用with语句确保推理完成后释放资源
        with torch.inference_mode():
            # 输入张量必须和模型在同一个设备中,但是张量可以在不同设备间移动
            input_ids = tokenizer.encode(prompt, return_tensors="pt").to('xpu')
            print(input_ids)
            # 1、tokenizer的解码操作通常在CPU上进行
            # 2、CPU处理文本解码更方便,且不需要占用GPU/XPU资源
            # 3、最终的文本处理和返回都是在CPU上进行的
            generate_ids = model.generate(
                input_ids=input_ids,
                # bos_token_id=151645,
                # max_new_tokens=max_new_tokens,
                # repetition_penalty=repetition_penalty
            )
            
            response = tokenizer.batch_decode(generate_ids, skip_special_tokens=True)[0]
            response = response[len(prompt):]
            return response.strip()
    except Exception as e:
        print(f"生成过程发生错误: {str(e)}")
        return str(e), 500  # 返回错误信息和500状态码
        

if __name__ == '__main__':
    app.run(port=8080, host="0.0.0.0")

3、问题

3.1、Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": visualstudio.microsoft.com/visual-cpp-…

原因:缺少C++工具

解决:按照提示:安装C++ build tools,进入visual studio下载,选中C++相关的tools(使用C++的桌面开发,主要是安装C++生成工具、windows sdk等),按照默认一路下载安装。

3.2、Initializing libiomp5md.dll, but found libiomp5md.dll already initialized

解决:anaconda的环境下存在两个libiomp5md.dll文件。所以直接去虚拟环境的路径下搜索这个文件,可以看到在环境里有两个dll文件.

其中第一个是torch路径下的,第二个是虚拟环境本身路径下的,转到第二个目录下把它剪切到其他路径下备份就好(最好把路径也备份一下)。

3.3、csrc/cpu/comm/ccl.cpp(8): fatal error C1083: 无法打开包括文件: “oneapi/ccl.hpp”: No such file or directory

解决:安装oneapi base toolkit和oneapi HPC kit

3.4、generated_ids = model.generate()接口长时间不返回

解决:无须解决,第一次启动模型的时候进行预热,第一次调用接口慢可能约1-10分钟,后续的接口回归正常响应时间。