如何丰富模型的输入用以提升在文本模式交互形态下的性能

116 阅读18分钟

本文没有任何对时间的预期。本文要做的只有相信模型,并把当前数据集在这个任务上的最好指标找到。

本文从以下几个目标出发,预期达到的目的是对比通过字符倒排索引匹配模式构建的数据是否具有生成式语言大模型的生成提升效果。

先摆出我们今天的数据集

1:医疗问答数据集。

【金山文档】 医疗问答数据集

kdocs.cn/l/cekS6UNg8…

2:药物说明书数据集。

【金山文档】 药物说明书数据集

一阶段数据

{
        "content": "科室:妇产科,疾病:女性不孕,问题:我卵巢不排卵,结婚多年还是不孕,有哪些技术可以治疗女性不孕?",
        "summary": "卵巢不排卵是女性不孕的一个重要因素,还有部分女性卵泡发育异常或排卵异常而造成不孕,而高效的可控促排卵技术便是针对该类病症,能同时促进女性卵泡发育及排卵,进而帮助精子与卵子成功结合,达到助孕目的。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:两年了一直没有怀上孩子,去检查发现是输卵管阻塞性不孕症,这该如何治疗?",
        "summary": "输卵管通液术:从月经干净3天后可以进行。将庆大霉素16万单位,2%普鲁卡因2毫升,地塞米松5毫克,α-糜蛋白酶5毫克溶于20毫升生理盐水中,经输卵管通液导管注入宫腔。隔日 1次,至排卵期前停止治疗。可连续治疗2~3个月经周期。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:和老公备孕一年多,一直没怀孕,而且这段时间,我的体温是忽高忽低的,有时候还比较热,是不是排卵发生了障碍?",
        "summary": "排卵是否有障碍,可以每天早晨起床测试体温。每天早晨醒来后口表测量基础体温(BBT),并按周期标记出变化曲线。基础体温曲线应呈双相形式,高温相应维持10天以上。意义在于:(1)可以回顾性分析本周期是否发生排卵;(2)分析是否可能有黄体期过短的征象。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:女性的子宫是孕育孩子的地方,每月排卵很重要,那哪些原因会使女性不排卵导致不孕?",
        "summary": "1)卵巢病变如先天性卵巢发育不全,PCOS,卵巢功能早衰,功能性卵巢肿瘤,卵巢子宫异位囊肿;(2)HPO轴功能紊乱,引起无排卵性月经,闭经等;(3)全身性疾病如重度营养不良,甲状腺功能亢进影响卵巢功能导致不排卵"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:我听说孕激素可以治疗子宫内膜癌,刚好我就有子宫内膜癌,不知道孕激素的治疗效果好吗?",
        "summary": "孕激素治疗子宫内膜癌的效果非常不错,而孕激素与细胞毒药物联合应用的反应率,多数为50%,与单用细胞毒药物相似,可控制癌细胞生长,孕激素与放疗有协同作用。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:如果我想要在之后生育的话口服避孕药会不会对身体有什么危害,这里面的雌孕激素起什么作用呢?",
        "summary": "雌孕激素通过其受体发挥作用,有研究发现超声检查提示不利于着床者的内膜其雌激素受体水平下降;使用克罗米芬(选择性雌激素受体调节因子)促排卵患者较使用其它药物促排卵者其子宫内膜变薄,可能与雌激素受体水平下降有关。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:半年前得过一次子宫内膜增生,但现在又复发了,阴道一直出血,可不可以用孕激素治疗?",
        "summary": "孕激素对子宫内膜增生,能起到防范的作用,由于孕激素可以抵抗雌激素引起的有丝分裂效应,并诱导二次分化。因此,孕激素是能够使无不典型子宫内膜增生状态获得有效缓解的药物治疗方法,包括连续口服孕激素或宫腔内局部应用孕激素。"
    },
    {
        "content": "科室:妇产科,疾病:女性不孕,问题:结婚4年,一直没有怀上宝宝,去医院检查,医生说是无排卵性不孕,无排卵性不孕的原因是什么?",
        "summary": "因卵巢不排卵而造成的不孕症,称为无排卵性不孕症。排卵障碍是构成不孕的主要原因之一,卵巢有规律的排卵是生育的必要条件,无排卵的原因多由于下丘脑—垂体—卵巢轴中任何一环存在病理障碍所致,但也能受身体其他内分泌腺疾病因素所影响"
    }

