一、学习路径

既然本项目班的最终目的是考研复试使用,那就有必要按照复试的思路重新整理一下知识,重点谈理论。

  • 线性回归:本节的核心在于初识梯度下降算法。
  • 回归实战:本节重点在于初识“数据”、“模型”、“超参数和训练流程”的模块化结构
  • 图像分类知识实战:这部分我们学习了卷积神经网络模型并实战,核心在于理解卷积神经网络的结构以及网络参数的计算
  • 无监和自监督督学习:主要介绍了如何在没有数据的情况下,自行学习数据特征
  • 自然会语言处理知识实战:这部分我们初识Transformer框架,并基于其Encoder部分学习了Bert模型并实战,我们需要基于Transformer理解Bert的模型结构,并重点理解注意力机制
  • 文字生成:其实就是学习Transformer的Decoder部分,实战使用了Bart模型
  • 大模型

二、核心知识回顾

2.1 前馈神经网络FNN重点

梯度下降算法

梯度下降是深度学习的核心,我们知道,梯度是一个向量,而向量都有方向,梯度的反方向就是函数下降最快的方向。在深度学习中,我们会构造一个损失函数,用来施加惩罚力度,损失函数值越大,惩罚力度越大,模型为了避免受到处罚,就需要沿着梯度的方向下降,具体做法是:

  • 前向传播: 是「线性变换(权重矩阵运算) + 非线性激活」的逐层计算过程,最终输出模型预测值
  • 反向传播: 计算损失函数梯度,得到损失函数每个参数下降的梯度,
  • 参数更新: 按照公式新参数 = 旧参数 - 学习率(lr) × 损失对该参数的梯度更新参数(实战中adam算法会更新lr)。
  • 重复迭代,直到参数无明显下降
算法名称 核心逻辑 优点 缺点 适用场景
批量梯度下降(BGD) 全部样本算梯度,再更新参数 梯度准确,收敛稳定 数据量大时速度极慢、耗内存 小数据集(样本数<1 万)
随机梯度下降(SGD) 单个样本算梯度,立刻更新参数 速度快,能跳出局部最优 梯度震荡,收敛不稳定 大数据集,追求训练效率
小批量梯度下降(Mini-Batch SGD) 一小批样本(如 32/64/128)算梯度,再更新参数 平衡速度和稳定性(最优折中) 需要调 batch_size 绝大多数深度学习场景(通用)
自适应优化器(Adam/AdamW) 在 Mini-Batch SGD 基础上,动态调整学习率(结合动量 + 自适应步长) 收敛最快、最稳定,调参简单 极少数场景下泛化性略差 分类 / 回归 / 大模型预训练(首选)

常用激活函数

激活函数 公式 用途 描述
ReLU max(0,x) 隐藏层 计算快、收敛快、梯度稳定
Tanh tanh ⁡ ( x ) = e x − e − x e x + e − x \tanh(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}} tanh(x)=ex+exexex 隐藏层 -
Sigmoid σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+ex1 二分类输出层 输出可看作概率
Softmax Softmax ( x i ) = e x i ∑ j e x j \text{Softmax}(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}} Softmax(xi)=jexjexi 多分类输出层 输出标准概率分布

常用损失函数

我上网查了一下还不少,但是项目里好像就用过MSE和CrossEntropy

损失函数 英文 公式 适用任务 特点
均方误差 MSE L = 1 N ∑ ( y p r e d − y t r u e ) 2 L = \frac{1}{N}\sum (y_{pred} - y_{true})^2 L=N1(ypredytrue)2 回归 梯度稳定,对大误差惩罚重,受异常值影响大
平均绝对误差 MAE L = 1 N ∑ y p r e d − y t r u e L = \frac{1}{N}\sum y_{pred} - y_{true} L=N1ypredytrue 回归 对异常值稳健,零点不可导
平滑L1损失 SmoothL1 小误差用MSE,大误差用MAE 回归、目标检测 兼顾稳定与抗异常
交叉熵损失 CrossEntropy L = − ∑ y t r u e log ⁡ ( y p r e d ) L = -\sum y_{true}\log(y_{pred}) L=ytruelog(ypred) 多分类 自带Softmax,训练快,最常用
二分类交叉熵 BCE L = − [ y log ⁡ y ^ + ( 1 − y ) log ⁡ ( 1 − y ^ ) ] L = -[y\log\hat{y}+(1-y)\log(1-\hat{y})] L=[ylogy^+(1y)log(1y^)] 二分类 配合Sigmoid使用
带权重交叉熵 WeightedCrossEntropy 给少类别加权重 样本不均衡分类 缓解类别不平衡

