大模型高效微调(Finetune)实战教程——以DeepSeek-R1-Distill-Qwen-7B为例¶


No description has been provided for this image
🤖 Pei Xinlei
📱 18560809513
📧 peixl13@chinaunicom.cn

No description has been provided for this image
No description has been provided for this image No description has been provided for this image

Unsloth是一个开源工具,专门用来加速大语言模型(LLMs)的微调过程。它的主要功能和优势包括:

  • 🔭 高效微调:Unsloth 的微调速度比传统方法快 2-5 倍,内存占用减少 50%-80%。这意味着你可以用更少的资源完成微调任务。
  • ⚡ 低显存需求:即使是消费级 GPU(如 RTX 3090),也能轻松运行 Unsloth。例如,仅需 7GB 显存就可以训练 1.5B 参数的模型。
  • 🎯 支持多种模型和量化:Unsloth 支持 Llama、Mistral、Phi、Gemma 等主流模型,并且通过动态 4-bit 量化技术,显著降低显存占用,同时几乎不损失模型精度。
  • 🎁 开源与免费:Unsloth 提供免费的 Colab Notebook,用户只需添加数据集并运行代码即可完成微调。

微调的基本流程如下:

No description has been provided for this image

第一步:安装依赖&环境验证¶

In [2]:
%%capture
# 卸载当前已安装的 unsloth 包(如果已安装),然后从 GitHub 的源代码安装最新版本。
# 这样可以确保我们使用的是最新功能和修复。
!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git
# 安装 bitsandbytes 和 unsloth_zoo 包。
# bitsandbytes 是一个用于量化和优化模型的库,可以帮助减少模型占用的内存。unsloth_zoo 可能包含了一些预训练模型或其他工具,方便我们使用。
!pip install bitsandbytes unsloth_zoo xformers
In [3]:
import sys
import torch
import platform
from importlib.metadata import version

# 输出 Python 版本
print("Python 版本:", sys.version)

# 输出操作系统信息
print("操作系统:", platform.platform())

# 检查 CUDA 是否可用及相关信息
print("CUDA 是否可用:", torch.cuda.is_available())
if torch.cuda.is_available():
    print("CUDA 版本 (PyTorch 编译时使用的):", torch.version.cuda)
    print("当前 CUDA 设备数量:", torch.cuda.device_count())
    print("当前 CUDA 设备:", torch.cuda.current_device())
    print("当前 CUDA 设备名称:", torch.cuda.get_device_name(torch.cuda.current_device()))

# 输出 PyTorch 版本
print("PyTorch 版本:", torch.__version__)

# 输出其他库的版本(如果已安装)
libraries = ["triton", "unsloth", "xformers"]
for lib in libraries:
    try:
        print(f"{lib} 版本:", version(lib))
    except ImportError:
        print(f"{lib} 未安装")
Python 版本: 3.11.11 (main, Dec  4 2024, 08:55:07) [GCC 11.4.0]
操作系统: Linux-6.1.85+-x86_64-with-glibc2.35
CUDA 是否可用: True
CUDA 版本 (PyTorch 编译时使用的): 12.4
当前 CUDA 设备数量: 1
当前 CUDA 设备: 0
当前 CUDA 设备名称: Tesla T4
PyTorch 版本: 2.6.0+cu124
triton 版本: 3.2.0
unsloth 版本: 2025.3.19
xformers 版本: 0.0.29.post3

第二步:加载预训练模型¶

In [4]:
from unsloth import FastLanguageModel  # 导入FastLanguageModel类,用来加载和使用模型
import torch  # 导入torch工具,用于处理模型的数学运算

max_seq_length = 2048  # 设置模型处理文本的最大长度,相当于给模型设置一个“最大容量”
dtype = None  # 设置数据类型,让模型自动选择最适合的精度
load_in_4bit = True  # 使用4位量化来节省内存,就像把大箱子压缩成小箱子

# 加载预训练模型,并获取tokenizer工具
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/DeepSeek-R1-Distill-Qwen-7B",  # 指定要加载的模型名称
    max_seq_length=max_seq_length,  # 使用前面设置的最大长度
    dtype=dtype,  # 使用前面设置的数据类型
    load_in_4bit=load_in_4bit,  # 使用4位量化
    # token="hf_...",  # 如果需要访问授权模型,可以在这里填入密钥
)
🦥 Unsloth: Will patch your computer to enable 2x faster free finetuning.
🦥 Unsloth Zoo will now patch everything to make training faster!
==((====))==  Unsloth 2025.3.19: Fast Qwen2 patching. Transformers: 4.50.0.
   \\   /|    Tesla T4. Num GPUs = 1. Max memory: 14.741 GB. Platform: Linux.
