如题目>▽<
MSE(Mean Square Error,平均平方误差)
用于计算真值与预测值之间的损失
梯度下降(贪心)
求导往梯度的负方向更新,α为学习率为前进速率
有可能存在鞍点,此处梯度为0,在梯度下降优化时,在此处会没办法继续迭代
梯度下降算法的公式
训练过程代码,在训练时通过梯度下降更新权重w,使得损失进行下降
学习失败,最终的训练损失变为U型,最常见的原因为学习率取过大了
随机梯度下降(SGD)
在N个数据中,从里面随机的选1个。使用单个样本的损失对权重进行求导然后更新,即使陷入鞍点,训练数据的随机噪声可能会向前推动更新,跨越过鞍点向着最优值前进。
但随机梯度下降无法并行计算,因此可以使用批量(mini-batch)的随机梯度下降,每次用一组batch的样本取求相应的梯度进行更新。
反向传播
计算图
以下是一个两层神经网络的结构,MM为矩阵乘法,ADD为加法,W为每层的权重(决定模型拟合的曲线的样子),b为每层的偏置bias(决定如何平移),对每层的输出需要加一个非线性的激活函数(不然的话不管多深的神经网络都能化简成一个权重和转置,相当于只有一层)
训练过程
- 准备数据集
- 设计模型
- 建立损失和优化器
- 进行训练周期(前馈算损失、反馈算梯度、更新用梯度下降算法更新权重)
需要torch.nn下的都需要构建计算图
1 | class LinearModel(torch.nn.Module): |
逻辑斯蒂回归
回归(连续 )与分类(离散)
分类:计算出每种类别的概率值(和为1),找概率中的最大值
Logistic函数:$\sigma(x)=\frac1{1+e^{-x}}$,能够将实数值对应的输出映射到0-1之间,该函数为一种饱和函数,因为求导的结果类似于正态分布
sigmoid函数(S型)激活函数
满足单调增函数、饱和函数的函数为sigmoid函数。由于logistic比较有名,因此有时会直接将其叫做sigmoid函数
计算分布之间的差异,使用二分类的交叉熵损失(BCE)$loss=-(y\log\hat{y}+(1-y)\log(1-\hat{y}))$
logistic函数无参因此不需要对参数进行初始化,直接调用即可
处理多维特征的输入
对于多维数据,可以与数据库关系表进行类比,每一行的样本相当于记录,每一列的特征相当于字段
对于一个8维特征的样本在进入线性层是输入也要改变乘8维进行对齐,最终输出的y还是1维因此输出维数不变。也可以8维转4维,4维转1维,但需要注意层与层之间需要使用激活函数,为线性变换增加非线性因子,使得可以拟合相应的非线性的变换。
梯度消失
ReLU激活函数取值为0-1,如果最后输出的结果小于零,经过ReLU函数会输出0,这在后面算loss时可能会出现ln0,因此最后一层应该使用sigmoid函数
加载数据集
- Epoch:所有样本都进行了一次训练
- Batch-size:每次训练时所用的样本数量,即一次前馈反馈更新所用的样本数量
- Iteration:batch一共分了多少个,样本数量
/
Batch-size
1 | import torch |
多分类问题
使用SoftMax函数使最终输出的所有分类结果大于0,和为1,$P(y=i)=\frac{e^{z_i}}{\sum_{j=0}^{K-1}e^{z_j}},i\in{0,…,K-1}$
此处使用NLLoss,下图一整个为交叉熵损失,此时神经网络的最后一层是不需要做激活的
在导入图像时使用PIL或OpenCV读入的图像一般为WxHxC,需要转换成CxWxH,然后进行归一化,因为神经网络喜欢01分布的数据
卷积神经网络(CNN)
卷积
全连接网络:一个网络全由线性层串行连接
M为原始图像边长,N为卷积核边长,最终的卷积结果边长为(M-N)/步长(stride)+1
,加步长可以有效降低特征图的大小
将原始n通道W-in,H-in的图像经过m个卷积核(卷积核大小任意但维度必须和原始图像一致)生成m个特征图再concat按顺序拼接在一起生成m通道W-out,H-out的特征图。因此卷积过程中的需要创建一个4维的张量,$m\times n\times kernel_size_{width}\times kernel_size_{height}$
代码如下[10,5,3,3,]
代表输出通道,输入通道,卷积核大小
下采样
最大池化层(MaxPooling),只取每个窗口中的最大值,因此通道数不变。只改变尺寸
1 | maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2) |
一个简单的卷积网络模型示例,这里代码写错是先pooling后relu,与左边结构不一致
1 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") |
1x1卷积
可以跨越不同通道相同位置元素值融合信息
可以有效进行降维,减少运算量
GooleNet其中一个模块
1 | # concat操作 |
resnet
解决梯度消失问题,在反向传播时,要用链式法则把一连串的梯度乘起来,假设每一处的梯度都是小于1的那么会越来越小趋近于0
可以看到,当z对x的偏导的第一项非常小的时候,整体会在1附近,因此一连串相乘时就不会趋近于0了,就能够把开始离输入非常近的层进行充分的训练。F(x)与x可以相加,因此F的输出和x的张量维度必须一致(c、h、w)
一个残差快的实现
正则化
用于减少机器学习过拟合的过程的方法,针对w权重进行正则化处理:L1、L2、Dropout
L1、L2范数
将w理解为高维空间中的一个点,这个点到原点的距离为欧式距离则为L2范数,到原点的曼哈顿距离为L1范数
为什么要引入,由于神经网络训练时的w、b不固定有可能会过大,这样会造成用于测试时,新的数据和大参数相乘后,会放大误差和噪声,判断结果更容易错误,因此可以对参数的取值通过正则化进行限制。
L1正则化可以带来稀疏性,在w向量某些项上有值,其他项是零,即某些特征起作用,而不是所有特征起作用,即将特征之间的特征去耦合了,这种去耦合过程恰恰也是减少过拟合的过程。
L2正则化只是把w权重的绝对值缩小了。整体来看,加入正则化对最终结果的偏差没有特别大,因此能用就用。
其中第一个式子超参数为C,第二个式子超参数为λ
Transformer
编解码
对token进行数字化,分词器将token投射到数轴上,one-hot编码将每个token分配一个单独的维度,最后组成一个有多少token就有多少维度的高维空间。
问题:
- one-hot:token之间的语义关系全靠维度间的关系体现,没有充分利用在空间中的长度
- 分词器:把所有语义都变成了长度问题,完全没有里用维度关系来表示语义信息。
解决方法:找一个维度高但没那么高的空间来协助完成编码和解码的工作,这个空间就是潜空间
编码:把文本中的token变成one-hot码然后降维,Embedding(嵌入):把高维空间里的对象投射到低维空间中(把输入的一句话根据语义投射到潜空间中),Token被嵌入后就变成了多维的向量,每个维度都代表一个独立的语义
Word2Vec
不直接训练出解码token的结果,而是像训练出一个词典,帮助模型对token进行词嵌入。只做向量求和和向量分解,没有非线性的需求,变换前后的空间相同。
CBOW
有点像力的分解,训练目的不是为了使其具备完形填空的预测能力,而是要训练出能体现语义的嵌入矩阵。能够预测出缺失的token是由于缺失的token是有上下文语义关系的,能够进行对应。
Skip-gram
已知一个token,根据它的词向量去求上下文对应的token的分量,看是否和训练数据一致
注意力
一组词向量经过三个矩阵相乘得到QKV三个矩阵,然后经过一堆运算后再输出一组词向量。词嵌入解决了单个词单个token语义的问题,注意力机制要解决的是许多词组合在一起体现的语义。
注意力机制的目的是能够识别由于上下文关联而对词典中原本客观的语义进行调整和改变的幅度,因此V表示从词典中查出来的Token的客观语义,A'
相当于这段话因为上下文关联而产生的修改系数。Q、K是得到了这一组的词向量自己和自己之间的相互关系A,再把这个相互关系拿来修正词向量,让词向量的每个维度都得到修正,语义越接近代表A中的值越大
- 自注意力:生成QKV的是相同的数据(闷头自学,先理解设定语义再了解表达语义)
- 交叉注意力:Q和KV生成的数据不同(有参考资料,省去了理解设定语义的过程)
位置编码
如果没有位置编码Transformer会把所有的token一起放到模型里面去并行计算,这样词语的前后顺序携带的信息就无法体现出来了,使用三角函数使这种编码的每个token都有绝对位置(唯一编码)和相对位置(通过三角函数的相位差计算距离)
多头注意力
相当于进行多次注意力机制,能提取出更多的特征,对于每个注意力计算出的结果,对应维度的语义都是相近的,因此组成一组。对于例子中的这种三种语义可以理解成类似于图片的三个通道进行1x1卷积。这种多头注意力机制可以跨越很多格建立联系(长程依赖)