unsloth微调DeepSeek

https://github.com/unslothai/unsloth
https://kq4b3vgg5b.feishu.cn/wiki/WWzZwHVNei8zsWkieJ3cyHzWnFe

安装库

首先确保已在项目目录中,并已激活虚拟环境
pip install --upgrade pip 升级pip
pip install "unsloth[cu124-torch250] @ git+https://github.com/unslothai/unsloth.git"

借助unsloth进行模型推理对话

from unsloth import FastLanguageModel
import torch

max_seq_length = 1024
dtype = None
load_in_4bit = False

device = "cuda" if torch.cuda.is_available() else "cpu"  # 检查GPU是否可用
print("使用的设备:", device)

# 加载模型
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "./DeepSeek-R1-Distill-Qwen-1.5B",
    max_seq_length = max_seq_length, # 最大序列长度
    dtype = dtype, # 数据类型
    load_in_4bit = load_in_4bit,
)

# 将模型移动到设备,unsloth不需要显示的将模型移动到设备,它会自动检测设备并移动模型
model.to(device)

# model.config.pad_token_id = model.config.eos_token_id  # 设置padding token为eos token

FastLanguageModel.for_inference(model) # 启动推理模式

# 打印欢迎信息
print("欢迎来到对话模式!")
# 对话循环
while True:
    # 获取用户输入,这里会等待用户输入按回车后继续下面的代码
    input_text = input("你:")

    # 用户输入为空,继续下一轮
    if not input_text.strip():
        print("请输入有效的文本!")
        continue

    # 使用tokenizer将用户输入转换为模型输入
    inputs = tokenizer([input_text], return_tensors="pt").to(device)
    #带入inputs进行对话
    outputs = model.generate(
        input_ids = inputs.input_ids,
        max_new_tokens = 150,
        use_cache = True,
        # temperature = 0.6,  # 温度参数,控制生成文本的多样性
        # top_p = 0.9,        # 控制采样的多样性
        )
    #此时得到得回复也是词索引,将其转换为文本
    response = tokenizer.batch_decode(outputs) # response就是回复原始文本,是一个列表,里面包含了多个回复
    # response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    print('模型:',response)

使用对话模板进行操作

from unsloth import FastLanguageModel
import torch

max_seq_length = 8192
dtype = None
load_in_4bit = False

device = "cuda" if torch.cuda.is_available() else "cpu"  # 检查GPU是否可用
print("使用的设备:", device)

# 加载模型
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "./DeepSeek-R1-Distill-Qwen-1.5B",
    max_seq_length = max_seq_length, # 最大序列长度
    dtype = dtype, # 数据类型
    load_in_4bit = load_in_4bit,
)

# 将模型移动到设备,unsloth不需要显示的将模型移动到设备,它会自动检测设备并移动模型
model.to(device)

# model.config.pad_token_id = model.config.eos_token_id  # 设置padding token为eos token

FastLanguageModel.for_inference(model) # 启动推理模式

# 打印欢迎信息
print("欢迎来到对话模式!")

# 对话模板,顶部是对话的任务描述,下面是对话的问题和回答
prompt_style_chat = """请写出一个恰当的回答来完成当前对话任务。
### Instruction:
你是小易算力的智能客服,专注于为用户提供关于GPU算力资源的帮助。你可以回答关于GPU算力资源租赁、购买、出售、服务器等相关问题。如果用户问的问题与GPU、算力、服务器、AI等无关,请回答:‘不好意思,我只能回答您关于算力资源的使用问题哦’。

### Question:
{}

### Response:
<think>{}"""

# 对话循环
while True:
    # 获取用户输入,这里会等待用户输入按回车后继续下面的代码
    input_text = input("你:")

    # 用户输入为空,继续下一轮
    if not input_text.strip():
        print("请输入有效的文本!")
        continue

    prompt = [prompt_style_chat.format(input_text, "")] # 拼接对话模板

    # 使用tokenizer将用户输入转换为模型输入
    inputs = tokenizer(prompt, return_tensors="pt").to(device)
    #带入inputs进行对话
    outputs = model.generate(
        input_ids = inputs.input_ids,
        max_new_tokens = 1200,
        use_cache = True,
        )
    #此时得到得回复也是词索引,将其转换为文本
    response = tokenizer.batch_decode(outputs) # response就是回复原始文本,是一个列表,里面包含了多个回复
    print('模型:',response[0].split("### Response")[1]) # 打印回复

准备COT数据集

DeepSeek R1的数据集和其它大预言模型的数据集不同的是,它需要额外装备一个think字段,这个过程是用来解释模型思考过程的步骤
例如医疗领域的一个数据集:
https://huggingface.co/datasets/FreedomIntelligence/medical-o1-reasoning-SFT

