|
ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 18.24px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 2px solid rgb(0, 152, 116);color: rgb(63, 63, 63);">背景 我们通常会看到XX大厂又发布base模型和chat模型时,这两种模型的有什么区别呢? ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">其实,所有的大语言模型(LLM)的工作方式都是接收一些文本,然后预测最有可能出现在其后面的文本。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">base模型,也称为基础模型,是在大量各种文本上训练出来的预测后续文本的模型。这意味着生成的后续文本不一定是对指令或对话的响应。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">chat模型,又称为对话模型,是在base模型的基础上,通过对话记录(指令-响应)进行进一步的微调和强化学习。这使得它能够在接收指令和用户对话时,生成符合指令和人类预期的assistant响应内容。简单来说,chat模型更关注对话生成和交互场景,能更好地模拟人类对话。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);"> ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 18.24px;font-weight: bold;display: table;margin: 2em auto 1em;padding-right: 1em;padding-left: 1em;border-bottom: 2px solid rgb(0, 152, 116);color: rgb(63, 63, 63);">1、微调ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">微调,简单说就是给我们的开源 LLM 的 CKPT 增加更多数据,让它多掌握一些知识,或者改变它的一些初始生成结果。ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;margin: 1.5em 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">微调会调整模型的权重,并能更好地控制模型的生成输出。与 few-shot prompting 方式相比,微调也能解决因 token 消费过多、模型响应速度慢以及上下文窗口不够带来的问题。 ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17.6px;font-weight: bold;display: table;margin: 4em auto 2em;padding-right: 0.2em;padding-left: 0.2em;background: rgb(0, 152, 116);color: rgb(255, 255, 255);">为啥需要微调大模型?ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 16px;border-left: none;padding: 1em;border-radius: 8px;color: rgba(0, 0, 0, 0.5);background: rgb(247, 247, 247);margin: 2em 8px;">大模型通常是针对通用任务进行训练的,可能并不总是适合特定任务。 微调是调整大模型参数的过程,以使其在特定任务上的性能更好。 1、提高准确性微调可以显着提高大模型在特定任务上的准确性。例如,在对新闻文章数据集进行微调后,大模型可能能够更准确地识别文章的情感。 2、提高效率可以使大模型在特定任务.上更有效。例如,在对问答数据集进行微调后,大模型可能能够更快、更准确地回答问题。 3、提高泛化能力可以提高大模型的泛化能力,这意味着它们可以更好地执行与训练数据中数据不同的任务。例如,在对不同类型的创意文本格式(如诗歌、代码、脚本、音乐作品、电子邮件、信件等)的数据集进行微调后,大模型可能能够生成我们用看件下微调大模型的优可以减少训练大模型所需的数据量。 什么情况下需要微调大模型?1、在特定任务上实现高精度当大模型如GPT、BERT等在预训练阶段并不完全适应特定领域或任务,比如法律文档分析、医疗信息处理,微调可以帮助模型学习特定领域的专业术语和知识。 2、行业的数据量有限尽管大模型可能具有丰富的知识,但针对特定任务的训练数据可能较少。微调可以帮助模型更好地适应这些小规模数据,避免过拟合。 3、模型更新新数据或新需求出现时,对模型进行微调可以确保模型始终是最新的。 4、隐私或安全考虑如果数据敏感,内部组织可能更愿意使用微调而不是公开模型,以保护数据隐私。 2、模型量化模型量化是一种优化技术,它通过减少模型中权重和激活值的表示精度来降低模型的存储需求和计算复杂度。 在深度学习中,量化通常指的是将浮点数(如32位浮点数)转换为较低精度的表示(如16位、8位甚至更低的整数)。 这种转换可以在不显著牺牲模型性能的情况下,大幅减少模型的内存占用和推理时间。 
主要类型包括1、线性量化:这是最常见的量化方法,它将浮点数线性映射到整数范围。例如,一个8位量化会将浮点数映射到0到255或-128到127的整数范围。 2、非线性量化:这种方法使用非线性函数来映射浮点数到整数,通常用于特定类型的数据或模型。 3、对称量化:在对称量化中,量化范围是对称的,例如-127到127,适用于数据分布相对均匀的情况。 4、非对称量化:非对称量化允许量化范围是非对称的,例如0到255,适用于数据分布偏斜的情况。 好处有以下几点1、减少内存占用:量化后的模型权重和激活值占用更少的内存,使得模型可以在内存受限的设备上运行。 2、加速推理:低精度计算通常比高精度计算更快,可以在硬件加速器(如GPU、FPGA、ASIC)上实现更快的推理速度。 3、降低功耗:减少计算精度可以降低能耗,对于移动设备和嵌入式系统尤其重要。 4、提高吞吐量:在服务器端,量化可以提高处理请求的速率,从而提高服务质量。 3、完整代码你将学习如何进行数据预处理、训练、运行模型和保存模型(例如,为 Llama.cpp)。
Llama-3 8b 是在令牌数量为15万亿(trillion tokens)的数据集上训练的,而Llama-2只使用了2万亿令牌。 #安装Unsloth、Xformers(FlashAttention)和所有其他软件包 !pipinstall"unsloth[colab-new]@git+https://github.com/unslothai/unsloth.git" !pipinstall--no-deps"xformers<0.0.26"trlpeftacceleratebitsandbytes
•支持 Llama、Mistral、CodeLlama、TinyLlama、Vicuna、Open Hermes 等模型。 还有 Yi、Qwen(llamafied)、Deepseek,以及所有基于 Llama、Mistral 的架构。 •unsloth支持16位LoRA或4位QLoRA,速度提升两倍。 •max_seq_length可以设置为任何值,因为unsloth通过kaiokendev的方法进行自动RoPE缩放。 •[NEW] 通过PR 26037,unsloth支持下载4位模型的速度提升4倍!
fromunslothimportFastLanguageModel importtorch max_seq_length=2048#选择想要的任意方法!内部已经实现了对RoPE(ReachablePolicyOptimizationforEfficientExploration)缩放的自动支持。 dtype=None#对于自动检测,请使用"None";如果使用TeslaT4或V100加速器,请使用Float16;如果使用Ampere架构的加速器,请使用Bfloat16。 load_in_4bit=True#使用4位量化(quantization)技术来减少内存使用。这可以是一个可选项
#unsloth支持4位预量化模型,这可以使得下载速度提高4倍,并且不会出现内存不足(OutofMemory,简称OOM)的问题。 fourbit_models=[ "unsloth/mistral-7b-bnb-4bit", "unsloth/mistral-7b-instruct-v0.2-bnb-4bit", "unsloth/llama-2-7b-bnb-4bit", "unsloth/gemma-7b-bnb-4bit", "unsloth/gemma-7b-it-bnb-4bit",#InstructversionofGemma7b "unsloth/gemma-2b-bnb-4bit", "unsloth/gemma-2b-it-bnb-4bit",#InstructversionofGemma2b "unsloth/llama-3-8b-bnb-4bit",#[NEW]15TrilliontokenLlama-3 ]#Moremodelsathttps://huggingface.co/unsloth
model,tokenizer=FastLanguageModel.from_pretrained( model_name="unsloth/llama-3-8b-bnb-4bit", max_seq_length=max_seq_length, dtype=dtype, load_in_4bit=load_in_4bit, )

