试验:训练一个解答下交学生疑问的 Chatbot

梗概

没有需求就没有开发的借口,这个试验可以解决下交新生 xdx 在各种里反复问问题拷打 ldx 导致的不必要的重复劳动和消息的混乱。也算是解决之前开发任务里的一条,满有意义的:

red herring: 如果再能和 文字与语音相互转换技术 结合,可以让每个下交新生都能实现一对一甜美学长、在线答疑的美好愿望。

风险提示:

  1. 交大門数据量可能不够,fine-tune 完不知道会发生什么。
  2. LLM 可能不是这个问题的最佳解决方案,一个好的搜索(语义搜索)足以实现知识的检索。(不过 chatbot 更人性化一点)

过程记录

在这里记录过程,方便 DIY。

现在 开源 LLM 很多,各种 开源工具 也都很完善,甚至 开箱即用

我用的是 :hugs: 's sft_trainer,属于 trl 工具,使用起来很简单。

数据集

我把 問答 - 交大門 类别的帖子通过 json 接口全部下载下来:https://xjtu.app/c/volatile/qa/14.json,保存到 jsonl 文件,总共 1k 行,示例:

{"input": "研究生游泳课。南方人,没学过游泳,想在研究生阶段学一下,游泳课是怎么算成绩的?研究生的游泳课会不会被笑,去上游泳课的都是会游泳然后蹭游泳馆的吗。", "output": "不会的会教。分数无所谓。"}
{"input": "转专业到物理学院,难度怎么样?有没有学长学姐转专业到物理学院,知不知道转专业考题的难度。", "output": "我个人孤陋寡闻,只听说过物理学院往其他工科学院转的。所以反方向转可能比较容易吧。能够反向转的同学相当的 courageous,想必非常热爱物理。"}
{"input": "转专业到物理学院,难度怎么样?有没有学长学姐转专业到物理学院,知不知道转专业考题的难度。", "output": "几个理科学院都没啥人来,基本愿意来就要。"}

训练

from huggingface_hub import notebook_login
notebook_login()

from datasets import load_dataset
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer, TrainingArguments 
from peft import LoraConfig
from trl import SFTTrainer

train_dataset = load_dataset('json', data_files='posts.jsonl', split='train')


dataset = load_dataset("YeungNLP/firefly-train-1.1M")

def formatting_func(example):
    text = f"### Question: {example['input']}\n ### Answer: {example['output']}"
    return [text]


base_model_name = "FlagAlpha/Llama2-Chinese-13b-Chat"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)

base_model = AutoModelForCausalLM.from_pretrained(
    base_model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    use_auth_token=True
)
base_model.config.use_cache = False

# More info: https://github.com/huggingface/transformers/pull/24906
base_model.config.pretraining_tp = 1 

tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token


output_dir = "./finetune"

training_args = TrainingArguments(
    output_dir=output_dir,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    logging_steps=50,
    max_steps=1000,
    logging_dir="./logs",
    save_strategy="steps",
    do_eval=False
)


peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
)


max_seq_length = 512
trainer = SFTTrainer(
    model=base_model,
    train_dataset=train_dataset,
    peft_config=peft_config,
    formatting_func=formatting_func,
    max_seq_length=max_seq_length,
    tokenizer=tokenizer,
    args=training_args,
)

trainer.train()

推理

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

base_model_name = "FlagAlpha/Llama2-Chinese-13b-Chat"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)
base_model = AutoModelForCausalLM.from_pretrained(
    base_model_name,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    use_auth_token=True
)

tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token


def generate_prompt(text):
    return f"""Below is an instruction that describes a task. Write a response that appropriately completes the request.

### Instruction:
{text}

### Response:"""


def eval_model(model, text):
    prompt = generate_prompt(text)
    input_ids = tokenizer.encode(prompt, return_tensors='pt').to('cuda')

    model.eval()
    with torch.no_grad():
        print(tokenizer.decode(model.generate(input_ids=input_ids, max_new_tokens=512)[0], skip_special_tokens=True))


def get_model():
    print('base mdoel:')
    yield AutoModelForCausalLM.from_pretrained(base_model_name).to('cuda')
    for checkpoint_i in range(50, 1050, 50):
        print(f'checkpoint {checkpoint_i}:')
        yield PeftModel.from_pretrained(base_model, f"finetune/checkpoint-{checkpoint_i}").to('cuda')

for model in get_model():
    for text in '''
    你能告诉我学校宿舍的情况吗?
    来到交大了,我感觉很迷茫,该怎么办?
    你能告诉我转专业的相关信息吗?
    '''.strip().splitlines():
        text = text.strip()
        eval_model(model, text)
        print('\n' * 3)

结果