O^O/ \_/ \    Torch: 2.6.0+cu124. CUDA: 7.5. CUDA Toolkit: 12.4. Triton: 3.2.0
\        /    Bfloat16 = FALSE. FA [Xformers = 0.0.29.post3. FA2 = False]
 "-____-"     Free license: http://github.com/unslothai/unsloth
Unsloth: Fast downloading is enabled - ignore downloading bars which are red colored!
model.safetensors.index.json:   0%|          | 0.00/100k [00:00<?, ?B/s]
model-00001-of-00002.safetensors:   0%|          | 0.00/4.97G [00:00<?, ?B/s]
model-00002-of-00002.safetensors:   0%|          | 0.00/3.52G [00:00<?, ?B/s]
Loading checkpoint shards:   0%|          | 0/2 [00:00<?, ?it/s]
generation_config.json:   0%|          | 0.00/236 [00:00<?, ?B/s]
tokenizer_config.json:   0%|          | 0.00/6.78k [00:00<?, ?B/s]
tokenizer.json:   0%|          | 0.00/11.4M [00:00<?, ?B/s]
special_tokens_map.json:   0%|          | 0.00/472 [00:00<?, ?B/s]

第三步:微调前测试¶

In [5]:
# 定义提示风格的字符串模板,用于格式化问题
prompt_style = """
Below is an instruction that describes a task, paired with an input that provides further context.
Write a response that appropriately completes the request.
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning.
Please answer the following medical question.

### Question:
{}

### Response:
<think>{}
"""

# 定义具体的医学问题
question = "一个患有急性阑尾炎的病人已经发病5天,腹痛稍有减轻但仍然发热,在体检时发现右下腹有压痛的包块,此时应如何处理?"
In [6]:
# 将大模型设置为推理模式
FastLanguageModel.for_inference(model)

# 使用 tokenizer 对格式化后的问题进行编码,并移动到 GPU
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>
好,我现在要帮这位用户解答一个关于急性阑尾炎的医疗问题。首先,我得仔细理解用户提供的背景信息。病人已经发病5天,腹痛稍微减轻,但还有发热,现在体检时发现右下腹有压痛的包块。我需要判断接下来的处理步骤。

首先,急性阑尾炎通常是严重的感染性疾病,需要及时处理。病程5天不算太长,但发热和包块提示可能有其他问题,比如胆囊炎或者其他器官的感染。所以,我得考虑包块的性质和可能的并发症。

包块的大小和位置也很重要。如果包块较大,可能压迫到其他脏器,比如输尿管或者右侧肾,这会导致右侧肾盂肾炎,这是一种严重的并发症。如果包块较小,可能需要进一步的检查,比如超声波或者穿刺活检,以确定性质。

接下来,我应该考虑进一步的诊断。如果没有明显其他症状,比如发热持续、剧烈疼痛,或者伴随其他器官的症状,可能包块是良性的,比如脂肪瘤或软组织瘤。但如果有这些迹象,就需要考虑恶性可能性。

诊断方面,超声检查是一个快速且可靠的手段。如果发现包块是实性、大于3cm,或者有不规则的形状,可能提示恶性。同时,检查包块的穿刺活检也是必要的,尤其是如果怀疑恶性的话。

治疗方面,如果包块是良性的,可能需要保守处理,比如超声引导下穿刺引流,或者手术切除。但如果包块是恶性的,尤其是当有严重并发症的迹象时,可能需要立即手术治疗。

此外,我还要考虑发热的原因。发热可能是感染的迹象,但也可能是其他原因,比如代谢性疾病或者寄生虫感染。但在这个情况下,结合腹痛和包块,更可能的是感染性疾病。

总结一下,处理步骤应该是:首先评估包块的性质和大小,进行超声检查,必要时穿刺活检,根据结果决定是否手术治疗。同时,关注发热的情况,如果持续不退,可能需要进一步的治疗或者考虑其他原因。

最后,我需要确保回答条理清晰,步骤明确,让医生能够快速做出决策。同时,语言要准确,避免歧义,确保信息的正确性。
</think>

