AI基础知识:深度学习模型架构与微调实战

本文探讨深度学习模型选型、架构与微调,涵盖CNN、Transformer等,并以BERT情感分析实战,助你高效应用AI。

原文标题:AI 基础知识从 0.3 到 0.4——如何选对深度学习模型?

原文作者:阿里云开发者

冷月清谈:

本文旨在帮助读者理解深度学习模型的基础知识及其选型策略,并详细讲解了预训练模型与微调的重要性及方法。文章首先澄清了“模型架构”与“具体模型”的区别,将模型架构比作建筑蓝图(如CNN、Transformer),而具体模型则是训练完成的“成品”(如GPT)。随后,文中列举了卷积神经网络(CNNs)、循环神经网络(RNNs)、Transformer模型、生成对抗网络(GANs)和图神经网络(GNNs)这五种常见模型架构,并针对它们各自的特点和适用场景进行了详细介绍,例如CNNs擅长图像处理,Transformer在NLP和CV领域表现出色。文章指出,在实际机器学习开发中,从零开始训练模型的情况已经越来越少,大多数开发者更倾向于利用预训练模型进行微调优化。预训练模型是在大规模通用数据集上训练好的,学习了通用特征和知识的模型。文章详细阐述了四种微调方法:标准微调、监督微调(SFT)、低秩适配(LoRA)以及知识蒸馏,并分析了它们的优缺点及适用场景,特别是LoRA在减少参数量、知识蒸馏在模型压缩上的优势。最后,文章通过一个IMDB电影评论情感分析的实战案例,演示了如何使用Hugging Face平台、BERT预训练模型进行数据准备、模型初始化、训练和评估的全过程,为读者提供了从理论到实践的完整指导。

怜星夜思:

1、文章里介绍了这么多模型架构,有CNN、RNN、Transformer等等,感觉每个都很厉害。但实际咱们做项目的时候,到底应该怎么选才能找到最适合自己业务需求的模型呢?有没有什么“潜规则”或者大神们的经验分享一下?
2、文章里提到了好几种微调方法,像SFT、LoRA、知识蒸馏,感觉都挺有用的。但如果我的项目预算有限,数据量也不大,那种微调方式最适合我这种“小作坊”呢?有没有什么推荐的?
3、文章里提到了DeepSeek和OpenAI的“蒸馏争议”,这让我想到了一个问题:既然大家都在用预训练模型,那模型训练过程中用的数据会不会有版权问题?要是用了别人的预训练模型,结果被反过来质疑“偷”技术,企业该怎么规避这种风险?

原文内容

【系列文章】

 
 

沿着 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 通过卷积操作高效提取数据的局部空间特征,特别适用于具有网格状结构的数据,如图像。

典型模型:

  • LeNet-5早期的 CNN,用于手写数字识别。

  • AlexNet在 ImageNet 竞赛中显著提升图像分类性能,推动深度学习的发展。

  • VGGNet通过加深网络(如 VGG16、VGG19)提升性能。

  • ResNet (Residual Networks)引入残差模块,解决深层网络的梯度消失问题。

  • EfficientNet通过复合缩放方法优化模型规模与性能平衡。

  • YOLO(You Only Look Once)为目标检测设计,提供了图像分类、目标检测、实例分割、关键点检测等任务支持

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

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

典型模型:

  • 标准RNN基础循环网络,存在梯度消失问题。

  • 长短期记忆网络 (Long Short-Term Memory, LSTM)引入门控机制,解决梯度消失问题。

  • 门控循环单元 (Gated Recurrent Units, GRU)结构更简洁,计算效率更高,功能类似于LSTM。

  • 双向 RNN (Bi-directional RNNs)双向处理序列,提高信息捕捉能力。

Transformer 模型

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

典型模型:

  • Transformer (原始模型)用于机器翻译任务。

  • BERT (Bidirectional Encoder Representations from Transformers)预训练语言模型,用于多种 NLP 任务。

  • GPT (Generative Pre-trained Transformer) 系列用于文本生成、对话系统等。

  • Vision Transformer (ViT)将 Transformer 应用于图像分类。

  • DETR (DEtection TRansformer)用于目标检测任务。

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

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

