链载Ai

标题: AI 基础知识从 0.3 到 0.4——如何选对深度学习模型? [打印本页]

作者: 链载Ai    时间: 昨天 21:46
标题: AI 基础知识从 0.3 到 0.4——如何选对深度学习模型?

ingFang SC", system-ui, -apple-system, "system-ui", "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-align: justify;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);line-height: 1.75em;visibility: visible;">

沿着 AI 的发展脉络,本系列文章从Seq2Seq到RNN,再到Transformer,直至今日强大的GPT模型,我们将带你一步步深入了解这些关键技术背后的原理与实现细节。无论你是初学者还是有经验的开发者,相信读完这个系列文章后,不仅能掌握Transformer的核心概念,还能对其在整个NLP领域中的位置有一个全面而深刻的认识。那就让我们一起开始这段学习之旅吧!


在深度学习的语境里“模型”是一个高频出现的词汇,我们听说过识别手写数字的 CNN 模型,处理自然语言的 Transformer 模型,还有能写文章、做对话的 GPT 模型,这么多模型我们在解决业务问题时候应该如何做选型?

模型与模型架构

仔细观察还会发现一个问题 —— GPT 模型只有一个,而 CNN、Transformer 却有很多,比如 ResNet、VGG 属于 CNN 家族,BERT、GPT 又都和 Transformer 相关,这些概念之间究竟是怎样的关系?

我们首先需要了解机器学习中两个关键概念——模型架构(Model Architecture)与具体模型(Trained Model)的区别。就像建筑设计中「蓝图」与「建成的房子」的关系 ——CNN 和 Transformer 是模型架构,类似于可复用的「设计蓝图」,允许开发者根据需求调整细节(如层数、参数),从而衍生出无数具体实现;而 GPT 则是基于 Transformer 蓝图构建并训练完成的「成品模型」,是前者的一个典型实例。

以之前讨论的手写数字分类任务为例:

