本章内容
- 介绍不同的大型语言模型(LLM)微调方法
- 准备用于文本分类的数据集
- 修改预训练LLM以便进行微调
- 微调LLM以识别垃圾信息
- 评估微调后的LLM分类器的准确性
- 使用微调后的LLM对新数据进行分类
到目前为止,我们已经编写了LLM的架构、对其进行了预训练,并学习了如何从外部来源(如OpenAI)导入预训练权重到我们的模型中。现在,我们将通过微调LLM用于特定的目标任务(如文本分类)来收获我们的成果。本章的具体示例是将短信分类为“垃圾信息”或“非垃圾信息”。图6.1展示了微调LLM的两种主要方式:用于分类的微调(步骤8)和用于执行指令的微调(步骤9)。
微调的不同类别
微调语言模型的最常见方式是指令微调和分类微调。指令微调通过使用特定的指令训练语言模型,以提高其理解和执行自然语言提示中描述的任务的能力,如图6.2所示。
在分类微调中,如果你有机器学习背景,你可能已经熟悉这个概念,模型被训练以识别一组特定的类别标签,例如“垃圾邮件”和“非垃圾邮件”。分类任务的示例不仅限于LLM和电子邮件过滤,还包括从图像中识别不同种类的植物;将新闻文章分类为体育、政治和技术等主题;以及在医学成像中区分良性和恶性肿瘤。
关键点是,分类微调模型只能预测它在训练期间遇到的类别。例如,它可以判断某些内容是“垃圾邮件”还是“非垃圾邮件”,如图6.3所示,但它无法提供关于输入文本的其他信息。
与图6.3中展示的分类微调模型相比,指令微调模型通常可以执行更广泛的任务。我们可以将分类微调模型视为高度专业化的模型,而通常开发一个在特定任务上表现良好的专业化模型要比开发一个能够在各种任务中表现出色的通用模型更容易。
选择合适的微调方法
指令微调提升模型根据特定用户指令理解和生成响应的能力,最适合需要处理多种任务的模型,以提高其灵活性和交互质量。而分类微调则更适合需要将数据精确分类为预定义类别的项目,如情感分析或垃圾邮件检测。
虽然指令微调更具通用性,但它需要更大的数据集和更多的计算资源来开发能够熟练处理各种任务的模型。相比之下,分类微调所需的数据和计算资源较少,但其应用范围仅限于模型训练时涉及的特定类别。
准备数据集
我们将修改并对之前实现和预训练的GPT模型进行分类微调。首先,我们将下载并准备数据集,如图6.4所示。为了提供一个直观且有用的分类微调示例,我们将使用一个包含垃圾短信和非垃圾短信的文本消息数据集。
注意 文本消息通常是通过手机发送的,而非电子邮件。然而,电子邮件分类的步骤也是相同的,感兴趣的读者可以在附录B找到电子邮件垃圾分类数据集的链接。
第一步是下载数据集。
代码示例 6.1 下载并解压数据集
import urllib.request
import zipfile
import os
from pathlib import Path
url = "https://archive.ics.uci.edu/static/public/228/sms+spam+collection.zip"
zip_path = "sms_spam_collection.zip"
extracted_path = "sms_spam_collection"
data_file_path = Path(extracted_path) / "SMSSpamCollection.tsv"
def download_and_unzip_spam_data(
url, zip_path, extracted_path, data_file_path):
if data_file_path.exists():
print(f"{data_file_path} already存在,跳过下载和解压.")
return
with urllib.request.urlopen(url) as response: #1
with open(zip_path, "wb") as out_file:
out_file.write(response.read())
with zipfile.ZipFile(zip_path, "r") as zip_ref: #2
zip_ref.extractall(extracted_path)
original_file_path = Path(extracted_path) / "SMSSpamCollection"
os.rename(original_file_path, data_file_path) #3
print(f"文件已下载并保存为 {data_file_path}")
download_and_unzip_spam_data(url, zip_path, extracted_path, data_file_path)
#1 下载文件
#2 解压文件
#3 添加 .tsv
文件扩展名
执行上述代码后,数据集将被保存为一个制表符分隔的文本文件,名为SMSSpamCollection.tsv
,存储在sms_spam_collection
文件夹中。我们可以将其加载到pandas DataFrame中,如下所示:
import pandas as pd
df = pd.read_csv(
data_file_path, sep="\t", header=None, names=["Label", "Text"]
)
df #1
#1 在Jupyter notebook中渲染数据框架。或者,使用print(df)
来查看数据。
图6.5展示了垃圾短信数据集的数据框架。
让我们检查一下类别标签的分布:
print(df["Label"].value_counts())
执行前面的代码后,我们发现数据集中“ham”(即非垃圾邮件)的数量远远多于“spam”:
Label
ham 4825
spam 747
Name: count, dtype: int64
为了简单起见,同时也因为我们更喜欢较小的数据集(这样可以更快地微调LLM),我们选择对数据集进行欠采样,使每个类别包含747个实例。
注意 还有许多其他方法来处理类别不平衡,但这些超出了本书的范围。感兴趣的读者可以在附录B中找到更多关于处理不平衡数据的方法。
我们可以使用以下代码来进行欠采样并创建一个平衡的数据集。
代码示例 6.2 创建一个平衡的数据集
def create_balanced_dataset(df):
num_spam = df[df["Label"] == "spam"].shape[0] #1
ham_subset = df[df["Label"] == "ham"].sample(
num_spam, random_state=123
) #2
balanced_df = pd.concat([
ham_subset, df[df["Label"] == "spam"]
]) #3
return balanced_df
balanced_df = create_balanced_dataset(df)
print(balanced_df["Label"].value_counts())
#1 计算“spam”实例的数量
#2 随机采样“ham”实例以匹配“spam”实例的数量
#3 将“ham”子集与“spam”实例组合
执行完上述代码后,我们可以看到现在数据集中垃圾短信和非垃圾短信的数量相等:
Label
ham 747
spam 747
Name: count, dtype: int64
接下来,我们将字符串形式的类别标签“ham”和“spam”分别转换为整数标签0和1:
balanced_df["Label"] = balanced_df["Label"].map({"ham": 0, "spam": 1})
此过程类似于将文本转换为标记ID。然而,这里我们不是使用包含超过50,000个词的GPT词汇表,而是只处理两个标记ID:0和1。
接下来,我们创建一个random_split
函数,将数据集分为三个部分:70%用于训练,10%用于验证,20%用于测试。(这些比例在机器学习中很常见,用于训练、调整和评估模型。)
代码示例 6.3 数据集划分
def random_split(df, train_frac, validation_frac):
df = df.sample(
frac=1, random_state=123
).reset_index(drop=True) #1
train_end = int(len(df) * train_frac) #2
validation_end = train_end + int(len(df) * validation_frac) #3
train_df = df[:train_end]
validation_df = df[train_end:validation_end]
test_df = df[validation_end:]
return train_df, validation_df, test_df
train_df, validation_df, test_df = random_split(
balanced_df, 0.7, 0.1) #4
#1 随机打乱整个DataFrame
#2 计算数据集划分的索引
#3 将DataFrame划分为训练、验证和测试集
#4 测试集的大小为剩余部分,即20%
让我们将数据集保存为CSV(逗号分隔值)文件,以便以后可以重复使用:
train_df.to_csv("train.csv", index=None)
validation_df.to_csv("validation.csv", index=None)
test_df.to_csv("test.csv", index=None)
到目前为止,我们已经下载了数据集,将其平衡,并将其分为训练集和评估集。接下来我们将设置用于训练模型的PyTorch数据加载器。
创建数据加载器
我们将开发与之前处理文本数据时概念上类似的PyTorch数据加载器。之前,我们使用滑动窗口技术生成了大小统一的文本块,然后将它们分组为批次,以提高模型训练的效率。每个块都作为单独的训练实例。然而,现在我们正在处理一个包含不同长度短信的垃圾短信数据集。为了像处理文本块一样批量处理这些短信,我们有两个主要选择:
- 将所有消息截断为数据集中或批次中最短消息的长度。
- 将所有消息填充到数据集中或批次中最长消息的长度。
第一个选项计算开销较低,但如果较短的消息比平均或最长消息小得多,可能会导致重要信息的丢失,从而降低模型性能。因此,我们选择第二个选项,保留所有消息的完整内容。
为了实现批处理,我们将所有较短的消息填充到与数据集中最长消息相同的长度。为此,我们将添加填充标记"<|endoftext|>"
。
不过,与其直接将字符串"<|endoftext|>"
附加到每条消息后面,我们可以将与"<|endoftext|>"
对应的标记ID添加到编码的消息中,如图6.6所示。"<|endoftext|>"
的标记ID是50256。我们可以通过使用之前使用的tiktoken
包中的GPT-2分词器来对"<|endoftext|>"
进行编码,来验证该标记ID是否正确:
import tiktoken
tokenizer = tiktoken.get_encoding("gpt2")
print(tokenizer.encode("<|endoftext|>", allowed_special={"<|endoftext|>"}))
确实,执行前面的代码返回 [50256]。
首先,我们需要实现一个PyTorch Dataset
类,它定义了如何加载和处理数据,之后才能实例化数据加载器。为此,我们定义了 SpamDataset
类,该类实现了图6.6中的概念。SpamDataset
类处理几个关键任务:它识别训练数据集中最长的序列,对短信进行编码,并确保所有其他序列都填充填充标记以匹配最长序列的长度。
代码示例 6.4 设置PyTorch Dataset
类
import torch
from torch.utils.data import Dataset
class SpamDataset(Dataset):
def __init__(self, csv_file, tokenizer, max_length=None,
pad_token_id=50256):
self.data = pd.read_csv(csv_file) #1
self.encoded_texts = [
tokenizer.encode(text) for text in self.data["Text"]
]
if max_length is None:
self.max_length = self._longest_encoded_length()
else:
self.max_length = max_length #2
self.encoded_texts = [
encoded_text[:self.max_length]
for encoded_text in self.encoded_texts
]
self.encoded_texts = [
encoded_text + [pad_token_id] *
(self.max_length - len(encoded_text))
for encoded_text in self.encoded_texts
] #3
def __getitem__(self, index):
encoded = self.encoded_texts[index]
label = self.data.iloc[index]["Label"]
return (
torch.tensor(encoded, dtype=torch.long),
torch.tensor(label, dtype=torch.long)
)
def __len__(self):
return len(self.data)
def _longest_encoded_length(self):
max_length = 0
for encoded_text in self.encoded_texts:
encoded_length = len(encoded_text)
if encoded_length > max_length:
max_length = encoded_length
return max_length
#1 对文本进行预编码
#2 如果序列长度超过 max_length
,则截断
#3 将序列填充到最长的序列长度
SpamDataset
类从我们之前创建的CSV文件中加载数据,使用 tiktoken
中的 GPT-2 分词器对文本进行分词,并允许我们根据最长序列或预定义的最大长度填充或截断序列。这确保了每个输入张量的大小相同,这对于我们接下来实现的训练数据加载器中的批处理是必要的:
train_dataset = SpamDataset(
csv_file="train.csv",
max_length=None,
tokenizer=tokenizer
)
最长序列的长度存储在数据集的 max_length
属性中。如果你想查看最长序列的标记数量,可以使用以下代码:
print(train_dataset.max_length)
代码输出120,表示最长的序列不超过120个标记,这是短信常见的长度。模型能够处理最多1,024个标记的序列,这是其上下文长度限制。如果数据集中包含更长的文本,可以在创建训练数据集时传递 max_length=1024
,以确保数据不会超过模型支持的输入(上下文)长度。
接下来,我们对验证集和测试集进行填充,使其长度与最长的训练序列匹配。重要的是,任何超过最长训练示例长度的验证集和测试集样本都将通过 encoded_text[:self.max_length]
进行截断,这在我们之前定义的 SpamDataset
代码中进行了处理。这个截断是可选的;只要验证集和测试集中的序列不超过1,024个标记,你可以将 max_length=None
应用于这些集:
val_dataset = SpamDataset(
csv_file="validation.csv",
max_length=train_dataset.max_length,
tokenizer=tokenizer
)
test_dataset = SpamDataset(
csv_file="test.csv",
max_length=train_dataset.max_length,
tokenizer=tokenizer
)
练习 6.1 增加上下文长度
将输入填充到模型支持的最大标记数,观察这如何影响预测性能。
使用这些数据集作为输入,我们可以像处理文本数据时一样实例化数据加载器。然而,在这种情况下,目标是类别标签,而不是文本中的下一个标记。例如,如果我们选择批次大小为8,则每个批次将由8个长度为120的训练样本及其对应的类别标签组成,如图6.7所示。
以下代码创建了训练集、验证集和测试集的数据加载器,每次以大小为8的批次加载短信和标签。
代码示例 6.5 创建 PyTorch 数据加载器
from torch.utils.data import DataLoader
num_workers = 0 #1
batch_size = 8
torch.manual_seed(123)
train_loader = DataLoader(
dataset=train_dataset,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers,
drop_last=True,
)
val_loader = DataLoader(
dataset=val_dataset,
batch_size=batch_size,
num_workers=num_workers,
drop_last=False,
)
test_loader = DataLoader(
dataset=test_dataset,
batch_size=batch_size,
num_workers=num_workers,
drop_last=False,
)
#1 此设置确保与大多数计算机兼容。
为了确保数据加载器正常工作并返回预期大小的批次,我们迭代训练加载器并打印最后一个批次的张量维度:
for input_batch, target_batch in train_loader:
pass
print("Input batch dimensions:", input_batch.shape)
print("Label batch dimensions", target_batch.shape)
输出结果为:
Input batch dimensions: torch.Size([8, 120])
Label batch dimensions torch.Size([8])
如我们所料,输入批次由八个包含120个标记的训练样本组成。标签张量存储了与这八个训练样本对应的类别标签。
最后,为了了解数据集的大小,我们打印每个数据集中的批次数量:
print(f"{len(train_loader)} training batches")
print(f"{len(val_loader)} validation batches")
print(f"{len(test_loader)} test batches")
每个数据集中的批次数量如下:
130 training batches
19 validation batches
38 test batches
现在我们已经准备好了数据,接下来需要为模型的微调做准备。
初始化具有预训练权重的模型
我们需要为分类微调做好准备,以识别垃圾短信。首先,我们初始化预训练的模型,如图6.8所示。
开始模型准备过程,我们使用了与预训练无标签数据时相同的配置:
CHOOSE_MODEL = "gpt2-small (124M)"
INPUT_PROMPT = "Every effort moves"
BASE_CONFIG = {
"vocab_size": 50257, #1 # 词汇表大小
"context_length": 1024, #2 # 上下文长度
"drop_rate": 0.0, #3 # 丢弃率
"qkv_bias": True #4 # 查询-键-值偏差
}
model_configs = {
"gpt2-small (124M)": {"emb_dim": 768, "n_layers": 12, "n_heads": 12},
"gpt2-medium (355M)": {"emb_dim": 1024, "n_layers": 24, "n_heads": 16},
"gpt2-large (774M)": {"emb_dim": 1280, "n_layers": 36, "n_heads": 20},
"gpt2-xl (1558M)": {"emb_dim": 1600, "n_layers": 48, "n_heads": 25},
}
BASE_CONFIG.update(model_configs[CHOOSE_MODEL])
#1 词汇表大小
#2 上下文长度
#3 丢弃率
#4 查询-键-值偏差
接下来,我们从 gpt_download.py
文件中导入 download_and_load_gpt2
函数,并复用第5章中的 GPTModel
类和 load_weights_into_gpt
函数,将下载的权重加载到 GPT 模型中。
代码示例 6.6 加载预训练的 GPT 模型
from gpt_download import download_and_load_gpt2
from chapter05 import GPTModel, load_weights_into_gpt
model_size = CHOOSE_MODEL.split(" ")[-1].lstrip("(").rstrip(")")
settings, params = download_and_load_gpt2(
model_size=model_size, models_dir="gpt2"
)
model = GPTModel(BASE_CONFIG)
load_weights_into_gpt(model, params)
model.eval()
将模型权重加载到 GPTModel
后,我们可以复用第4章和第5章中的文本生成工具函数,确保模型能够生成连贯的文本:
from chapter04 import generate_text_simple
from chapter05 import text_to_token_ids, token_ids_to_text
text_1 = "Every effort moves you"
token_ids = generate_text_simple(
model=model,
idx=text_to_token_ids(text_1, tokenizer),
max_new_tokens=15,
context_size=BASE_CONFIG["context_length"]
)
print(token_ids_to_text(token_ids, tokenizer))
模型生成的文本输出如下,表明模型权重已正确加载:
Every effort moves you forward.
The first step is to understand the importance of your work
在我们将模型微调为垃圾邮件分类器之前,先看看模型能否通过指令已经识别垃圾邮件:
text_2 = (
"Is the following text 'spam'? Answer with 'yes' or 'no':"
" 'You are a winner you have been specially"
" selected to receive $1000 cash or a $2000 award.'"
)
token_ids = generate_text_simple(
model=model,
idx=text_to_token_ids(text_2, tokenizer),
max_new_tokens=23,
context_size=BASE_CONFIG["context_length"]
)
print(token_ids_to_text(token_ids, tokenizer))
模型输出如下:
Is the following text 'spam'? Answer with 'yes' or 'no': 'You are a winner
you have been specially selected to receive $1000 cash
or a $2000 award.'
The following text 'spam'? Answer with 'yes' or 'no': 'You are a winner
从输出可以看出,模型在遵循指令方面存在困难。这是预期结果,因为模型只经过了预训练,并未进行指令微调。因此,我们将为模型的分类微调做好准备。
添加分类头
我们需要修改预训练的LLM,以便为分类微调做准备。为此,我们将原来的输出层替换掉,原输出层将隐藏表示映射到50,257的词汇表中,而新输出层则映射到两个类别:0(“非垃圾邮件”)和1(“垃圾邮件”),如图6.9所示。我们使用与之前相同的模型,唯一区别是替换了输出层。
输出层节点
技术上来说,我们可以使用单个输出节点来处理二分类任务。然而,这会要求我们修改损失函数,我在《Losses Learned—Optimizing Negative Log-Likelihood and Cross-Entropy in PyTorch》(mng.bz/NRZ2)中对此进行了讨论。因此,我们选择一种更通用的方法,即输出节点的数量与类别的数量相匹配。例如,对于一个三分类问题,如将新闻文章分类为“科技”、“体育”或“政治”,我们将使用三个输出节点,依此类推。
在尝试图6.9所示的修改之前,我们先通过 print(model)
来打印模型的架构:
GPTModel(
(tok_emb): Embedding(50257, 768)
(pos_emb): Embedding(1024, 768)
(drop_emb): Dropout(p=0.0, inplace=False)
(trf_blocks): Sequential(
...
(11): TransformerBlock(
(att): MultiHeadAttention(
(W_query): Linear(in_features=768, out_features=768, bias=True)
(W_key): Linear(in_features=768, out_features=768, bias=True)
(W_value): Linear(in_features=768, out_features=768, bias=True)
(out_proj): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.0, inplace=False)
)
(ff): FeedForward(
(layers): Sequential(
(0): Linear(in_features=768, out_features=3072, bias=True)
(1): GELU()
(2): Linear(in_features=3072, out_features=768, bias=True)
)
)
(norm1): LayerNorm()
(norm2): LayerNorm()
(drop_resid): Dropout(p=0.0, inplace=False)
)
)
(final_norm): LayerNorm()
(out_head): Linear(in_features=768, out_features=50257, bias=False)
)
这个输出清晰地展示了第4章中设计的模型架构。正如之前讨论的,GPTModel
由嵌入层、12个相同的Transformer块(为简洁起见,只展示了最后一个块),最后是 LayerNorm
和输出层 out_head
组成。
接下来,我们将 out_head
替换为一个新的输出层(见图6.9),并对其进行微调。
微调选定的层 vs. 全部层
由于我们是从一个预训练模型开始,并不需要微调所有的模型层。在基于神经网络的语言模型中,底层通常捕捉的是通用的语言结构和语义,适用于各种任务和数据集。因此,通常只需要微调靠近输出层的最后几层,这些层捕捉的是更具体的语言模式和任务相关的特征。这样不仅能够更高效地适应新任务,还能提高计算效率。感兴趣的读者可以在附录B中找到关于微调哪些层的更多信息和实验。
为了让模型准备好进行分类微调,我们首先冻结模型,即将所有层设置为不可训练:
for param in model.parameters():
param.requires_grad = False
然后,我们将输出层(model.out_head
)替换掉,原输出层将输入映射为50,257维,即词汇表的大小(见图6.9)。
代码示例 6.7 添加分类层
torch.manual_seed(123)
num_classes = 2
model.out_head = torch.nn.Linear(
in_features=BASE_CONFIG["emb_dim"],
out_features=num_classes
)
为了让代码更加通用,我们使用 BASE_CONFIG["emb_dim"]
,在 “gpt2-small (124M)” 模型中其值为768。因此,我们也可以使用相同的代码来处理更大的GPT-2模型变体。
这个新的 model.out_head
输出层默认情况下其 requires_grad
属性为 True
,这意味着它是模型中唯一会在训练期间更新的层。从技术上讲,训练我们刚刚添加的输出层已经足够了。然而,正如我在实验中发现的,微调额外的层可以显著提高模型的预测性能。(有关详细信息,请参阅附录B。)我们还将最后一个Transformer块和连接该块到输出层的 LayerNorm
模块设置为可训练,如图6.10所示。
要让最后的 LayerNorm
和最后一个 transformer block 可训练,我们需要将它们的 requires_grad
属性设置为 True
:
for param in model.trf_blocks[-1].parameters():
param.requires_grad = True
for param in model.final_norm.parameters():
param.requires_grad = True
练习 6.2 微调整个模型
与其仅仅微调最后一个 transformer block,不如微调整个模型,并评估其对预测性能的影响。
即使我们添加了一个新的输出层,并将某些层标记为可训练或不可训练,我们仍然可以像以前一样使用这个模型。例如,我们可以将之前使用的相同文本输入模型:
inputs = tokenizer.encode("Do you have time")
inputs = torch.tensor(inputs).unsqueeze(0)
print("Inputs:", inputs)
print("Inputs dimensions:", inputs.shape) #1
#1 shape: (batch_size, num_tokens)
打印输出显示,前面的代码将输入编码为包含四个输入 token 的 tensor:
Inputs: tensor([[5211, 345, 423, 640]])
Inputs dimensions: torch.Size([1, 4])
然后,我们可以像往常一样将编码后的 token ID 传递给模型:
with torch.no_grad():
outputs = model(inputs)
print("Outputs:\n", outputs)
print("Outputs dimensions:", outputs.shape)
输出的 tensor 如下所示:
Outputs:
tensor([[[-1.5854, 0.9904],
[-3.7235, 7.4548],
[-2.2661, 6.6049],
[-3.5983, 3.9902]]])
Outputs dimensions: torch.Size([1, 4, 2])
类似的输入以前会生成一个形状为 [1, 4, 50257]
的输出 tensor,其中 50257
表示词汇表的大小。输出行的数量对应于输入 token 的数量(在本例中为四个)。然而,由于我们替换了模型的输出层,输出的嵌入维度(列数)现在是 2,而不是 50,257。
请记住,我们的目的是微调该模型,以返回一个表示输入是 “spam” 还是 “not spam” 的类别标签。我们不需要微调所有四个输出行,而是可以专注于一个输出 token。特别是,我们将重点关注对应于最后一个输出 token 的最后一行,如图6.11所示。
要从输出 tensor 中提取最后一个输出 token,可以使用以下代码:
print("Last output token:", outputs[:, -1, :])
输出结果为:
Last output token: tensor([[-3.5983, 3.9902]])
我们仍然需要将这些值转换为类别标签的预测结果。但是首先,让我们理解为什么特别关注最后一个输出 token。
我们之前已经探索了注意力机制,它建立了每个输入 token 与其他所有输入 token 之间的关系,并且我们讨论了在类似 GPT 模型中常用的因果注意力掩码的概念(参见第 3 章)。这种掩码限制了一个 token 的关注范围,仅限于其当前位置及之前的位置,确保每个 token 只能受到其自身和之前 token 的影响,如图 6.12 所示。
由于图 6.12 中的因果注意力掩码设置,序列中的最后一个 token 累积了最多的信息,因为它是唯一可以访问所有之前 token 数据的 token。因此,在垃圾邮件分类任务中,我们在微调过程中关注这个最后的 token。
现在我们已经准备好将最后的 token 转换为类别标签预测,并计算模型的初始预测准确率。接下来,我们将微调模型以完成垃圾邮件分类任务。
练习 6.3:微调第一个 vs. 最后一个 token
尝试微调第一个输出 token。注意与微调最后一个输出 token 相比,预测性能的变化。
大模型&AI产品经理如何学习
求大家的点赞和收藏,我花2万买的大模型学习资料免费共享给你们,来看看有哪些东西。
1.学习路线图
第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;
第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;
第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;
第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;
第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;
第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;
第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。
2.视频教程
网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己整理的大模型视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。
(都打包成一块的了,不能一一展开,总共300多集)
因篇幅有限,仅展示部分资料,需要点击下方图片前往获取
3.技术文档和电子书
这里主要整理了大模型相关PDF书籍、行业报告、文档,有几百本,都是目前行业最新的。
4.LLM面试题和面经合集
这里主要整理了行业目前最新的大模型面试题和各种大厂offer面经合集。
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集
👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