
|原文章发布于2024年09月09日
端侧 ChatGPT 时刻到来!旗舰端侧模型面壁「小钢炮」系列进化为全新 MiniCPM 3.0 基座模型,再次以小博大,以 4B 参数,带来超越 GPT-3.5 的性能,强得不像端侧模型。并且,量化后仅 2GB 内存,端侧友好。
这还是一款瑞士军刀般全面开挂的基座模型,一口气带来:
·无限长文本,榜单性能超越 Kimi,超长文本也不崩;
·Function Calling,性能比肩 GPT-4o 的端侧最强 Function Calling;
·超强 RAG 外挂三件套,中文检索第一、生成超 Llama3-8B。
➤ MiniCPM 3.0 开源地址:
🔗 https://github.com/OpenBMB/MiniCPM
🔗 https://huggingface.co/openbmb/MiniCPM3-4B
我们也为大家准备了部署微调教程,方便大家快速上手 MiniCPM 3.0
➤ MiniCPM 3.0 完整教程地址:
🔗 https://modelbest.feishu.cn/wiki/LrdMwKKt3iZgoYkQlPRcvY1PnXc
Chat 方法
from transformers import AutoTokenizer,AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("/root/ld/ld_model_pretrained/minicpm3")
model=AutoModelForCausalLM.from_pretrained("/root/ld/ld_model_pretrained/minicpm3",trust_remote_code=True).cuda()
history=[]
query=input("user:")
response,history=model.chat(tokenizer, query=query,history=history)
print("model:",response)
query=input("user:")
response,history=model.chat(tokenizer, query=query,history=history)
print("model:",response)
#history是列表形式[{"role": "assistant", "content": answer1},{"role": "assistant", "content": response}。。。。] Generate 方法
1. 继续生成类(非问答)方法
from transformers import AutoTokenizer, AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("/root/ld/ld_model_pretrained/minicpm3",trust_remote_code=True).cuda()
tokenizer = AutoTokenizer.from_pretrained("/root/ld/ld_model_pretrained/minicpm3",trust_remote_code=True)
prompt = "Hey, are you conscious? Can you tell me "
inputs = tokenizer(prompt, return_tensors="pt")
# Generate
generate_ids = model.generate(inputs.input_ids.cuda(), max_length=300,do_sample=False)
output=tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]print(output) 2. 对话类(问答)方法
Function call 简易实现
注意:
1. tools列表中的每一个函数,需要定义一个同名的函数,确保能够调用
2. tools中的函数声明,应该严格按照示例中格式进行
3. 对于工具的实现函数,比如第五行get_delivery_date这个函数,要保证的是与tools中同名,同参数名,能够跑通,具体实现不重要。模型只管这个工具的输入和返回值,返回值应该设计成容易被大模型理解。
#!/usr/bin/env python
# encoding: utf-8import refrom transformers import AutoTokenizer,AutoModelForCausalLM
def get_delivery_date(order_id=None):# 应该定义下方Tools中每一个函数的实现方法if order_id == None:
return "没有订单号无法查询"
else:
print("get_delivery_date:这里应该替换查询方法函数,结果用return返回")return "2024-09-02"
def get_response_call(tool_call_str):
# 正则表达式
pattern = r'(?<=```python\n)(.*?)(?=\n```\n)'
# 使用正则表达式匹配
match = re.search(pattern, tool_call_str)
if match:
function_call = match.group(1)
return function_call
else:
return None
tools = [
{
"type": "function",
"function": {
"name": "get_delivery_date",# 函数名,需要定义一个一样的python函数
# description 是这个工具的描述,最好是英文,通俗易懂最好
"description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'",
"parameters": {
"type": "object",
"properties": {
"order_id": {#参数名
"type": "string",#参数类型
"description": "The customer's order ID.",# 参数实现
},
},
"required": ["order_id"],# 哪些是必须要的
"additionalProperties": False,
},
},
}
]
messages = [
{
"role": "system",
"content": "You are a helpful customer support assistant. Use the supplied tools to assist the user.",
}
]
query="Hi, can you tell me the delivery date for my order,my order id is 123456。"
tokenizer = AutoTokenizer.from_pretrained(
"/root/ld/ld_model_pretrained/minicpm3", trust_remote_code=True
)
prompt = tokenizer.apply_chat_template(
messages, tools=tools, tokenize=False, add_generation_prompt=True
)
model=AutoModelForCausalLM.from_pretrained("/root/ld/ld_model_pretrained/minicpm3", trust_remote_code=True).cuda()
response,history=model.chat(tokenizer, query=query,history=messages,do_sample=False)#由于functioncall的精确性,这里建议将do_sample设置为False
call_str=get_response_call(response)
print(eval(call_str))
# output:"""2024-09-02"""
方法二:vLLM 部署
暂时在 OpenBMB 仓库,向官方提交了pr
git clone https://github.com/OpenBMB/vllm.git
cd vllm
git checkout minicpm3
pip install e . vLLM python 运行
from vllm import LLM, SamplingParams
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--model_path", type=str, default="/root/ld/ld_model_pretrained/minicpm3")
parser.add_argument("--prompt_path", type=str, default="")
parser.add_argument("--batch", type=int, default=2) #可以修改这个batch达到并发
args = parser.parse_args()
prompts=["你好啊","吃饭了没有","你好,今天天气怎么样?","孙悟空是谁?"]
prompt_template = "<|im_start|> user\n{} <|im_end|>"
prompts = [prompt_template.format(prompt.strip()) for prompt in prompts]
params_dict = {
"n": 1,
"best_of": 1,
"presence_penalty": 1.0,
"frequency_penalty": 0.0,
"temperature": 0.5,
"top_p": 0.8,
"top_k": -1,
"use_beam_search": False,
"length_penalty": 1,
"early_stopping": False,
"stop": None,
"stop_token_ids": None,
"ignore_eos": False,
"max_tokens": 1000,
"logprobs": None,
"prompt_logprobs": None,
"skip_special_tokens": True,
}
# Create a sampling params object.
sampling_params = SamplingParams(**params_dict)
# Create an LLM.
llm = LLM(model=args.model_path, tensor_parallel_size=1, dtype='bfloat16',trust_remote_code=True,max_model_len=2048,gpu_memory_utilization=0.5)
# Generate texts from the prompts. The output is a list of RequestOutput objects
# that contain the prompt, generated text, and other information.
batch_input=[]
for prompt in prompts:
batch_input.append(prompt)
if len(batch_input)==args.batch:
outputs = llm.generate(batch_input, sampling_params)
# Print the outputs.
for output in outputs:
prompt = output.prompt
print("用户:{}".format(prompt))
generated_text = output.outputs[0].text
# find the first <用户> and remove the text before it.
print("AI助手:{}".format(generated_text))
batch_input=[] vLLM openapi
1.启动vllm的server
vllm serve /root/ld/ld_model_pretrained/minicpm3 --dtype auto --api-key token-abc123 --trust-remote-code --max_model_len 2048 --gpu_memory_utilization 0. 2.使用python调用api接口
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-abc123",
)
completion = client.chat.completions.create(
model="/root/ld/ld_model_pretrained/minicpm3",
messages=[
{"role": "user", "content": "hello,nice to meet you."}
]
)
print(completion.choices[0].message) 方法三:llama.cpp 部署
设备:linux,mac
1. 下载llama.cpp的minicpm3分支
git clone https://github.com/OpenBMB/llama.cpp.gitgit checkout minicpm3 2. 编译llama.cpp
cd lama.cpp/models
mkdir Minicpm3 3. 获取MiniCPM的gguf模型
(1) 创建llama.cpp/models/Minicpm路径
cd lama.cpp/modelsmkdir Minicpm3 (2) 下载[MiniCPM3模型]所有文件(也可以是训练后的模型)并保存到llama.cpp/models/Minicpm
(3) 将模型转换为gguf格式
python3 -m pip install -r requirements.txt
#将pytorch模型转化为fp16的gguf
python3 convert-hf-to-gguf.py models/Minicpm3/ --outfile /your/path/llama.cpp/models/Minicpm3/CPM-4B-F16.gguf
#完成以上步骤,llama.cpp/models/Minicpm3目录下有一个CPM-4B-F16.gguf的模型文件 4. 将fp16的gguf文件进行量化
#使用本行代码执行成功后,/models/Minicpm/下将存在 ggml-model-Q4_K_M.gguf的4bit量化文件
./llama-quantize ./models/Minicpm3/CPM-4B-F16.gguf ./models/Minicpm3/ggml-model-Q4_K_M.gguf Q4_K_M 5. 将fp16的gguf文件进行量化。
#使用本行代码执行成功后,/models/Minicpm/下将存在 ggml-model-Q4_K_M.gguf的4bit量化文件
./llama-quantize ./models/Minicpm3/CPM-4B-F16.gguf ./models/Minicpm3/ggml-model-Q4_K_M.gguf Q4_K_M
#如果找不到llama-quantize,可以尝试以下方法
cd llama.cpp
make llama-quantize 6. 开始推理
(1) 命令行推理
./llama-cli -c 1024 -m ./models/Minicpm/ggml-model-Q4_K_M.gguf -n 1024 --top-p 0.7 --temp 0.7 --prompt "<|im_start|>user\n请写一篇关于人工智能的文章,详细介绍人工智能的未来发展和隐患。<|im_end|>\n<|im_start|>assistant\n" (2) server服务
发起http服务,参数解析请见,llamacpp参数:
./llama-server -m ./models/Minicpm3/CPM-2B-F16.gguf -c 2048 使用python 调用服务,返回结果
import requests
url = "http://localhost:8080/completion"
headers = {
"Content-Type": "application/json"
}
data = {
"prompt": "MiniCPM3 是哪家公司发布的?",
"n_predict": 128
}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 200:
result = response.json()
print(result["content"])
else:
print(f"Request failed with status code {response.status_code}: {response.text}")
1. 获取我们fork的分支代码
PR暂未合并,请务必使用我们的分支
git clone https://github.com/LDLINGLINGLING/ollama.git
cd ollama
git checkout minicpm
tar -zxvf ollama.tar.gz -C .
cd ollama 2. 编译ollama
cd ollama
go generate ./... #这个过程需要访问google等网址
go build . 3. 按照Llamacpp的教程获取量化后的gguf文件
4. 在ollama主路径下开启服务
./ollama serve 5. 创建一个model.file文件
vim minicpm3.Modelfile From 后面写入量化后的gguf文件地址
FROM ./MiniCPM-V-2_6/ggml-model-Q4_K_M.ggufTEMPLATE """{{ if .System }}<|im_start|>system{{ .System }}<|im_end|>{{ end }}{{ if .Prompt }}<|im_start|>user{{ .Prompt }}<|im_end|>{{ end }}<|im_start|>assistant<|im_end|>{{ .Response }}<|im_end|>"""PARAMETER stop "<|endoftext|>"PARAMETER stop "<|im_end|>"PARAMETER num_ctx 4096 6. 创建ollama实例
ollama create minicpm -f minicpm3.Modelfile 7. 运行模型
ollama run minicpm3 在此教程中,我们使用llama_factory方法做微调训练
1. 首先安装llama_factory依赖
2. 处理数据
将数据集处理成Minicpm/finetune/llama_factory_example/llama_factory_data文件夹中的格式,示例包括dpo,kto,sft三种微调方式并放置到llama_factory/data目录下。
(1) dpo数据格式
对于一个"human"的answer,需要给一个chosen(好的答案),一个rejected(坏的答案)
[
{
"conversations": [
{
"from": "human",
"value": "你吃饭了没有,吃的什么啊?"
],
"chosen": {
"from": "gpt",
"value": "刚吃了啊,你去哪里玩?"
},
"rejected": {
"from": "gpt",
"value": "吃得茄子,西红柿,红烧肉。"
}
}
] (2)kto数据格式:
其中每个messages代表一条数据,label代表是该条数据的回复是否合理
不需要和dpo那样相同问题不同答案,对于每个问题和答案对给予一个评价
每个问题和回复都可以有一个True(好的),或者false(不好的评价)
{
"messages": [
{
"content": "minicpm3.0哪里最强?",
"role": "user"
},
{
"content": "哪里都强,六边形战士好吗",
"role": "assistant"
}
],
"label": true
},
{
"messages": [
{
"content": "minicpm3.0 有哪些优点。",
"role": "user"
},
{
"content": "1.长文本能力。2.function call能力 3.其他所有能力",
"role": "assistant"
},
{
"content": "细说长文本能力",
"role": "user"
},
{
"content": "反正很强,细说就去我们github吧。https://github.com/OpenBMB/MiniCPM.git",
"role": "assistant"
}
],
"label": false
}
] (3)sft数据格式如下,每个字典组成一条数据
[
{
"instruction": "你现在比牛顿还牛的科学家",
"input": "识别并解释给定列表中的两个科学理论:细胞理论和日心说。",
"output": "细胞理论是生物科学的一个理论,它认为所有生命体都是由微小的基本单元——细胞所构成。这是生物学的一个基础理论,认为细胞是所有生物的基本结构和功能单位,所有的生物都是由一个或多个细胞组成,细胞只能通过细胞分裂产生新的细胞。这一理论由薛定谔、施瓦内和雪莱于1839年首次提出。\n\n日心说是指太阳是太阳系的中心,也就是说,行星围绕太阳旋转的理论。这个理论打破了传统的地心说观点,认为地球并不是宇宙的中心。日心说的提出者是尼古拉·哥白尼,他在16世纪初发表了他的著作《天体运行论》,阐述了太阳系行星围绕太阳运行的模型,为天文学的发展做出了巨大贡献。"
}
] 3. 将数据信息添加到dataset_info.json
在llama_factory/data/dataset_info.json中添加数据集信息,保证dataset_info.json中能找到你的数据集,如下例:
file_name为制作数据集的文件名
比如"sft_zh_demo"代表数据名称,在面配置文件yaml中会用到
需要修改的就只有两个一个是数据的键名,比如"sft_zh_demo","kto_en_demo.json"
{"identity": {
"file_name": "identity.json"
},
"sft_zh_demo": {
"file_name": "alpaca_zh_demo.json"
},
"kto_en_demo": {
"file_name": "kto_en_demo.json",
"formatting": "sharegpt",
"columns": {
"messages": "messages",
"kto_tag": "label"
},
"tags": {
"role_tag": "role",
"content_tag": "content",
"user_tag": "user",
"assistant_tag": "assistant"
}
},
"dpo_en_demo": {
"file_name": "dpo_en_demo.json",
"ranking": true,
"formatting": "sharegpt",
"columns": {
"messages": "conversations",
"chosen": "chosen",
"rejected": "rejected"
}
}
} 4. 设置训练脚本
(1)将MiniCPM/finetune/llama_factory_example中文件复制到LLaMA-Factory/examples/minicpm目录下
cd LLaMA-Factory/examples
mkdir minicpm
#以下代码中的/your/path要改成你的MiniCPM代码和LLaMA-Factory路径
cp -r /your/path/MiniCPM/finetune/llama_factory_example/* /your/path/LLaMA-Factory/examples/minicpm (2) 根据你需要微调的方式,以dpo为例
LLaMA-Factory/examples/minicpm/minicpm_dpo.yaml必须修改的配置参数如下
model_name_or_path: openbmb/MiniCPM3-4B # 或者你本地保存的地址
template: cpm3 #注意如果微调minicpm3就写cpm3,否则写cpm
dataset: dpo_en_demo # 这里写dataset_info.json中的键名
output_dir: your/finetune_minicpm/save/path # 你微调后模型的保存地址
bf16: true # 如果你的设备支持bf16,否则false
deepspeed: examples/deepspeed/ds_z2_config.json # 如果显存不够可以改成ds_z3_config.json (3) 修改LLaMA-Factory/examples/minicpm/single_node.sh文件中以下配置
#以下这行修改为你机器有多少张gpu
NPROC_PER_NODE=8
NNODES=1
RANK=0
MASTER_ADDR=127.0.0.1
MASTER_PORT=29500
#以下两行如果是A100,H100等以上的高端显卡可以删除
export NCCL_P2P_DISABLE=1
export NCCL_IB_DISABLE=1
#以下数字设置为你机器中参与训练的显卡,这里是0-7号卡都参与训练
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 torchrun \
--nproc_per_node $NPROC_PER_NODE \
--nnodes $NNODES \
--node_rank $RANK \
--master_addr $MASTER_ADDR \
--master_port $MASTER_PORT \
#以下这行需要修改成配置文件地址,
如/root/ld/ld_project/LLaMAFactory/examples/minicpm/minicpm_dpo.yaml
src/train.py /your/path/LLaMA-Factory/examples/minicpm/minicpm_dpo.yaml 5. 开始训练
cd LLaMA-Factory
bash /your/path/LLaMA-Factory/examples/minicpm/single_node.sh 更多模型部署FAQ、微调指南,请查阅知识库:
🔗 https://modelbest.feishu.cn/wiki/LrdMwKKt3iZgoYkQlPRcvY1PnXc
➤ 欢迎加入 OpenBMB 社区一起讨论

官方网站
https://www.openbmb.org
GitHub
https://github.com/OpenBMB
https://github.com/thunlp
长期开放招聘|含实习
开发岗 | 算法岗 | 产品岗
交流QQ群
735930538