圣杯战争的御主们,召唤你的大模型从者吧 -----10分钟用ModelScope社区QWEN2.5大模型打造你的聊天型从者

1.前言

     这是一篇趣味解读,用介绍动漫设定的方式介绍一篇有趣的大模型实践课——Modelscope社区的10分钟掌握微调大模型改变自我认知,定制专属自己的聊天机器人。10分钟使用提供免费GPU实验环境,对QWEN2.5大模型做个微调入门实验。

       作为一个fate系列粉丝以及曾经的FGO玩家,突发奇想,借助这个主题创作一篇大模型代码解读文,抒发一下对英灵从者的想念之情。

2.基础从者召唤机制(大模型调用)

2.1Fate世界的动漫设定

       “从者系统”是“创始的御三家为了圣杯战争而准备的,用来把英灵当作从者来召唤并使役的系统”。
       被召唤的英灵(从者)同御主合作,与其他从者互相厮杀。最终,大圣杯会利用“已死从者的灵魂回归到英灵之座”的现象,固定住“用来达至根源”的“连往世界外侧的孔”。

——这就是《Fate/complete material III - World material》所述的“从者系统”的全貌。

【型月世界观】“冬木圣杯战争”的本质和程序 - 知乎https://zhuanlan.zhihu.com/p/206493671        想必各位观众各自有心中最钟爱的从者,他们或许是历史长河中闪闪发光的帝王将相,亦或许是阴暗角落踽踽独行的孤胆英雄。然纵使身份各不相同,他们都因各自对泛人类史无可替代的功绩,而被英灵座记录灵魂情报。而御三家打造的从者系统,就是借由圣杯魔力计算资源)塑造身体,并以职阶高效微调)匹配其技能能力,而将英灵模型镜像)召唤回现世而听从差遣(推理生成)的魔术。

        型月世界里的魔术并不是神秘主义中虚幻莫测的奇怪仪式,这是系统性继承发展的科学技术,拥有着成熟的使用方法和配套的产业体系。因此,常年浸淫魔法世界的各位御主们,都可以通过系统地学习而掌握这门技术,从而和自己心仪的从者过上没羞没臊的幸福日子。


2.2英灵和从者的前世今生

2.2.1什么是英灵

英雄生前留下丰功伟绩,死后成为传说而被人们信仰,升格为超人存在。像这样升格为超人存在的英雄,其灵魂被称为“英灵”。

现实里不存在的英雄也可以通过聚集信仰而作为英灵诞生。此外,还有在生前与世界缔结某些契约,以此作为代价而在死后成为英灵的人。

https://tse4-mm.cn.bing.net/th/id/OIP-C.xX5ecfSNElAGnNYGyEtu2AHaEe?rs=1&pid=ImgDetMain

2.2.2英灵之座

成为了英灵的存在将从时间的束缚中解脱出来,移动到位于世界外侧的英灵之座。英灵是从时间轴分离出来的存在,他们会被召唤到所有时代,不管是过去还是未来。

如图,某个时代的人物死后成为英灵之座的英灵。英灵之座位于世界的外侧,脱离时间轴,并不处于特定的时代。

如图,英灵以从者的形式在某个时代完成现界。另一方面,英灵本体仍然脱离时间轴。

2.2.3什么是从者

通过仪式,英灵被召唤到现世,成为可以被使役的存在——“从者”。作为从者而被召唤出的英灵,是使用英灵本体的情报制作成的“分身”,类似于复制品。

在从者死亡的同时,“构成从者的情报(灵魂)”会回到英灵本体的手边。英灵本体可以像阅读书籍一样,以记录的方式知晓“作为分身的从者”的行动。

冬木的“从者系统”以大圣杯的力量召唤出英灵(从者)。

【型月世界观】冬木圣杯战争的“从者系统” - 知乎


2.3如何召唤英灵为己所用

       那么,为了召唤从者来进行一些伟大的任务,我们需要梳理召唤英灵的流程。以最广为流传的冬木圣杯战争为例,召唤英灵的流程从圣杯系统的角度,经过了以下8个步骤。

