当前位置:AIGC资讯 > AIGC > 正文

ChatGLM3-6B使用lora微调实体抽取,工具LLaMA-Factory,医学数据集CMeEE

一、下载ChatGLM3-6B

下载地址,需要魔法

测试模型:

新建文件predict.py。运行下面测试代码。建议这里的transformers包最好和LLaMA-Factory环境的transformers包版本保持一致或者直接用LLaMA-Factory的环境。

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

device = "cuda" # the device to load the model onto

model = AutoModelForCausalLM.from_pretrained("./models/chatglm3-6b",torch_dtype=torch.float16,trust_remote_code=True).half().cuda()
tokenizer = AutoTokenizer.from_pretrained("./models/chatglm3-6b",trust_remote_code=True)

model.to(device)
model = model.eval()
# response, history = model.chat(tokenizer, """ 你是谁""", history=[])
response, history = model.chat(tokenizer, """ 从给定文本中提取医疗程序、疾病、症状、肌体、药品、体检项目、微生物、医疗器械、科室这几类的实体名,用字典格式返回。文本:房内折返性心动过速,每年发作1至3次,需药物干预。""", history=[])

print(response)

问题:你是谁

答:我是一个名为 ChatGLM3-6B 的人工智能助手,是基于清华大学 KEG 实验室和智谱 AI 公司于 2023 年共同训练的语言模型开发的。我的任务是针对用户的问题和要求提供适当的答复和支持。

问题:从给定文本中提取医疗程序、疾病、症状、肌体、药品、体检项目、微生物、医疗器械、科室这几类的实体名,用字典格式返回。文本:房内折返性心动过速,每年发作1至3次,需药物干预。

答:

{
  "医疗程序": [],
  "疾病": [],
  "症状": [],
  "肌体": [],
  "药品": [],
  "体检项目": [],
  "微生物": [],
  "医疗器械": [],
  "科室": []
}

模型在微调前几乎提取不了医学中的专业名词 。

问题中的文本来自CMeEE-V2_dev.json中最后一句。

二、部署LLaMA-Factory

按照LLaMA-Factory项目中的要求创建好LLaMA-Factory的环境。有问题请放评论。

启动命令:llamafactory-cli webui

打开:本地启动打开: http://0.0.0.0:7860

或 服务器启动 服务器地址:7860

如果出现 :尚不支持多 GPU 训练。

切换为单卡启动:CUDA_VISIBLE_DEVICES=0  llamafactory-cli webui

三、数据集格式转换

 CMeEE下载链接

将医学数据集CMeEE制作为ChatGLM3-6B的训练数据集。转换代码如下:修改file_path为要转换的医学数据集CMeEE的json文件地址,修改倒数第二行的保存位置。本次实验只选择前200个进行操作,if index==200: break  。 想全部进行转换请注释掉这句。instruction中可自行修改指令。

import json

# 指定JSON文件的路径
file_path = r'CMeEE-V2_dev.json'

# 读取JSON文件
with open(file_path, 'r', encoding='utf-8') as file:
    datasets = json.load(file)

# print(datasets)

# 定义类型映射
type_mapping = {
    "pro": "医疗程序",
    "dis": "疾病",
    "sym": "症状",
    "bod": "肌体",
    "dru": "药品",
    "ite": "体检项目",
    "mic": "微生物",
    "equ": "医疗器械",
    "dep": "科室"
}

llf_data = []

for index,data in enumerate(datasets):
    # 创建一个包含所有类型的字典,初始值为空列表
    entities_by_type = {value: [] for key, value in type_mapping.items()}

    # 遍历所有实体,将它们按类型分类
    for entity in data["entities"]:
        entity_type = entity["type"]
        if entity_type in type_mapping:
            entities_by_type[type_mapping[entity_type]].append(entity["entity"])

    # 创建输出数据
    txt = data["text"]
    output_data = {
        "instruction": f"从给定文本中提取医疗程序、疾病、症状、肌体、药品、体检项目、微生物、医疗器械、科室这几类的实体名,用字典格式返回。文本:{txt}",
        "input": "",
        "output": f"{entities_by_type}",
        "history": []
    }
    llf_data.append(output_data)

    if index==200:
        break
llf_data = json.dumps(llf_data, ensure_ascii=False, indent=2)
print(llf_data)

with open(r'chatglm3_finetune_data.json', 'w', encoding='utf-8') as f:
    f.write(llf_data)

 请注意instruction、input、output对应的值全部都要是字符串形式。history的值为列表。否则后续微调时可能会报错:

raise RuntimeError("Cannot find valid samples, check `data/README.md` for the data format.")
RuntimeError: Cannot find valid samples, check `data/README.md` for the data format.

