
Llama 3.2入门基础教程(非常详细),Llama 3.2微调、部署以及多模态训练入门到精通,收藏这一篇就够了!
9 月 25 日 Meta 发布了 Llama 3.2,包括 11B 和 90B 的视觉语言模型。
9 月 25 日 Meta 发布了 Llama 3.2,包括 11B 和 90B 的视觉语言模型。
前排提示,文末有大模型AGI-CSDN独家资料包哦!
Llama 3技术剖析与部署
相较于Llama2, Llama3的改变其实并不是太大。 Tokenizer变成了128K的词表,使用了GQA,不在是原来的只在Llama2-70B里使用了。所以说,最大的改变就是词表与GQA。然后在训练上变化比较大,参数变大了,400B的还没放出来。但它的训练是变化很大的。训练数据明显比过去多,15T的token数差不多是Llama2的四倍多,而且这个数据的质量明显要高呢。
新的数据过滤器,幻觉、NSFW、语义重复、分类这些都有提高或者新增。
预训练的数据也在变好,再加上适当的优化技术。
所以真的结构上的改变是GQA。
那看一下GQA是咋回事吧。 一切的改进都是针对Transformer的QKV这块来的。
原始的是这样的,每一个QKV的计算都是分别进行的,这样QKV的计算其实要有大量的计算。基本上是一个下面的计算
考虑到这样一个大的计算会有非常大的计算量,于是把这个Attention拆成了小块,然后连接在一起。也就是下面的MHA其实也是一种优化,但是很明显,在LLM变成极大后,这个东西还要再优化,因为它还是消耗了太大的计算量。
于是最早有人想优化成MQA那种,就是一个K、一个V对应所有的Q,这种方式确实很容易扩大QKV的参数规模,同时非常有效的减少KV缓存。但是因为这个参数它太共同了,所以后期要在FFN那块增加相应的参数才成。效果也没有证明好了。
于是又有了更优的版本:GQA,所有的优化都是“中庸”嘛,中不偏,庸不易。
于是GQA呢,是简单的把MHA分成几组,每组共用一个就好了。从Llama2-70b,还有Llama3全系来看呢,GQA这个确实是在性能与KV缓存的显存占用上获得了很好的平衡。
谈到这儿,你有没有发现现在讲Llama3,其实是有很多基础的东西,如attention, mha, ffn一类的东西,你可能有些模糊了呢?我非常建议有举的人都去听听由知乎知学堂开设的这门AI大模型公开课,课程带你学习GPT背后的技术原理,LangChain、Fine-tune技术,从理论实践,到深度讲解,带你全程体验微调过程,定制属于自己的大模型。课上还能直接对话AI技术大佬,现场答疑,非常不错。这样你能掌握一套更全面的知识了。
既然这套东西没有什么大的改动,那我们就看看怎么用吧。
通常我们可以这样认为 Prompt是要优先RAG,RAG是要优先微调Finetune的。我们就从部署一个Llama3开始吧。看看怎么用Prompt,再怎么用RAG,再怎么微调Finetune它。
模型基本使用方法
这次我们搞个接地气的,直接用一个大家想不到的模型:中国联通AI创新中心微调的“Unichat-llama3-Chinese-8B”,看看联通的实力如何。毕竟我们用中文更容易看到效果。
运行代码很简单:
import transformers
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
model_id = "UnicomLLM/Unichat-llama3-Chinese-8B" #可以是本地路径
pipeline = transformers.pipeline(
"text-generation",
model=model_id,
model_kwargs={"torch_dtype": torch.bfloat16},
device="cuda",
)
messages = [
{"role": "system", "content": "A chat between a curious user and an artificial intelligence assistant.The assistant gives helpful, detailed, and polite answers to the user's questions."},
{"role": "user", "content": "你是谁"},
]
prompt = pipeline.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
terminators = [
pipeline.tokenizer.eos_token_id,
pipeline.tokenizer.convert_tokens_to_ids("<|eot_id|>")
]
outputs = pipeline(
prompt,
max_new_tokens=2048,
eos_token_id=terminators,
do_sample=False,
temperature=0.6,
top_p=1,
repetition_penalty=1.05
)
print(outputs[0]["generated_text"][len(prompt):])
理论上你就能运行了,如果不缺支持库(24G显存的运行会顺畅些)
Rag
这事吧,其实也不难,现在的框架已经很丰富了。我们举个例子吧。
通常langchain rag的流程如下
代码吧,搞一份供参考吧:
from langchain.llms.base import LLM
from typing import Any, List, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from transformers import AutoTokenizer, AutoModelForCausalLM, RagTokenizer, RagRetriever, RagSequenceForGeneration
import torch
class LLaMA3_LLM(LLM):
tokenizer: AutoTokenizer = None
model: AutoModelForCausalLM = None
rag_tokenizer: RagTokenizer = None
rag_retriever: RagRetriever = None
rag_generator: RagSequenceForGeneration = None
def __init__(self, mode_name_or_path :str, rag_name_or_path: str):
super().__init__()
print("正在从本地加载模型和RAG组件...")
self.tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, use_fast=False)
self.model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, torch_dtype=torch.bfloat16, device_map="auto")
self.tokenizer.pad_token = self.tokenizer.eos_token
# 初始化RAG组件
self.rag_tokenizer = RagTokenizer.from_pretrained(rag_name_or_path)
self.rag_retriever = RagRetriever.from_pretrained(rag_name_or_path)
self.rag_generator = RagSequenceForGeneration.from_pretrained(rag_name_or_path)
print("完成本地模型和RAG组件的加载")
def bulid_input(self, prompt, history=[]):
user_format='user\n\n{content}'
assistant_format='assistant\n\n{content}'
history.append({'role':'user','content':prompt})
prompt_str = ''
# 拼接历史对话
for item in history:
if item['role']=='user':
prompt_str+=user_format.format(content=item['content'])
else:
prompt_str+=assistant_format.format(content=item['content'])
return prompt_str
def _call(self, prompt : str, stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any):
input_str = self.bulid_input(prompt=prompt)
input_ids = self.tokenizer.encode(input_str, add_special_tokens=False, return_tensors='pt').to(self.model.device)
# 使用RAG模型进行检索
with torch.no_grad():
retrieved = self.rag_retriever(input_str, return_tensors="pt")
generated = self.rag_generator(input_ids=retrieved['retrieved_indices'], attention_mask=retrieved['retrieved_attention_mask'])
# 检查是否成功生成了回复
if generated is None:
return "Sorry, I couldn't generate a response."
outputs = generated.sequences.tolist()[0][len(input_ids[0]):]
response = self.tokenizer.decode(outputs).strip().replace('', "").replace('assistant\n\n', '').strip()
return response
@property
def _llm_type(self) -> str:
return "LLaMA3_LLM"
from LLM import LLaMA3_LLM
llm = LLaMA3_LLM(mode_name_or_path = "/root/autodl-tmp/LLM-Research/Meta-Llama-3-8B-Instruct")
llm("你是谁")
微调
微调这事,其实主要还是看数据,太少了你也不要有太大期望。不过参考代码还是可以给一下。
首先你的数据是这样的(多个重复):
{
"instruction": "回答以下用户问题,仅输出答案。",
"input": "1+1等于几?",
"output": "2"
}
然后代码差不多是这样的(这次从modelscope下载, 期望你能知道安装相应的库)
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('LLM-Research/Meta-Llama-3-8B-Instruct', cache_dir='/root/autodl-tmp', revision='master')
def process_func(example):
MAX_LENGTH = 384 # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer(f"<|start_header_id|>user<|end_header_id|>\n\n{example['instruction'] + example['input']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
response = tokenizer(f"{example['output']}<|eot_id|>", add_special_tokens=False)
input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
if len(input_ids) > MAX_LENGTH: # 做一个截断
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
tokenizer = AutoTokenizer.from_pretrained('/root/autodl-tmp/LLM-Research/Meta-Llama-3-8B-Instruct', use_fast=False, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained('/root/autodl-tmp/LLM-Research/Meta-Llama-3-8B-Instruct', device_map="auto",torch_dtype=torch.bfloat16)
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
args = TrainingArguments(
output_dir="./output/llama3",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
logging_steps=10,
num_train_epochs=3,
save_steps=100,
learning_rate=1e-4,
save_on_each_node=True,
gradient_checkpointing=True
)
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train()
lora_path='./llama3_lora'
trainer.model.save_pretrained(lora_path)
tokenizer.save_pretrained(lora_path)
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
from peft import PeftModel
mode_path = '/root/autodl-tmp/LLM-Research/Meta-Llama-3-8B-Instruct'
lora_path = './llama3_lora' # lora权重路径
# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_path)
# 加载模型
model = AutoModelForCausalLM.from_pretrained(mode_path, device_map="auto",torch_dtype=torch.bfloat16)
# 加载lora权重
model = PeftModel.from_pretrained(model, model_id=lora_path, config=config)
prompt = "你是谁?"
messages = [
# {"role": "system", "content": "现在你要扮演皇帝身边的女人--甄嬛"},
{"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
model_inputs = tokenizer([text], return_tensors="pt").to('cuda')
generated_ids = model.generate(
model_inputs.input_ids,
max_new_tokens=512,
eos_token_id=tokenizer.encode('<|eot_id|>')[0]
)
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)
多模态训练
可能还要等等,现在的llama3官方还没有提供400B的那个多模态版本。不过GitHub上有个llama-multimodal-vqa的项目,大概的方向是这样的,用一个CLIP把图像编码成了Token,再用Llama3训练一下。但是结果真的不太成啊。还是等官方400b吧。
读者福利:如果大家对大模型感兴趣,这套大模型学习资料一定对你有用
对于0基础小白入门:
如果你是零基础小白,想快速入门大模型是可以考虑的。
一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以根据这些资料规划好学习计划和方向。
包括:大模型学习线路汇总、学习阶段,大模型实战案例,大模型学习视频,人工智能、机器学习、大模型书籍PDF。带你从零基础系统性的学好大模型!
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓
👉AI大模型学习路线汇总👈
大模型学习路线图,整体分为7个大的阶段:(全套教程文末领取哈)
第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;
第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;
第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;
第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;
第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;
第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;
第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。
👉大模型实战案例👈
光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
👉大模型视频和PDF合集👈
观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费
】🆓
更多推荐
所有评论(0)