回归是连续值,分类是概率向量

2.2 卷积神经网络

我复试打算用bert,所以卷积就简单点过一下好了,基本没什么关系,等复试之后再详细整理

卷积神经网络结构

卷积神经网络由卷积部分(特征提取器)+ 全连接部分(分类 / 回归头)构成
卷积部分实现图片
特征提取
,是利用卷积核压缩,激活,池化然后展平的过程
全连接部分就是加一个全连接头

2.3 Transfomer

transformer的结构

在这里插入图片描述

transformer包含encoderdecoder两部分,先只看encoder。
encoder将输入inputs通过词表映射为inputs embedding,然后复合positional encoding,输入一个N层的网络,每一层的网络都是相同的。网络内部采用了残差连接多头自注意力机制归一化前馈神经网络,在这个过程中,词向量融合了非常多的语义,以及做了很多设计,我们跟着transformer给出的流程来一点点梳理:

  • inputs是一个自然语言形式输入的句子,我们通过查词表,将其转换为向量形式,并填充或裁剪,让其形状适合网络[batch_size, seq_len]
    接下来,我们为句子向量设计位置向量,并直接相加,这样就为句子向量融合了位置信息
  • 接下来,通过多头自注意力机制,将注意力头分为多个头,通过分头,模型可以学习更多维度的关系,例如指代关系,语法关系,局部搭配等,它们隶属于不同的注意力头
  • 同时,自注意力这里还要完成Q、K、V的计算,Q代表查询权重,K代表键权重,V代表值权重,所以在计算出一个字的注意力矩阵时,实际上是完成了字自身的意义字和其他字的关系的融合。值得一提的是,我们实际训练的其实是V = X × W_V
  • 计算出Q、K、V后,就i可以计算出注意力向量,注意力向量融合了以上的所有关系
  • 接下来进行残差连接和归一化处理
  • 然后将数据传入前馈网络FNN,对每个词融入更高级的特征提取和分类
  • 在transformer中,K和V会被传入decoder,供decoder的Q查询,以及还要传入注意力向量
    这样,大概就是encoder的流程了,接下来的bert就是按照encoder的框架设计的,bert时我复试准备说的项目,需要重点准备

三、基于BERT的中文酒店评论情感分析系统

我准备Bert的核心思路是抓专业名词,抓前因后果,而不必注意具体的数字细节,到时候酒店改下名就行

代码梳理

李哥的代码还是相当规范的。

jiudian.txt

这是数据文件,第一行是 label,review,需要去掉
然后下面的都是具体内容,格式为[0/1],[具体评论],01为标签,是人工做的,0为差评,1为好评,处理时需要将标签和评论分离

data.py

本模块对数据进行预处理:定义了一个JdDaraset类,存储标签和评论;通过按照换行符和第一个逗号进行分割,得到一个标签列表和数据列表;生产训练集和验证集迭代器loader

model.py

本模块主要加载bert预训练模型,完成分词逻辑和分类头编写,并封装好前向传播的过程
加载bert预训练模型:使用网络下载的模型
分词逻辑:通过加载Bert自带的分词器,获取三个embedding,分别是 input_ids, attention_mask, token_type_ids。inputs_ids是词元 ID,是分词器借助词表完成从词到编号的转换;attention_mask是注意力掩码,用于标注填充内容;token_type_ids是句子类型 ID,再情感分类任务中全部为0
分类头编写:情感分类任务本质是二分类任务,transformer的encoder中FNN只完成特征的重新提取,并没有完成特征数将为,所以我们需要编写一个全连接神经网络完成从768到2分类的转换
前向传播:定义了一次前向的过程,将分词送入模型训练,返回序列输出sequence_out和池化输出pooled_output,在encoder中已经算是最终步骤了
forward可以是train里的一部分,也可以是做任务时得到输出的函数