我们现在添加了 LoRA(Layer-wise Relevance Analysis,即层次相关性分析)适配器,使得只需更新模型中的 1% 到 10% 的参数! model=FastLanguageModel.get_peft_model( model, r=16,#Chooseanynumber>0!Suggested8,16,32,64,128 target_modules=["q_proj","k_proj","v_proj","o_proj", "gate_proj","up_proj","down_proj",], lora_alpha=16, lora_dropout=0,#Supportsany,but=0isoptimized bias="none",#Supportsany,but="none"isoptimized #[NEW]"unsloth"uses30%lessVRAM,fits2xlargerbatchsizes! use_gradient_checkpointing="unsloth",#Trueor"unsloth"forverylongcontext random_state=3407, use_rslora=False,#WesupportrankstabilizedLoRA loftq_config=None,#AndLoftQ )
数据准备我们现在使用 yahma 的Alpaca数据集,共包含 52K 条数据。 数据集如下: 
alpaca_prompt="""Belowisaninstructionthatdescribesatask,pairedwithaninputthatprovidesfurthercontext.Writearesponsethatappropriatelycompletestherequest.
###Instruction: {}
###Input: {}
###Response: {}"""
EOS_TOKEN=tokenizer.eos_token#tokenized输出中必须添加EOS\_TOKEN(结束标记)。这是一个特殊的标记,用于告诉模型一个序列已结束 defformatting_prompts_func(examples): instructions=examples["instruction"] inputs=examples["input"] outputs=examples["output"] texts=[] forinstruction,input,outputinzip(instructions,inputs,outputs): #表示必须添加EOS\_TOKEN(结束标记),否则生成的序列会无限延续下去 text=alpaca_prompt.format(instruction,input,output)+EOS_TOKEN texts.append(text) return{"text":texts,} pass
fromdatasetsimportload_dataset dataset=load_dataset("yahma/alpaca-cleaned",split="train") dataset=dataset.map(formatting_prompts_func,batched=True,)
模型训练这里使用 60 步进行训练,加速处理,也可以设置 num_train_epochs=1 以进行完整的运行,并将 max_steps=None 关闭。 fromtrlimportSFTTrainer fromtransformersimportTrainingArguments
trainer=SFTTrainer( model=model, tokenizer=tokenizer, train_dataset=dataset, dataset_text_field="text", max_seq_length=max_seq_length, dataset_num_proc=2, packing=False,#在短序列情况下,可以将训练速度提高5倍。 args=TrainingArguments( per_device_train_batch_size=2, gradient_accumulation_steps=4, warmup_steps=5, max_steps=60, learning_rate=2e-4, fp16=nottorch.cuda.is_bf16_supported(), bf16=torch.cuda.is_bf16_supported(), logging_steps=1, optim="adamw_8bit", weight_decay=0.01, lr_scheduler_type="linear", seed=3407, output_dir="outputs", ), )
#显示当前GPU的内存信息 gpu_stats=torch.cuda.get_device_properties(0) start_gpu_memory=round(torch.cuda.max_memory_reserved()/1024/1024/1024,3) max_memory=round(gpu_stats.total_memory/1024/1024/1024,3) print(f"GPU={gpu_stats.name}.Maxmemory={max_memory}GB.") print(f"已预留{start_gpu_memory}GB的内存")

trainer_stats=trainer.train() 60 步进行训练。 
#@title显示最终的内存和时间统计数据 used_memory=round(torch.cuda.max_memory_reserved()/1024/1024/1024,3) used_memory_for_lora=round(used_memory-start_gpu_memory,3) used_percentage=round(used_memory/max_memory*100,3) lora_percentage=round(used_memory_for_lora/max_memory*100,3) print(f"{trainer_stats.metrics['train_runtime']}secondsusedfortraining.") print(f"{round(trainer_stats.metrics['train_runtime']/60,2)}minutesusedfortraining.") print(f"Peakreservedmemory={used_memory}GB.") print(f"Peakreservedmemoryfortraining={used_memory_for_lora}GB.") print(f"Peakreservedmemory%ofmaxmemory={used_percentage}%.") print(f"Peakreservedmemoryfortraining%ofmaxmemory={lora_percentage}%.")

推理让我们运行模型!您可以更改指令和输入 - 输出留空! #alpaca_prompt=Copiedfromabove FastLanguageModel.for_inference(model)#Enablenative2xfasterinference inputs=tokenizer( [ alpaca_prompt.format( "Continuethefibonnacisequence.",#instruction "1,1,2,3,5,8",#input "",#output-leavethisblankforgeneration! ) ],return_tensors="pt").to("cuda")
outputs=model.generate(**inputs,max_new_tokens=64,use_cache=True) tokenizer.batch_decode(outputs)
输出: ['<|begin_of_text|>Belowisaninstructionthatdescribesatask,pairedwithaninputthatprovidesfurthercontext.Writearesponsethatappropriatelycompletestherequest.\n\n###Instruction:\nContinuethefibonnacisequence.\n\n###Input:\n1,1,2,3,5,8\n\n###Response:\n13,21,34,55,89,144,233,377,610,987<|end_of_text|>'] 您也可以使用TextStreamer进行连续推理 - 这样您可以看到每个词的生成,而不是等待整个过程结束! #alpaca_prompt=Copiedfromabove FastLanguageModel.for_inference(model)#Enablenative2xfasterinference inputs=tokenizer( [ alpaca_prompt.format( "Continuethefibonnacisequence.",#instruction "1,1,2,3,5,8",#input "",#output-leavethisblankforgeneration! ) ],return_tensors="pt").to("cuda")
fromtransformersimportTextStreamer text_streamer=TextStreamer(tokenizer) _=model.generate(**inputs,streamer=text_streamer,max_new_tokens=128)
输出: #alpaca_prompt=Copiedfromabove FastLanguageModel.for_inference(model)#Enablenative2xfasterinference inputs=tokenizer( [ alpaca_prompt.format( "Continuethefibonnacisequence.",#instruction "1,1,2,3,5,8",#input "",#output-leavethisblankforgeneration! ) ],return_tensors="pt").to("cuda")
fromtransformersimportTextStreamer text_streamer=TextStreamer(tokenizer) _=model.generate(**inputs,streamer=text_streamer,max_new_tokens=128)
保存、加载微调好的模型要将最终模型保存为LoRA适配器,可以使用Huggingface的push_to_hub进行在线保存或save_pretrained进行本地保存。 [注意]这只保存LoRA适配器,而不是完整模型。要保存为16位或GGUF,请向下滚动! model.save_pretrained("lora_model")#Localsaving tokenizer.save_pretrained("lora_model") #model.push_to_hub("your_name/lora_model",token="...")#Onlinesaving #tokenizer.push_to_hub("your_name/lora_model",token="...")#Onlinesaving
输出: ('lora_model/tokenizer_config.json', 'lora_model/special_tokens_map.json', 'lora_model/tokenizer.json')
现在,如果你想加载我们刚刚保存的LoRA适配器用于推理,请将False设置为True: ifFalse: fromunslothimportFastLanguageModel model,tokenizer=FastLanguageModel.from_pretrained( model_name="lora_model",#YOURMODELYOUUSEDFORTRAINING max_seq_length=max_seq_length, dtype=dtype, load_in_4bit=load_in_4bit, ) FastLanguageModel.for_inference(model)#Enablenative2xfasterinference
#alpaca_prompt=YouMUSTcopyfromabove!
inputs=tokenizer( [ alpaca_prompt.format( "WhatisafamoustalltowerinParis?",#instruction "",#input "",#output-leavethisblankforgeneration! ) ],return_tensors="pt").to("cuda")
outputs=model.generate(**inputs,max_new_tokens=64,use_cache=True) tokenizer.batch_decode(outputs)
输出: ["<|begin_of_text|>Belowisaninstructionthatdescribesatask,pairedwithaninputthatprovidesfurthercontext.Writearesponsethatappropriatelycompletestherequest.\n\n###Instruction:\nWhatisafamoustalltowerinParis?\n\n###Input:\n\n\n###Response:\nTheEiffelTowerisafamouslandmarkinParis,France.Itisawroughtirontowerthatwasbuiltin1889fortheWorld'sFair.Standingat324meterstall,itisthetallestbuildinginParisandoneofthemostrecognizablelandmarksintheworld.<|end_of_text|>"] 你也可以使用 Hugging Face 的AutoModelForPeftCausalLM。只有在你没有安装unsloth的情况下,才应该使用它。因为4bit模型下载不支持,Unsloth 的推理速度是 2 倍以上。 ifFalse: #IhighlydoNOTsuggest-useUnslothifpossible frompeftimportAutoPeftModelForCausalLM fromtransformersimportAutoTokenizer model=AutoPeftModelForCausalLM.from_pretrained( "lora_model",#YOURMODELYOUUSEDFORTRAINING load_in_4bit=load_in_4bit, ) tokenizer=AutoTokenizer.from_pretrained("lora_model")
将 VLLM 保存为 float16也支持直接保存为float16。选择merged_16bit以保存为 float16,或选择merged_4bit以保存为 int4。 另外还支持lora适配器作为备用。使用push_to_hub_merged将模型上传至你的 Hugging Face 账户! #Mergeto16bit ifFalse:model.save_pretrained_merged("model",tokenizer,save_method="merged_16bit",) ifFalse:model.push_to_hub_merged("hf/model",tokenizer,save_method="merged_16bit",token="")
#Mergeto4bit ifFalse:model.save_pretrained_merged("model",tokenizer,save_method="merged_4bit",) ifFalse:model.push_to_hub_merged("hf/model",tokenizer,save_method="merged_4bit",token="")
#JustLoRAadapters ifFalse:model.save_pretrained_merged("model",tokenizer,save_method="lora",) ifFalse:model.push_to_hub_merged("hf/model",tokenizer,save_method="lora",token="")
GGUF / llama.cpp 转换为了将文件保存为GGUF/llama.cpp格式,unsloth现在原生支持这一功能! 克隆了llama.cpp,并且默认将其保存为q8_0格式。unsloth支持所有方法,例如q4_k_m。 使用save_pretrained_gguf进行本地保存,使用push_to_hub_gguf进行上传到 Hugging Face。 一些受支持的量化方法(完整列表请参阅unsloth的Wiki 页面): •q8_0- 快速转换。资源消耗较高,但通常可以接受。 •q4_k_m- 推荐使用。对于一半的 attention.wv 和 feed_forward.w2 张量使用 Q6_K,其他情况使用 Q4_K。 •q5_k_m- 推荐使用。对于一半的 attention.wv 和 feed_forward.w2 张量使用 Q6_K,其他情况使用 Q5_K。
#Saveto8bitQ8_0 ifFalse:model.save_pretrained_gguf("model",tokenizer,) ifFalse:model.push_to_hub_gguf("hf/model",tokenizer,token="")
#Saveto16bitGGUF ifFalse:model.save_pretrained_gguf("model",tokenizer,quantization_method="f16") ifFalse:model.push_to_hub_gguf("hf/model",tokenizer,quantization_method="f16",token="")
#Savetoq4_k_mGGUF ifFalse:model.save_pretrained_gguf("model",tokenizer,quantization_method="q4_k_m") ifFalse:model.push_to_hub_gguf("hf/model",tokenizer,quantization_method="q4_k_m",token="")
现在,在llama.cpp或基于 UI 的系统如GPT4All中使用model-unsloth.gguf文件或model-unsloth-Q4_K_M.gguf文件。 |