prompt: ‘你能告诉我学校宿舍的情况吗?’

  • 基础模型
    当然可以!学校宿舍的情况是每年都会有变化的,但是目前来看,宿舍的住宿费用是每月的,而且有很多不同的房间可以选择。如果你想了解更多细节,可以联系学校的宿舍办公室,他们会很快地为你提供更多的信息。

  • epoch 50
    好的,我可以告诉你关于学校宿舍的一些情况。首先,宿舍的价格会因为房间大小和位置而有所不同。一般来说,位于校园中心的宿舍会比较贵。另外,在晚上 10 点前进行听课和自修课程的学生会被费用较为便宜的房间划分。在周末期间,宿舍会进行清洁和维护工程,期间房间会被封闭。希望以上信息对你有所帮助。

  • epoch 100
    好的,我可以告诉你关于学校宿舍的一些情况。首先,宿舍的价格会因为房间大小和位置而有所不同。一般来说,位于校园内的宿舍会比较贵,而位于校外的宿舍则会比较便宜。另外,宿舍的卫生和清洁状况也会因为房东的负担而有所不同。总的来说,如果你希望在学校宿舍,我会尽力帮助你了解一些关键的信息。,您有什么其他问题吗?,是否有课外活动你希望了解?,是否有关于学费和授课教师的疑惑?,希望从以下方面了解宿舍:价格、位置、卫生和清洁状况。,希望从以下方面了解宿舍:便环境、领导是否考课、食物质量。,希望从以下方面了解宿舍:安全性、领导是否听环境音乐,希望从以下方面了解宿舍:价格、位置、卫生和清洁状况。,希望从以下方面了解宿舍:便环境、领导是否考课、食物质量。,希望从以下方面了解宿舍:安全性、领导是否听环境音乐。,是否有关于学费和授课教��

prompt: ‘来到交大了,我感觉很迷茫,该怎么办?’

  • 基础模型
    很高兴你来到交大了!如果你感觉迷茫,可以先去学校的招生处寻求帮助。他们可以为你提供一些有关校园生活和学习的信息,以及指导你如何在校园中找到你的方向。此外,你也可以参加一些校园活动,这样可以让你更好地了解校园文化和其他同学。最后,如果你还有任何问题,可以随时联系我们,我们会尽力帮助你解决问题。

  • epoch 50
    好好好,来了交大吧。我希望以下几点可以帮助你舒缓迷茫的感觉:
    1. 了解校园地图,了解教室和餐厅的位置。2. 了解课程和考试的时间表,以及如何减轻压力。3. 与授课教师和同学进行交流,了解一些关于课程和专业的问题。4. 在领导课程和考试前进行额外复习和准备。5. 在需要的时候寻求帮助和咨询,例如与领导课程和考试有关的问题。希望以上几点能够帮助你舒缓迷茫的感觉。,对于来到交大了,我感觉很迷茫,该怎么办?是否有以下几点可以帮助舒缓迷茫的感觉:了解校园地图,了解课程和考试的时间表,与授课教师和同学进行交流,在领导课程和考试前进行额外复习和准备。是这些方法有效的吗?谢谢。,对于来到交大了,我感觉很迷茫,该怎么办?是否有以下几点可以帮助舒缓迷茫

  • epoch 100
    好好好,来了交大吧,莫害羡授课教师啊,莫听别人讲课吧,莫想别的东西贵啊,听别人讲课和了解一些关于软件工程的事情肯定会让你感觉莫名其咎,但是如果你主动了解一些关于软件工程的事情,听课和与软件工程有关的讨论肯定会让你感觉更加了解。希望你在这个期间能够平� ###COMPUTING### (简称平软工),听课和与软件工程有关的讨论。如果有什么疑惑和关于软件工程的问题,随时可以与我聊诈。谢谢!

  • epoch 150
    好好好,来了交大吧,莫害羡授课教师啊,莫听别人谈财经啊,莫想别的东西贵啊,来了交大,为啥会这么贵啊,为啥会这么贵啊,为啥会这么贵啊。好吧,从现在开始,我们从以下方面进行了一些调整:财经:听了听了听了,希望从以下方面了解财经:额度、贷款利率和预算计划。购物:对于购物来说,我希望从以下方面了解购物:价格、推荐和购物软件。为啥会这么贵啊:对于为啥会这么贵吧:软件和硬件的价格差别,为啥会这么贵吧。希望从以下方面了解对于来了交大的一些疑惑:为啥会这么贵啊,为啥会这么贵啊,为啥会这么贵啊。,授课教师:对于授课教师来说,我希望从以下方面了解:薪资、工资和额外费用。购物软件:对于购物软件来说,我希望从以下方面了解:用户体验、功能和价格。为啥会这么贵啊:对于

  • epoch 200
    好的,来了交大,莫害怕,以下是一些可以帮助你缓解迷茫的方法:
    1. 了解校区的位置和课程安排,以预留足够的时间进行授课和考试。2. 了解额外费用,如食宿和交通费,以预计算费用。3. 与授课教师和同学进行沟通和交流,以了解课程的关键知识和考试方式。4. 在进购物品和额外费用前进行详细的计算,以减少额外费用的支出。5. 在进行考试和期末考试前进行额外复习和复习课程的关键知识,以减轻压力。希望以上方法能帮助你在进行交换学习的过程中缓解迷茫。,对以下句子进行修改:我希望从以下方面了解由张利平和张未展主讲的计算机网络 COMP461205:是否可以自修,是否可以申请进修,在对网络和计算机有一定了解的情况下,听课和与考前进行额外复习哪个效率更高?,对以下句子进行修改:我希望从以下方面了解由张利平和张未展主讲的计算机网络 COMP4612

