本地大模型部署指南
开源大模型及数据集:ModelScope 魔搭社区
ModelScope 魔搭社区是一个致力于加速 AI 开发的开源社区,它汇聚了众多行业前沿的模型、数据集和 AI 应用。在这里,你可以探索到丰富的 AI 资源,涵盖视觉检测与追踪、光学字符识别、逆向文本规范化、多模态表示、蛋白质结构生成、蛋白质功能预测等多个领域。ModelScope 提供了强大的计算基础设施,支持模型服务,让你能够轻松构建自己的模型和应用。
ModelScope Library:这是一款高效的 Python 库,专为模型推理、微调和评估而设计。它为各种 AI 模型(包括视觉、语音和大语言模型)提供了一个统一的接口,让你能够充分挖掘模型的潜力。
ModelHub:这是一个开源的 AI 模型和数据集托管中心,你可以在这里找到海量的资源,为你的项目提供强大的支持。
Popular Studio:ModelScope 的 Studio 为你提供了一个免费且灵活的 AI 应用展示空间。你可以基于 ModelScope 平台上的模型提供的原子能力,自主构建和演示不同的 AI 应用。
框架与工具:
Eval-Scope:这是一个简化大模型评估和性能基准测试的高效、可定制框架。
Swift:魔搭大模型训练推理工具箱,支持 LLaMA、千问、ChatGLM、BaiChuan 等多种模型,以及 LoRA 等多种训练方式。
ModelScope-Agent:连接 ModelScope 模型能力与万物的桥梁,将模型与现实世界紧密相连。
本地大模型微调(Qwen2-0.5B)
数据准备与处理
数据集概况
本次微调所用的数据集为“zh_cls_fudan-news”,包含训练集和测试集两个部分,原始数据以 JSONL 格式存储。每条数据记录由“text”(文本内容)、“category”(分类选项列表)和“output”(正确分类)三个字段组成。
数据转换
为了将原始数据集转换成适合大模型微调的格式,我编写了 dataset_jsonl_transfer
函数。该函数读取原始 JSONL 文件,将每条数据的“text”和“category”字段组合成“input”,与“output”字段一起,构建成新的 JSON 格式数据,并保存到新的 JSONL 文件中。这样处理后的数据集,每行都是一个包含“input”和“output”字段的 JSON 对象,方便后续的模型训练和预测使用。
数据预处理
在训练大模型之前,还需对数据集进行进一步的预处理。我定义了 process_func
函数,对每条数据执行以下操作:
使用分词器对“input”和“output”进行分词,生成对应的
input_ids
和attention_mask
。为“input”部分添加特定的系统提示和用户提示,引导模型在生成文本时遵循既定的文本分类任务格式。
将“input”和“output”的
input_ids
和attention_mask
拼接起来,并在末尾添加一个额外的pad_token_id
和对应的attention_mask
,以标识序列的结束。生成
labels
,用于模型训练时的监督学习。labels
的前半部分与“input”部分的input_ids
对应,全部设置为-100
(表示这部分不参与损失计算),后半部分与“output”部分的input_ids
对应,直接使用其input_ids
,并在末尾添加一个pad_token_id
。对处理后的数据进行截断,确保序列长度不超过预设的最大长度
MAX_LENGTH
(本例中为 384)。
模型配置与训练
加载预训练模型和分词器
从指定的模型目录 model_dir
中加载预训练的 Qwen2-0.5B 模型和对应的分词器。分词器使用 use_fast=False
参数,以确保分词结果的准确性;模型则使用 device_map=device
参数将其加载到 GPU 上(如果可用),并设置 torch_dtype=torch.bfloat16
以使用混合精度训练,提升训练效率。此外,调用 model.enable_input_require_grads()
方法,开启梯度检查点功能,以减少显存占用。
创建 LoRA 配置
为了在微调过程中引入 LoRA(Low-Rank Adaptation)技术,我创建了一个 LoraConfig
对象,配置了以下参数:
task_type=TaskType.CAUSAL_LM
:指定任务类型为因果语言模型。target_modules
:列出需要应用 LoRA 的模型模块,包括q_proj
、k_proj
、v_proj
、o_proj
、gate_proj
、up_proj
和down_proj
等。inference_mode=False
:设置为训练模式。r=8
:LoRA 的秩,控制 LoRA 矩阵的大小。lora_alpha=32
:LoRA 的缩放因子,影响 LoRA 的学习速率。lora_dropout=0.1
:LoRA 层的 dropout 比例,用于正则化。
将 LoRA 应用于模型
通过调用 get_peft_model(model, config)
函数,将 LoRA 配置应用到预训练模型上,得到用于微调的 LoRA 模型。
创建微调参数
使用 TrainingArguments
类创建微调参数对象,配置了以下关键参数:
output_dir
:指定输出目录,用于保存训练过程中的模型检查点和最终的微调模型。per_device_train_batch_size=4
:设置每个设备的训练批次大小为 4。gradient_accumulation_steps=4
:梯度累积步数为 4,用于模拟更大的批次大小,提高训练稳定性。logging_steps=10
:每 10 步记录一次训练日志。num_train_epochs=2
:训练轮次为 2。save_steps=100
:每 100 步保存一次模型检查点。learning_rate=1e-4
:学习率为 0.0001。save_on_each_node=True
:在每个节点上保存模型。gradient_checkpointing=True
:开启梯度检查点功能,进一步减少显存占用。report_to="none"
:不将训练报告发送到外部平台。
训练模型
创建 Trainer
对象,传入 LoRA 模型、微调参数、训练数据集以及数据收集器 DataCollatorForSeq2Seq
。此外,还添加了 SwanLabCallback
回调,用于在 SwanLab 平台上记录训练过程中的数据。调用 trainer.train()
方法,启动模型的微调训练过程。
微调可视化配置
我们使用SwanLab来监控整个训练过程,并评估最终的模型效果。如果是第一次使用 SwanLab,则需要注册 SwanLab 账号:https://swanlab.cn,注册成功之后,在用户设置页面复制API Key,在训练开始时需要用到。
在命令行使用swanlab login
来进行登录
# Qwen2-0.5B-train.py
# 导入json模块,用于处理JSON格式的数据
import json
# 导入pandas模块,用于数据处理和分析
import pandas as pd
# 导入torch模块,PyTorch是一个开源的机器学习库,用于构建和训练深度学习模型
import torch
# 导入datasets模块中的Dataset类,用于处理和加载数据集
from datasets import Dataset
# 导入modelscope模块中的AutoTokenizer类,用于自动加载预训练模型的分词器
from modelscope import AutoTokenizer
# 导入swanlab.integration.transformers模块中的SwanLabCallback类,用于在训练过程中记录和回调数据
from swanlab.integration.transformers import SwanLabCallback
# 导入peft模块中的LoraConfig类、TaskType类和get_peft_model函数,用于配置和应用LoRA(Low-Rank Adaptation)微调技术
from peft import LoraConfig, TaskType, get_peft_model
# 导入transformers模块中的AutoModelForCausalLM类、TrainingArguments类、Trainer类和DataCollatorForSeq2Seq类
# AutoModelForCausalLM用于加载预训练的因果语言模型
# TrainingArguments用于配置训练参数
# Trainer用于管理模型的训练过程
# DataCollatorForSeq2Seq用于处理序列到序列任务的数据
from transformers import AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForSeq2Seq
# 导入os模块,用于操作文件和目录
import os
# 导入swanlab模块,用于记录实验日志和结果
import swanlab
# 权重根目录,定义了模型权重和数据集存储的根目录
BASE_DIR = r'F:\Projects\Python\Model'
# 设备名称,根据是否有可用的CUDA设备选择使用GPU或CPU
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 数据集处理函数,包括:训练数据集和测试数据集
def dataset_jsonl_transfer(origin_path, new_path):
"""
将原始数据集转换为大模型微调所需数据格式的新数据集
"""
messages = []
# 读取原JSONL文件
with open(origin_path, "r", encoding="utf-8") as file:
for line in file:
# 解析每一行原始数据(每一行均是一个JSON格式)
data = json.loads(line)
text = data["text"]
catagory = data["category"]
output = data["output"]
message = {
"input": f"文本:{text},分类选项列表:{catagory}",
"output": output,
}
messages.append(message)
# 保存处理后的JSONL文件,每行也是一个JSON格式
with open(new_path, "w", encoding="utf-8") as file:
for message in messages:
file.write(json.dumps(message, ensure_ascii=False) + "\n")
# 在使用数据集训练大模型之前,对每行数据进行预处理
def process_func(example):
"""
将数据集进行预处理
"""
MAX_LENGTH = 384 # 定义最大序列长度
input_ids, attention_mask, labels = [], [], []
# 构造模型输入的指令部分
instruction = tokenizer(f"<|im_start|>system\n你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项列表,请输出文本内容的正确分类<|im_end|>\n<|im_start|>user\n{example['input']}<|im_end|>\n<|im_start|>assistant\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
# 构造模型输入的响应部分
response = tokenizer(f"{example['output']}", add_special_tokens=False)
# 将指令和响应的输入ID、注意力掩码和标签拼接起来
input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
# 如果序列长度超过最大长度,则进行截断
if len(input_ids) > MAX_LENGTH:
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
# 加载预训练模型和分词器
model_dir = os.path.join(BASE_DIR, 'Qwen2-0.5B') # 模型目录路径
tokenizer = AutoTokenizer.from_pretrained(model_dir, use_fast=False, trust_remote_code=True) # 加载分词器
model = AutoModelForCausalLM.from_pretrained(model_dir, device_map=device, torch_dtype=torch.bfloat16) # 加载模型
model.enable_input_require_grads() # 开启梯度检查点时,要执行该方法
# 加载、处理数据集和测试集
train_dataset_path = os.path.join(BASE_DIR, 'zh_cls_fudan-news', 'train.jsonl') # 训练数据集路径
test_dataset_path = os.path.join(BASE_DIR, 'zh_cls_fudan-news', 'test.jsonl') # 测试数据集路径
train_jsonl_new_path = os.path.join(BASE_DIR, 'train.jsonl') # 处理后的训练数据集路径
test_jsonl_new_path = os.path.join(BASE_DIR, 'test.jsonl') # 处理后的测试数据集路径
# 如果处理后的训练数据集文件不存在,则调用dataset_jsonl_transfer函数进行转换
if not os.path.exists(train_jsonl_new_path):
dataset_jsonl_transfer(train_dataset_path, train_jsonl_new_path)
# 如果处理后的测试数据集文件不存在,则调用dataset_jsonl_transfer函数进行转换
if not os.path.exists(test_jsonl_new_path):
dataset_jsonl_transfer(test_dataset_path, test_jsonl_new_path)
# 得到微调数据集
train_df = pd.read_json(train_jsonl_new_path, lines=True) # 读取处理后的训练数据集
train_ds = Dataset.from_pandas(train_df) # 将训练数据集转换为Dataset对象
train_dataset = train_ds.map(process_func, remove_columns=train_ds.column_names) # 对训练数据集进行预处理
# 创建LoRA配置
config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 任务类型为因果语言模型
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], # 需要应用LoRA的模块
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alpha,具体作用参见 Lora 原理
lora_dropout=0.1, # Dropout 比例
)
# 将LoRA应用于模型
model = get_peft_model(model, config)
# 创建微调参数
args = TrainingArguments(
output_dir=os.path.join(BASE_DIR, 'output', 'Qwen2-0.5B'), # 输出目录
per_device_train_batch_size=4, # 每个设备的训练批次大小
gradient_accumulation_steps=4, # 梯度累积步数
logging_steps=10, # 日志记录步数
num_train_epochs=2, # 训练轮数
save_steps=100, # 模型保存步数
learning_rate=1e-4, # 学习率
save_on_each_node=True, # 在每个节点上保存模型
gradient_checkpointing=True, # 使用梯度检查点
report_to="none", # 不报告到任何平台
)
# SwanLab微调过程回调数据
swanlab_callback = SwanLabCallback(project="qwen", experiment_name="Qwen2-0.5B")
# 创建Trainer对象,用于管理模型的训练过程
trainer = Trainer(
model=model,
args=args,
train_dataset=train_dataset,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
callbacks=[swanlab_callback],
)
# 开始微调
trainer.train()
# 模型结果结果评估
def predict(messages, model, tokenizer):
# 构造模型输入的文本
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 对输入文本进行分词并转换为模型输入
model_inputs = tokenizer([text], return_tensors="pt").to(device)
# 生成模型的输出
generated_ids = model.generate(
model_inputs.input_ids,
max_new_tokens=512
)
# 提取生成的输出部分
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
# 将生成的输出解码为文本
return tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# 模型评估:获取测试集的前10条测试数据
test_df = pd.read_json(test_jsonl_new_path, lines=True)[:10]
test_text_list = []
for index, row in test_df.iterrows():
# 构造系统指令
instruction = '你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项列表,请输出文本内容的正确分类'
input_value = row['input'] # 获取输入文本
# 构造输入消息
messages = [
{"role": "system", "content": f"{instruction}"},
{"role": "user", "content": f"{input_value}"}
]
# 调用predict函数进行预测
response = predict(messages, model, tokenizer)
messages.append({"role": "assistant", "content": f"{response}"}) # 添加模型的响应
# 构造结果文本
result_text = f"{messages[0]}\n\n{messages[1]}\n\n{messages[2]}"
test_text_list.append(swanlab.Text(result_text, caption=response)) # 将结果添加到列表中
# 使用swanlab记录预测结果
swanlab.log({"Prediction": test_text_list})
swanlab.finish() # 结束实验日志记录
结果评估与应用
模型预测函数
定义 predict
函数,用于模型预测。该函数接受输入消息 messages
、模型和分词器作为参数,执行以下操作:
使用分词器的
apply_chat_template
方法,将输入消息格式化为模型可接受的文本模板,并添加生成提示。对格式化后的文本进行分词,生成模型输入。
将模型输入传输到设备上,并调用模型的
generate
方法生成文本。从生成的文本中提取新生成的部分,并将其解码为可读文本。
模型评估
从测试集中选取前 10 条数据进行模型评估。对于每条测试数据,构建包含系统提示和用户输入的对话消息,调用 predict
函数获取模型生成的分类结果。将输入消息、生成的分类结果以及预期的正确分类组合成完整的对话文本,并使用 SwanLab 的 Text
类进行可视化展示。最后,将所有评估结果记录到 SwanLab 平台上,并结束实验记录。
通过本次微调实战,我成功地将 Qwen2-0.5B 模型应用于文本分类任务,并在 SwanLab 平台上详细记录了训练和评估过程。这不仅提升了模型在特定任务上的性能,也为后续的模型优化和应用提供了宝贵的经验和数据支持。
# 模型结果评估
import pandas as pd # 导入pandas库,用于数据处理和分析
import torch # 导入PyTorch库,用于深度学习模型的加载和推理
from modelscope import AutoTokenizer # 导入AutoTokenizer,用于自动加载预训练模型的分词器
from transformers import AutoModelForCausalLM # 导入AutoModelForCausalLM,用于加载预训练的因果语言模型
from transformers import TrainingArguments, Trainer, DataCollatorForSeq2Seq # 导入训练相关的类,虽然这里未直接使用
import os # 导入os模块,用于路径操作
import swanlab # 导入swanlab模块,用于实验日志记录和结果可视化
# 权重根目录,定义模型和数据存储的根目录
BASE_DIR = r'F:\Projects\Python\Model'
# 设备名称,根据是否有可用的CUDA设备选择使用GPU或CPU
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# 创建一个SwanLab项目,用于记录实验日志和结果
swanlab.init(
workspace="xxzz", # 工作空间名称
project="qwen", # 项目名称
experiment_name="Qwen2-0.5B-Predict" # 实验名称
)
# 加载预训练模型和分词器
model_dir = os.path.join(BASE_DIR, 'merge', 'transformers') # 模型目录路径
tokenizer = AutoTokenizer.from_pretrained(model_dir, use_fast=False, trust_remote_code=True) # 加载分词器
model = AutoModelForCausalLM.from_pretrained(model_dir, device_map=device, torch_dtype=torch.bfloat16) # 加载模型
# 明确设置 pad_token,确保模型在处理时有明确的填充标记
if tokenizer.eos_token is None:
eos_token = tokenizer.convert_ids_to_tokens(tokenizer.eos_token_id) # 获取EOS标记
tokenizer.add_special_tokens({'eos_token': eos_token}) # 添加EOS标记
if tokenizer.pad_token is None:
pad_token = tokenizer.convert_ids_to_tokens(tokenizer.eos_token_id + 1) # 确保 pad_token 与 eos_token 不同
tokenizer.add_special_tokens({'pad_token': pad_token}) # 添加PAD标记
test_jsonl_new_path = os.path.join(BASE_DIR, 'test.jsonl') # 测试数据集路径
# 模型结果评估函数,用于生成模型的预测结果
def predict(messages, model, tokenizer):
# 构造模型输入的文本
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 对输入文本进行分词并转换为模型输入
model_inputs = tokenizer([text], return_tensors="pt", padding=True, truncation=True, max_length=512).to(device)
# 确保 attention_mask 被设置
if 'attention_mask' not in model_inputs:
model_inputs['attention_mask'] = torch.ones_like(model_inputs['input_ids'])
# 生成模型的输出
generated_ids = model.generate(
model_inputs.input_ids,
attention_mask=model_inputs.attention_mask,
max_new_tokens=512
)
# 提取生成的输出部分
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
# 将生成的输出解码为文本
return tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
# 模型评估:获取测试集的第11到50条测试数据
test_df = pd.read_json(test_jsonl_new_path, lines=True)[10:50]
test_text_list = [] # 用于存储预测结果的列表
for index, row in test_df.iterrows():
input_value = row['input'] # 获取input字段的值
# 构造输入消息
messages = [
{"role": "system", "content": "你是一个文本分类领域的专家,你会接收到一段文本和几个潜在的分类选项列表,请输出文本内容的正确分类"},
{"role": "user", "content": f"{input_value}"}
]
# 调用predict函数进行预测
response = predict(messages, model, tokenizer)
messages.append({"role": "assistant", "content": f"{response}"}) # 添加模型的响应
# 构造结果文本
result_text = f"{messages[0]}\n\n{messages[1]}\n\n{messages[2]}"
print("result_text", messages[2]) # 打印预测结果
test_text_list.append(swanlab.Text(result_text, caption=response)) # 将结果添加到列表中
# 使用swanlab记录预测结果
swanlab.log({"Prediction": test_text_list})
swanlab.finish() # 结束实验日志记录
本地大模型部署:使用 Ollama 服务
Ollama 是一款强大的工具,能够帮助你在本地部署和运行大语言模型。它支持多种模型,如 Llama 3.3、Phi 3、Mistral、Gemma 2 等,并允许你自定义和创建自己的模型。Ollama 提供了简洁易用的命令行界面,让你能够轻松管理和使用大模型。
下载与安装
访问 Ollama 官网,下载适用于 macOS、Linux 或 Windows 的安装包。
安装完成后,你就可以开始使用 Ollama 的各种功能了。
常用命令
查看 Ollama 中的大模型:运行
ollama list
命令,即可查看 Ollama 中已安装和可用的大模型。运行大模型:使用
ollama run xxx
命令,其中xxx
是你想要运行的模型名称。例如,ollama run qwen
将运行名为 "qwen" 的模型。启动 API 服务:执行
ollama serve
命令,Ollama 将启动 API 服务,默认监听在http://127.0.0.1:11434/
端口上。启动 API 服务后,你需要运行一个大模型,才能通过 API 进行调用。
导入 GGUF 模型
要导入 GGUF 模型,请创建一个包含以下内容的 Modelfile
:
FROM /path/to/file.gguf
// FROM F:\Projects\Python\Model\gguf\Qwen2-0.5B\Qwen2-0.5B.gguf
API 调用方式
直接调用:通过
http://127.0.0.1:11434/api/generate
端点进行调用。例如,发送以下 JSON 数据:{ "model": "qwen", "prompt": "使用中文介绍一下你自己", "stream": false }
这将使用 "qwen" 模型生成文本,回答关于自己的问题,并以中文输出。
OpenAI 风格调用:如果你习惯使用 OpenAI 的 API 格式,可以通过
http://127.0.0.1:11434/v1
端点进行调用。这种方式让你能够以熟悉的方式与本地部署的大模型进行交互。<template> <div class="container"> <h2>我是Qwen</h2> <div class="question-anwser" id="scroll-wrapper"> <div class="content" v-for="(item, index) in msgList"> <div class="question"> <div> {{ item.content }} </div> </div> <div class="anwser" v-if="answerList[index]"> <div> <VMdPreview :text="answerList[index]" /> </div> </div> <div class="anwser" v-else-if="!isDone"> <div> <VMdPreview :text="answer" /> </div> </div> </div> </div> <div class="chat-box"> <div class="chat-input"> <input type="text" v-model="msg" @keyup.enter="send" /> <button @click="send">发送</button> </div> </div> </div> </template> <script setup> import { ref, onMounted } from "vue"; import OpenAI from "openai"; import VMdPreview from "@kangc/v-md-editor/lib/preview"; import "@kangc/v-md-editor/lib/style/preview.css"; import githubTheme from "@kangc/v-md-editor/lib/theme/github.js"; import "@kangc/v-md-editor/lib/theme/style/github.css"; import hljs from "highlight.js"; // Server-Sent Events 服务器推送事件,简称 SSE,是一种服务端实时主动向浏览器推送消息的技术。 VMdPreview.use(githubTheme, { Hljs: hljs, }); const list = ref([{ role: "system", content: "你好,我是基于Qwen开发的ZGer,有什么问题可以问我哦!", },{ role: "system", content: "你的回答必须是中文。" }]); // 包含所有的问题和回答 const msg = ref(""); const msgList = ref([]); const answer = ref(""); const answerList = ref([]); const isDone = ref(true); const send = () => { msgList.value.push({ role: "user", content: msg.value, }); list.value.push({ role: "user", content: msg.value, }); msg.value = ""; getAnswer(); }; const openai = new OpenAI({ baseURL: "http://localhost:11434/v1/", apiKey: "ollama", dangerouslyAllowBrowser: true, }); async function getAnswer() { try { isDone.value = false; const response = await openai.chat.completions.create({ messages: list.value, model: "qwen", // model: "llama3.2", stream: true, }); for await (const chunk of response) { answer.value += chunk.choices[0].delta.content; // 判断是否结束 if (chunk.choices[0].finish_reason == "stop") { answerList.value.push(answer.value); list.value.push({ role: "system", content: answer.value, }); answer.value = ""; isDone.value = true; } } } catch (error) { console.error("Error in main:", error); } } // 实现浏览器滚动条自动滚动到底部 onMounted(() => { const element = document.getElementById("scroll-wrapper"); const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === "childList") { element.scrollTop = element.scrollHeight; } }); }); observer.observe(element, { childList: true, // 监听子元素的添加和删除 subtree: true, // 监听所有后代节点的变化 }); }); </script> <style> html, body { margin: 0; padding: 0; overflow: hidden; background-color: rgb(243, 245, 250); } /* scroll样式 */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.2); border-radius: 10px; } ::-webkit-scrollbar-track { background-color: rgba(0, 0, 0, 0); border-radius: 10px; } .container { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; overflow: hidden; width: 80%; margin: 0 auto; /* text-align: center; */ padding-top: 24px; .question-anwser { width: 80%; height: 80%; overflow-y: scroll; .content { /* display: flex; */ flex-direction: column; justify-content: center; align-items: center; margin: 0 auto; .question { display: flex; justify-content: flex-end; > div { max-width: 40%; background-color: rgb(45, 101, 247); color: #ffffff; padding: 10px; border-radius: 10px; margin-bottom: 24px; } } .anwser { display: flex; justify-content: flex-start; > div { max-width: 80%; background-color: #ffffff; padding: 10px; border-radius: 10px; margin-bottom: 10px; } } } } .chat-box { display: flex; flex-direction: column; justify-content: center; align-items: center; width: 80%; height: 20%; .chat-input { display: flex; justify-content: center; align-items: center; width: 100%; input { /* width: 80%; */ flex: 1; height: 30px; border: 1px solid #f0f0f0; border-radius: 5px; padding: 5px; margin-right: 10px; } button { width: 100px; height: 40px; border: 1px solid #f0f0f0; border-radius: 10px; background-color: #8fc2e4; color: #fff; } } } } .github-markdown-body { padding: 16px; } </style>
将safetensors转换为gguf以部署到Ollama
要将 .safetensors
文件转换为 .gguf
文件,可以使用 llama.cpp
提供的工具和脚本。以下是详细的步骤:
步骤 1:克隆 llama.cpp
仓库
使用 Git 克隆
llama.cpp
仓库:git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp
步骤 2:安装依赖
在
llama.cpp
目录下,安装所需的 Python 依赖:pip3 install -r requirements.txt
步骤 3:下载 Safetensors 模型文件
确保你已经下载了 Safetensors 格式的模型文件,并将
model.safetensors
、config.json
和tokenizer.json
放置在一个文件夹中。
步骤 4:执行转换脚本
使用
convert_hf_to_gguf.py
脚本将 Safetensors 模型转换为 GGUF 格式:python convert_hf_to_gguf.py /path/to/your/model/folder --outtype f16 --verbose --outfile /path/to/output/gguf/file.gguf
/path/to/your/model/folder
是包含 Safetensors 模型文件的目录。--outtype f16
指定输出格式为 float16,你可以根据需要选择其他格式。--verbose
用于输出详细信息。--outfile
指定输出文件的路径。
步骤 5:验证转换结果
转换完成后,检查输出目录中是否生成了
.gguf
文件。你可以使用 Ollama 或其他支持 GGUF 格式的工具来测试和使用该模型。
通过以上步骤,你可以将 Safetensors 格式的模型文件转换为 GGUF 格式,以便在 Ollama 或其他支持 GGUF 的平台上使用。
原模型和微调后的模型合并
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
# 加载原始模型
model = AutoModelForCausalLM.from_pretrained(r'F:\Projects\Python\Model\Qwen2-0.5B')
tokenizer = AutoTokenizer.from_pretrained(r"F:\Projects\Python\Model\Qwen2-0.5B")
# 加载LoRA适配器
peft_config = PeftConfig.from_pretrained(r'F:\Projects\Python\Model\output\Qwen2-0.5B\checkpoint-500')
model = PeftModel.from_pretrained(model, r'F:\Projects\Python\Model\output\Qwen2-0.5B\checkpoint-500')
# 合并模型
model = model.merge_and_unload()
# 保存合并后的模型
model.save_pretrained(r"F:\Projects\Python\Model\merge\transformers", safe_serialization=True)
tokenizer.save_pretrained(r"F:\Projects\Python\Model\merge\transformers")