第一步验证模型在医疗问答数据集上的效果。

在第一步中的验证过程中发现了个很吃惊的问题,我的数据集生成的结果如果没有模型生成的结果好应该怎么办?

***** predict metrics *****
  predict_bleu-4             =     4.6048
  predict_rouge-1            =    20.8503
  predict_rouge-2            =      3.505
  predict_rouge-l            =    15.0911
  predict_runtime            = 0:27:55.31
  predict_samples            =       2000
  predict_samples_per_second =      1.194
  predict_steps_per_second   =      0.038

把一些能翻译成中文的翻译成中文

***** 预测性能 *****
  predict_bleu-4             =     4.6048
  predict_rouge-1            =    20.8503
  predict_rouge-2            =      3.505
  predict_rouge-l            =    15.0911
  预测时间            = 0:27:55.31
  预测条数            =       2000
  predict_samples_per_second =      1.194
  predict_steps_per_second   =      0.038

这里完全不是空穴来潮。在对原生的生成效果观察后发现了一个比较窒息的问题。模型生成的内容看起来比我们数据集里面的效果要好一些。

{"labels": "如果病人出现输卵管堵塞的病情时,需要根据堵塞的具体情况,选择合适的治疗方案进行治疗。对于患者出现输卵管通而不畅的病情,可以选择输卵管通液术来进行治疗。如果对于急性炎症和感染性疾病所引起的输卵管堵塞,可以使用合适的抗生素类药物来进行治疗。如果输卵管堵塞比较严重,有输卵管不通的病情,可以考虑选择进行手术治疗,或者在宫腹腔镜下联合进行微创手术治疗。", 
"predict": "治疗输卵管堵塞的方法会因个人情况和病情严重程度而有所不同,以下是一些可能的治疗方法:\n\n1. 通液术:通过在患者体内注射药物,让输卵管通畅的一种方法。这种方法可以初步判断输卵管堵塞情况,但无法判断具体堵塞部位和程度,因此需要进一步检查。\n\n2. 造影术:在患者体内注射碘化油,通过X光检查来评估输卵管堵塞情况。这种方法可以更准确地判断输卵管堵塞部位和程度,并确定治疗方案。\n\n3. 宫腹腔镜检查:通过在患者腹部打开几个小洞,进行宫腹腔镜检查来评估输卵管堵塞情况。\n\n4. 手术治疗:如输卵管结扎、切除或重建等。\n\n治疗输卵管堵塞需要根据个人情况和病情严重程度来制定治疗方案。如果被诊断为输卵管堵塞,建议与医生讨论最佳治疗方法,并确定治疗计划。"}
{"labels": "每个人对疼痛的敏感度不同,其产生的疼痛程度也有差异,在输卵管的神经分布都存在肌层,在输卵管粘膜层很少分布,所以粘膜层对疼痛并不敏感,因此,这种手术并不会给患者带来撕心裂肺的疼痛。又由于患者的体质不同,对疼痛的表现也不一样。有些女性对推入的液体会觉得小腹酸胀。还有在扩宫的时候,女性也会觉得疼痛以及会有被撕裂的感觉。因此输卵管造影的疼痛,还是会根据患者的体质来确定。但是总体来说,输卵管造影带来的疼痛还是在女性的忍受范围之内。但具体情况医生在做手术时都会加以控制,会给患者用一些镇定剂,麻醉剂等,或者是不用宫钳来夹住宫颈等的方法,这样患者就不会感觉到疼痛。", 
"predict": "输卵管造影是一种常见的女性不孕检查方法,通过在患者体内注入碘剂并观察输卵管的结构和情况,以达到治疗输卵管堵塞的目的。在输卵管造影的过程中,可能会有一些疼痛的感觉,但这通常被描述为轻微的刺痛或不适感,程度因人而异。\n\n建议在进行输卵管造影之前,与医生讨论疼痛的感受和可能需要的止痛药。在检查过程中,可以通过使用镇痛药物来减轻疼痛,或进行局部麻醉来减轻疼痛。不过,有些人可能会对碘剂过敏或对疼痛敏感,因此在进行检查时,需要告知医生疼痛的感受和程度,以便根据情况制定相应的治疗方案。"}
{"labels": "造成卵泡发育不好的最主要原因有两点,分泌雌激素不足、孕激素和雌激素的比例失调,卵泡发育不良会影响正常的受孕生育,如果确认卵泡不发育,首先要做激素六项检查,看看具体哪项激素水平异常,然后再根据这项激素来调理,恢复卵巢的正常功能,促使卵泡发育成熟。", 
"predict": "造成卵泡发育不良的原因有很多,以下是一些可能的原因:\n\n1. 卵巢问题:一些卵巢疾病,如卵巢巧克力囊肿、卵巢早衰、卵巢肿瘤等,都可能导致卵巢无法正常排卵。\n\n2. 输卵管问题:输卵管堵塞或不畅也是造成女性不孕的原因之一。\n\n3. 生殖道问题:生殖道感染或炎症也可能导致输卵管堵塞或不畅,进而影响精子和卵子的相遇和成功受精。\n\n4. 免疫因素:一些女性可能具有免疫性不孕,因为免疫系统对生殖道进行了攻击,导致无法受精。\n\n5. 年龄因素:年龄也是影响女性生育能力的一个因素。随着年龄的增长,卵巢和输卵管的功能会逐渐衰退,导致卵子数量减少,精子活力下降,最终导致不孕。\n\n建议进一步检查和诊断,确定具体原因并获得针对原因的治疗方案。除了常见的治疗方式,如促排卵、试管等,还可以根据具体原因采用个性化的治疗方法。"}
{"labels": "不同的地区医院价格也是不一样的,也比较权威地区比较特殊,或者三甲级医院价格稍微贵一点,一般医院通常情况下价格不会超过500元。输卵管通液术,是检查输卵管是否通畅的一种方法,并且还具有一定的治疗功效。检查者通过导管向宫腔内注入液体,根据注入液体阻力大小,有无回流以及注射液体量,和患者的感觉来判断输卵管是否通畅。", 
"predict": "输卵管通液术是一种常见的女性不孕检查方法,通过向输卵管内注入液体来检查输卵管是否通畅。不同地区和医院的价格可能会有所不同,以下是一些常见地区的参考费用:\n\n- 上海:输卵管通液术的费用大约为200-300元/次。\n- 北京:输卵管通液术的费用大约为300-500元/次。\n- 深圳:输卵管通液术的费用大约为400-600元/次。\n\n请注意,实际费用可能因地区和医院的不同而有所变化。在进行此检查前,建议与当地的医疗机构联系以获取更详细的费用信息。"}
{"labels": "输卵管通而不畅,这是输卵管堵塞的当中症状最轻的一种状况,这个治疗的话一般的是采用中药灌肠加理疗的方法去治疗效果最好,这种情况下一般是1个月治疗10天,然后下次月经干净以后3-7天之内再去通水,通水术后再采用中药灌肠加理疗的方法去治疗。一般经过3个月经周期的治疗,这个通而不畅的情况绝大多数能够恢复正常的,通而不畅治疗的中药一般是医生会根据你的舌苔和脉象来开具活血化瘀较坚散结类中药来对症调理。", 
"predict": "人工授精(AII)是指将精子从阴道进入输卵管,但医生会在输卵管内将其取出,而不是将其直接运送到子宫。如果输卵管是通的,但是并不畅通,那么可能会增加感染和炎症的风险,同时也会增加自然怀孕的难度。\n\n在这种情况下,医生可能会考虑进行人工授精,或者建议进行其他治疗措施,如输卵管成形术或宫腹联合术等,以增加自然怀孕的机会。在决定如何处理您的问题时,建议咨询专业的妇产科医生,根据您的具体情况做出最佳决策。"}
{"labels": "输卵管堵塞一般伴随的症状是右下腹会出现一些胀痛感,而且会感觉到浑身乏力,腰部出现酸痛的感觉,分泌物也相对增多,输卵管阻塞主要是由于妇科炎症,比如附件炎、盆腔炎、子宫内膜炎等,进而引起输卵管出现粘性阻塞,建议在月经干净后3到7天去医院做个输卵管造影检查,先配合消炎药抗感染治疗。", 
"predict": "输卵管堵塞可能出现的症状包括:\n\n1. 腹部不适:输卵管堵塞可能导致腹部不适,包括疼痛、隐痛、坠痛等,尤其是在进行性活动或性交时。\n\n2. 阴道分泌物增多:输卵管堵塞时,可能会出现阴道分泌物增多的现象,尤其是当输卵管堵塞导致炎症时。\n\n3. 不孕:输卵管是与卵巢和子宫相邻的器官,如果输卵管堵塞,则会导致精子无法通过输卵管与卵子相遇,从而导致不孕。\n\n4. 月经不调:输卵管与卵巢相邻,如果输卵管堵塞,则可能会影响卵巢的功能,导致月经不调。\n\n5. 其他症状:除了以上提到的症状,输卵管堵塞也可能会伴随着其他症状,例如胃肠道不适、恶心、呕吐、腹泻等。\n\n如果怀疑自己患有输卵管堵塞,建议尽快就医进行诊断,并进行相关的检查和治疗。"}
{"labels": "一般情况输卵管造影手术后出现感染都会有肚子痛,然后发热,出现分泌物的情况,也可能会有异常子宫出血。输卵管造影后要求禁止性生活两周,禁止盆浴两周,服用消炎药预防感染,如果出现腹痛,发热,异常分泌物等情况要及时就诊。应该注意平时的清洁卫生可以有效的防止。", 
"predict": "输卵管造影术是一种检查女性输卵管情况的方法,但也存在感染的风险。感染的症状可以因感染病原体的不同而有所差异,但通常包括以下症状:\n\n1. 疼痛:输卵管造影术可能会导致疼痛,特别是在进行碘化油注入时。\n\n2. 炎症反应:在输卵管造影术后,炎症可能会在输卵管和子宫内形成,导致炎症反应,引起腹痛、腰痛、阴道分泌物增多等症状。\n\n3. 避孕失败:输卵管造影术后需要避孕一段时间,因为碘化油在输卵管内停留时间过长可能会导致意外怀孕。\n\n如果出现以上症状,建议及时就医,并告知医生曾经进行过输卵管造影术,以便医生评估病情和制定治疗方案。"}