在面对急性阑尾炎的患者时,处理情况需要综合考虑多种因素。首先,评估患者是否有其他严重症状,如发热持续、剧烈腹痛或伴随其他器官受压的情况。如果包块较大且压迫到输尿管或右侧肾,应考虑右侧肾盂肾炎的并发症。此时,超声检查是关键,以确定包块的性质和大小。若包块实性且大于3cm或有不规则形态,建议进行穿刺活检以排除恶性可能。根据检查结果,决定是否进行手术治疗,包括超声引导穿刺或直接手术切除。同时,发热的持续性需要进一步评估,可能涉及感染或其他原因。及时诊断和处理是确保患者康复的关键。<|end▁of▁sentence|>

第四步:加载数据集¶

In [7]:
# 定义一个用于格式化提示的多行字符串模板
train_prompt_style = """
Below is an instruction that describes a task, paired with an input that provides further context.
Write a response that appropriately completes the request.
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.

### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning.
Please answer the following medical question.

### Question:
{}

### Response:
<think>
{}
</think>
{}
"""
In [8]:
# 定义结束标记(EOS_TOKEN),用于指示文本的结束
EOS_TOKEN = tokenizer.eos_token  # 必须添加结束标记

# 导入数据集加载函数
from datasets import load_dataset

# 加载指定的数据集,选择中文语言和训练集的前500条记录
dataset = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT", 'zh', split = "train[0:500]", trust_remote_code=True)

# 打印数据集的列名,查看数据集中有哪些字段
print(dataset.column_names)
README.md:   0%|          | 0.00/1.65k [00:00<?, ?B/s]
medical_o1_sft_Chinese.json:   0%|          | 0.00/64.8M [00:00<?, ?B/s]
Generating train split:   0%|          | 0/24772 [00:00<?, ? examples/s]
['Question', 'Complex_CoT', 'Response']
In [9]:
# 定义一个函数,用于格式化数据集中的每条记录
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,  # 返回包含所有格式化文本的字典
    }

# 组装数据集
dataset = dataset.map(formatting_prompts_func, batched = True)
dataset["text"][0]
Map:   0%|          | 0/500 [00:00<?, ? examples/s]
Out[9]:
'\nBelow is an instruction that describes a task, paired with an input that provides further context.\nWrite a response that appropriately completes the request.\nBefore answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.\n\n### Instruction:\nYou are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning.\nPlease answer the following medical question.\n\n### Question:\n根据描述,一个1岁的孩子在夏季头皮出现多处小结节,长期不愈合,且现在疮大如梅,溃破流脓,口不收敛,头皮下有空洞,患处皮肤增厚。这种病症在中医中诊断为什么病?\n\n### Response:\n<think>\n这个小孩子在夏天头皮上长了些小结节,一直都没好,后来变成了脓包,流了好多脓。想想夏天那么热,可能和湿热有关。才一岁的小孩,免疫力本来就不强,夏天的湿热没准就侵袭了身体。\n\n用中医的角度来看,出现小结节、再加上长期不愈合,这些症状让我想到了头疮。小孩子最容易得这些皮肤病,主要因为湿热在体表郁结。\n\n但再看看,头皮下还有空洞,这可能不止是简单的头疮。看起来病情挺严重的,也许是脓肿没治好。这样的情况中医中有时候叫做禿疮或者湿疮,也可能是另一种情况。\n\n等一下,头皮上的空洞和皮肤增厚更像是疾病已经深入到头皮下,这是不是说明有可能是流注或瘰疬?这些名字常描述头部或颈部的严重感染,特别是有化脓不愈合,又形成通道或空洞的情况。\n\n仔细想想,我怎么感觉这些症状更贴近瘰疬的表现?尤其考虑到孩子的年纪和夏天发生的季节性因素,湿热可能是主因,但可能也有火毒或者痰湿造成的滞留。\n\n回到基本的症状描述上看,这种长期不愈合又复杂的状况,如果结合中医更偏重的病名,是不是有可能是涉及更深层次的感染?\n\n再考虑一下,这应该不是单纯的瘰疬,得仔细分析头皮增厚并出现空洞这样的严重症状。中医里头,这样的表现可能更符合‘蚀疮’或‘头疽’。这些病名通常描述头部严重感染后的溃烂和组织坏死。\n\n看看季节和孩子的体质,夏天又湿又热,外邪很容易侵入头部,对孩子这么弱的免疫系统简直就是挑战。头疽这个病名听起来真是切合,因为它描述的感染严重,溃烂到出现空洞。\n\n不过,仔细琢磨后发现,还有个病名似乎更为合适,叫做‘蝼蛄疖’,这病在中医里专指像这种严重感染并伴有深部空洞的情况。它也涵盖了化脓和皮肤增厚这些症状。\n\n哦,该不会是夏季湿热,导致湿毒入侵,孩子的体质不能御,其病情发展成这样的感染?综合分析后我觉得‘蝼蛄疖’这个病名真是相当符合。\n</think>\n从中医的角度来看,你所描述的症状符合“蝼蛄疖”的病症。这种病症通常发生在头皮,表现为多处结节,溃破流脓,形成空洞,患处皮肤增厚且长期不愈合。湿热较重的夏季更容易导致这种病症的发展,特别是在免疫力较弱的儿童身上。建议结合中医的清热解毒、祛湿消肿的治疗方法进行处理,并配合专业的医疗建议进行详细诊断和治疗。\n<|end▁of▁sentence|>'