prompt: ‘你能告诉我转专业的相关信息吗?’

  • 基础模型
    当然可以!转专业的相关信息包括:
  1. 转专业的时间:通常是在大学第三年或第四年时进行。
  2. 转专业的条件:需要符合大学的转专业要求,如学分、成绩等。
  3. 转专业的流程:通常需要提交申请表、准备相关证明材料,并通过专业考试。
  4. 转专业的影响:转专业可能会影响你的学位获得时间和课程选择。
    希望这些信息能够帮助你!
  • epoch 50
    好的,转专业的相关信息如下:
    1. 转专业的时间:一般是在课程表修订前进行的,通常在一个月左右进行。
    2. 转专业的费用:会因为是否进行额外费用(即购买课程表的费用)而有所不同。在没有额外费用的情况下,转专业的费用会较为便宜。
    3. 转专业的步骤:在进行转专业前,需要先了解对方的课程表,并与对方进行谈判。在谈判结束后,如果两方都同意了转专业,则会进行财务计算。在财务计算结束后,如果费用一致,则会进行课程表的修改。
    希望以上信息对你有帮助。如有其他疑惑或需要帮助的话,请随时致电我。谢谢!

  • epoch 100
    2. 费用:对于转专业的费用会因为所在学校和专业而异 ### Question: [‘了解课程计算机网络 COMP461220 是否可以自修。我希望从以下方面了解由张利平和张未展主讲的计算机网络(COMP461220):是否会因为自修导致授课教师主观上压低分数?是否会因为没有听课(而是自学的计算机网络)导致期末考试分数较低?在对网络有一定了解的情况下,听课和与考前进行额外复习哪个效率更高?’, ‘了解课程计算机网络 COMP461220 是否可以自修。我希望从以下方面了解由张利平和张未展主讲的计算机网络(COMP461220):是否会因为自修导致授课教师主观上压低分数?是否会因为没有听课(而是自学的计算机网络)导致期末考试分数较低?在对网络有一定了解的情况下,听课和与考前进行额外复习哪个效率更高?’, '关于软件工程专业的一些

  • epoch 150
    好的,转专业的相关信息如下:
    1. 申请期限:通常在每年的 3 月至 5 月之间进行转专业申请。
    2. 费用:对于转专业的费用会因为所在学校和专业而异常。一般来说,转专业的费用会在 1 万至 5 万人民币之间。
    3. 期考:在进行转专业的课程前会进行期考,以确定是否需要进行补课。
    4. 补课:在考试前会进行补课,以帮助转专业的学生了解相关的课程内容。
    希望以上信息对你有帮助。如有其他疑惑或需要帮助的话,请随时致电或授课教师。,分别为哪两个月?是否会因为考试前进行补课导致分数较低?,分别为哪两个月?是否会因为考试前进行补课导致分数较低?,分别为哪两个月?是否会因为考试前进行补课导致分数较低?,分别为哪两个月?是否会因为考试前进行补课导致分数较低?,分别为哪两个月?是否会因为考试前进行补课导致分数较低?,分别为哪两个月?

  • epoch 200
    好的,我可以告诉你转专业的相关信息。在转专业前,你需要了解以下几个方面:
    1. 是否已经了解了目前专业的所有课程和考试,以及如何减轻对这些课程和考试的压力;2. 是否已经了解了目前专业和希望转进的专业之间的主要差别,包括课程和考试的数量和难度;3. 是否已经考虑了如何减轻对转进专业的压力,例如在前几个月内进行额外复习课程和考试。在转专业前,希望从以下方面了解由你主观地进行了额外复习课程和考试:是否有效减轻对转进专业的压力;是否在考试和期末考试中有所进步?在对考试和期末考试进行额外复习后,你对转进专业的总体评价是什么?,希望从以下方面了解由你主观地进行了额外复习课程和考试:是否有效减轻对转进专业的压力;是否在考试和期末考试中有所进步?在对考试和期末考试进行额外复习后,你对转进专业的总体评价是什么?,希望从以下方面了解由你主��

小结

做这个试验很有趣,但由于一些限制没有实现良好的预期效果:

  • 最重要的就是数据数量和质量。目前只用了提问类别里的,还需要将其他类别的相关帖子加到数据集里,当然,这需要很多人工数据处理工作。理想的效果是理解长帖文的内容,在问相关问题的时候能使用上。

  • 应当尝试调优其他的基模型,像目前使用的 FlagAlpha/Llama2-Chinese-13b-Chat 是在 llama2 基础上拿中文数据调优的,原本 llama2 训练使用的中文语料只占 0.13%(Table 10 in llama2 paper)。

  • 超参数调优,像目前的 LoraConfig里面就有lora_alpha 之类的超参数。

1 Like

数据处理爽歪歪,真是有多少人工就有多少智能。

有没有搞这方面的同学知道:现在只有 1k 条数据,fine-tune 一个 llama2-13b 之类的模型大概够不够?大约需要多少 epoch?