label中是数据集中的答案

predict中是模型预估出来的答案

第二步验证基于医疗问答数据集ptuning后的模型性能。

先基于要测试的两千条数据做一次训练与验证。

***** train metrics *****
  epoch                    =       24.0
  train_loss               =     0.7418
  train_runtime            = 3:10:46.04
  train_samples            =       2000
  train_samples_per_second =      4.194
  train_steps_per_second   =      0.262

第1000步的验证效果

***** predict metrics *****
  predict_bleu-4             =    24.6901
  predict_rouge-1            =    38.7151
  predict_rouge-2            =    22.6595
  predict_rouge-l            =    34.4844
  predict_runtime            = 0:17:32.63
  predict_samples            =       2000
  predict_samples_per_second =        1.9
  predict_steps_per_second   =      0.238

第2000步的验证结果

***** predict metrics *****
  predict_bleu-4             =    83.5685
  predict_rouge-1            =     86.564
  predict_rouge-2            =     83.327
  predict_rouge-l            =    85.6946
  predict_runtime            = 0:17:33.31
  predict_samples            =       2000
  predict_samples_per_second =      1.899
  predict_steps_per_second   =      0.237

第3000步的验证结果

***** predict metrics *****
  predict_bleu-4             =    88.8539
  predict_rouge-1            =    90.8235
  predict_rouge-2            =    88.6727
  predict_rouge-l            =    90.2377
  predict_runtime            = 0:17:34.36
  predict_samples            =       2000
  predict_samples_per_second =      1.897
  predict_steps_per_second   =      0.237