第五步:执行微调¶

In [10]:
# 将大模型设置为训练模式
FastLanguageModel.for_training(model)

# 使用参数高效微调(PEFT)中的lora方式执行微调,设定一些超参数
model = FastLanguageModel.get_peft_model(
    model,  # 传入已经加载好的预训练模型
    r = 16,  # 设置 LoRA 的秩,决定添加的可训练参数数量
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",  # 指定模型中需要微调的关键模块
                      "gate_proj", "up_proj", "down_proj"],
    lora_alpha = 16,  # 设置 LoRA 的超参数,影响可训练参数的训练方式
    lora_dropout = 0,  # 设置防止过拟合的参数,这里设置为 0 表示不丢弃任何参数
    bias = "none",    # 设置是否添加偏置项,这里设置为 "none" 表示不添加
    use_gradient_checkpointing = "unsloth",  # 使用优化技术节省显存并支持更大的批量大小
    random_state = 3407,  # 设置随机种子,确保每次运行代码时模型的初始化方式相同
    use_rslora = False,  # 设置是否使用 Rank Stabilized LoRA 技术,这里设置为 False 表示不使用
    loftq_config = None,  # 设置是否使用 LoftQ 技术,这里设置为 None 表示不使用
)
Unsloth 2025.3.19 patched 28 layers with 28 QKV layers, 28 O layers and 28 MLP layers.
In [11]:
from trl import SFTTrainer  # 导入 SFTTrainer,用于监督式微调
from transformers import TrainingArguments  # 导入 TrainingArguments,用于设置训练参数
from unsloth import is_bfloat16_supported  # 导入函数,检查是否支持 bfloat16 数据格式

trainer = SFTTrainer(  # 创建一个 SFTTrainer 实例
    model=model,  # 传入要微调的模型
    tokenizer=tokenizer,  # 传入 tokenizer,用于处理文本数据
    train_dataset=dataset,  # 传入训练数据集
    dataset_text_field="text",  # 指定数据集中文本字段的名称
    max_seq_length=max_seq_length,  # 设置最大序列长度
    dataset_num_proc=2,  # 设置数据处理的并行进程数
    packing=False,  # 是否启用打包功能(这里设置为 False,打包可以让训练更快,但可能影响效果)
    args=TrainingArguments(  # 定义训练参数
      per_device_train_batch_size=2,  # 每个设备(如 GPU)上的批量大小
      gradient_accumulation_steps=4,  # 梯度累积步数,用于模拟大批次训练
      warmup_steps=5,  # 预热步数,训练开始时学习率逐渐增加的步数
      max_steps=100,  # 最大训练步数
      learning_rate=2e-4,  # 学习率,模型学习新知识的速度
      fp16=not is_bfloat16_supported(),  # 是否使用 fp16 格式加速训练(如果环境不支持 bfloat16)
      bf16=is_bfloat16_supported(),  # 是否使用 bfloat16 格式加速训练(如果环境支持)
      logging_steps=1,  # 每隔多少步记录一次训练日志
      optim="adamw_8bit",  # 使用的优化器,用于调整模型参数
      weight_decay=0.01,  # 权重衰减,防止模型过拟合
      lr_scheduler_type="linear",  # 学习率调度器类型,控制学习率的变化方式
      seed=3407,  # 随机种子,确保训练结果可复现
      output_dir="outputs",  # 训练结果保存的目录
      report_to="none",  # 是否将训练结果报告到外部工具(如 WandB),这里设置为不报告
    ),
)
Unsloth: Tokenizing ["text"] (num_proc=2):   0%|          | 0/500 [00:00<?, ? examples/s]
In [12]:
# 执行训练
trainer_stats = trainer.train()
==((====))==  Unsloth - 2x faster free finetuning | Num GPUs used = 1
   \\   /|    Num examples = 500 | Num Epochs = 2 | Total steps = 100
