深度学习的定义
深度学习是机器学习 (ML) 的一个子集,指人工神经网络(由算法建模而成,能够像人的大脑一样工作)学习大量数据。
深度学习的工作原理是什么?
深度学习由神经网络层驱动。神经网络由一系列算法按照人类大脑的工作方式松散建模而成,而使用大量数据进行训练,即对神经网络的神经进行配置。经过训练后,深度学习模型可以处理新数据,能够摄取并实时分析多个来源的数据,无需人为干预。在深度学习中,图形处理单元 (GPU) 可以同时处理多个计算,以优化方式训练深度学习模型。

深度学习的概念源于对人工神经网络的研究,很多深度学习算法都使用神经网络进行表示,因为神经网络的性能精度和通用效果都非常好,于是业界习惯性地把深度学习算法等同于AI。
目标函数softmax
在使用深度学习来处理分类问题的时候,需要衡量目标类别与当前预测的差距,目标函数可以帮助衡量模型的好坏,softmax 就是一个目标函数: 讲结果变为一个概率值
Softmax函数,又称 归一化指数函数 。
该函数 是最流行的 分类任务目标函数,也是 Sigmoid函数 的一种 推广。可转换为交叉熵误差 (CE) 。
它将原始的实数输入(通常是神经网络的输出)转换成概率值。具体来说,Softmax 操作会把一个向量的每个元素转换为 [0, 1] 范围内的值,并且所有输出的和为 1,从而可以将它们解释为概率。
给定一个向量 z=[z1,z2,…,zn]z=[z1,z2,…,zn] 作为输入,Softmax 函数输出一个与输入向量形状相同的概率分布:

- zi 是输入向量中的第 ii 个元素。
- 输出的每个 Softmax(zi)Softmax(zi) 是一个概率值,所有概率值的和为 1。