再基于全量的10万对数据训练一次,这里面我们需要注意一个问题,数据量越大的情况,我们所需要训练的步数是越多的。

这里我们看到在10万条数据3000步训练的时候,模型根本没有拟合。

***** train metrics *****
  epoch                    =       0.48
  train_loss               =     3.2057
  train_runtime            = 4:49:47.44
  train_samples            =     100000
  train_samples_per_second =      2.761
  train_steps_per_second   =      0.173

所以我们先不做验证,我们把训练加到30000步。再去观察训练结果。

***** predict metrics *****
  predict_bleu-4             =     6.2653
  predict_rouge-1            =    24.1779
  predict_rouge-2            =      5.867
  predict_rouge-l            =    19.7997
  predict_runtime            = 0:40:19.46
  predict_samples            =       2000
  predict_samples_per_second =      0.827
  predict_steps_per_second   =      0.103

数据量越大,拟合起来越费劲。

添加图片注释,不超过 140 字(可选)

经过25个小时的训练,模型损失依旧在下降。但当前损失仍然不是最佳的损失范围。损失越小模型拟合程度越高。

6000步模型性能

***** predict metrics *****
  predict_bleu-4             =     7.9497
  predict_rouge-1            =    25.4564
  predict_rouge-2            =     6.2579
  predict_rouge-l            =    20.9441
  predict_runtime            = 0:42:49.38
  predict_samples            =       2000
  predict_samples_per_second =      0.778
  predict_steps_per_second   =      0.097

