优质博客推荐
网络模型讲解
专有名词
Downstream Tasks: 下游任务, 即要实现的目标任务, 类比操作系统上的应用
Pre-train: 公共基本, 处理下游任务前的基础模型, eg: BERT, 类比操作系统
Error surface(误差曲面)是机器学习和深度学习中一个重要的概念,特别是在优化算法和神经网络训练的背景下。误差曲面描述了模型参数空间中损失函数(或误差函数)的变化情况
η \eta η :学习率, 即梯度下降时控制梯度下降的大小因素之一 eg: η ∂ L ∂ w \eta\frac{\partial{L}}{\partial{w}} η ∂ w ∂ L
Model Bias: 模型偏差, 模型和真实之间的差距, eg: 用线性预测折线
update: 经过一个batch更新了一次参数, 所以batch_size越小参数更新次数越多
epoch: 经过一轮, 所有的batch都过了一遍
Batch_Size: batch越小,那一个epoch中更新参数的次数会更多,batch越大,一个epoch中参数更新的次数会更小。但由于GPU可以并行计算,所以并不是batch越小,所需要的时间越少。优先选择较小的batch
Momentum: 不止考虑梯度下降的方向,还要考虑前面的梯度方向,就好比物理中的惯性,有可能避免局部最小
DL
基础
基础模版
1 2 3 4 5 6 dataset = MyDataset(file) tr_set = DataLoader(dataset, batch_size, shuffle=True ) model = MyModel().to(device) criterion = nn.MSELoss() optimizer = torch.optim.SGD(model.parameters(), learning_rate)
1 2 3 4 5 6 7 8 9 10 for epoch in range (n_epochs): model.train() for x, y in tr_set: optimizer.zero_grad() x, y = x.to(device), y.to(device) pred = model(x) loss = criterion(pred, y) loss.backward() optimizer.step()
1 2 3 4 5 6 7 8 model.eval () preds = [] for x in tt_set: x = x.to(device) with torch.no_grad(): pred = model(x) preds.append(pred.cpu())
1 2 3 4 5 6 torch.save(model.state_dict(), path) ckpt = torch.load(path) model.load_state_dict(ckpt)
见Loss知issue
判断在训练集上的Loss
如果在训练集上Loss很大, 那优先判断是不是model bias
, 将模型变复杂看Loss会不会更好
如果模型复杂效果更差, 那便是Grad Optimization
的问题
然后判断在测试集上的Loss
如果在测试集上Loss很大, 那优先判断是不是overfitting
解决overfitting
的方法有数据增强和收集数据增加训练集; 给模型增加限制,eg: 设置较少的参数/较少的特征或者公用参数; 提前停止; Dropout; Regularization
learnin_rate
Update learnin_rate
Adagrad
不仅考虑现在的梯度还要考虑以前的梯度
θ i t + 1 ← θ i t − η σ i t g i t σ i t = 1 t + 1 ∑ i = 0 t ( g i t ) 2 \theta^{t+1}_i\leftarrow\theta^{t}_i-\frac{\eta}{\sigma^t_i}g^t_i\\
\sigma^t_i=\sqrt{\frac{1}{t+1}\sum^t_{i=0}(g^t_i)^2}
θ i t + 1 ← θ i t − σ i t η g i t σ i t = t + 1 1 i = 0 ∑ t ( g i t ) 2
RMSProp
通过α \alpha α 控制是当前的梯度参考价值大还是现在的梯度参考价值大
θ i t + 1 ← θ i t − η σ i t g i t σ i t = α ( σ i t − 1 ) 2 + ( 1 − α ) ( g i t ) 2 \theta^{t+1}_i\leftarrow\theta^{t}_i-\frac{\eta}{\sigma^t_i}g^t_i\\
\sigma^t_i=\sqrt{\alpha(\sigma^{t-1}_i)^2+(1-\alpha)(g^t_i)^2}
θ i t + 1 ← θ i t − σ i t η g i t σ i t = α ( σ i t − 1 ) 2 + ( 1 − α ) ( g i t ) 2
Adam
RMSProp + Momentum
Learning Rate Scheduling
θ i t + 1 ← θ i t − η t σ i t g i t \theta^{t+1}_i\leftarrow\theta^{t}_i-\frac{\eta^t}{\sigma^t_i}g^t_i
θ i t + 1 ← θ i t − σ i t η t g i t
Learning Rate Decay
一开始距离终点很远,慢慢的距离终点在变近,所以η \eta η 慢慢变小,相当于踩刹车
下图是在Adagrad的基础上增加Learning Rate Decay之后的效果
Warm Up
Increase and then decrease 先变大后变小
Soft-max
输入: 通常被称为logit
Loss of Classification
常用 Cross-entropy
为什么要选 Cross-entropy, 因为Cross-entropy更容易走到loss小的区域, 而MSE的左上角比较平缓不容易走到右下角
CNN
结构
输入层Input layer
卷积层 CONV layer
池化层 Pooling layer
全连接层 FC layer
输出层 Output layer
对原始图像做预处理: 去均值、归一化等
CONV layer
通过控制卷积核的大小,步幅和填充提取特征,每个神经元通过不同的卷积核关注图像的不同的特征
Pooling layer
利用特征不变形和特征降维压缩图像
流程
INPUT
[ [ CONV -> RELU ]N -> POOL? ]M
[ FC -> RELU ]K
FC
AlexNet
结构
5个卷积层后紧跟个全连接层, 采用ReLu激活函数,并在全连接层后增加Dropout层减少过拟合
VGG16
结构
采用连续的3×3卷积核代替AlexNet中的较大卷积核(11×11、5×5)
ResNet
残差结构
优势
可以较好的解决梯度消失|爆炸和模型退化的问题
梯度消失: 假设每一层的梯度是一个小于1的数, 随着层数变多,前面层的梯度会越来越小
模型退化: 随着层数的加深, 效果退化, 不如层数少的训练效果好
亮点
提示出residual模块
使用Batch Normalization加速训练(丢弃dropout)
DenseNet
结构
DenseNet的网络结构主要由DenseBlock 和Transition 组成
在DenseBlock中,各个层的特征图大小一致,可以在channel维度上连接。DenseBlock中的非线性组合函数H ( ⋅ ) H(⋅) H ( ⋅ ) 采用的是BN+ReLU+3x3 Conv的结构,如图所示。另外值得注意的一点是,与ResNet不同,所有DenseBlock中各个层卷积之后均输出k k k 个特征图,即得到的特征图的channel数为k k k ,或者说采用k k k 个卷积核。k k k 在DenseNet称为growth rate,这是一个超参数。一般情况下使用较小的k k k (比如12),就可以得到较佳的性能。假定输入层的特征图的channel数为k 0 k_0 k 0 ,那么L L L 层输入的channel数为 k 0 + k ( L − 1 ) k_0+k(L−1) k 0 + k ( L − 1 ) ,因此随着层数增加,尽管 k k k 设定得较小,DenseBlock的输入会非常多,不过这是由于特征重用所造成的,每个层仅有 k k k 个特征是自己独有的。
Transition层主要用于连接两个相邻的DenseBlock,整合上一个DenseBlock获得的特征,缩小上一个DenseBlock的宽高,达到下采样效果,特征图的宽高减半。Transition层包括一个1x1卷积(用于调整通道数)和2x2AvgPooling(用于降低特征图大小),结构为BN+ReLU+1x1 Conv+2x2 AvgPooling。因此,Transition层可以起到压缩模型的作用 。
结构
残差和标准化
LayerNorm
原理
层归一化是一种常用的归一化技术,它在每一层的输出上进行归一化操作,使得输出的均值为0,方差为1。这样可以使得模型在训练过程中更稳定,因为它可以减少内部协变量的移动,即输入数据的分布在训练过程中的改变。此外,层归一化还可以加速模型的收敛速度,提高模型的训练效率。
公式
y = x − E ( x ) V a r ( x ) + ϵ ∗ γ + β y=\frac{x-E(x)}{\sqrt{Var(x)+\epsilon}}*\gamma+\beta
y = V a r ( x ) + ϵ x − E ( x ) ∗ γ + β
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class LayerNorm (nn.Module): def __init__ (self, feature, eps=1e-6 ): """ nn.Parameter: 将参数告知优化器此参数需要优化(学习) :param feature: self-attention 的 x 的大小 :param eps: """ super (LayerNorm, self ).__init__() self .gamma = nn.Parameter(torch.ones(feature)) self .beta = nn.Parameter(torch.zeros(feature)) self .eps = eps def forward (self, x ): mean = x.mean(-1 , keepdim=True ) std = x.std(-1 , keepdim=True ) return self .gamma * (x - mean) / (std + self .eps) + self .beta
Add&Norm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class SublayerConnection (nn.Module): """ 这不仅仅做了残差,这是把残差和 layernorm 一起给做了 """ def __init__ (self, size, dropout=0.1 ): super (SublayerConnection, self ).__init__() self .dropout = nn.Dropout(p=dropout) self .layer_norm = LayerNorm(size) def forward (self, x, sublayer ): """ :param x: 就是self-attention的输入 :param sublayer: self-attention层 :return: """ return self .layer_norm(x + self .dropout(sublayer(x)))
Attention
公式
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( d k Q K T ) V
Q|K|V
注意力分数
红圈中内容代表I am a stu中I字对I字的注意力分数
注意力权重
每一个字的注意力分数对每个字的一维特征进行加权求和
缩小点积范围
下图是Softmax函数的分布, 如果不缩小点积的范围那么大多数值会分布在两端,梯度很小的地方,会造成梯度消失
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class MutiHeadAttention (nn.Module): def __init__ (self, d_model, num_heads ): super ().__init__() self .num_heads = num_heads self .d_model = d_model self .w_q = nn.Linear(d_model, num_heads) self .w_k = nn.Linear(d_model, num_heads) self .w_v = nn.Linear(d_model, num_heads) self .w_combine = nn.Linear(d_model, num_heads) self .softmax = nn.Softmax(dim=-1 ) def forward (self, q, k, v, mask=None ): batch_size, time, dimension = q.shape n_dim = self .d_model // self .num_heads q, k, v = self .w_q(q), self .w_k(k), self .w_v(v) q = q.view(batch_size, time, self .num_heads, n_dim).permute(0 , 2 , 1 , 3 ) k = k.view(batch_size, time, self .num_heads, n_dim).permute(0 , 2 , 1 , 3 ) v = v.view(batch_size, time, self .num_heads, n_dim).permute(0 , 2 , 1 , 3 ) score = q @ k.transpose(2 , 3 ) / math.sqrt(n_dim) if mask is not None : score = score.masked_fill(mask == 0 , -10000 ) score = self .softmax(score) @ v score = score.permute(0 , 2 , 1 , 3 ).contiguous().view(batch_size, time, dimension) out = self .w_combine(score) return out
Position Embedding
公式
P E ( p o s , 2 i ) = s i n ( p o s / 1000 0 2 i / d m o d e l ) P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1000 0 2 i / d m o d e l ) PE_{(pos,2i)}=sin(pos/10000^{2i/d_{model}})\\
PE_{(pos,2i+1)}=cos(pos/10000^{2i/d_{model}})
P E ( p o s , 2 i ) = s i n ( p o s / 1 0 0 0 0 2 i / d m o d e l ) P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1 0 0 0 0 2 i / d m o d e l )
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class PositionalEncoding (nn.Module): def __init__ (self, d_model, max_len=512 , device='cuda' ): super ().__init__() self .encodeing = torch.zeros(max_len, d_model, device=device) self .encodeing.requires_grad = False pos = torch.arange(0 , max_len, device=device) pos = pos.float ().unsqueeze(dim=1 ) _2i = torch.arange(0 , d_model, step=2 , device=device).float () self .encodeing[:, 0 ::2 ] = torch.sin(pos / 10000 ** (_2i / d_model)) self .encodeing[:, 1 ::2 ] = torch.cos(pos / 10000 ** (_2i / d_model)) def forward (self, x ): batch_size, seq_len = x.size() return self .encodeing[:seq_len, :]
理由
如下图,attention的计算中并不包含位置信息,交换K和V的字顺序计算出的甲醛和值相同的,因此要引入位置信息
1 2 nn.Embedding(src_vocab_size, d_model): 词汇表大小×词嵌入的维度 torch.unsqueeze(dim): 在指定位置添加一个维度