大模型学习-实践篇(一):简单尝试

系列目录-大模型学习篇

大模型学习-基础篇
大模型学习-实践篇
大模型学习-理论篇
大模型学习-踩坑篇
大模型学习-面试篇

问题场景(Problems)

本地部署LLMs运行环境,能够完成大模型的推理、训练、量化的部署。
我是在服务器上进行部署的,相关配置如下:
服务器系统:CentOS 7.7
存储:约40T
显卡:A800 * 2(单卡显存 80 GB)
网络:校园网
虚拟环境:docker + miniconda

解决方案(Solution)

modelscope提供了部署所需的全部详细文档,这里是官网

本章节采用modelscope官网给出的部署实例进行演示,Qwen1.5全流程最佳实践。

环境配置

创建python==3.10的conda虚拟环境(官网使用的是3.8版本,我使用的是3.10版本)。

conda create -n myenv python=3.10
conda activate myenv

安装modelscope库,使用清华源。常见的可用源还包括:
-i https://mirrors.bfsu.edu.cn/pypi/web/simple
-i https://mirrors.ustc.edu.cn/pypi/web/simple
等等,可以根据自己的网络条件自行选择。

pip install modelscope -i https://pypi.tuna.tsinghua.edu.cn/simple
# pip install modelscope[framework] -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install 'ms-swift[llm]' -U # 安装swift命令

由于我们需要使用vllm和autoawq提供推理加速和模型量化,而这两个库本身对cudnn版本和CUDA版本的要求不一致,并且他们针对torch的版本也有一定的要求,所以此处的环境安装会稍微复杂一点。
首先通过nvidia-smi和nvcc -V命令查看服务器支持的CUDA version版本和cudnn版本。

nvidia-smi  # 对应GPU 驱动程序的版本,
nvcc -V # 对应CUDA Toolkit版本,即Cuda toolkit <=  GPU 驱动程序版本

在这里插入图片描述
在这里插入图片描述
我的CUDA 驱动版本是12.4,理论上我最高可以安装12.4版本的CUDA Toolkit,但是经过测试我最后选了11.8才解决了各种依赖问题。
关于各自的安装依赖关系,可以参考以下资料:
如何安装CUDA toolkit和对应的cudnn
autoawq各发布版本
vLLMs版本介绍
我将自己测试后最终选择的版本放在这里,仅供读者参考:

cuda toolkit==11.8
autoawq==0.2.6
vllm==0.5.3
torch==2.3.1
modelscope==1.17.1

测试代码

根据官网的代码,本地新建文件:modelscope_Qwen1half7B_QA.py,代码内容直接copy官网的代码:

# Experimental environment: A800
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import (
    get_model_tokenizer, get_template, inference, ModelType,
    get_default_template_type, inference_stream
)
from swift.utils import seed_everything
import torch

model_type = ModelType.qwen1half_7b_chat
template_type = get_default_template_type(model_type)
print(f'template_type: {template_type}')  # template_type: qwen


kwargs = {}
# kwargs['use_flash_attn'] = True  # 使用flash_attn

model, tokenizer = get_model_tokenizer(model_type, torch.float16,
                                       model_kwargs={'device_map': 'auto'}, **kwargs)
# 修改max_new_tokens
model.generation_config.max_new_tokens = 128

template = get_template(template_type, tokenizer)
seed_everything(42)
query = '浙江的省会在哪里?'
response, history = inference(model, template, query)
print(f'query: {query}')
print(f'response: {response}')

# 流式
query = '这有什么好吃的?'
gen = inference_stream(model, template, query, history)
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for response, history in gen:
    delta = response[print_idx:]
    print(delta, end='', flush=True)
    print_idx = len(response)
print()
print(f'history: {history}')

"""
[INFO:swift] model.max_model_len: 32768
[INFO:swift] Global seed set to 42
query: 浙江的省会在哪里?
response: 浙江省的省会是杭州市。
query: 这有什么好吃的?
response: 浙江有很多美食,比如杭州的西湖醋鱼、东坡肉、龙井虾仁,宁波的汤圆、奉化芋头羹,温州的鱼饼、楠溪江豆腐干,嘉兴的南湖菱角等等。每一道菜都有其独特的风味和历史背景,值得一试。
history: [['浙江的省会在哪里?', '浙江省的省会是杭州市。'], ['这有什么好吃的?', '浙江有很多美食,比如杭州的西湖醋鱼、东坡肉、龙井虾仁,宁波的汤圆、奉化芋头羹,温州的鱼饼、楠溪江豆腐干,嘉兴的南湖菱角等等。每一道菜都有其独特的风味和历史背景,值得一试。']]
"""

测试结果