例如:输入向量 [ 1 , 2 , 3 , 4 , 1 , 2 , 3 ] 对应的Softmax函数的值为 [ 0.024 , 0.064 , 0.175 , 0.475 , 0.024 , 0.064 , 0.175 。输出向量中拥有最大权重的项对应着输入向量中的最大值“4”。这也显示了这个函数通常的意义:
对向量进行归一化,凸显其中最大的值并抑制远低于最大值的其他分量。
交叉熵损失
交叉熵损失函数(Cross-Entropy Loss)用来计算 分类任务中 预测概率分布与真实标签分布之间的差异。交叉熵损失衡量了两个概率分布之间的距离,特别是在分类任务中,衡量了预测类别分布和实际标签分布的差异。
交叉熵损失的公式:
给定真实标签分布 y=[y1,y2,…,yn]y=[y1,y2,…,yn] 和模型的预测输出概率分布 p=[p1,p2,…,pn]p=[p1,p2,…,pn],交叉熵损失定义为:

- yi 是真实标签(通常是一个 one-hot 向量,表示类别标签)。
- pii 是模型预测的概率值,通常由 Softmax 得到。

Softmax 和交叉熵损失的结合:
在多分类问题中,通常会先通过 Softmax 转换模型的输出为概率分布,再使用交叉熵损失计算损失值。因此,Softmax 和交叉熵损失经常是紧密配合使用的,但它们的功能和作用是不同的。
- Softmax:将神经网络的原始输出(通常是未归一化的 logits)转换为概率分布。
- 交叉熵损失:计算模型预测的概率分布与真实标签之间的差异。
交叉熵损失和均方误差损失对比分析
均方误差

- cross_entropy 具有 rmse 不具有的优点:避免学习速率降低的情况。(注意这种效果仅限于输出层,隐藏层的学习速率与其使用的激活函数密切相关。)
- 主要原因是逻辑回归配合 MSE 损失函数时,采用梯度下降法进行学习时,会出现模型一开始训练时,学习速率非常慢的情况(MSE 损失函数)
- 下面这个更清晰
https://zhuanlan.zhihu.com/p/35709485 交叉熵损失 更能捕捉到预测效果的差异
举例:模型预测输出:

均方误差损失的结果:

交叉熵损失的结果:

- 使用逻辑函数得到概率,并结合交叉熵当损失函数时,在模型效果差的时候学习速度比较快,在模型效果好的时候学习速度变慢。
- 均方损失:假设误差是正态分布,适用于线性的输出(如回归问题),特点是对于与真实结果差别越大,则惩罚力度越大,这并不适用于分类问题
- 交叉熵损失:假设误差是二值分布,可以视为预测概率分布和真实概率分布的相似程度。在分类问题中有良好的应用。
w的初始值分布
Xavier Normal
(也称作 Glorot Normal)是 权重初始化 的一种方法,旨在避免深度神经网络中训练过程中的梯度消失和梯度爆炸问题。
在训练深度神经网络时,如果权重初始化得不好,可能会导致训练难以进行。特别是在网络层数很深的情况下,梯度在反向传播时可能会变得非常小(梯度消失)或非常大(梯度爆炸),这会导致训练过程不稳定或收敛困难。
Xavier 初始化(也叫 Glorot 初始化)是为了解决这个问题提出的一种权重初始化方法,尤其适用于 sigmoid 和 tanh 等激活函数的神经网络。Xavier Normal
是 正态分布(也叫高斯分布)初始化方法的一种。它的关键思想是,根据神经网络的输入和输出层的大小来决定初始化权重的标准差,从而保持信号在网络中的传播不会太大或太小。
公式:
对于层 ll 的权重初始化,Xavier Normal
的标准差(σσ)是根据输入单元数(ninnin)和输出单元数(noutnout)来计算的,标准差的公式如下:

其中:
- Nin 是当前层的输入神经元数量。
- Nout 是当前层的输出神经元数量。
因此,每一层的权重矩阵会从一个均值为 0,标准差为 σ 的 正态分布 中随机采样。
比如 784+300, 就是 np.sqrt(2/1084)
为什么是这种初始化方法?
Xavier 初始化方法的目标是让每一层的 输入信号 和 梯度信号 都能通过网络正常传播而不会衰减(梯度消失)或爆炸(梯度爆炸)。
a. 激活值的分布:
如果初始化权重过大,经过激活函数(如 sigmoid
或 tanh
)的输出可能会饱和(即接近 0 或 1),导致梯度接近于 0,这就会导致梯度消失问题。反之,如果权重过小,信号在通过网络时会过度缩小,可能导致训练非常缓慢,甚至无法收敛。
Xavier 初始化通过调节权重的标准差,使得每层的输入和输出信号在初始化时有适当的方差,从而避免了过度压缩或爆炸的情况。
b. 避免梯度消失或爆炸:
- 通过选择适当的初始化标准差,Xavier 方法帮助保持梯度在网络中传播时不会迅速消失或变得太大,尤其在深层网络中非常重要。
- 在激活函数为
sigmoid
或tanh
时,Xavier 初始化能使得每层的激活值分布保持在合理的范围内,从而避免梯度消失问题。
如何在 PyTorch 中使用 Xavier Normal 初始化:
在 PyTorch 中,你可以使用 torch.nn.init.xavier_normal_()
来应用 Xavier Normal 初始化。该方法会将张量的权重初始化为符合 Xavier Normal 的分布。
例如,初始化一个卷积层或全连接层的权重:
1 | import torch |
5. 与其他初始化方法的对比:
- Xavier Normal:适用于
tanh
和sigmoid
激活函数的网络。通过n_in + n_out
来平衡输入输出的方差,适合解决梯度消失/爆炸问题。 - He 初始化:类似于 Xavier 初始化,但适用于 ReLU 激活函数,标准差为 2ninnin2。ReLU 激活函数的输出通常会有更多的零值(因为负数的输出被“抑制”),因此 He 初始化会稍微增大标准差。
- 均匀初始化:与 Xavier 相比,均匀分布初始化是从一个均匀分布中采样,而不是正态分布。这个方法通常会导致训练的不稳定,尤其是对于深层网络。
深度学习实现分类问题
数据预处理
1 | import matplotlib as mpl |
在PyTorch中,DataLoader
是一个迭代器,它封装了数据的加载和预处理过程,使得在训练机器学习模型时可以方便地批量加载数据。DataLoader
主要负责以下几个方面:
批量加载数据:
DataLoader
可以将数据集(Dataset)切分为更小的批次(batch),每次迭代提供一小批量数据,而不是单个数据点。这有助于模型学习数据中的统计依赖性,并且可以更高效地利用GPU等硬件的并行计算能力。数据打乱:默认情况下,
DataLoader
会在每个epoch(训练周期)开始时打乱数据的顺序。这有助于模型训练时避免陷入局部最优解,并且可以提高模型的泛化能力。多线程数据加载:
DataLoader
支持多线程(通过参数num_workers
)来并行地加载数据,这可以显著减少训练过程中的等待时间,尤其是在处理大规模数据集时。数据预处理:
DataLoader
可以与transforms
结合使用,对加载的数据进行预处理,如归一化、标准化、数据增强等操作。内存管理:
DataLoader
负责管理数据的内存使用,确保在训练过程中不会耗尽内存资源。易用性:
DataLoader
提供了一个简单的接口,可以很容易地集成到训练循环中。
定义模型
1 | class NeuralNetwork(nn.Module): # 都是继承自nn.Module |
模型结构如下:

model.named_parameters()
这是查看模型中所有 可训练参数 的方法。它会返回一个生成器,包含每个参数的名称和形状。
1 | for name, param in model.named_parameters(): # 打印模型参数 |

model.state_dict()
state_dict()
方法返回一个字典,其中包含模型的所有参数(权重和偏置),以及优化器的状态(如果有的话)。这个字典中的键是参数的名称,值是参数的值(tensor)。包括所有的权重信息,会很复杂
这种方法用于保存模型参数,能看见参数属于模型的哪一部分

1 | # 看看模型参数 |
训练
pytorch的训练需要自行实现,包括
- 定义损失函数
- 定义优化器
- 定义训练步
- 训练
注意:
- logits = model(datas) 的时候会调用进入到forward,进行前向计算,会生成计算得到的逻辑值logits,
- 再进入计算损失,使用交叉熵损失计算前会softmax,之后对其生成的概率值进行计算交叉熵
- 优化器Optimizer需要将模型参数都写入model.parameters():模型的所有可学习参数,requires_grad=True
1 | # 1. 定义损失函数 采用交叉熵损失 |
1 | # 训练 |
loss.backward()
是 PyTorch 中用于计算梯度的方法。 它是在进行反向传播(backpropagation) 过程中的一个关键步骤。 下面是 loss.backward()
方法的主要作用:
- 根据计算图: PyTorch 中的计算图是由前向传播过程中的张量操作构建的。 当调用 loss.backward()` 时, 它会遵循计算图中的连接关系, 从损失节点开始向后传播, 计算每个相关参数的梯度。
- 梯度计算:
loss.backward()
方法会根据链式法则自动计算每个参数的梯度。 它会沿着计算图反向传播梯度, 将梯度值累积到每个参数的.grad
属性中。 - 梯度累积: 如果在调用
loss.backward()
前进行了多次前向传播和损失计算, 那么每次调用loss.backward()
时, 梯度将被累积到参数的.grad
属性中。 这通常用于在训练过程中使用小批量样本进行梯度更新 - 参数更新: 在计算完梯度后, 可以使用优化器(如
torch.optim
中的优化器) 来更新模型的参数, 将梯度信息应用于参数更新规则。
总而言之, loss.backward()
的作用是根据计算图和损失函数, 计算模型参数的梯度。 这些
梯度可以用于更新模型参数, 以便在训练过程中最小化损失函数。
评估
注意:当进行评估时,模型需要先进入评估模式:model.eval()# 进入评估模式
以确保不会进行梯度计算,以及dropout的丢失损失的情况。并且在下一次进入训练模式的时候也需要先进入训练模式:model.train() # 进入训练模式 以开启反向传播
1 | from sklearn.metrics import accuracy_score |
画图
1 | #画线要注意的是损失是不一定在零到1之间的 |