典型模型:

  • 原始 GAN最基础的生成对抗框架。

  • DCGAN (Deep Convolutional GAN)结合卷积神经网络提升图像生成效果。

  • StyleGAN生成高质量的人脸图像,并可控制样式特征。

  • CycleGAN实现无监督的图像到图像转换,如马到斑马。

  • BigGAN大规模GAN模型,提升生成图像的质量与多样性。

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

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

典型模型:

  • Graph Convolutional Networks (GCNs)基于图卷积操作进行特征提取。

  • Graph Attention Networks (GATs)引入注意力机制,动态分配邻居节点的权重。

  • GraphSAGE通过采样邻居节点,实现大规模图数据的高效训练。

总结

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

  • 计算机视觉CNN、ResNet、ViT(Vision Transformer)

  • 自然语言处理RNN、LSTM、GRU、Transformer(如 BERT、GPT)

  • 生成任务GAN、VAE

  • 图结构数据GNN、GCN

  • 序列与时间数据RNN、LSTM、GRU、Transformer

开始选择模型

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

预训练模型

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

比如基于 Transformer 架构的 BERT、GPT 系列模型,基于 CNN 架构的 ResNet-101、VGG16 等,都是预训练模型。这些预训练模型覆盖了自然语言处理、计算机视觉、音频处理、多模态任务和推荐系统等多个领域。开发者可以在 Hugging Face HubPyTorch HubTensorFlow 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),即远小于其最小维度,则称其为低秩矩阵。

  • 低秩矩阵:在保持模型表现的同时,通过引入低秩矩阵在特定层(如 Transformer 的自注意力层)中调整权重。

  • 参数冻结预训练模型的原始参数冻结,仅训练新增的低秩矩阵参数。

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 开发者平台,无论是想快速调用预训练模型的新手,还是需要大规模分布式训练的企业,都能在平台上找到对应的解决方案:

  • 海量预训练模型提供超过 10 万 + 预训练模型,支持 NLP、计算机视觉、语音处理、多模态等任务,覆盖分类、生成、翻译、摘要、问答等多种场景。

  • 丰富的公开数据集收录超 5 万 + 公开数据集,涵盖文本、图像、语音、表格等类型,如 IMDB 影评、MNIST、COCO、维基百科等,支持一键加载。

  • 数据处理工具提供 datasets 库,支持数据清洗、预处理、分拆(如训练集 / 验证集 / 测试集),兼容多种格式(CSV、JSON、Parquet 等)。

  • 快速部署演示通过 “Hugging Face Spaces”,用户可直接在浏览器中部署模型演示(Demo),支持 Gradio、Streamlit、HTML 等界面,无需复杂服务器配置。

  • 开源生态核心库(Transformers、Datasets 等)完全开源,社区贡献活跃,文档丰富,适合研究者、开发者和企业使用。

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

使用预训练模型

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

  • 文本长度适中(平均 200-300 词),适合验证模型的长文本理解能力。

  • 已完成预处理(去除 HTML 标签、统一格式),可直接使用。

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

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

导入必要的库
import torch
from torch.utils.data import Dataset, DataLoader
from torch.optim import AdamW
from transformers import BertTokenizer, BertForSequenceClassification, get_linear_schedule_with_warmup
from datasets import load_dataset
import numpy as np
from sklearn.metrics import accuracy_score, f1_score
  • torchPyTorch 的核心库。

  • Dataset, DataLoaderDataset 用于定义数据集,DataLoader 用于批量加载数据。

  • AdamW一种基于 Adam 优化器的变体,添加了权重衰减(weight decay)。

  • TransformersHugging Face 提供的预训练模型库

  • BertTokenizer 用于分词

  • BertForSequenceClassification 用于序列分类任务

  • get_linear_schedule_with_warmup 是学习率调度器,线性递减并带有预热阶段

  • datasetsHugging Face 的数据集库,load_dataset 用于加载各种公开数据集。

  • accuracy_score, f1_scoresklearn 提供的评估指标,用于计算准确率和 F1 分数。