O^O/ \_/ \    Batch size per device = 2 | Gradient accumulation steps = 4
\        /    Data Parallel GPUs = 1 | Total batch size (2 x 4 x 1) = 8
 "-____-"     Trainable parameters = 40,370,176/7,000,000,000 (0.58% trained)
Unsloth: Will smartly offload gradients to save VRAM!
[100/100 27:59, Epoch 1.59/2]
Step Training Loss
1 2.716100
2 3.082100
3 2.798900
4 2.797500
5 2.322000
6 2.494300
7 2.701300
8 2.528200
9 2.564100
10 2.415500
11 2.152400
12 2.052900
13 2.052000
14 2.247500
15 1.989500
16 1.903100
17 2.297800
18 2.281300
19 1.959400
20 2.002300
21 1.920200
22 1.930500
23 1.970600
24 1.925400
25 2.173000
26 2.104100
27 2.039400
28 1.787000
29 2.074500
30 2.267400
31 2.072800
32 2.043400
33 1.970800
34 1.885800
35 2.006400
36 2.031200
37 2.066900
38 1.707100
39 2.059300
40 1.837000
41 2.048900
42 1.715900
43 1.964100
44 1.671500
45 2.070300
46 1.928500
47 2.029300
48 1.863700
49 1.838000
50 1.888700
51 1.744300
52 1.839200
53 1.765000
54 2.054400
55 1.983000
56 1.866000
57 1.743900
58 1.966100
59 1.762600
60 2.025800
61 1.393900
62 1.939400
63 2.215300
64 1.993100
65 1.874300
66 1.752300
67 1.802900
68 2.014400
69 1.877800
70 1.565300
71 1.690100
72 1.903200
73 1.817500
74 1.896300
75 2.054800
76 1.610000
77 1.960400
78 1.893200
79 1.962600
80 1.945200
81 1.769600
82 1.619300
83 1.878200
84 1.587200
85 1.863500
86 1.885700
87 1.958700
88 1.666200
89 1.895700
90 1.950900
91 1.762100
92 1.890000
93 2.067100
94 1.837900
95 1.925300
96 1.951300
97 2.056500
98 1.741900
99 2.002600

[100/100 28:21, Epoch 1/2]
Step Training Loss
1 2.716100
2 3.082100
3 2.798900
4 2.797500
5 2.322000
6 2.494300
7 2.701300
8 2.528200
9 2.564100
10 2.415500
11 2.152400
12 2.052900
13 2.052000
14 2.247500
15 1.989500
16 1.903100
17 2.297800
18 2.281300
19 1.959400
20 2.002300
21 1.920200
22 1.930500
23 1.970600
24 1.925400
25 2.173000
26 2.104100
27 2.039400
28 1.787000
29 2.074500
30 2.267400
31 2.072800
32 2.043400
33 1.970800
34 1.885800
35 2.006400
36 2.031200
37 2.066900
38 1.707100
39 2.059300
40 1.837000
41 2.048900
42 1.715900
43 1.964100
44 1.671500
45 2.070300
46 1.928500
47 2.029300
48 1.863700
49 1.838000
50 1.888700
51 1.744300
52 1.839200
53 1.765000
54 2.054400
55 1.983000
56 1.866000
57 1.743900
58 1.966100
59 1.762600
60 2.025800
61 1.393900
62 1.939400
63 2.215300
64 1.993100
65 1.874300
66 1.752300
67 1.802900
68 2.014400
69 1.877800
70 1.565300
71 1.690100
72 1.903200
73 1.817500
74 1.896300
75 2.054800
76 1.610000
77 1.960400
78 1.893200
79 1.962600
80 1.945200
81 1.769600
82 1.619300
83 1.878200
84 1.587200
85 1.863500
86 1.885700
87 1.958700
88 1.666200
89 1.895700
90 1.950900
91 1.762100
92 1.890000
93 2.067100
94 1.837900
95 1.925300
96 1.951300
97 2.056500
98 1.741900
99 2.002600
100 1.835600