从指标上看模型有一定的提升。

9000步模型性能

***** predict metrics *****
  predict_bleu-4             =      7.886
  predict_rouge-1            =    25.7573
  predict_rouge-2            =     6.7556
  predict_rouge-l            =    20.9581
  predict_runtime            = 0:36:40.45
  predict_samples            =       2000
  predict_samples_per_second =      0.909
  predict_steps_per_second   =      0.114

从损失看,我们需要更小的学习率以及更大的warmup策略。

接下来,我们继续重新更新参数,降低学习率,用来尝试在10万条医疗指令问答数据集上拟合。

PRE_SEQ_LEN=128
LR=2e-3

CUDA_VISIBLE_DEVICES=0 python3 main.py \
    --do_train \
    --train_file AdvertiseGen/medical_prompt_question_answer_all.json \
    --prompt_column content \
    --response_column summary \
    --overwrite_cache \
    --model_name_or_path /root/autodl-tmp/ChatGLM-6B-Int4  \
    --output_dir output/all-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \
    --overwrite_output_dir \
    --max_source_length 128 \
    --max_target_length 128 \
    --per_device_train_batch_size 8 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --predict_with_generate \
    --max_steps 30000 \
    --logging_steps 100 \
    --save_steps 3000 \
    --learning_rate $LR \
    --pre_seq_len $PRE_SEQ_LEN 

这里很多同学可能有疑问为什么要用int4的chatglm。最开始做的2000条验证中,我们能看到,即便是int4在2000条数据上也能获取到很不错的表现。

训练过程截图。

这里其实我们可以换一个方式来观察,用tensorboard来观察实验过程。对学习率和对损失的观察。

学习率的变化曲线

损失的变化曲线

第三步验证基于医疗问答数据集finetune后的模型性能。

这里,我们尽可能的将我们的模型输入丰富一下。输入越丰富性能越优秀。以下是我如何将这十万条医疗对话做成一个还算可以的模型输入。

import pandas as pd
import json

medical_question_answer = pd.read_csv("./dataset/medical_question_answer.csv").to_json(orient="records")


