DeepSeek 1.5B模型微调实战:药品对码高效实现

背景

药品对码

不同机构,存储药品信息的格式不同,合作时需要对齐双方的药品信息,双方药品编码建立关联关系; 例如: 对方的药品

id通用名批准文号规格生成厂商
1024维生素E软胶囊H35020242100mg/粒x60粒/瓶/盒国药控股星鲨制药(厦门)有限公司

我方药品库内批准文号、通用名与之匹配的有

id通用名批准文号规格生成厂商
5364维生素E软胶囊国药准字H350202420.1gx15粒x2板/盒国药控股星鲨制药(厦门)有限公司
5368维生素E软胶囊国药准字H350202420.1gx60粒/瓶国药控股星鲨制药(厦门)有限公司
5388维生素E软胶囊国药准字H350202420.1gx20粒x2板/盒国药控股星鲨制药(厦门)有限公司
5394维生素E软胶囊国药准字H350202420.1gx16粒x2板/盒国药控股星鲨制药(厦门)有限公司

对码后建立关联关系

id对方机构ID对方药品ID我方药品ID
1100010245368

肉眼很容易看出,第二条匹配,但是用传统的程序并不好写,只能穷举对方可能的千奇百怪的写法,还可能遗漏;所以,这里适合用AI代替;

向AI发问

向本地部署的 DeepSeek-R1-Distill-Qwen-7B 提问

从输入中找出属于国药控股星鲨制药(厦门)有限公司的,与规格: 100mg/粒x60粒/瓶/盒, 最匹配的一项, 并返回其序号, 如果没有找到则返回0
1. 国药控股星鲨制药(厦门)有限公司, 0.1gx15粒x2板/盒
2. 国药控股星鲨制药(厦门)有限公司, 0.1gx60粒/瓶
3. 国药控股星鲨制药(厦门)有限公司, 0.1gx20粒x2板/盒
4. 国药控股星鲨制药(厦门)有限公司, 0.1gx16粒x2板/盒

<details open><summary class='thinking-summary'><span>✅ 思考完成</span></summary>

<div class='thinking-container'>

好的,我现在要解决这个问题。用户给了四个选项,都是国药控股星鲨制药(厦门)有限公司的,但规格不同。我需要找出与用户提供的规格最匹配的一项,然后返回它的序号,如果没有就返回0。

首先,用户给的规格是100mg/粒 × 60粒/瓶/盒。我需要仔细分析每个选项,看看哪个最接近。

看选项1:0.1gx15粒x2板/盒。这里的0.1g等于100mg,粒数是15,而用户的是60粒。所以粒数不符,但包装是2板/盒,可能指的是两盒装,但数量不够,所以这个选项不匹配。

选项2:0.1gx60粒/瓶。0.1g是100mg,粒数正好是60,但包装是每瓶,没有提到每盒,所以可能缺少了部分信息,但包装方式可能与用户的不同,所以这个选项可能部分匹配。

选项3:0.1gx20粒x2板/盒。0.1g是100mg,粒数20,包装是2板/盒。粒数不够,所以这个选项也不匹配。

选项4:0.1gx16粒x2板/盒。同样,0.1g是100mg,粒数16,也不够,所以也不匹配。

现在,我需要比较这些选项中哪个最接近。用户的需求是100mg/粒,60粒/瓶/盒。选项2正好有100mg,60粒,但包装是每瓶,而用户可能需要每盒。选项1有15粒,不够,但包装是2板/盒,可能意味着两盒装,但数量太少。选项3和4都是更少的粒数,所以都不符合。

所以,最接近的是选项2,因为它有正确的粒数和正确的重量,虽然包装方式不同,但其他选项都不符合。因此,我应该选择选项2,序号是2。

</div>
</details>

根据以上分析,最匹配的是选项2,返回其序号。

答案:2

微调

可以看到,AI实际上已经有足够的智力回答对码问题,只需要稍加调整就可以用了

  1. 提供多样的训练数据,使AI能使用更多的写法,比如:0.58gx12sx2板/盒
  2. 去除think部分
  3. 约束输出,仅输出序号

节省资源考虑,我选择1.5B的模型做LoRA微调,1.5B对于这个简单任务,已经够用了

步骤