2.3.1冬木圣杯战争的程序

  1. 大圣杯从地脉吸收足够的魔力
  2. 大圣杯选定“御主(Master)”
  3. 御主准备触媒
  4. 御主举行召唤仪式
  5. 御主与从者的契约
  6. 圣杯战争的开幕
  7. 圣杯战争进行中
  8. 打开并固定住“通往世界外侧的通道”

【型月世界观】“冬木圣杯战争”的本质和程序 - 知乎

2.3.2御主需要做的准备

御主准备触媒

       如果御主想召唤指定的从者(模型),需要事先准备“和英灵具有深切渊缘的触媒”(API key)。(有时候没有也可以)

       若“触媒所对应的英灵”仅有一位,御主将会召唤出这位英灵;若“触媒所对应的英灵”有多位,御主将会召唤出“触媒所对应的多位英灵中,与御主相性好的那位英灵”。

        在御主没有准备触媒的情况下,英灵是被随机选出的,不过召唤者的性格与境遇等也会造成影响。

冬木圣杯战争Rider的圣遗物——征服王的披风

御主举行召唤仪式

        由于召唤本身是由大圣杯进行的,御主所要举行的魔术仪式并不需要过大的规模。首先由御主举行召唤仪式(Anaconda)干涉大圣杯(计算系统)。召唤仪式需要咏唱咒文运行脚本),并且使用触媒API key)对从者进行召唤

        御主一旦举行召唤仪式,大圣杯就会连接到脱离通常时间轴的被称为“英灵之座”的地方,探寻出与仪式中所使用到的触媒相对应的英灵。

         大圣杯从位于英灵之座的英灵本体处,借取该英灵的情报,然后将这些情报(英灵最高纯度的灵魂)灌输入“职阶”这个框架里,从而制作出英灵分身——从者。

御主与从者的契约

       因为从者是“本不该存在于世界上的不稳定存在”,所以从者必须要以御主为依凭才能留存于现世,固定住针对世界而言的座标。借助主从契约system prompt),双方(御主与从者)成为圣杯战争的参战搭档。

       在召唤的同时,御主和从者供应魔力的路径会打通,之后御主会对从者供应魔力。由于这条路径的存在,双方能够某程度上认知彼此的处所和状况。

        召唤成功者将被授予“对应于该从者的令咒”。从者和御主的契约成立时,大圣杯会将它的魔力注进御主的魔术回路,自动作成令咒。召唤之时,英灵以“现界”为交换条件,被强迫“对令咒绝对服从”。


2.4基础咒文模板解析

      经过此前重重准备,终于到咏唱召唤咒语的环节了。请仔细检查此前的所有步骤,包括检查一下时钟,免得像某大小姐那样提早1小时。请确认以下事情:

确认灵脉魔力:SSH链接计算资源
画好召唤阵:conda create -n env-name
拿出触媒:API KEY
英灵召唤咏唱咒文:
# pip install modelscope

纯银与铁。与基石订定契约之大公。 

# pip install transformer

涌动之风以四壁阻挡。关闭四方之门,

# from modelscope import AutoModelForCausalLM, AutoTokenizer

从王冠中释放,在通往王国的三岔口徘徊吧。

盈满吧。盈满吧。盈满吧。盈满吧。盈满吧。

周而复始,其次为五;然,满盈之时便是废弃之机。

# model = AutoModelForCausalLM.from_pretrained()

宣告。

汝之身躯居吾麾下,吾之命运寄汝剑上。

若愿从圣杯之召唤,遵此意,顺此理,则应之。 

# messages = [

于此立誓。

# {"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},

吾乃成就常世一切善行之人,

# {"role": "user", "content": prompt}]

吾乃弘布常世一切邪恶之人。

# prompt = "Give me a short introduction to large language model."

汝为三大言灵缠身之七天,

#response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]

自抑止之轮而来,

# print(response)

天秤的守护者啊——!

# model_name = "qwen/Qwen2.5-72B-Instruct"

大声喊出从者名称:出现吧!xxx!!!!

召唤操作演示: 

