IPEX-LLM¶
IPEX-LLM 是一个用于在英特尔CPU和GPU(例如带有iGPU的本地PC、Arc、Flex和Max等独立GPU)上运行LLM的PyTorch库,具有非常低的延迟。
本示例介绍了如何使用LlamaIndex与ipex-llm
进行文本生成和在英特尔GPU上进行聊天。
注意
您可以参考此处获得
IpexLLM
的完整示例。请注意,如果要在Intel GPU上运行,请在运行示例时在命令参数中指定-d 'xpu'
。
安装先决条件¶
为了在Intel GPU上受益于IPEX-LLM,有几个先决步骤来安装工具和准备环境。
如果您是Windows用户,请访问在带有Intel GPU的Windows上安装IPEX-LLM指南,按照安装先决条件更新GPU驱动程序(可选)并安装Conda。
如果您是Linux用户,请访问在带有Intel GPU的Linux上安装IPEX-LLM,按照安装先决条件安装GPU驱动程序、Intel® oneAPI Base Toolkit 2024.0和Conda。
安装llama-index-llms-ipex-llm
¶
完成先决条件安装后,您应该已创建一个包含所有先决条件的conda环境,激活您的conda环境并按如下方式安装llama-index-llms-ipex-llm
:
conda activate <your-conda-env-name>
pip install llama-index-llms-ipex-llm[xpu] --extra-index-url https://pytorch-extension.intel.com/release-whl/stable/xpu/us/
此步骤还将安装ipex-llm
及其依赖项。
注意
您还可以使用
https://pytorch-extension.intel.com/release-whl/stable/xpu/cn/
作为extra-index-url
。
运行时配置¶
为了获得最佳性能,建议根据您的设备设置一些环境变量:
针对带有Intel Core Ultra集成GPU的Windows用户¶
在Anaconda Prompt中:
set SYCL_CACHE_PERSISTENT=1
set BIGDL_LLM_XMX_DISABLED=1
针对带有Intel Arc A-Series GPU的Linux用户¶
# 配置oneAPI环境变量。对于APT或离线安装的oneAPI,这是必需步骤。
# 对于PIP安装的oneAPI,请跳过此步骤,因为环境已在LD_LIBRARY_PATH中配置。
source /opt/intel/oneapi/setvars.sh
# 建议的环境变量,以获得最佳性能
export USE_XETLA=OFF
export SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1
export SYCL_CACHE_PERSISTENT=1
注意
第一次在Intel iGPU/Intel Arc A300系列或Pro A60上运行每个模型时,可能需要几分钟来编译。
IpexLLM
¶
在初始化IpexLLM
时设置device_map="xpu"
将把LLM模型放在英特尔GPU上,并受益于IPEX-LLM的优化。
在加载Zephyr模型之前,您需要定义completion_to_prompt
和messages_to_prompt
来格式化提示。根据模型卡为zephyr-7b-alpha遵循正确的提示格式。这对于准备模型可以准确解释的输入至关重要。使用IpexLLM本地加载Zephyr模型时,请使用IpexLLM.from_model_id
。它将直接以Huggingface格式加载模型,并自动将其转换为低比特格式以进行推理。
# 将字符串转换为zephyr特定的输入
def completion_to_prompt(completion):
return f"<|system|>\n</s>\n<|user|>\n{completion}</s>\n<|assistant|>\n"
# 将聊天消息列表转换为zephyr特定的输入
def messages_to_prompt(messages):
prompt = ""
for message in messages:
if message.role == "system":
prompt += f"<|system|>\n{message.content}</s>\n"
elif message.role == "user":
prompt += f"<|user|>\n{message.content}</s>\n"
elif message.role == "assistant":
prompt += f"<|assistant|>\n{message.content}</s>\n"
# 确保我们以系统提示开头,如果需要插入空白
if not prompt.startswith("<|system|>\n"):
prompt = "<|system|>\n</s>\n" + prompt
# 添加最终的助手提示
prompt = prompt + "<|assistant|>\n"
return prompt
from llama_index.llms.ipex_llm import IpexLLM
llm = IpexLLM.from_model_id(
model_name="HuggingFaceH4/zephyr-7b-alpha",
tokenizer_name="HuggingFaceH4/zephyr-7b-alpha",
context_window=512,
max_new_tokens=128,
generate_kwargs={"do_sample": False},
completion_to_prompt=completion_to_prompt,
messages_to_prompt=messages_to_prompt,
device_map="xpu",
)
请注意,在此示例中我们将使用HuggingFaceH4/zephyr-7b-alpha模型进行演示。它需要更新
transformers
和tokenizers
包。pip install -U transformers==4.37.0 tokenizers==0.15.2
然后您可以像往常一样进行完成任务或聊天任务:
print("----------------- 完成 ------------------")
completion_response = llm.complete("很久很久以前,")
print(completion_response.text)
print("----------------- 流式完成 ------------------")
response_iter = llm.stream_complete("很久很久以前,有一个小女孩")
for response in response_iter:
print(response.delta, end="", flush=True)
print("----------------- 聊天 ------------------")
from llama_index.core.llms import ChatMessage
message = ChatMessage(role="user", content="简要解释一下大爆炸理论")
resp = llm.chat([message])
print(resp)
print("----------------- 流式聊天 ------------------")
message = ChatMessage(role="user", content="什么是人工智能?")
resp = llm.stream_chat([message], max_tokens=256)
for r in resp:
print(r.delta, end="")
另外,您也可以将低比特模型保存到磁盘上,然后使用from_model_id_low_bit
而不是from_model_id
重新加载它以供后续使用,甚至可以在不同的机器之间使用。这种方法在空间上更高效,因为低比特模型所需的磁盘空间显著比原始模型少。而且from_model_id_low_bit
在速度和内存使用方面也比from_model_id
更高效,因为它跳过了模型转换步骤。
要保存低比特模型,请按如下所示使用save_low_bit
。然后从保存的低比特模型路径加载模型。还使用device_map
将模型加载到xpu。
请注意,低比特模型的保存路径仅包含模型本身,而不包含令牌化器。如果您希望将所有内容放在一个地方,您需要手动从原始模型的目录下载或复制令牌化器文件到低比特模型的保存位置。
尝试使用加载的低比特模型进行流式完成。
saved_lowbit_model_path = (
"./zephyr-7b-alpha-low-bit" # 保存低比特模型的路径
)
llm._model.save_low_bit(saved_lowbit_model_path)
del llm
llm_lowbit = IpexLLM.from_model_id_low_bit(
model_name=saved_lowbit_model_path,
tokenizer_name="HuggingFaceH4/zephyr-7b-alpha",
# tokenizer_name=saved_lowbit_model_path, # 如果你想这样使用,将令牌化器复制到保存路径
context_window=512,
max_new_tokens=64,
completion_to_prompt=completion_to_prompt,
generate_kwargs={"do_sample": False},
device_map="xpu",
)
response_iter = llm_lowbit.stream_complete("什么是大型语言模型?")
for response in response_iter:
print(response.delta, end="", flush=True)