初始环境准备

  1. 安装好Python环境,我的版本是 3.12.3,可通过命令 python --version查看版本
  2. 安装显卡驱动,我的显卡是RTX 4090,可通过命令 nvidia-smi 查看取得是否安装好
  3. 下载模型 DeepSeek-R1-Distill-Qwen-1.5B

安装LLaMA-Factory

  1. 下载LLaMA-Factory

  2. 创建python虚拟环境并安装依赖```
    cd LLaMA-Factory/
    python/python3 -m venv .venv
    source .venv/bin/activate

    windows下用

    .venv\Scripts\activate

    安装依赖,建议用国内镜像

    pip install -e “.[torch,metrics]”

    启动web ui,默认端口:7860

    llamafactory-cli webui

    
    
    

准备训练数据并训练

训练数据格式
[
  {
    "system": "你是一位资深药师和药品数据管理员,精通药品和医疗器械的标准规格格式以及人们的各种手写写法。",
    "instruction": "从输入中找出属于陕西利君现代中药有限公司的,与规格: 2x15片/板/盒, 最匹配的一项, 并返回其序号, 如果没有找到则返回0",
    "input": "1. 陕西利君现代中药有限公司, 12片x3板/盒\n2. 陕西利君现代中药有限公司, 15片x2板/盒\n3. 陕西利君现代中药有限公司, 12片x2板/盒\n",
    "output": "2"
  },
  {
    "system": "你是一位资深药师和药品数据管理员,精通药品和医疗器械的标准规格格式以及人们的各种手写写法。",
    "instruction": "从输入中找出属于辉瑞制药有限公司的,与规格: 100mgx1片/板/盒, 最匹配的一项, 并返回其序号, 如果没有找到则返回0",
    "input": "1. 晖致制药(大连)有限公司, 0.1gx1片/盒\n2. 晖致制药(大连)有限公司, 0.1gx5片/盒\n3. 晖致制药(大连)有限公司, 0.1gx10片/盒\n",
    "output": "1"
  }
]

我准备了近3万条

注册数据集

在这里插入图片描述
编辑 /LLaMA-Factory/data/dataset_info.json 文件添加你的数据集

配置基础模型和数据集

在这里插入图片描述

其他参数保持默认

训练

在这里插入图片描述

点击开始,等待训练完成

在这里插入图片描述

加载基础模型和Adapter查看

加载

在这里插入图片描述

测试

在这里插入图片描述

在这里插入图片描述

合并导出模型并评估

导出

在这里插入图片描述

评估

LLaMA-Factory的 Evaluate&Predict 功能并不适用于当前任务,我们需要准备评估数据并计算模型回答的准确率

评估数据集

格式和训练数据集一致,我准备了5000条

评估代码

predict.py

import json
import time
from typing import (Any, Dict, List, Literal)
import torch
from transformers import (
    AutoModelForCausalLM, 
    AutoTokenizer, 
    AutoConfig, 
    LogitsProcessorList, 
    InfNanRemoveLogitsProcessor, 
    GenerationConfig)

class Response:
    def __init__(self, response_text: str, response_length: int, prompt_length: int, finish_reason: Literal["stop", "length"]):
        self.response_text = response_text
        self.response_length = response_length
        self.prompt_length = prompt_length
        self.finish_reason = finish_reason

# 合并导出的微调模型路径
BASE_MODEL_PATH = "/home/xuyd/yb_medicine_match"
# 评估数据的路径
EVAL_DATA_PATH = "/home/xuyd/LLaMA-Factory/data/yb_medicine/standard_check.json"
# 错误输出路径
ERROR_OUTPUT_PATH = "/home/xuyd/LLaMA-Factory/errors.json"

# 加载模型配置
config = AutoConfig.from_pretrained(BASE_MODEL_PATH, trust_remote_code=True, cache_dir=None, revision='main', token=None)

# 加载模型
model = AutoModelForCausalLM.from_pretrained(
    pretrained_model_name_or_path=BASE_MODEL_PATH,
    trust_remote_code=True,
    device_map="auto",
    torch_dtype=torch.bfloat16,
    config=config,
)
model.requires_grad_(False)
model.eval()

# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(
    pretrained_model_name_or_path=BASE_MODEL_PATH, 
    use_fast_tokenizer=True, 
    skip_special_tokens=False, 
    padding_side="right")

# 设置生成参数
generating_args : Dict[str,Any] = {
    'do_sample' : True,
    'temperature' : 0.5,
    'top_p' : 0.7,
    'top_k' : 50,
    'num_return_sequences' : 1,
    'repetition_penalty' : 1.0,
    'length_penalty' : 1.0,
    'eos_token_id' : tokenizer.eos_token_id,
    'pad_token_id' : tokenizer.pad_token_id,
    'max_length' : 1024,
    'max_new_tokens' : 1024
}

def build_token_ids(item) -> List[int]:
    """构建token_ids"""
    token_ids = []
    token_ids += [tokenizer.bos_token_id]
    token_ids += tokenizer.encode(item["system"], add_special_tokens=False)
    token_ids += tokenizer.encode(f"<|User|>{item['instruction']}\n\n{item['input']}\n\n<|Assistant|>", add_special_tokens=False)
    return token_ids

def get_logits_processor() -> LogitsProcessorList:
    """创建logits处理器,防止无效输出"""
    logits_processor = LogitsProcessorList()
    logits_processor.append(InfNanRemoveLogitsProcessor())
    return logits_processor

def extract_answer(text):
    """从文本中提取答案"""
    for char in text:
        if char.isdigit():
            return char
    return "0"  # 未找到数字时返回0

def clean_output(text: str) -> str:
    """清理模型输出,只保留最后一行"""
    lines = text.strip().splitlines()  # 按行分割并去掉首尾空格
    last_line = lines[-1] if lines else ""  # 取最后一行
    return last_line.strip()

def process_item(item):
    """处理单个评估项"""
    # 构建prompt
    prompt_ids = build_token_ids(item)

    prompt_length = len(prompt_ids)
    inputs = torch.tensor([prompt_ids], device=model.device)
    attention_mask = torch.ones_like(inputs, dtype=torch.bool)

    gen_kwargs = dict(
            inputs=inputs,
            attention_mask=attention_mask,
            generation_config=GenerationConfig(**generating_args),
            logits_processor=get_logits_processor(),
        )
        
    generate_output = model.generate(**gen_kwargs)

    response_ids = generate_output[:, prompt_length:]
    response = tokenizer.batch_decode(
        response_ids, clean_up_tokenization_spaces=True, skip_special_tokens=True
    )

    results = []
    for i in range(len(response)):
        eos_index = (response_ids[i] == tokenizer.eos_token_id).nonzero()
        response_length = (eos_index[0].item() + 1) if len(eos_index) else len(response_ids[i])
        results.append(
            Response(
                response_text=clean_output(response[i]),
                response_length=response_length,
                prompt_length=prompt_length,
                finish_reason="stop" if len(eos_index) else "length",
            )
        )

    # 解析答案
    first = results[0]
    print(f"原始输出:{first.response_text}")
    model_answer = extract_answer(first.response_text) 
    
    # 构建结果
    result = item.copy()
    result["model_output"] = model_answer
    result["is_correct"] = (model_answer == str(item["output"]))
    return result

def main():
    # 加载评估数据
    with open(EVAL_DATA_PATH, "r", encoding="utf-8") as f:
        eval_data = json.load(f)
    
    errors = []
    
    # 处理数据
    start_time = time.time()
    for item in eval_data:
        processed = process_item(item)
        if not processed["is_correct"]:
            print(f"错误:{processed}")
            errors.append(processed)
    end_time = time.time()
    print(f"评估完成,耗时:{end_time - start_time:.2f}s")
    
    # 保存错误记录
    with open(ERROR_OUTPUT_PATH, "w", encoding="utf-8") as f:
        json.dump(errors, f, ensure_ascii=False, indent=2)
    
    print(f"评估完成,错误数量:{len(errors)}/{len(eval_data)}")
    print(f"错误记录已保存至:{ERROR_OUTPUT_PATH}")

if __name__ == "__main__":
    main()    

执行评估

python predict.py

结果

速度很快,大约23ms执行一次,但正确率并不理想,准确率只有95%,我希望达到99%,我觉得还需要以下调整

  1. 默认的LoRA秩为8,太小了,可以调大一点
  2. 加强提示词,查看评估错误的条目,发现有的规格中,用字母d代替了中文袋,但是模型并未分辨出来

在这里插入图片描述

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值