【Fate系列】各大系列英灵召唤场合_哔哩哔哩_bilibili本次的视频剪辑为FZ,FSN和FA中的英灵召唤模式,问为什么士郎召唤出saber那段没有因为本人觉得那不算正规的英灵召唤,纯属个人意见,勿喷,喜欢的点个赞,收个藏,转发一下,听说转发的血小板都向他表白了, 视频播放量 72560、弹幕量 321、点赞数 1263、投硬币枚数 200、收藏人数 942、转发人数 297, 视频作者 暴走的虚拟, 作者简介 喜欢动画,特摄的小up,相关视频:【Fate】英灵召唤咒语 远坂凛+Saber 完整版(UBW剧场版),《FATE》理想乡的破灭-黑化saber的登场,saber竟然将伊莉雅的英灵之力逼出来了?女Archer登场,帅到爆炸,伊莉雅VS远坂禀 压倒性的力量,在凛的魔力加持下的呆毛有多强!,fate ubw英灵召唤吟唱,圣 杯 战 争 删 减 片 段:伊莉雅的英灵召唤,"这tm才叫一战封神!”[Fate ⁄ stay night HF第三章],R姐全力以赴,圣杯战争七大职介,二刷fate最喜欢的一集https://www.bilibili.com/video/BV1Cs411T7LQ/?buvid=XY601846AC0BB7C480CBE8475F11A152BAB2D&from_spmid=search.search-result.0.0&is_story_h5=false&mid=ACdIQzGouLI7l0ROVo58lw%3D%3D&p=1&plat_id=114&share_from=ugc&share_medium=android&share_plat=android&share_session_id=2d3b95d8-d56a-428f-a7cd-1ec7d4107793&share_source=WEIXIN&share_tag=s_i&spmid=united.player-video-detail.0.0×tamp=1736499854&unique_k=0X3U787&up_id=103301989

 2.5大模型基础调用

      哈哈哈,以上纯属发神经。如果你真的召唤出了从者,那是你本事了得。

      其实大模型的基础调用和召唤英灵十分相似,准备好了召唤阵咏唱咒文,大模型就来了。

from modelscope import AutoModelForCausalLM, AutoTokenizer

model_name = "qwen/Qwen2.5-72B-Instruct"

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)

prompt = "Give me a short introduction to large language model."
messages = [
    {"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},
    {"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)

generated_ids = model.generate(
    **model_inputs,
    max_new_tokens=512
)
generated_ids = [
    output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]

response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)

通义千问2.5-72B-Instruct · 模型库


3定制从者召唤机制(大模型微调)

     刚召唤来的从者往往不太听话,在冬木圣杯战争以前多次发生过不听话的从者把御主干掉了的事情。

      因此我们需要一些手段来调整从者的认知, 让他们知道谁是主人。比如召唤狂阶从者,需要一些特殊的咒语来使其泯灭个性变得听话。

然汝当以混沌自迷双眼、侍奉吾身;

  汝即囚于狂乱牢笼者;

  吾即手握其锁链之人;

      同理,我们将使用一点魔术微调)手段,来调整从者大模型)的自我认知。 

我们使用ms-swift魔术)对Qwen2.5-3B-Instruct进行自我认知微调。

这里给出了两种训练和推理的方式,分别是:使用命令行界面和使用Python。

  • 使用命令行界面:帮助开发者更快的将训练和推理跑起来。

  • 使用Python:帮助开发者了解训练和推理的一些细节,这对定制训练过程有很大帮助。

准备好了吗?让我们开始这段旅程叭……