定义数据集类

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

# 自定义数据集类:将 IMDB 数据集转换为 PyTorch 可用的格式
class IMDBDataset(Dataset):
    """
    自定义数据集类,用于处理IMDB电影评论数据
    
    参数:
        dataset: Hugging Face数据集对象
        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):
        """返回数据集中样本的数量"""
        return len(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 数据集...")
# 从 Hugging Face 加载 IMDB 电影评论数据集
imdb_dataset = load_dataset('imdb')
print("成功加载 IMDB 数据集")
划分训练集和验证集

使用 Hugging Face 数据集库自带的 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 模型和分词器")
  • 分词器 (BertTokenizer):

  • 加载预训练的 bert-base-uncased 分词器,该分词器将文本分割成小的词片段,并将其转换为对应的词汇表索引。

  • uncased 表示分词器会将文本转换为小写,忽略大小写信息。

  • 模型 (BertForSequenceClassification):

  • 加载预训练的 bert-base-uncased 模型,并在顶部添加一个用于序列分类的全连接层。

  • num_labels=2 表示分类任务有两个类别(正面和负面)。

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

定义数据集和数据加载器

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

# 设置序列最大长度并创建数据集对象
max_length = 128
print(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 = 16
print(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-5
optimizer = AdamW(model.parameters(), lr=learning_rate)
# 计算总训练步数
num_epochs = 3
total_steps = len(train_dataloader) * num_epochs
# 创建学习率调度器,在训练过程中逐步降低学习率
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=total_steps)
  • 使用 AdamW 优化器,根据损失函数的梯度信息,调整模型参数(如权重、偏置),以最小化损失函数。

  • get_linear_schedule_with_warmup 创建一个线性学习率调度器,该调度器会在训练过程中逐步调整学习率,帮助模型更好地收敛

  • num_warmup_steps=0: 无预热阶段,从一开始就使用线性递减。

  • num_training_steps=total_steps: 总训练步数,等于每个 epoch 的步数乘以 epoch 数。

设备设置

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

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

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

训练模型

训练三轮,每一轮中先进行训练,再进行验证,计算训练损失、验证损失和验证准确率。如果当前验证准确率超过之前的最佳值,更新 best_val_accuracy 并保存模型的状态字典到 best_model.pth

# 3. 模型训练阶段
print("\n3. 模型训练阶段")
print(f"开始训练,总周期数: {num_epochs}")
best_val_accuracy = 0
for epoch in range(num_epochs):
    print(f"\n开始第 {epoch + 1}/{num_epochs} 个训练周期")
    
    # 训练模式
    model.train()
    total_train_loss = 0
    print("训练中...")
    for batch in train_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.loss
        total_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 = 0
    with torch.no_grad():  # 不计算梯度
        for batch in val_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.loss
            total_val_loss += loss.item()
            
            # 获取预测结果
            logits = outputs.logits
            preds = 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}')
    
    # 保存最佳模型
    if val_accuracy > best_val_accuracy:
        best_val_accuracy = val_accuracy
        print(f"发现更好的模型,保存模型权重 (准确率: {val_accuracy:.4f})")
        torch.save(model.state_dict(), 'best_model.pth')

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

  • 前向传播是指将输入数据(代码中的 input_ids 和 attention_mask)依次通过神经网络的各个层,经过一系列的线性变换和非线性激活函数处理,最终得到模型的预测输出。

  • 反向传播是在得到损失值之后,通过链式法则计算损失函数对模型中每个参数的梯度。通过计算梯度,可以知道应该如何调整模型的参数,使得损失函数的值减小,从而提高模型的性能。

第 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 =
with torch.no_grad():  # 不计算梯度
    for batch in test_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}’)

自定义测试

自定义一个测试函数:

# 定义情感预测函数:用于对新文本进行情感分析
def predict_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()  # 设置为评估模式
    with torch.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’if positive_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 = "This film is a masterpiece! The cinematography and soundtrack are unparalleled."
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
  1. 自定义文本测试
    对自定义文本进行情感分析…
    输入文本: This film is a masterpiece! The cinematography and soundtrack are unparalleled.
    预测结果: positive (积极概率: 0.9983, 消极概率: 0.0017)
done!
# 程序完成
print("\n程序执行完毕!")

与 AI 智能体进行实时音视频通话


AI 实时音视频互动是一种旨在帮助企业快速构建 AI 与用户之间的视频或语音通话应用的解决方案。用户只需通过白屏化的界面操作,即可快速构建一个专属的AI智能体,并通过视频云 ARTC 网络与终端用户进行实时交互。


点击阅读原文查看详情。


作为一个吃瓜群众兼AI爱好者,我觉得“蒸馏争议”这种事儿,大部分还是大公司之间的商业博弈,就像武林高手过招,互相给对方找点不痛快。对我们小老百姓或者小公司来说,这种风险该怎么规避呢?我觉得最重要的就是站稳脚跟,别作死。啥叫不作死?就是别去用那些来源不明、版权模糊的数据去训练你的核心模型。然后,用别人开源的预训练模型,就得把它的许可证看清楚了,能商用、能改、能再分发的,你就大胆用。至于『偷技术』这种高帽,除非你模型真的牛到动了人家的奶酪,不然谁有空盯着你?但话说回来,咱们在搞技术的时候,心里还是得有杆秤,尽量合规,避免不必要的麻烦。毕竟,AI发展速度太快,法律法规根本跟不上,所以还是得靠自觉和行业共识。

哎呀,预算有限数据量又不大,这简直是咱们“小作坊”的日常!别纠结了,这种情况下,我绝对推荐你用LoRA!它简直是为咱们这种穷人量身定做的。你想啊,它不用动原模型的大部分参数,就加一点点“外挂”,然后只训练这些小外挂就行了。这样不仅省显存、省时间,还不容易把模型训废了。SFT那种全量微调,模型小点还行,稍微大一点就直接爆显存了,而且数据少还容易过拟合。知识蒸馏嘛,那是模型上线部署之前用来压缩模型的,咱们还没到那一步呢,而且你得先有个“大牛”老师模型才行。所以,LoRA大法好,谁用谁知道!

对于“项目预算有限,数据量也不大”的情况,选择微调方法确实需要精打细算。我个人的理解是,可以从数据特性和模型用途出发。如果数据量确实非常小,且任务与预训练模型的通用任务有一定差异,LoRA(低秩适配)是极具吸引力的选择。它在参数效率和性能之间取得了很好的平衡,能让你用更少的资源达到不错的微调效果。而如果你的目标是部署一个非常轻量级的模型,并且你可以接受略低于原大模型的性能,同时有条件获取或自建一个强大的教师模型进行指导,那么知识蒸馏也是一个非常有效的路径,它可以将大模型的“知识”高效迁移给小模型。SFT(监督微调)虽然直接,但对于小数据量场景,需警惕过拟合风险,可能需要更精细的学习率策略和更多的调优。总的来说,LoRA在你的场景下性价比最高。

管他什么CNN、RNN、Transformer,我个人觉得最重要的“潜规则”就是:先跑个baseline!别一开始就想着一步到位,用最先进最复杂的模型。先拿个最简单、最容易实现的模型跑起来,看看效果怎么样。比如情感分析就BERT微调一下,图片分类就ResNet起步。效果不行再一步步优化,加上PEFT啊、知识蒸馏啊啥的。数据量大不大、模型效果要求高不高、有没有GPU,这些都是影响你选择的因素。对了,还有一点很重要,看看你团队里有没有人熟悉特定模型,有经验的人能给你省老多事了。别为了追求“高大上”结果把自己坑了!

这个问题问得好,现在AI圈子里最怕的就是“训练数据”和“模型产出”的灰色地带。就“数据版权”来说,肯定有!你用网上的图片、文章去训练模型,那些内容的版权就在原作者手里啊。所以,负责任的做法是尽量用那些公开的数据集,或者有授权的数据。至于“被质疑偷技术”嘛,就像这次DeepSeek和OpenAI的事件,很多时候是商业竞争的一部分,但也确实给咱们敲了警钟。规避风险?最简单粗暴但也最有效的办法就是:优先选择那些明确标明可以商业使用、可以基于它进行二次开发甚至『蒸馏』的开源模型。然后,内部开发过程要尽量透明,保留好每一步的记录,比如用了什么数据集,模型的哪个版本,做了哪些修改。万一真出事儿了,也能有理有据地回应。毕竟,真金不怕火炼,但你得有“真金”的凭证不是?

针对“文章里介绍了这么多模型架构,有CNN、RNN、Transformer等等,感觉每个都很厉害。但实际咱们做项目的时候,到底应该怎么选才能找到最适合自己业务需求的模型呢?有没有什么“潜规则”或者大神们的经验分享一下?”这个问题,我的经验是,首要任务是深入理解你的“数据特性”和“任务目标”。比如,你的数据是图像、文本序列还是图结构?任务是分类、生成还是预测?如果是图像,CNN或ViT是首选;如果是长序列文本且需要捕捉长距离依赖,Transformer系列无疑是最好的选择。其次,考虑“计算资源”和“实时性要求”,大型模型效果虽好,但部署成本高、推理慢。最后是“可解释性”需求,在某些重要领域,透明度比极致性能更重要。多看看SOTA论文和开源项目如何解决类似问题,很有参考价值。

关于“项目预算有限,数据量也不大”的情况下选择微调方式的问题,从效率和资源消耗角度看,LoRA(低秩适配)是你的首选。LoRA通过引入低秩矩阵进行微调,显著减少了需要训练的参数量,从而大大降低了计算资源需求和存储空间,同时又能保持甚至提升模型性能。对于小数据量,全量微调(SFT)很容易过拟合,LoRA在这方面表现更好。知识蒸馏虽然也能得到小模型,但它需要一个高性能的教师模型(通常是大模型)来指导学生模型学习,这本身就可能涉及前期训练大模型的成本,或者找到一个合适的预训练大模型也需要考量。所以,如果目标是快速且高效地在特定小数据集上优化预训练模型,强烈推荐探索LoRA等PEFT(Parameter-Efficient Fine-Tuning)方法。

回答“既然大家都在用预训练模型,那模型训练过程中用的数据会不会有版权问题?要是用了别人的预训练模型,结果被反过来质疑‘偷’技术,企业该怎么规避这种风险?”这个问题,确实触及了AI领域的法律和伦理前沿。首先,模型训练数据的版权问题是存在的,尤其当数据来源于网络抓取时,可能涉及个人隐私和版权侵犯。使用预训练模型本身,通常需遵守其许可协议(如Apache 2.0, MIT等),这些协议通常允许商业使用和修改。但“蒸馏争议”的出现,则更进一步引出了“模型产出物”的知识产权问题。企业规避风险的核心在于:1. 合法合规的数据源:确保训练数据或用于微调的数据来源合法,避免使用未经授权、侵犯版权或隐私的数据。2. 明确许可的预训练模型:优先选择那些开源许可明确、允许商业使用和二次开发甚至蒸馏的模型。3. 模型可追溯性:尽可能追踪模型的训练过程、数据来源和使用的工具,以便在争议时提供证据。4. 法律咨询:在涉及核心业务或敏感数据时,寻求专业法律意见,建立内部的AI伦理和合规审查机制。

作为一名AI技术爱好者,被问到“应该怎么选才能找到最适合自己业务需求的模型”这个问题,我的小秘密是:看预算,看老板的需求,然后去Hugging Face Hub上逛一圈!开玩笑啦,不过这确实反映了实际情况。最实际的经验就是:找到你的业务场景最接近的公开数据集和SOTA模型,然后直接用它们的预训练模型微调,这是最快见效的办法。如果实在找不到特别匹配的,那就从最经典的通用架构(比如BERT for NLP,ResNet for CV)开始魔改。毕竟,站在巨人的肩膀上总是没错的。再不行,就多跟同行交流,或者看看最新的技术博客,跟着大厂的趋势走,大概率不会错。