def is_chinese(string):
    """
    检查整个字符串是否包含中文
    :param string: 需要检查的字符串
    :return: bool
    """
    for ch in string:
        if u'\u4e00' <= ch <= u'\u9fff':
            return True

    return False


# print(medical_knowledge)
# print(medical_question_answer)
knowledge_chinese = []

medical_question_answer = json.loads(medical_question_answer)[:100000]
medical_prompt_question_answer = []
for i in medical_question_answer:
    # print(i)
    try:
        department, disease, question, answer = i.values()
    except:
        print(i)
        continue

    knowledge_chinese.append({
        "content": "科室:" + department + ",疾病:" + disease + ",问题:" + question,
        "summary": answer
    })
json.dump(knowledge_chinese, open("medical_prompt_question_answer_all.json", "w", encoding="utf-8"),
          indent=4,
          ensure_ascii=False)

2023年5月31日 更新模型训练指标

对finetune第1000步保存的模型在2000条数据上进行验证

***** predict metrics *****
  predict_bleu-4             =     9.6621
  predict_rouge-1            =    27.4604
  predict_rouge-2            =     9.1965
  predict_rouge-l            =    22.1498
  predict_runtime            = 2:19:59.41
  predict_samples            =       2000
  predict_samples_per_second =      0.238
  predict_steps_per_second   =      0.238

第四步面向医疗问答数据集中涉及到的医疗实体进行知识补全。形成prompt。验证模型性能。

第一,我们通过爬虫获取到了一份药品说明书。

第二,我们通过药品名称的匹配,来丰富医疗信息的输入作为模型输入。

show time

import pandas as pd
import json

medical_question_answer = pd.read_csv("./dataset/medical_question_answer.csv").to_json(orient="records")

medical_knowledge = pd.read_excel("./dataset/medical.xlsx").to_json(orient="records")


def is_chinese(string):
    """
    检查整个字符串是否包含中文
    :param string: 需要检查的字符串
    :return: bool
    """
    for ch in string:
        if u'\u4e00' <= ch <= u'\u9fff':
            return True

    return False


# print(medical_knowledge)
# print(medical_question_answer)
knowledge_chinese = []
medical_knowledge = json.loads(medical_knowledge)[:100000]
for medical_knowledge_one in medical_knowledge:
    medical_knowledge_chinese = []
    for medical_knowledge_value in medical_knowledge_one.values():
        if isinstance(medical_knowledge_value, str):
            if is_chinese(medical_knowledge_value):
                medical_knowledge_chinese.append(medical_knowledge_value)
    knowledge_chinese.append(medical_knowledge_chinese)

medical_question_answer = json.loads(medical_question_answer)[:100000]
medical_prompt_question_answer = []
for i in medical_question_answer:
    # print(i)
    try:
        department, disease, question, answer = i.values()
    except:
        print(i)
        continue
    i['knowledge'] = []

    # 先观察疾病能构建什么样的数据
    for medical_knowledge_one in knowledge_chinese:
        # print(medical_knowledge_one)
        if disease in medical_knowledge_one:
            # print(disease)
            # print(medical_knowledge_one)
            if medical_knowledge_one not in i['knowledge']:
                i['knowledge'].append(medical_knowledge_one)
    for medical_knowledge_one in knowledge_chinese:
        for medical_knowledge_inner in medical_knowledge_one:
            if medical_knowledge_inner in question:
                # print(question)
                # print(medical_knowledge_one)
                if medical_knowledge_one not in i['knowledge']:
                    i['knowledge'].append(medical_knowledge_one)
    medical_prompt_question_answer.append(i)
json.dump(medical_prompt_question_answer, open("medical_prompt_question_answer.json", "w", encoding="utf-8"), indent=4,
          ensure_ascii=False)

4.1 基于未训练的官方开源chatglm验证基于药品说明书丰富的医疗问答指令数据集。

4.2 基于ptuning训练的基于药品说明书丰富的医疗问答指令数据集。

4.3 基于finetuning训练的基于药品说明书丰富的医疗问答指令数据集。