model=keras.Sequential([keras.Input(shape=(28,28,1)),#输入层(图像尺寸)keras.layers.Conv2D(32,(3,3),activation='relu'),#卷积层keras.layers.MaxPooling2D((2,2)),#池化层keras.layers.Flatten(),#展平层keras.layers.Dense(128,activation='relu'),#全连接层keras.layers.Dense(10,activation='softmax')#输出层])

这里定义的是架构,描述了模型的层次、各层的类型、连接方式以及数据流动的路径。它是模型的 “骨架”,决定了模型如何处理输入数据、提取特征以及生成输出。

#训练模型model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])model.fit(train_images.reshape(-1,28,28,1),train_labels,epochs=5,batch_size=32,validation_data=(val_images.reshape(-1,28,28,1),val_labels))

当上述架构通过model.fit()训练后,学习到具体的权重和偏置,也就产生了包含具体参数的模型,能够对新图像进行分类预测。因此可以这样理解

常见模型架构类型

个人理解工程同学首先要对常见的模型眼熟,比如目标检测任务能联想到 CNN、YOLO,这样 AI 就能帮大家开写代码了

卷积神经网络 (Convolutional Neural Networks, CNNs)

CNNs 通过卷积操作高效提取数据的局部空间特征,特别适用于具有网格状结构的数据,如图像。

典型模型:

循环神经网络 (Recurrent Neural Networks, RNNs)

RNNs 通过其循环结构处理序列数据,能够捕捉时间上的依赖关系,适用于需要处理时序信息的任务。

典型模型:

Transformer 模型

Transformer 基于自注意力机制,能够并行处理整个序列,擅长捕捉长距离依赖关系,广泛应用于 NLP 和计算机视觉领域。

典型模型:

生成对抗网络 (Generative Adversarial Networks, GANs)

GANs 通过生成器与判别器的对抗训练,实现高质量数据的生成,广泛应用于生成任务和数据增强。

典型模型:

图神经网络 (Graph Neural Networks, GNNs)

GNNs 专为处理图结构数据设计,通过节点间的连接关系传递和聚合信息,适用于复杂的关系数据。

典型模型:

总结

不同架构因设计原理的差异,在数据处理、特征提取和任务适配上各有专攻,适用于不同类型的任务:

开始选择模型

拿到业务需求、收集数据、确定目标、选择模型架构,就可以开始进行模型训练了,但在机器学习开发的日常实践中,完全 从零开始训练模型的情况已越来越少,大多数开发者会基于任务需求与数据特性,优先选择在预训练模型基础上进行微调优化。这种站在巨人肩膀上的策略,既充分利用了大规模数据预训练积累的通用特征表示,又能通过轻量化的适配过程快速满足特定场景需求。

预训练模型

预训练模型(Pre-trained Models)是在特定模型架构基础上,通过在大规模通用数据集上进行初步训练,学习到通用特征或知识,设定了具体参数的神经网络模型。

比如基于 Transformer 架构的 BERT、GPT 系列模型,基于 CNN 架构的 ResNet-101、VGG16 等,都是预训练模型。这些预训练模型覆盖了自然语言处理、计算机视觉、音频处理、多模态任务和推荐系统等多个领域。开发者可以在Hugging Face Hub、PyTorch Hub、TensorFlow Hub等平台,获取这些预训练模型。

Hugging Face Hub:https://huggingface.co/models

PyTorch Hub:https://pytorch.org/hub/

TensorFlow Hub:https://www.tensorflow.org/hub

现在回头看 GPT (Generative Pre-trained Transformer) 是不是知道大概是什么意思了。

微调 Fine-tuning

因为预训练模型一般使用通用数据集训练,为了更好的支持业务需求,开发者会对预训练模型进行微调。微调是指在预训练模型上,针对特定任务或特定数据集,进行少量参数的调整和训练,以使模型更好地适应新的任务需求。

随着模型规模的不断增大和应用场景的多样化,出现了多种微调方法,以提高效率、减少计算资源消耗或提升模型性能。

1. 标准微调(Standard Fine-tuning)

标准微调是最基本的微调方法,即将预训练模型在特定任务的数据集上进行全量参数的进一步训练。通常情况下,微调时会采用较低的学习率,以避免破坏预训练模型中学到的通用特征。

2. 监督微调(Supervised Fine-Tuning, SFT)

监督微调是在标准微调基础上,利用有标注数据进行进一步训练,旨在提升模型在特定监督任务上的表现。SFT 通常应用于需要明确标签的任务,如分类、序列标注等。

3. 低秩适配(Low-Rank Adaptation, LoRA)

LoRA 是一种 PEFT 的微调方法,通过在预训练模型的权重矩阵中引入低秩矩阵来适配新任务,而无需大幅调整原有模型的参数。这种方法能够显著减少微调过程中新增的参数量,同时保持或提升模型性能。

在矩阵理论中,秩(Rank)指的是矩阵中线性无关行或列的最大数量。一个矩阵的秩决定了其线性独立性的程度。

满秩矩阵:如果一个 m×n 矩阵的秩 r 等于其最小维度 min⁡(m,n),则称其为满秩矩阵。

低秩矩阵:如果一个 m×n 矩阵的秩 r满足 r≪min⁡(m,n),即远小于其最小维度,则称其为低秩矩阵。

4. 知识蒸馏(Knowledge Distillation)

知识蒸馏是通过将大型复杂模型(教师模型)的知识传递给小型高效模型(学生模型),以实现模型压缩和性能优化的技术。尽管知识蒸馏主要用于模型压缩,但它也可以作为微调的一种补充技术,进一步提升模型在特定任务上的表现。

基本原理:

小小成本就能干大事,2025 年初 DeepSeek-R1 横空出世,671B 参数,训练仅消耗 278.8 万 GPU 小时,成本约为 GPT-4 的 1/200。是不是可以理解为什么 OpenAI 会公开质疑 DeepSeek 可能通过蒸馏 “窃取” 其技术成果。

当然已被《DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning》打脸

https://arxiv.org/abs/2501.12948

Hugging face

Hugging Face提供了 模型 + 数据集 + 工具 + 社区 的一站式 AI 开发者平台,无论是想快速调用预训练模型的新手,还是需要大规模分布式训练的企业,都能在平台上找到对应的解决方案:

学习使用的预训练模型及数据集都可以在 Hugging face 获取,也可以瞅瞅ModelScope。

使用预训练模型

IMDB 影评数据集包含 5 万条电影评论(2.5 万训练/2.5 万测试),标注为正面/负面情感,是情感分析领域的标杆数据集。

接下来我们使用预训练的 bert-base-uncased 模型,对 IMDB 电影评论数据集进行情感分析,也就是判断评论是积极的还是消极的

因为需要下载 Hugging face 的数据集与预训练模型,代码本地运行需要保证对 Hugging face 的访问畅通。

导入必要的库

importtorchfromtorch.utils.dataimportDataset,DataLoaderfromtorch.optimimportAdamWfromtransformersimportBertTokenizer,BertForSequenceClassification,get_linear_schedule_with_warmupfromdatasetsimportload_datasetimportnumpyasnpfromsklearn.metricsimportaccuracy_score,f1_score

定义数据集类

IMDBDataset 继承自 PyTorch 的Dataset类,用于封装 IMDB 数据集:

#自定义数据集类:将IMDB数据集转换为PyTorch可用的格式classIMDBDataset(Dataset):"""自定义数据集类,用于处理IMDB电影评论数据参数:dataset:HuggingFace数据集对象tokenizer:BERT分词器max_length:序列最大长度"""def__init__(self,dataset,tokenizer,max_length):self.dataset=dataset#原始数据集self.tokenizer=tokenizer#BERT分词器self.max_length=max_length#序列最大长度def__len__(self):"""返回数据集中样本的数量"""returnlen(self.dataset)def__getitem__(self,idx):"""获取指定索引的数据样本并进行预处理"""#获取文本和标签text=self.dataset[idx]['text']label=self.dataset[idx]['label']#使用BERT分词器对文本进行编码encoding=self.tokenizer.encode_plus(text,add_special_tokens=True,#添加[CLS]和[SEP]特殊标记max_length=self.max_length,#最大序列长度padding='max_length',#填充到最大长度truncation=True,#截断超长序列return_tensors='pt'#返回PyTorch张量)#返回模型所需的输入格式return{'input_ids':encoding['input_ids'].flatten(),#输入ID'attention_mask':encoding['attention_mask'].flatten(),#注意力掩码'labels':torch.tensor(label,dtype=torch.long)#标签}

加载 IMDB 数据集

使用load_dataset从 Hugging Face 的数据集库中加载 IMDB 数据集:

print("1.数据准备阶段")print("正在加载IMDB数据集...")#从HuggingFace加载IMDB电影评论数据集imdb_dataset=load_dataset('imdb')print("成功加载IMDB数据集")

划分训练集和验证集

使用 Hugging Face 数据集库自带的ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;">train_test_split方法,将训练集划分为训练集和验证集,比例为 80% 训练,20% 验证。

#将训练集分割为训练集和验证集(80%-20%分割)print("划分训练集和验证集...")train_val_split=imdb_dataset['train'].train_test_split(test_size=0.2,seed=42)train_data=train_val_split['train']#train_test_split验证集被命名为'test'val_data=train_val_split['test']print(f"训练集样本数:{len(train_data)},验证集样本数:{len(val_data)}")

加载分词器和模型

#2.模型初始化阶段print("2.模型初始化阶段")print("加载BERT模型和分词器...")#加载预训练的BERT分词器和模型tokenizer=BertTokenizer.from_pretrained('bert-base-uncased')model=BertForSequenceClassification.from_pretrained('bert-base-uncased',num_labels=2)print("成功加载BERT模型和分词器")

bert-base-uncased模型,包含 1.1 亿个参数,每个参数通常以 32 位浮点数(FP32) 存储,每个 FP32 占 4 字节,下载和占用磁盘空间 440M 左右。

定义数据集和数据加载器

使用前面定义的IMDBDataset类,将训练集、验证集和测试集封装为 PyTorch 数据集对象。

#设置序列最大长度并创建数据集对象max_length=128print(f"创建数据集对象,序列最大长度:{max_length}")train_dataset=IMDBDataset(train_data,tokenizer,max_length)val_dataset=IMDBDataset(val_data,tokenizer,max_length)test_dataset=IMDBDataset(imdb_dataset['test'],tokenizer,max_length)

max_length=128指定每条文本的最大长度为 128 个 token,超出部分会被截断,未达到的部分会被填充。

#创建数据加载器batch_size=16print(f"创建数据加载器,批次大小:{batch_size}")train_dataloader=DataLoader(train_dataset,batch_size=batch_size,shuffle=True)val_dataloader=DataLoader(val_dataset,batch_size=batch_size,shuffle=False)test_dataloader=DataLoader(test_dataset,batch_size=batch_size,shuffle=False)

shuffle=True表示每个 epoch 前会打乱数据,增强模型的泛化能力。

定义优化器和学习率调度器

#设置优化器和学习率调度器print("配置优化器和学习率调度器")learning_rate=2e-5optimizer=AdamW(model.parameters(),lr=learning_rate)#计算总训练步数num_epochs=3total_steps=len(train_dataloader)*num_epochs#创建学习率调度器,在训练过程中逐步降低学习率scheduler=get_linear_schedule_with_warmup(optimizer,num_warmup_steps=0,num_training_steps=total_steps)

设备设置

检查是否有可用的 GPU(cuda),如果有,则使用 GPU 加速训练,否则使用 CPU。

#设置运行设备(GPU/CPU)device=torch.device('cuda'iftorch.cuda.is_available()else'cpu')print(f"运行设备:{device}")model.to(device)#将模型移动到指定设备

如果没有 GPU 预计需要 3 小时左右跑完。

训练模型

训练三轮,每一轮中先进行训练,再进行验证,计算训练损失、验证损失和验证准确率。如果当前验证准确率超过之前的最佳值,更新best_val_accuracy并保存模型的状态字典到ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;">best_model.pth。

#3.模型训练阶段print("\n3.模型训练阶段")print(f"开始训练,总周期数:{num_epochs}")best_val_accuracy=0forepochinrange(num_epochs):print(f"\n开始第{epoch+1}/{num_epochs}个训练周期")#训练模式model.train()total_train_loss=0print("训练中...")forbatchintrain_dataloader:#将数据移动到指定设备input_ids=batch['input_ids'].to(device)attention_mask=batch['attention_mask'].to(device)labels=batch['labels'].to(device)#清除之前的梯度optimizer.zero_grad()#前向传播outputs=model(input_ids,attention_mask=attention_mask,labels=labels)loss=outputs.losstotal_train_loss+=loss.item()#反向传播loss.backward()#更新参数optimizer.step()scheduler.step()#更新学习率#计算平均训练损失avg_train_loss=total_train_loss/len(train_dataloader)#验证模式print("验证中...")model.eval()#设置为评估模式val_predictions=[]val_true_labels=[]total_val_loss=0withtorch.no_grad():#不计算梯度forbatchinval_dataloader:#将数据移动到指定设备input_ids=batch['input_ids'].to(device)attention_mask=batch['attention_mask'].to(device)labels=batch['labels'].to(device)#前向传播outputs=model(input_ids,attention_mask=attention_mask,labels=labels)loss=outputs.losstotal_val_loss+=loss.item()#获取预测结果logits=outputs.logitspreds=torch.argmax(logits,dim=1)#收集预测结果和真实标签val_predictions.extend(preds.cpu().tolist())val_true_labels.extend(labels.cpu().tolist())#计算验证指标avg_val_loss=total_val_loss/len(val_dataloader)val_accuracy=accuracy_score(val_true_labels,val_predictions)print(f'第{epoch+1}个周期:训练损失={avg_train_loss:.4f},验证损失={avg_val_loss:.4f},验证准确率={val_accuracy:.4f}')#保存最佳模型ifval_accuracy>best_val_accuracy:best_val_accuracy=val_accuracyprint(f"发现更好的模型,保存模型权重(准确率:{val_accuracy:.4f})")torch.save(model.state_dict(),'best_model.pth')

前向传播(Forward Propagation)和反向传播(Backward Propagation)是深度学习中两个至关重要的概念,它们共同构成了神经网络模型训练的核心流程

第 1 个周期: 训练损失 = 0.3398, 验证损失 = 0.2854, 验证准确率 = 0.8792发现更好的模型,保存模型权重 (准确率: 0.8792)
第 2 个周期: 训练损失 = 0.1799, 验证损失 = 0.2949, 验证准确率 = 0.8864发现更好的模型,保存模型权重 (准确率: 0.8864)
第 3 个周期: 训练损失 = 0.0822, 验证损失 = 0.3687, 验证准确率 = 0.8888发现更好的模型,保存模型权重 (准确率: 0.8888)

模型评估

# 4. 模型评估阶段print("\n4. 模型评估阶段")# 加载训练过程中保存的最佳模型print("加载最佳模型权重...")model.load_state_dict(torch.load('best_model.pth'))
# 在测试集上评估模型print("在测试集上评估模型...")model.eval() # 设置为评估模式predictions = []true_labels = []withtorch.no_grad(): # 不计算梯度 forbatchintest_dataloader: # 将数据移动到指定设备 input_ids = batch['input_ids'].to(device) attention_mask = batch['attention_mask'].to(device) labels = batch['labels'].to(device) # 前向传播 outputs = model(input_ids, attention_mask=attention_mask) logits = outputs.logits preds = torch.argmax(logits, dim=1) # 收集预测结果和真实标签 predictions.extend(preds.cpu().tolist()) true_labels.extend(labels.cpu().tolist())
# 计算评估指标accuracy = accuracy_score(true_labels, predictions)f1 = f1_score(true_labels, predictions)print(f'测试集准确率:{accuracy:.4f}')print(f'测试集F1分数:{f1:.4f}')

自定义测试

自定义一个测试函数:

# 定义情感预测函数:用于对新文本进行情感分析defpredict_sentiment(text, tokenizer, model, max_length=128, device='cpu'): """  使用训练好的BERT模型对文本进行情感分析   参数:    text: 要分析的文本字符串    tokenizer: BERT分词器    model: 训练好的BERT模型    max_length: 序列最大长度    device: 运行设备('cpu'或'cuda')     返回:    包含情感预测结果的字典  """ # 预处理文本  encoding = tokenizer.encode_plus(    text,    add_special_tokens=True,    max_length=max_length,    padding='max_length',    truncation=True,    return_tensors='pt'  ) # 将张量移动到指定设备  input_ids = encoding['input_ids'].to(device)  attention_mask = encoding['attention_mask'].to(device)
# 预测阶段 model.eval() # 设置为评估模式 withtorch.no_grad(): # 不计算梯度,节省内存 outputs = model(input_ids, attention_mask=attention_mask) logits = outputs.logits # 转换为概率值 prob = torch.softmax(logits, dim=1).squeeze().cpu().numpy()
# 解析结果 negative_prob = prob[0] # 负面情感概率 positive_prob = prob[1] # 正面情感概率 sentiment ='positive'ifpositive_prob >0.5else'negative'# 情感判断 # 返回预测结果 return{ 'text': text, 'sentiment': sentiment, 'negative_prob':f'{negative_prob:.4f}', 'positive_prob':f'{positive_prob:.4f}' }

对自定义文本进行测试:

#5.自定义文本测试print("\n5.自定义文本测试")print("对自定义文本进行情感分析...")custom_text="Thisfilmisamasterpiece!Thecinematographyandsoundtrackareunparalleled."print(f"输入文本:{custom_text}")result=predict_sentiment(custom_text,tokenizer,model,device=device)print(f"预测结果:{result['sentiment']}(积极概率:{result['positive_prob']},消极概率:{result['negative_prob']})")

输出:

测试集准确率: 0.8857测试集F1分数: 0.8842
5. 自定义文本测试对自定义文本进行情感分析...输入文本: This film is a masterpiece! The cinematography and soundtrack are unparalleled.预测结果: positive (积极概率: 0.9983, 消极概率: 0.0017)

done!

#程序完成print("\n程序执行完毕!")







欢迎光临 链载Ai (https://www.lianzai.com/) Powered by Discuz! X3.5