train.py

本模块定义了完整的训练流程,核心包括模型训练,模型评估、模型保存及打印
**模型训练:**也就是前向传播,损失计算,反向传播和参数更新的过程,使用到了优化器,学习率更新和梯度裁剪
模型评估:
模型保存及打印:

main.py

这是Bert模型训练的启动模块,我们主要通过部分超参数的定义了解模型细节的选择:

trainpara = {'model': myBertModel(bert_path, num_class, device).to(device),
             'train_loader': train_loader,
             'val_loader': val_loader,
             'scheduler': CosineAnnealingWarmRestarts(optimizer, T_0=20, eta_min=1e-9),
             'optimizer': torch.optim.AdamW(model.parameters(), lr=learning_rate, weight_decay=0.0001),
             'learning_rate': 1e-4,
             'warmup_ratio' : 0.1,
             'weight_decay' : 0.0001,

             'use_lookahead' : True,
             'loss': nn.CrossEntropyLoss(),
             'epoch': epoch,
             'device': device,
             'save_path': save_path,
             'max_acc': 0.85,
             'val_epoch' : 1
             }
  • 优化器optimizer+学习率调度器scheduler:优化器(optimizer)+ 学习率调度器(scheduler)采用 AdamW + CosineAnnealingWarmRestarts(余弦退火热重启) 组合,是 Transformer 训练中的主流标配,适用于绝大多数场景。
    优化器负责执行梯度下降与参数更新。传统梯度下降使用固定学习率:“参数 = 参数 - 学习率 × 梯度”,由于所有参数共用同一个学习率,容易震荡、收敛缓慢。
    AdamW
    在 Adam 的基础上改进了权重衰减,能为每个参数自适应调整学习率,让参数更新更稳定、有效防止过拟合。
    CosineAnnealingWarmRestarts
    对全局学习率进行动态调整:
    余弦:学习率按余弦曲线平滑下降,而非直线下降;
    退火:模拟金属退火过程,先高学习率快速收敛,再缓慢降低;
    热重启:学习率降到最低后重新拉高,再继续余弦下降,帮助模型跳出局部最优。
    整套方案让训练更稳、更快、更不容易震荡与过拟合。

  • 交叉熵损失CrossEntropyLoss:是分类任务的最经典的损失函数,它会自动对模型输出做Softmax归一化处理,把原始数据处理为概率分布,然后计算y和y^之间的差作为模型更新的依据。

  • 准确率Accuracy:准确率 = (预测正确的样本数) ÷ (总样本数) × 100%,acc用于评价模型性能,判断是否保存该模型,而交叉熵损失用于作为模型参数更新的依据,不直接参与模型性能的评价

  • 常调参数batch_size(批次大小):
    调大:训练速度变快,模型更新更稳定,但太大会占更多内存(我 8000 条数据试了 8/16,再大 CPU 内存扛不住);
    调小:训练慢、更新震荡,但小数据集下更容易拟合。
    学习率(lr):
    调大:模型学的快,但容易震荡不收敛(BERT 微调不能用大 lr,我用 1e-4 刚好);
    调小:学的稳,但太慢甚至学不到东西。

其他问题

1、你训练模型用了多久?你的模型效果怎么样?

我的模型训练了4轮,每轮时间约50分钟,最终准确率达到了91%,主要还是迁移学习带来的效果比较好。

2、你为什么做这个项目

主要是出于兴趣和现在大趋势的重叠。一方面因为现在深度学习方向很火,事先积累这方面的实战经验肯定是对研究生生涯有好处的,transformer框架作为目前最主流的框架,是一切学习的基础,很值得提前了解;另一方面也是出于个人兴趣,因为我觉得深度学习很满足过去我对未来的想象,能亲手训练一个满足自己目的的模型真的是一件很酷的事

3、 你训练模型时遇到了哪些问题?

显存不足:因为在自己电脑上实现,所以显存经常不足,调小 batch 能运行了,但是batchsize太小导致模型容易震荡,后面租卡来训练才显的好点(model scope魔塔社区)
准确率低:认为可能是学习率过大,batchsize 太小,因为这样难以收敛,调整后变高,但准确率也受数据集的制约。

4、其他问题直接参考手册

更多推荐