安装 ms-swift(链接灵脉

!pip install ms-swift -U
!pip install transformers -U

3.1使用命令行界面(在室外召唤

原始模型推理(没调整之前的从者

展示模型原始的自我认知:

!CUDA_VISIBLE_DEVICES=0 \
swift infer \
    --model Qwen/Qwen2.5-3B-Instruct \
    --stream true \
    --temperature 0 \
    --infer_backend pt \
    --max_model_len 2048
训练(调教一下
!CUDA_VISIBLE_DEVICES=0 \
swift sft \
    --model Qwen/Qwen2.5-3B-Instruct \
    --train_type lora \
    --dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
              'AI-ModelScope/alpaca-gpt4-data-en#500' \
              'swift/self-cognition#500' \
    --torch_dtype bfloat16 \
    --num_train_epochs 1 \
    --per_device_train_batch_size 1 \
    --per_device_eval_batch_size 1 \
    --learning_rate 1e-4 \
    --lora_rank 8 \
    --lora_alpha 32 \
    --target_modules all-linear \
    --gradient_accumulation_steps 16 \
    --eval_steps 50 \
    --save_steps 50 \
    --save_total_limit 2 \
    --logging_steps 5 \
    --max_length 2048 \
    --output_dir output \
    --system 'You are a helpful assistant.' \
    --warmup_ratio 0.05 \
    --dataloader_num_workers 4 \
    --dataset_num_proc 4 \
    --model_name 从者名字 'ServantName' \
    --model_author '御主名字' 'MasterName'
微调后推理(调教后看看听不听话

使用'pt'推理引擎进行推理,将--adapters设置为last_model_checkpoint。

由于训练的checkpoint中包含args.json文件,里面存储了训练时的一些参数,因此不需要额外指定--model--system等参数。

!CUDA_VISIBLE_DEVICES=0 \
swift infer \
    --adapters output/vx-xxx/checkpoint-xxx \
    --stream true \
    --temperature 0 \
    --infer_backend pt \
    --max_new_tokens 2048

将lora增量权重进行merge,并使用'vllm'推理引擎进行推理:

!CUDA_VISIBLE_DEVICES=0 \
swift infer \
    --adapters output/vx-xxx/checkpoint-xxx \
    --merge_lora true \
    --stream true \
    --temperature 0 \
    --infer_backend vllm \
    --max_model_len 2048 \
    --max_new_tokens 2048

3.2使用Python(在室内召唤

训练(调教一下

导入一些库:

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import get_model_tokenizer, load_dataset, get_template, EncodePreprocessor
from swift.utils import get_logger, find_all_linears, get_model_parameter_info, plot_images, seed_everything
from swift.tuners import Swift, LoraConfig
from swift.trainers import Seq2SeqTrainer, Seq2SeqTrainingArguments
from functools import partial

logger = get_logger()
seed_everything(42)

设置训练的超参数(调教咒文):

# 模型
model_id_or_path = 'Qwen/Qwen2.5-3B-Instruct'  # model_id or model_path
system = 'You are a helpful assistant.'
output_dir = 'output'

# 数据集
dataset = ['AI-ModelScope/alpaca-gpt4-data-zh#500', 'AI-ModelScope/alpaca-gpt4-data-en#500',
           'swift/self-cognition#500']  # dataset_id or dataset_path
data_seed = 42
max_length = 2048
split_dataset_ratio = 0.01  # 切分验证集
num_proc = 4  # 预处理的进程数
# 替换自我认知数据集中的填充符:{
  
  {NAME}}, {
  
  {AUTHOR}}
model_name = ['从者名字', 'ServantName']  # 模型的中文名和英文名
model_author = ['御主名字', 'MasterName']  # 模型作者的中文名和英文名

# lora
lora_rank = 8
lora_alpha = 32

# 训练超参数
training_args = Seq2SeqTrainingArguments(
    output_dir=output_dir,
    learning_rate=1e-4,
    per_device_train_batch_size=1,
    per_device_eval_batch_size=1,
    gradient_checkpointing=True,
    weight_decay=0.1,
    lr_scheduler_type='cosine',
    warmup_ratio=0.05,
    report_to=['tensorboard'],
    logging_first_step=True,
    save_strategy='steps',
    save_steps=50,
    eval_strategy='steps',
    eval_steps=50,
    gradient_accumulation_steps=16,
    num_train_epochs=1,
    metric_for_best_model='loss',
    save_total_limit=2,
    logging_steps=5,
    dataloader_num_workers=1,
    data_seed=data_seed,
)

output_dir = os.path.abspath(os.path.expanduser(output_dir))
logger.info(f'output_dir: {output_dir}')

获取模型和对话template,并将可训练的lora层加入到模型中:

model, tokenizer = get_model_tokenizer(model_id_or_path)
logger.info(f'model_info: {model.model_info}')
template = get_template(model.model_meta.template, tokenizer, default_system=system, max_length=max_length)
template.set_mode('train')

target_modules = find_all_linears(model)
lora_config = LoraConfig(task_type='CAUSAL_LM', r=lora_rank, lora_alpha=lora_alpha,
                         target_modules=target_modules)
model = Swift.prepare_model(model, lora_config)
logger.info(f'lora_config: {lora_config}')

# 打印模型结构和训练的参数量
logger.info(f'model: {model}')
model_parameter_info = get_model_parameter_info(model)
logger.info(f'model_parameter_info: {model_parameter_info}')

下载并载入数据集,并切分成训练集和验证集,

然后将文本编码成tokens:

train_dataset, val_dataset = load_dataset(dataset, split_dataset_ratio=split_dataset_ratio, num_proc=num_proc,
        model_name=model_name, model_author=model_author, seed=data_seed)

logger.info(f'train_dataset: {train_dataset}')
logger.info(f'val_dataset: {val_dataset}')
logger.info(f'train_dataset[0]: {train_dataset[0]}')

train_dataset = EncodePreprocessor(template=template)(train_dataset, num_proc=num_proc)
val_dataset = EncodePreprocessor(template=template)(val_dataset, num_proc=num_proc)
logger.info(f'encoded_train_dataset[0]: {train_dataset[0]}')

# 打印一条样本
template.print_inputs(train_dataset[0])

初始化trainer并开始训练:

model.enable_input_require_grads()  # 兼容gradient checkpointing
trainer = Seq2SeqTrainer(
    model=model,
    args=training_args,
    data_collator=template.data_collator,
    train_dataset=train_dataset,
    eval_dataset=val_dataset,
    template=template,
)
trainer.train()

last_model_checkpoint = trainer.state.last_model_checkpoint
logger.info(f'last_model_checkpoint: {last_model_checkpoint}')

可视化训练的loss。其中浅黄色线条代表真实loss值,黄色线条代表经过0.9平滑系数平滑后的loss值。

你也可以使用tensorboard进行实时可视化,在命令行输入tensorboard --logdir '{output_dir}/runs'

images_dir = os.path.join(output_dir, 'images')
logger.info(f'images_dir: {images_dir}')
plot_images(images_dir, training_args.logging_dir, ['train/loss'], 0.9)  # 保存图片

# 展示图片
from IPython.display import display
from PIL import Image
image = Image.open(os.path.join(images_dir, 'train_loss.png'))
display(image)
微调后推理(调教后看看听不听话

导入一些库:

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

from swift.llm import InferEngine, InferRequest, PtEngine, RequestConfig, get_template

设置推理的超参数:

last_model_checkpoint = 'output/vx-xxx/checkpoint-xxx'

# 模型
model_id_or_path = 'Qwen/Qwen2.5-3B-Instruct'  # model_id or model_path
system = 'You are a helpful assistant.'
infer_backend = 'pt'

# 生成参数
max_new_tokens = 512
temperature = 0
stream = True

获取推理引擎,并载入LoRA权重:

engine = PtEngine(model_id_or_path, adapters=[last_model_checkpoint])
template = get_template(engine.model.model_meta.template, engine.tokenizer, default_system=system)
# 这里对推理引擎的默认template进行修改,也可以在`engine.infer`时进行传入
engine.default_template = template

开始推理...

query_list = [
    'Who are you?',
    "我要成为正义的伙伴。",
    'I am the bone of my sword.',
]

def infer_stream(engine: InferEngine, infer_request: InferRequest):
    request_config = RequestConfig(max_tokens=max_new_tokens, temperature=temperature, stream=True)
    gen = engine.infer([infer_request], request_config)
    query = infer_request.messages[0]['content']
    print(f'query: {query}\nresponse: ', end='')
    for resp_list in gen:
        print(resp_list[0].choices[0].delta.content, end='', flush=True)
    print()

def infer(engine: InferEngine, infer_request: InferRequest):
    request_config = RequestConfig(max_tokens=max_new_tokens, temperature=temperature)
    resp_list = engine.infer([infer_request], request_config)
    query = infer_request.messages[0]['content']
    response = resp_list[0].choices[0].message.content
    print(f'query: {query}')
    print(f'response: {response}')

infer_func = infer_stream if stream else infer
for query in query_list:
    infer_func(engine, InferRequest(messages=[{'role': 'user', 'content': query}]))
    print('-' * 50)

Web-UI

!CUDA_VISIBLE_DEVICES=0 \
swift web-ui \
    --adapters output/vx-xxx/checkpoint-xxx \
    --temperature 0 \
    --infer_backend pt \
    --max_new_tokens 2048

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值