第六步:微调后测试¶

In [13]:
# 打印前面的问题
print(question)
一个患有急性阑尾炎的病人已经发病5天,腹痛稍有减轻但仍然发热,在体检时发现右下腹有压痛的包块,此时应如何处理?
In [14]:
#测试同一个问题的答案
# 将模型切换到推理模式,准备回答问题
FastLanguageModel.for_inference(model)

# 将问题转换成模型能理解的格式,并发送到 GPU 上
inputs = tokenizer([prompt_style.format(question, "")], return_tensors="pt").to("cuda")

# 让模型根据问题生成回答,最多生成 10000 个新词
outputs = model.generate(
    input_ids=inputs.input_ids,  # 输入的数字序列
    attention_mask=inputs.attention_mask,  # 注意力遮罩,帮助模型理解哪些部分重要
    max_new_tokens=10000,  # 最多生成 4000 个新词
    use_cache=True,  # 使用缓存加速生成
)

# 将生成的回答从数字转换回文字
response = tokenizer.batch_decode(outputs)

# 打印回答
print(response[0].split("### Response:")[1])
<think>
这个病人已经有急性阑尾炎5天了,虽然腹痛稍微减轻了,但还是有发热的情况。现在体检的时候发现右下腹有个包块,这可真让人有点紧张。

首先,我得想想这个包块的性质。包块是硬的,而且可能伴随疼痛,这让我想到可能是结核。结核在阑尾炎中是很常见的,而且它常常会带来很多并发症。

可是,也别忘了,阑尾炎还有其他可能性,比如急性坏死性阑尾炎。这个情况,虽然也有可能,但一般来说,坏死性阑尾炎发生得很快,不像现在这样已经有几天了。

所以,这个包块可能更倾向于结核。结核在急性阑尾炎中确实是个大问题,而且在包块上常常有这些表现。这个包块还伴随疼痛,这让我更倾向于结核了。

不过,为了安全起见,还是得再想想有没有其他可能性。比如,急性坏死性阑尾炎,虽然可能性不大,但也不能完全排除。这个情况通常会伴随严重的腹痛和发热,而且会有包块,但可能更倾向于坏死性。

不过,通常情况下,如果包块只是硬的,而且没有特别剧烈的疼痛,可能还是更倾向于结核。所以,为了稳妥,我觉得还是先做结核的检查吧。

如果检查结果是结核,那就得马上处理,毕竟结核可真是个大麻烦。但如果还是坏死性,那就需要处理坏死,虽然可能性不大,但也不能掉以轻心。

不管怎样,结核检查还是必要的,这样就能明确情况,做出正确的处理决定。所以,先做个结核的检查,确认一下是结核还是坏死性,再根据结果来处理吧。
</think>
在急性阑尾炎的病人中,右下腹的包块可能是结核或坏死性阑尾炎的表现。根据目前的症状,虽然腹痛稍有减轻,但仍然伴随发热,且包块硬且可能伴随疼痛,这可能提示结核。因此,在这种情况下,建议进行结核检查,以明确诊断。结核处理是关键,因为它可能带来严重的并发症,而坏死性阑尾炎的可能性相对较低。因此,建议立即进行结核的检查,以做出正确的处理决定。
<|end▁of▁sentence|>

第七步:本地保存模型¶

In [ ]:
#保存Lora权重
model.save_pretrained("ckpts/lora_model")
tokenizer.save_pretrained("ckpts/lora_model")
In [ ]:
# 加载模型
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "ckpts/lora_model",
    max_seq_length = max_seq_length,
    load_in_4bit = True,
)
FastLanguageModel.for_inference(model)
inputs = tokenizer([prompt_style.format(question)], return_tensors='pt', max_length=max_seq_length).to("cuda")
outputs = model.generate(inputs['input_ids'], attention_mask=inputs['attention_mask'], max_length=max_seq_length, use_cache=True)
answer = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
print(answer)

第八步:Ollama调用¶

需先保存为GGUF格式的模型文件再调用:D