文章目录
一、基本概念
1、深度学习&机器学习
深度学习是机器学习的一个分支,它专注于构建深层次的神经网络结构来解决复杂问题,尤其是那些需要从原始数据中自动抽取高级抽象特征的问题。
2、回归模型&分类模型
回归模型和分类模型是机器学习中两种常见的预测模型。
1)回归模型:用于解决连续型变量的预测问题,通过分析和学习数据集中已经标记的样本,来建立输入特征与目标变量之间的函数关系,以便预测新数据点的输出值。
- 回归问题:对于一个输入样本,只输出一个值,表示预测结果。
2)分类模型:用于解决离散型变量的预测问题,通过分析和学习数据集中已经打过标签的例子,来学习如何将新数据点分配到预设的不同类别中。
- 二分类问题:对于一个输入样本,只输出一个(0, 1) 范围内的值。输出值越接近 1,表示该图片被判断为类别A的概率越高;输出值越接近 0,表示被判断为类别B的概率越高。
- 多类别分类问题:对于一个输入样本,输出n个值,表示属于n个的类别的概率各为多少。
3、one-hot
One-hot编码是一种常用的分类变量表示方法,它将离散的分类变量映射为一个由0和1组成的向量。在一个长度为n的向量中,只有对应类别的位置为1,其他位置都为0。
举个例子来说明,假设有一个包含三个类别的分类变量:红、绿和蓝。使用one-hot编码,可以将这三个类别映射为三维向量:
- 红色:[1, 0, 0]
- 绿色:[0, 1, 0]
- 蓝色:[0, 0, 1]
在机器学习和深度学习中,常常使用one-hot编码来表示输入特征或目标变量。
二、神经网络基础
1、神经网络结构
神经网络是由多个神经元(或称为节点)组成的网络结构,这些神经元按照层次结构排列。典型的神经网络结构包括输入层、隐藏层和输出层。
1)输入层
输入层接收原始数据或特征作为网络的输入。输入层通常包含与输入数据的特征数量相对应的神经元。每个神经元对应输入数据的一个特征,并将其作为输入传递给下一层。
2)隐藏层
隐藏层是位于输入层和输出层之间的一层或多层神经元组成的层。隐藏层的主要功能是对输入数据进行非线性变换和特征提取。每个隐藏层由多个神经元组成,这些神经元通过权重和激活函数的组合对输入进行线性和非线性操作,产生新的特征表示。在典型的深度神经网络中,通常会有多个隐藏层,这些隐藏层逐渐提取出更高级别、更抽象的特征表示。隐藏层的数量和大小(神经元数量)是神经网络结构设计中的重要参数,可以根据问题的复杂性和数据集的特征进行调整。
3)输出层
输出层是神经网络的最后一层,它产生模型的最终输出。输出层的结构取决于具体的任务类型。
对于回归问题,输出层通常只包含一个神经元,它可以直接输出预测值。
对于分类问题,输出层通常包含与类别数量相对应的神经元,并使用适当的激活函数生成表示各个类别概率的输出。
2、激活函数
激活函数通常被用于神经网络的隐藏层和输出层中的每个神经元。它的作用是对神经元的输入进行非线性变换,引入非线性性质,
在隐藏层中,激活函数将线性组合的输入进行非线性映射,从而使得神经网络能够学习和表示复杂的非线性关系。常见的激活函数有Tanh函数、ReLU函数等。
在输出层中,激活函数的选择通常依赖于任务的性质。
对于回归问题,可以使用恒等函数作为输出层的激活函数,直接使用原始的线性输出作为预测值;对于二分类问题,可以使用Sigmoid函数作为输出层的激活函数,将输出转换为0到1之间的概率值;对于多类别分类问题,通常使用Softmax函数作为输出层的激活函数,将输出转换为表示各个类别概率的分布。
1)Tanh函数
输出范围在(-1, 1)之间。在输入较大或较小时,函数的导数变得非常接近于零,存在梯度消失问题。
t a n h ( x ) = 1 − e − 2 x 1 + e − 2 x tanh(x)=\frac{1-e^{-2x}}{1+e^{-2x}} tanh(x)=1+e−2x1−e−2x
2)ReLU函数
输出范围在 ( 0 , + ∞ ) (0,+\infty ) (0,+∞)之间。当输入是正数时,梯度始终为常数1,有效缓解了梯度消失问题。
R e L U ( x ) = m a x ( 0 , x ) ReLU(x)=max(0,x) ReLU(x)=max(0,x)
尽管ReLU激活函数可以缓解梯度消失问题,但也存在一些问题,比如神经元死亡问题,即在训练过程中某些神经元可能永远不会被激活,导致它们对输入的响应始终为零。
为了解决这个问题,Leaky ReLU和ELU等变体被提出,它们在负区间上引入了一些小的斜率,以使神经元在输入为负时也能有一定的激活。
3)Sigmoid函数
输出范围在(0, 1)之间,常用于二元分类问题的输出层。在输入较大或较小时,函数的导数变得非常接近于零,存在梯度消失问题。
s i g m o i d ( x ) = 1 1 + e − x sigmoid(x)=\frac{1}{1+e^{-x}} sigmoid(x)=1+e−x1
4)Softmax函数
输出范围在(-1, 1)之间,常用于多分类问题的输出层。其主要目的是将实数向量映射为一个概率分布向量,使得每个元素都在0到1之间,并且所有元素的总和为1。
给定一个输入向量 Z = [ z 1 , z 2 , . . . , z n ] Z = [z_1, z_2, ..., z_n] Z=[z1,z2,...,zn],softmax函数对于第 i i i 个元素的计算公式如下:
softmax ( z i ) = e z i ∑ j = 1 n e z j \text{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{n} e^{z_j}} softmax(zi)=∑j=1nezjezi
3、损失函数
损失函数就是一个度量工具,它告诉我们模型的预测离理想结果有多远。模型的目标就是在训练过程中不断调整自身参数,力求最小化整个数据集上的损失函数值,从而提高预测准确性。
1)均方误差
适用于回归问题,衡量了模型输出与实际值之间的差异的平方。
M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 MSE=n1i=1∑n(yi−y^i)2
其中:
- n n n 是样本数量。
- y i y_i yi 是第 i i i个样本的真实值。
- y ^ i \hat{y}_i y^i 是模型对第 i i i个样本预测出的值。
2)交叉熵损失
适用于分类问题,衡量了预测概率和真实类别标签的匹配程度。
L = − 1 n ∑ i = 1 n ∑ j = 1 m H j l n P i j L= -\frac{1}{n}\sum_{i=1}^{n}\sum_{j=1}^{m} H_{j} ln P_{ij} L=−n1i=1∑nj=1∑mHjlnPij
其中:
- n n n 是样本数量, m m m是类别数量。
- H j H_{j} Hj 是one-hot向量中第 j j j列的值:对于正确类别 y y y, H y = 1 H_y=1 Hy=1,而对于所有其他类别, H x = 0 H_x=0 Hx=0
- P i j P_{ij} Pij 是第 i i i个样本的输出向量中第 j j j列的值。
因为使用均方差时预测过于严格,想要预测分类结果正确,不需要预测概率完全等于标签概率,只需要保证真实分类的预测概率最大即可,因此只需要让真实分类的预测值参与损失函数的计算。
例:
one-hot向量 | 真实分类 | 输出向量 | 预测分类 | 预测是否正确 | |
---|---|---|---|---|---|
样本1 | (0,0,1) | 猪 | (0.3,0.3,0.4) | 猪 | 正确 |
样本2 | (0,1,0) | 狗 | (0.3,0.4,0.3) | 狗 | 正确 |
样本3 | (1,0,0) | 猫 | (0.1,0.2,0.7) | 猪 | 错误 |
均方误差:
M S E = 1 3 [ ( 0.3 − 0 ) 2 + ( 0.3 − 0 ) 2 + ( 0.4 − 1 ) 2 + ( 0.3 − 0 ) 2 + ( 0.4 − 1 ) 2 + ( 0.3 ) 2 + ( 0.1 − 1 ) 2 + ( 0.2 − 0 ) 2 + ( 0.7 − 1 ) 2 ] = 0.81 MSE=\frac{1}{3}[(0.3-0)^2+(0.3-0)^2+(0.4-1)^2+(0.3-0)^2+(0.4-1)^2+(0.3)^2+(0.1-1)^2+(0.2-0)^2+(0.7-1)^2]=0.81 MSE=31[(0.3−0)2+(0.3−0)2+(0.4−1)2+(0.3−0)2+(0.4−1)2+(0.3)2+(0.1−1)2+(0.2−0)2+(0.7−1)2]=0.81
交叉熵:
L = − 1 3 [ l n 0.4 + l n 0.4 + l n 0.1 ] = 1.37 L=-\frac{1}{3}[ln0.4+ln0.4+ln0.1]=1.37 L=−31[ln0.4+ln0.4+ln0.1]=1.37
4、梯度下降
梯度下降是一种优化算法,它不断沿着损失函数梯度反方向调整模型参数,以逐步减小并最终逼近损失函数的最小值,从而达到优化模型的目的。
1)学习率
学习率是指在机器学习中用于控制模型参数更新步长的超参数。它决定了每次迭代中模型权重更新的幅度,即模型在每次参数更新时沿着损失函数的负梯度方向前进的距离。
通常,在训练开始时,需要对学习率进行合理的初始化。随着训练的进行,学习率可以根据需要进行调整,以提高模型的训练效果。
常见的学习率调整策略:
- 固定学习率:在整个训练过程中保持不变的学习率。
- 学习率衰减:随着训练的进行,逐渐降低学习率的大小,使得模型在接近最优解时更加稳定。
- 自适应学习率方法:根据模型的训练情况自动调整学习率,例如Adagrad、Adam等优化算法。
选择合适的学习率是一项重要的任务,需要在实验中进行调试和优化。常见的做法是尝试不同的学习率值,并观察模型在训练集和验证集上的性能表现,选择在训练过程中能够取得较好结果的学习率。
2)梯度下降过程
- 将参数 w 设定为某个初始值。
- 计算该参数下的损失函数梯度向量,它表示函数增长最快的方向。
- 更新参数向量:新w=旧w-梯度向量×学习率。
- 重复步骤2和步骤3直至满足停止条件,例如损失函数变化足够小或达到预设的最大迭代次数。
2)梯度下降算法分类
- 批量梯度下降:在每次迭代中使用整个训练数据集来计算梯度,精准度最高,但训练过程慢。
- 随机梯度下降(SGD):每次迭代仅用一个随机选取的样本点来估计梯度,适合大数据集且可以快速迭代。
- 小批量梯度下降/最速下降法:每次迭代使用一个小批量的数据样本计算梯度,效果最好。
- batch_size:每次计算梯度的数据样本集中的样本数量
5、反向传播算法
反向传播算法(Back-Propagation, BP)是一种利用链式法则加速计算参数梯度值的方法。
具体步骤如下:
- 计算损失函数对输出层输出的偏导数,即计算输出层的梯度。
- 将输出层的梯度传递到前一层,通过链式法则计算该层的梯度。
- 重复上述过程,直到计算出输入层的梯度。
- 根据计算得到的梯度,使用梯度下降等优化算法,更新网络参数。
-
梯度爆炸:当网络层数较多、梯度值较大时,梯度爆炸问题可能会出现。在反向传播过程中,梯度值会不断相乘,如果梯度值大于1,则经过多层的传播后,梯度值会指数级增大。这导致权重更新过大,网络参数发生剧烈变化,造成训练不稳定,甚至无法收敛。
-
梯度消失:当网络层数较多、梯度值较小时,梯度消失问题可能会出现。在反向传播过程中,梯度值会不断相乘,如果梯度值小于1,则经过多层的传播后,梯度值会指数级减小。这导致网络浅层的权重更新几乎为零,网络无法学习到有效的特征表示,导致训练困难或性能下降。
三、手撕单层感知机
1、模型图
2、数学推导
3、代码实现
import torch
import torch.nn as nn
#one-hot标签
labels=torch.tensor([[0,1],
[1,0]]).to(torch.float)
#模型输入
inputs=torch.tensor([[1,2,0],
[2,1,0]]).to(torch.float)
#模型定义
class SimpleModel(nn.Module):
def __init__(self,in_features=3,out_features=2):
super().__init__()
self.fc=nn.Linear(in_features,out_features,bias=False) #定义全连接层,权重矩阵会随即赋值
initial_weights=torch.tensor([[1.,2.,3.], #weight矩阵自动转置,1.表示是浮点数
[2.,1.,3.]])
self.fc.weight.data.copy_(initial_weights) #给全连接层设定权重矩阵的值
def forward(self,x):
return self.fc(x)
#模型实例化
model=SimpleModel()
#前向传播
outputs=model(inputs)
outputs
'''
tensor([[5., 4.],
[4., 5.]], grad_fn=<MmBackward0>)
'''
#softmax函数
#dim参数用于指定在tensor的哪个维度上进行操作,dim=0表示沿着行的方向进行操作,dim=1表示沿着列的方向进行操作。
probabilities=torch.softmax(outputs,dim=1)
probabilities
'''
tensor([[0.7311, 0.2689],
[0.2689, 0.7311]], grad_fn=<SoftmaxBackward0>)
'''
#交叉熵损失函数(自带一层softmax)
loss_fn=nn.CrossEntropyLoss()
loss=loss_fn(outputs,labels)
loss.item()
'''
1.31326162815094
'''
#自动求导
loss.backward()
model.fc.weight.grad
'''
tensor([[-0.3655, 0.3655, 0.0000],
[ 0.3655, -0.3655, 0.0000]])
'''
#优化器,使用随机梯度下降算法SGD
optimizer=torch.optim.SGD(model.parameters(), lr=1)
#更新weight矩阵
optimizer.step()
model.fc.weight
'''
Parameter containing:
tensor([[1.3655, 1.6345, 3.0000],
[1.6345, 1.3655, 3.0000]], requires_grad=True)
'''