转换完毕后如下形式:

制作好的训练集放在目录LLaMA-Factory/data下,也可以在其他目录下 。然后修改dataset_info.json文件。如果在其他目录,chatglm3_finetune_data.json需改为对应的绝对地址

{"chatglm3_finetune_data":{"file_name":"chatglm3_finetune_data.json"}}

四、Lora训练

打开llamafactory的webui。

设置好基本参数。训练30个epoch。如果你的显存较小batchsize无法调大,可以调大梯度累计的值来模拟大的batchsize。

设置好lora参数为32,秩设置越大、参数更新的数量越多、训练越慢。

设置保存名称

点击开始训练,等待训练结束。

结果位于saves/ChatGLM3-6B-Chat/lora下。

五、微调模型测试

新建文件predict_lora.py。运行下面测试代码。

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
from peft import PeftModel


device = "cuda" # the device to load the model onto

model = AutoModelForCausalLM.from_pretrained("./models/chatglm3-6b",torch_dtype=torch.float16,trust_remote_code=True).half().cuda()
tokenizer = AutoTokenizer.from_pretrained("./models/chatglm3-6b",trust_remote_code=True)
p_model = PeftModel.from_pretrained(model, model_id="/LLaMA-Factory/saves/ChatGLM3-6B-Chat/lora/train_2024-06-17-16-55-15")  # 将训练所得的LoRa权重加载起来

#
p_model.to(device)
p_model = p_model.eval()
response, history = p_model.chat(tokenizer, """ 从给定文本中提取医疗程序、疾病、症状、肌体、药品、体检项目、微生物、医疗器械、科室这几类的实体名,用字典格式返回。文本:房内折返性心动过速,每年发作1至3次,需药物干预。""", history=[])
print(response)
PeftModel.from_pretrained(model, model_id)中的model_id填入训练好的LORA模型绝对地址

运行结果:{'医疗程序': [], '疾病': ['房内折返性心动过速'], '症状': [], '肌体': [], '药品': [], '体检项目': [], '微生物': [], '医疗器械': [], '科室': []} 

微调后,已经可以提取出疾病的实体名称了。

合并使用模型时可能发生如下报错:

config = config_cls(**kwargs)
TypeError: LoraConfig.__init__() got an unexpected keyword argument 'layer_replication'

 解决方法:将测试文件中的transformers包和peft包的版本与训练时LLaMA-Factory环境中的transformers包和peft包版本保持一致。

有问题放评论,有用请点赞! 

总结

本文详细介绍了如何在本地环境中下载、部署、微调并使用ChatGLM3-6B模型,特别聚焦于将ChatGLM3-6B应用于医疗实体名提取的任务。以下是文章的总结:
### 一、下载ChatGLM3-6B
1. **下载与测试**:
- 提供了模型的下载地址(需特殊方法访问)。
- 测试模型通过`predict.py`脚本进行,展示了如何使用`transformers`库加载ChatGLM3-6B模型及其分词器,并对两个示例问题进行测试。
- 发现模型在微调前难以识别医学中的专业名词。
### 二、部署LLaMA-Factory
1. **环境搭建**:
- 按照LLaMA-Factory项目要求创建环境,并通过命令行`llamafactory-cli webui`启动服务。
- 指定服务器或本地启动的访问方式,并提供处理多GPU训练问题的方法(单卡启动)。
### 三、数据集格式转换
1. **数据集准备与转换**:
- 使用CMeEE医学数据集,通过Python脚本转换成ChatGLM3-6B训练所需的数据格式。
- 指定了数据文件路径和输出路径,并映射了数据集中实体类型与新高需求中的类型名称。
- 强调将数据集以特定格式保存在LLaMA-Factory的适当目录下,并相应地修改配置文件。
### 四、Lora训练
1. **训练过程**:
- 通过LLaMA-Factory的Web界面设置训练参数(epochs、batch size、gradient accumulation steps、LoRa参数等)。
- 点击开始训练,并在训练结束后找到结果保存位置。
### 五、微调模型测试
1. **测试微调后的模型**:
- 新建`predict_lora.py`脚本,使用`transformers`和`peft`库加载原始ChatGLM3-6B模型和训练好的LoRa权重。
- 运行测试代码再次对医疗文本进行实体名提取,看到模型在微调后能够有效提取出疾病实体的名称。
- 文中还提及了解决可能出现的版本不兼容问题的方法,确保测试环境与训练环境一致。
### 结尾
文章末尾鼓励读者尝试并分享遇到的问题和反馈,以促进知识的分享和交流。整体来说,文章为希望将大型语言模型应用于特定领域(如医学)的研究人员和开发者提供了详细的操作步骤和实用建议。

更新时间 2024-07-26