支持私有云部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


DeekSeek-R1大模型本地微调-构建医疗问答模型

发布日期:2025-03-18 05:02:07 浏览次数: 1548 来源:人工智能坊
推荐语

利用Kaggle Notebook和开源数据集,本地微调DeepSeek-R1大模型,构建高效医疗问答系统。

核心内容:
1. 注册wandb账号,获取API key,实现训练过程可视化
2. 通过hugging face国内镜像网站下载DeepSeek-R1模型和医疗问答数据集
3. 安装必要Python包,开始DeepSeek-R1模型的本地微调(finetuning)

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家
本次使用hugging face开源数据集(dataset),在Kaggle Notebook(Kaggle Notebook教程请见免费GPU云服务使用指南-Kaggle Notebook)免费云服务上完成对DeepSeek-R1-Distill-Llama-8B模型的本地微调。
1.注册wandb(https://wandb.ai/site)账号,获取wandb API key,来可视化训练过程。
wandb是一个免费的,用于记录实验数据的工具,很好地支持训练过程的可视化。打开wand官网(https://wandb.ai/site)注册账号,即可免费获取API key。
2.下载DeepSeek-R1-Distill-Llama-8B模型和开源数据集
由于国内无法访问hugging face,我们采用hugging face国内镜像网站(https://hf-mirror.com)下载模型和数据集(能科学上网的同学,也可以直接从hugging face下载模型和数据集)。开始前先打开Kaggle Notebook GPU加速(GPU加速方法请参考免费GPU云服务使用指南-Kaggle Notebook)。程序如下:
##创建模型下载目录!mkdir DeepSeek-R1-Distill-Llama-8B
##创建数据集下载目录!mkdir dataset
##把hugging face国内镜像加入环境变量!export HF_ENDPOINT=https://hf-mirror.com
pip install -U huggingface_hub
##下载“unsloth/DeepSeek-R1-Distill-Llama-8B”蒸馏模型!huggingface-cli download --resume-download unsloth/DeepSeek-R1-Distill-Llama-8B --local-dir DeepSeek-R1-Distill-Llama-8B
如下图所示,模型下载完成:
##下载开源医疗问答数据集!huggingface-cli download --repo-type dataset --resume-download FreedomIntelligence/medical-o1-reasoning-SFT --local-dir dataset
如下图所示,数据集下载完成:
2.安装pyton包,开始微调(finetuning)
##安装unsloth!pip install unsloth # install unsloth!pip install --force-reinstall --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git # Also get the latest version Unsloth!##重新安装 torchvision库(因为默认安装的版本不正确)!pip uninstall -y torch torchvision!pip install torch torchvision
##确认我们安装成功了unsloth!pip list | grep unsloth
如下图,unsloth安装成功:
##安装wandb,可视化微调过程!pip install wandb
import wandb
##使用注册时的API key登录wandb."Your API key"替换成在第一步生成的API keywandb.login(key = "Your API key")
##建立wandb工程run = wandb.init(project="fint-tune deepseek r1 with open medical data",                job_type="training",                anonymous="allow")
打开wandb网站(https://wandb.ai/site),可以看到如下图工程建立成功:
from unsloth import FastLanguageModelimport torchmax_seq_length = 2048dtype = Noneload_in_4bit = True
##指定文件目录加载model和tokenizermodel, tokenizer = FastLanguageModel.from_pretrained(model_name="/kaggle/working/DeepSeek-R1-Distill-Llama-8B",                                                    max_seq_length=max_seq_length,                                                    dtype=dtype,                                                    load_in_4bit=load_in_4bit)
如下图,模型加载成功:
##写推理模版prompt_style = """下面是描述任务的说明,并配有提供更多上下文的输入。编写适当完成请求的响应。在回答之前,请仔细思考问题并创建一个循序渐进的思维链,以确保合乎逻辑和准确的回答。
### Instruction:您是一位医学专家,在临床推理、诊断和治疗计划方面拥有先进的知识。请回答以下医疗问题。
### Question:{}
### Response:<think>{}"""
##问题描述question = "一名 61 岁的女性在咳嗽或打喷嚏等活动中长期不自主排尿,但夜间没有渗漏,接受了妇科检查和棉签测试。基于这些发现,膀胱测压最有可能揭示她的残余体积和逼尿肌收缩的什么信息?"
##模型推理FastLanguageModel.for_inference(model)
inputs = tokenizer([prompt_style.format(question, "")], return_tensors="pt").to("cuda")
outputs = model.generate(    input_ids=inputs.input_ids,    attention_mask=inputs.attention_mask,    max_new_tokens=1200,    use_cache=True,)response = tokenizer.batch_decode(outputs)print(response[0].split("### Response:")[1])
模型没有微调前的回答:
<think> 好的,我现在需要回答一个关于膀胱测压的问题。让我先仔细分析一下问题的内容。 首先,问题描述了一位61岁的女性,她在咳嗽或打喷嚏时长期不自主排尿,但夜间没有渗漏。因此,她的情况可能与膀胱的残余体积和逼尿肌的状态有关。患者接受了妇科检查和棉签测试,这可能包括了膀胱的超声检查和可能的尿道镜检查。 膀胱测压通常用于评估膀胱的残余体积(DBV)和膀胱收缩力(CB)。DBV是膀胱在膨胀状态下的体积,而CB则反映了膀胱壁肌肉的收缩能力。这些因素共同决定了患者是否能够自主排尿。 在咳嗽或打喷嚏时,膀胱的压力可能增加,导致尿液无法自主排出,这可能与膀胱的残余体积较大有关,因为膀胱在膨胀时体积增加,更容易被压缩。同时,膀胱收缩力不足也可能导致患者无法及时排尿,特别是在活动时。 夜间没有渗漏,可能说明患者的膀胱在夜间能够自主排尿,这可能与膀胱的收缩力较好有关。因此,膀胱测压可以帮助医生评估这两个因素,从而制定相应的治疗方案。 可能的治疗方向包括药物治疗,如抗胆碱药物,或者非侵入性方法如膀胱刺激电疗。如果残余体积较大,可能需要内镜下减压手术或膀胱膨胀术。 总结一下,膀胱测压可以揭示残余体积和膀胱收缩力的信息,这对于治疗不自主排尿的女性非常重要。 </think> 膀胱测压能够揭示患者的膀胱残余体积(DBV)和膀胱收缩力(CB)。膀胱残余体积是膀胱在膨胀状态下的体积,反映了膀胱容积的大小,而膀胱收缩力则反映了膀胱壁肌肉的收缩能力。这些因素直接影响排尿的自主性。 在咳嗽或打喷嚏时,膀胱的压力可能增加,导致尿液无法自主排出,这可能与膀胱残余体积较大有关。同时,膀胱收缩力不足也可能导致患者无法及时排尿,特别是在活动时。夜间没有渗漏可能说明患者的膀胱在夜间能够自主排尿,这可能与膀胱的收缩力较好有关。 因此,膀胱测压能够帮助医生评估膀胱残余体积和收缩力,从而制定相应的治疗方案。治疗方向可能包括药物治疗、非侵入性方法或手术干预。<|end▁of▁sentence|>

##写训练提示词模版train_prompt_style = """下面是描述任务的说明,并配有提供更多上下文的输入。编写适当完成请求的响应。在回答之前,请仔细思考问题并创建一个循序渐进的思维链,以确保合乎逻辑和准确的回答。
### Instruction:您是一位医学专家,在临床推理、诊断和治疗计划方面拥有先进的知识。请回答以下医疗问题。
### Question:{}
### Response:<think>{}</think>{}"""""

EOS_TOKEN = tokenizer.eos_token  # Must add EOS_TOKEN
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_prompt_style.format(input, cot, output) + EOS_TOKEN        texts.append(text)    return {        "text": texts,    }
from datasets import load_dataset
##加载训练数据集dataset = load_dataset("/kaggle/working/dataset", "zh",split = "train[0:500]")##数据集格式化dataset = dataset.map(formatting_prompts_func, batched = True)##输出第一个问答dataset["text"][0]
如下图,训练数据集加载成功:
##加载模训练FastLanguageModel.for_training(model)
##获得lora微调容器model = FastLanguageModel.get_peft_model(    model,    r=16,    target_modules=[        "q_proj",        "k_proj",        "v_proj",        "o_proj",        "gate_proj",        "up_proj",        "down_proj",    ],    lora_alpha=16,    lora_dropout=0,    bias="none",    use_gradient_checkpointing="unsloth",  # True or "unsloth" for very long context    random_state=3407,    use_rslora=False,    loftq_config=None,)
from trl import SFTTrainerfrom transformers import TrainingArgumentsfrom unsloth import is_bfloat16_supported
##创建训练器,设置训练超参赛trainer = SFTTrainer(    model=model,    tokenizer=tokenizer,    train_dataset=dataset,    dataset_text_field="text",    max_seq_length=max_seq_length,    dataset_num_proc=2,    args=TrainingArguments(        per_device_train_batch_size=2,        gradient_accumulation_steps=4,        # Use num_train_epochs = 1, warmup_ratio for full training runs!        warmup_steps=5,        max_steps=60,        learning_rate=2e-4,        fp16=not is_bfloat16_supported(),        bf16=is_bfloat16_supported(),        logging_steps=10,        optim="adamw_8bit",        weight_decay=0.01,        lr_scheduler_type="linear",        seed=3407,        output_dir="outputs",    ),)
如下图,模型训练器创建成功:
##开始训练模型trainer_stats = trainer.train()
由于时间有限,模型训练了60步。如下图使用开源医疗问答数据,训练完成:
##结束可视化训练过程wandb.finish()
如下图,在wabdb网站上的可视化训练过程:
##测试微调效果question = "一名 61 岁的女性在咳嗽或打喷嚏等活动中长期不自主排尿,但夜间没有渗漏,接受了妇科检查和棉签测试。基于这些发现,膀胱测压最有可能揭示她的残余体积和逼尿肌收缩的什么信息?"

FastLanguageModel.for_inference(model)inputs = tokenizer([prompt_style.format(question, "")], return_tensors="pt").to("cuda")
outputs = model.generate(    input_ids=inputs.input_ids,    attention_mask=inputs.attention_mask,    max_new_tokens=1200,    use_cache=True,)response = tokenizer.batch_decode(outputs)print(response[0].split("### Response:")[1])
<think> 这个女性61岁,她咳嗽或者打喷嚏的时候不自主排尿,但夜间没有渗漏。看起来她有控制排尿的能力,不过在特定活动时就不能控制了。嗯,妇科检查和棉签测试的结果都很关键。我们先想想这些检查结果能告诉我们什么。 首先,妇科检查可能会有很多信息。嗯,可能是膀胱的容量或者是膀胱的结构有问题。然后,棉签测试啊,这个主要是用来测量膀胱的容量和收缩力的。通常,女性的膀胱容量可能会有些不同,所以测量的时候也要考虑个体差异。 再想想,膀胱测压通常有两种情况:一种是测量膀胱的容量,另一种是测量膀胱的收缩力。测量膀胱容量主要是为了确定膀胱的最大容量,这个信息对判断膀胱容量是否超出正常范围很重要。 不过,咳嗽或者打喷嚏的时候不自主排尿,这可能涉及膀胱的容量和收缩力。测量膀胱的容量能帮助我们了解在某种刺激下膀胱能容纳多少液体,而测量收缩力则能告诉我们膀胱在压力下能缩小多少。 嗯,测量膀胱的容量和收缩力,结合她的症状来看,测量膀胱的容量更能直接反映她在特定活动时的排尿控制能力。因为咳嗽或者打喷嚏的时候,她的膀胱容量可能不足以在不自主排尿的情况下维持。 哦,等一下,测量膀胱的容量是不是更能直接反映她在特定活动时的排尿控制能力呢?这听起来很合理。因为测量膀胱的容量可以直接告诉我们她在这种活动下膀胱能容纳多少液体。 嗯,总结一下,膀胱测压最有可能揭示她的残余体积和逼尿肌收缩的信息。嗯,测量膀胱容量更能直接反映她在特定活动时的排尿控制能力,毕竟她在咳嗽或者打喷嚏时会不自主排尿。 哦,没错,这就是我们需要的信息。所以,最终的结论应该是测量膀胱的容量是最有可能揭示她的残余体积和逼尿肌收缩的信息。 </think> 基于这位61岁女性的症状和检查结果,膀胱测压最有可能揭示的信息是她的膀胱容量。测量膀胱容量可以帮助判断在特定活动(如咳嗽或打喷嚏)时,膀胱能容纳多少液体,从而更直接地反映她在这种活动下排尿控制的能力。因此,测量膀胱的容量是最有可能揭示她残余体积和逼尿肌收缩的信息。<|end▁of▁sentence|>

综上:微调后的模型回答有改善。如果加大训练步数,结果会更理想。
3.保存微调(finetuning)后的模型
##保存模型new_model_local = "DeepSeek-R1-Medical-Finetuned"model.save_pretrained(new_model_local)tokenizer.save_pretrained(new_model_local)
model.save_pretrained_merged("merged_models", tokenizer, save_method="merged_16bit")
希望本文起到抛砖引玉的作用,激励同学们的AI学习热情!


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询