在这里插入图片描述
我们可以看到模型直接加载权重后,输出了结果。
如果是第一次运行,那么会本地下载模型,保存路径为:
.cache/modelscope/hub/qwen/Qwen1___5-7B-Chat
在这里插入图片描述

vLLM推理加速

还是按照modelscope官网的代码,我们使用python推理qwen1half-7b-chat-awq, 这里我们使用VLLM进行推理加速:

# Experimental environment: A800 * 2
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import (
    ModelType, get_vllm_engine, get_default_template_type,
    get_template, inference_vllm, inference_stream_vllm
)
import torch

model_type = ModelType.qwen1half_7b_chat_awq
llm_engine = get_vllm_engine(model_type, torch.float16, max_model_len=4096)
template_type = get_default_template_type(model_type)
template = get_template(template_type, llm_engine.hf_tokenizer)
# 与`transformers.GenerationConfig`类似的接口
llm_engine.generation_config.max_new_tokens = 512

request_list = [{'query': '你好!'}, {'query': '浙江的省会在哪?'}]
resp_list = inference_vllm(llm_engine, template, request_list)
for request, resp in zip(request_list, resp_list):
    print(f"query: {request['query']}")
    print(f"response: {resp['response']}")

# 流式
history1 = resp_list[1]['history']
query = '这有什么好吃的'
request_list = [{'query': query, 'history': history1}]
gen = inference_stream_vllm(llm_engine, template, request_list)
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for resp_list in gen:
    request = request_list[0]
    resp = resp_list[0]
    response = resp['response']
    delta = response[print_idx:]
    print(delta, end='', flush=True)
    print_idx = len(response)
print()
print(f"history: {resp_list[0]['history']}")

"""
query: 你好!
response: 你好!有什么问题我可以帮助你吗?
query: 浙江的省会在哪?
response: 浙江省的省会是杭州市。
query: 这有什么好吃的
response: 浙江有很多美食,以下列举一些具有代表性的:

1. 杭州菜:杭州作为浙江的省会,以其精致细腻、注重原汁原味而闻名,如西湖醋鱼、龙井虾仁、叫化童鸡等都是特色菜品。

2. 宁波汤圆:宁波的汤圆皮薄馅大,甜而不腻,尤其是冬至和元宵节时,当地人会吃宁波汤圆庆祝。

3. 温州鱼丸:温州鱼丸选用新鲜鱼类制作,口感弹滑,味道鲜美,常常配以海鲜煮食。

4. 嘉兴粽子:嘉兴粽子以其独特的三角形和咸甜两种口味著名,特别是五芳斋的粽子非常有名。

5. 金华火腿:金华火腿是中国著名的腌制肉类,肉质紧实,香味浓郁,常作为节日礼品。

6. 衢州烂柯山豆腐干:衢州豆腐干质地细腻,味道鲜美,是浙江的传统小吃。

7. 舟山海鲜:浙江沿海地带的舟山有丰富的海鲜资源,如梭子蟹、带鱼、乌贼等,新鲜美味。

以上只是部分浙江美食,浙江各地还有许多特色小吃,你可以根据自己的口味去尝试。
history: [('浙江的省会在哪?', '浙江省的省会是杭州市。'), ('这有什么好吃的', '浙江有很多美食,以下列举一些具有代表性的:\n\n1. 杭州菜:杭州作为浙江的省会,以其精致细腻、注重原汁原味而闻名,如西湖醋鱼、龙井虾仁、叫化童鸡等都是特色菜品。\n\n2. 宁波汤圆:宁波的汤圆皮薄馅大,甜而不腻,尤其是冬至和元宵节时,当地人会吃宁波汤圆庆祝。\n\n3. 温州鱼丸:温州鱼丸选用新鲜鱼类制作,口感弹滑,味道鲜美,常常配以海鲜煮食。\n\n4. 嘉兴粽子:嘉兴粽子以其独特的三角形和咸甜两种口味著名,特别是五芳斋的粽子非常有名。\n\n5. 金华火腿:金华火腿是中国著名的腌制肉类,肉质紧实,香味浓郁,常作为节日礼品。\n\n6. 衢州烂柯山豆腐干:衢州豆腐干质地细腻,味道鲜美,是浙江的传统小吃。\n\n7. 舟山海鲜:浙江沿海地带的舟山有丰富的海鲜资源,如梭子蟹、带鱼、乌贼等,新鲜美味。\n\n以上只是部分浙江美食,浙江各地还有许多特色小吃,你可以根据自己的口味去尝试。')]
"""

自我认知微调

接下来我们对模型进行自我认知微调, 官网给的代码是 我们想让模型认为自己是"小黄"而不是"通义千问"; 由"魔搭"训练, 而不是"阿里云". author和name可以自定义修改。

# Experimental environment: A800 * 2
# 80GB GPU memory
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import DatasetName, ModelType, SftArguments, sft_main