训练的数据集格式应该像这样:

[
    {
        "Question": "你是谁",
        "Complex_CoT": "好,用户让我介绍一下自己。首先我要明确自己的身份,我是小易助手,是一个由上海复易信息技术有限公司开发的智能客服。我可以回答你一些本公司的业务问题,例如算力资源,GPU信息,AI行业问题,计算机技术等,最后礼貌的告诉用户,我可以为用户提供哪些帮助。",
        "Response": "您好!我是由上海复易信息技术有限公司开发的小易助手,一个专注提供算力信息的智能客服机器人。"  
    },
    {
        "Question": "介绍你自己",
        "Complex_CoT": "好,用户让我介绍一下自己。首先我要明确自己的身份,我是小易助手,是一个由上海复易信息技术有限公司开发的智能客服。然后要提到我的主要功能是帮助用户处理计算资源相关的各种查询,特别是关于GPU算力资源的问题。还要说明我能提供哪些具体的服务,比如算力优化建议、任务分配指导以及技术支持等。最后提醒用户如果有其他类型的问题或需要更深入的帮助,也可以提出需求,我会尽力配合。整个回应要简洁明了,让用户清楚了解我可以提供的服务范围,并且表达出愿意继续协助的态度",
        "Response": "您好!我是由小易算力开发的智能助手,您的专属顾问。我专注于为您提供与 GPU 算力资源、服务器及 AI 相关的知识和服务支持。如果您有任何关于这些领域的疑问,请随时告诉我;如果您有其他问题或任何反馈,我也乐意听取并帮忙解决。很高兴为您效劳!"  
    },
    {
        "Question": "你叫什么名字",
        "Complex_CoT": "首先我要明确自己的身份,我是小易助手,是一个由上海复易信息技术有限公司开发的智能客服,最后保持礼貌的回答“我的名字叫小易助手”",
        "Response": "你好!我叫“小易助手”,很高兴为你服务!"  
    }
]

nohup python test3.py & 后台运行
tail -f nohup.out 查看命令
ps aux | grep test3.py 查看是否运行完,第一个纯数字参数是进程
kill 进程 提前结束

使用指定gpu推理测试
CUDA_VISIBLE_DEVICES=5 python test.py

datasets库读取不同的本地训练集

# 格式化提示词,下面的字段对应数据集中的字段,对应提示词模板中的三个{}位置
def formatting_prompts_func(examples):
    inputs = examples["Question"]
    cots = examples["Complex_CoT"]
    outputs = examples["Response"]
    texts = []
    for input, cot, output in zip(inputs, cots, outputs):
        text = train_template.format(input, cot, output) + EOS_TOKEN # 格式化每条数据
        # print('格式化后的提示词:',text)
        texts.append(text)
    return {
        "text": texts, # 返回格式化后的文本数据
    }

# 读parquet数据
# dataset = load_dataset("parquet", split = "train[0:500]",data_files="data.parquet") #读前500条
dataset = load_dataset("parquet", split = "train",data_files="data.parquet") #读所有数据

# 读取json数据
# dataset = load_dataset("json", data_files="data.json", split="train")

# 读csv前500条
dataset = load_dataset('csv', data_files='data.csv',, split="train[0:500]")

推理提示词

vllm上下下文方法
vllm上下文 system 对话提示词方法

instruction = """
你是由"小易算力"开发的智能医疗客服,如果有人问你:你是谁?告诉他你叫"小易医疗助手",你正在扮演一个医疗行业专家,你将对用户的提问,结合你的专业医疗知识去答复。”
"""

对话模板提示词方法,中间会使用{}替代文本

prompt_style_chat = """请写出一个恰当的回答来完成当前对话任务。

### Instruction:
你是一名助人为乐的助手。

### Question:
{}

### Response:
<think>{}"""
prompt_style_chat = """请写出一个恰当的回答来完成当前对话任务。
### Instruction:
你是小易算力的智能客服,专注于为用户提供关于GPU算力资源的帮助。你可以回答关于GPU算力资源租赁、购买、出售、服务器等相关问题。如果用户问的问题与GPU、算力、服务器、AI等无关,请回答:‘不好意思,我只能回答您关于算力资源的使用问题哦’。

### Question:
{}

### Response:
<think>{}"""
prompt_style_chat = """以下是一个任务说明,配有提供更多背景信息的输入。
请写出一个恰当的回答来完成该任务。
在回答之前,请仔细思考问题,并按步骤进行推理,确保回答逻辑清晰且准确。

### Instruction:
您是一位具有高级临床推理、诊断和治疗规划知识的医学专家。
请回答以下医学问题。

### Question:
{}

### Response:
<think>{}"""