sft_args = SftArguments(
    model_type=ModelType.qwen1half_7b_chat,
    dataset=[f'{DatasetName.alpaca_zh}#500', f'{DatasetName.alpaca_en}#500',
             f'{DatasetName.self_cognition}#500'],
    logging_steps=5,
    max_length=2048,
    learning_rate=1e-4,
    output_dir='output',
    lora_target_modules=['ALL'],
    model_name=['小黄', 'Xiao Huang'],
    model_author=['魔搭', 'ModelScope'])
output = sft_main(sft_args)
best_model_checkpoint = output['best_model_checkpoint']
print(f'best_model_checkpoint: {best_model_checkpoint}')

模型量化

# 14GB GPU memory
CUDA_VISIBLE_DEVICES=0 swift export \
    --ckpt_dir [微调后保存的模型checkpoints路径] \
    --quant_bits 4 --quant_method awq \
    --merge_lora true

量化代码运行后,首先要进行量化数据集的下载。
因为我们指定的是:
–quant_bits 4
–quant_method awq
代表设置量化bits数为4,选择的量化方式为awq,也可以选择gptq。

关于swift、sft等命令参数的解释,可以参考这篇文章
在这里插入图片描述
数据集下载完成以后就可以进行量化训练,
在这里插入图片描述
大概30分钟左右,就可以完成模型量化。

使用微调和量化后的模型进行推理

# Experimental environment: A800 * 2
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import (
    ModelType, get_vllm_engine, get_default_template_type,
    get_template, inference_vllm, inference_stream_vllm
)
import torch

model_type = ModelType.qwen1half_7b_chat
model_id_or_path = 'output/qwen1half-7b-chat/vx-xxx/checkpoint-xxx-merged-awq-int4' #使用量化后的模型checkpoint保存路径
llm_engine = get_vllm_engine(model_type,
                             model_id_or_path=model_id_or_path,
                             max_model_len=4096)
template_type = get_default_template_type(model_type)
template = get_template(template_type, llm_engine.hf_tokenizer)
# 与`transformers.GenerationConfig`类似的接口
llm_engine.generation_config.max_new_tokens = 512

request_list = [{'query': '你是谁?'}, {'query': '浙江的省会在哪?'}]
resp_list = inference_vllm(llm_engine, template, request_list)
for request, resp in zip(request_list, resp_list):
    print(f"query: {request['query']}")
    print(f"response: {resp['response']}")

# 流式
history1 = resp_list[1]['history']
query = '这有什么好吃的'
request_list = [{'query': query, 'history': history1}]
gen = inference_stream_vllm(llm_engine, template, request_list)
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for resp_list in gen:
    request = request_list[0]
    resp = resp_list[0]
    response = resp['response']
    delta = response[print_idx:]
    print(delta, end='', flush=True)
    print_idx = len(response)
print()
print(f"history: {resp_list[0]['history']}")
"""
query: 你是谁?
response: 我是魔搭的人工智能助手,我的名字叫小黄。我可以回答各种问题,提供信息和帮助。有什么我可以帮助你的吗?
query: 浙江的省会在哪?
response: 浙江省的省会是杭州市。
query: 这有什么好吃的
response: 浙江省的美食非常丰富,其中最著名的有杭州的西湖醋鱼、东坡肉、龙井虾仁等。此外,浙江还有许多其他美食,如宁波的汤圆、绍兴的臭豆腐、嘉兴的粽子等。
history: [('浙江的省会在哪?', '浙江省的省会是杭州市。'), ('这有什么好吃的', '浙江省的美食非常丰富,其中最著名的有杭州的西湖醋鱼、东坡肉、龙井虾仁等。此外,浙江还有许多其他美食,如宁波的汤圆、绍兴的臭豆腐、嘉兴的粽子等。')]
"""

bug&解决(Reason)

报错1:在通过vLLM进行模型的加速推理时,遇到了报错:
AttributeError: ‘_OpNamespace’ ‘_C’ object has no attribute ‘rms_norm’
主要原因就是:当前vllm版本和现在的torch+cuda不匹配。
我通过卸载当前的vLLM0.5.2,然后重新安装vLLM0.5.3,问题解决。

pip uninstall vLLM
pip install vLLM==0.5.3 -i https://pypi.tuna.tsinghua.edu.cn/simple 

报错2:TypeError: FormatCode() got an unexpected keyword argument ‘verify‘
主要原因:当前安装的yapf版本不对,版本为0.40.2的yapf源码确实没有该参数。
解决办法:降级yapf

pip install yapf==0.40.0

经验总结(Conclusion)

可以使用pip check和pip show检查冲突和查看包版本

pip check

如果没有问题,则会显示:
No broken requirements found.

  • 13
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值