机器学习基础

机器学习基础

机器学习基本任务

在这里插入图片描述

监督学习

监督学习是最常见的一种机器学习类型,其任务的特点就是给定学习目标,这个学习目标又称标签、标注或实际值等,整个学习过程就是围绕如何使预测与目标更接近而来的。监督学习的过程如下图所示:

在这里插入图片描述

无监督学习

监督学习的输入数据中有标签或目标值,但在实际生活中,有很多数据是没有标签的,或者标签代价很高。这些没有标签的数据也可能包含很重要的规则或信息,从这类数据中学习到一个规则或规律的过程被称为无监督学习。在无监督学习中,我们通过推断输入数据中的结构来建模,模型包括关联学习、降维、聚类等。

半监督学习

半监督学习是监督学习与无监督学习相结合的一种学习方法。半监督学习使用大量的未标记数据,同时由部分使用标记数据进行模式识别。半监督学习目前正越来越受到人们的重视。
自编码器是一种半监督学习,其生成的目标就是未经修改的输入。语言处理中根据给定文本中的词预测下一个词,也是半监督学习的例子。
对抗生成式网络也是一种半监督学习,给定一些真图片或语音,然后通过对抗生成网络生成一些与真图片或是语音逼真的图形或语音。

强化学习

强化学习是机器学习的一个重要分支,是多学科多领域交叉的一个产物。强化学习主要包含4个元素:智能体(Agent)、环境状态、行动和奖励。强化学习的目标就是获得最多的累计奖励。
强化学习把学习看作一个试探评价的过程,Agent选择一个动作用于环境,环境接受该动作后状态发生变化,同时产生一个强化信号(奖或惩)反馈给Agent,Agent根据强化信号和环境当前状态再选择下一个动作,选择的原则是使受到正强化(奖)的概率增大。选择的动作不仅影响立即强化值,也影响下一时刻的状态和最终的强化值。
强化学习不同于监督学习,主要表现在教师信号上。强化学习中由环境提供的强化信号是Agent对所产生动作的好坏做的一种评价,而不是告诉Agent如何去产生正确的动作。由于外部环境只提供了很少的信息,所以Agent必须靠自身的经历进行学习。通过这种方式,Agent在行动一一被评价的环境中获得知识,改进行动方案以适应环境。

机器学习流程

机器学习一般需要先定义问题、收集数据、探索数据、预处理数据,对数据处理后,接下来开始训练模型、评估模型,然后优化模型等步骤。
在这里插入图片描述

明确目标

在实施一个机器学习项目之初,定义需求、明确目标、了解要解决的问题以及目标涉及的范围等都非常重要,它们直接影响后续工作的质量甚至成败。1)明确目标,首先需要明确大方向,比如当前的需求是分类问题还是预测问题或聚类问题等。2)清楚大方向后,需要进一步明确目标的具体含义。如果是分类问题,还需要区分是二分类、多分类还是多标签分类;如果是预测问题,要区别是标量预测还是向量预测;其他方法类似。3)确定问题,明确目标有助于选择模型架构、损失函数及评估方法等。

收集数据

数据可能涉及不同平台、不同系统、不同部分、不同形式等,对这些问题的了解有助于确定具体数据收集方案、实施步骤等。

数据预处理

收集到的数据,不一定规范和完整,这就需要对数据进行初步分析或探索,然后根据探索结果与问题目标,确定数据预处理方案。
对数据探索包括了解数据的大致结构、数据量、各特征的统计信息、整个数据质量情况、数据的分布情况等。为了更好地体现数据分布情况,数据可视化是一个不错的方法。通过对数据探索后,可能会发现不少问题:如存在缺失数据、数据不规范、数据分布不均衡、存在奇异数据、有很多非数值数据、存在很多无关或不重要的数据等。这些问题的存在直接影响数据质量,为此,数据预处理工作就应该是接下来的重点工作。数据预处理是机器学习过程中必不可少的重要步骤,特别是在生产环境中的机器学习,数据往往是原始、未加工和未处理过的,数据预处理常常占据整个机器学习过程的大部分时间。
数据预处理过程中,一般包括数据清理、数据转换、规范数据、特征选择等工作。

建立模型及损失函数

考虑:

  • 最后一层是否需要添加softmax或sigmoid激活层。
  • 选择合适损失函数。
  • 选择合适的优化器。

损失函数的选择:

在这里插入图片描述

评估及优化模型

评估方法:

  • 留出法(Holdout):留出法的步骤相对简单,直接将数据集划分为两个互斥的集合,其中一个集合作为训练集,另一个作为测试集。在训练集上训练出模型后,用测试集来评估测试误差,作为泛化误差的估计。使用留出法,还可以优化出一种更好的方法,就是把数据分成3部分:训练数据集、验证数据集、测试数据集。训练数据集用来训练模型,验证数据集用来调优超参数,测试集则用来测试模型的泛化能力。数据量较大时可采用这种方法。
  • K折交叉验证:不重复地随机将训练数据集划分为k个,其中k-1个用于模型训练,剩余的一个用于测试。
  • 重复的K折交叉验证:当数据量比较小,数据分布不很均匀时可以采用这种方法。

过拟合与欠拟合

在训练模型过程中,经常会出现刚开始训练时,训练和测试精度不高(或损失值较大),然后通过增加迭代次数或通过优化,训练精度和测试精度继续提升,如果出现这种情况,当然最好。但随着我们训练迭代次数的增加
或不断优化,也有可能会出现训练精度或损失值继续改善,但测试精度或损失值不降反升的情况,如下图所示。
在这里插入图片描述

出现这种情况,说明我们的优化过头了,把训练数据中一些无关紧要甚至错误的模式也学到了。这就是通常说的出现过拟合了。那如何解决这类问题?机器学习中有很多解决方法,这些方法又统称为正则化。

权重正则化

房屋面积(Size)和预测房价(Price)的回归模型:

在这里插入图片描述
通过正则化使参数变小甚至趋于原点。图(a)考虑的特征太少,模型过于简单,导致欠拟合。图(c)在建立模型时把一些噪声数据也包括进去了,使得模型复杂,导致过拟合。

如果要降低模型的复杂度,可以通过缩减它们的系数来实现,如把第3次、4次项的系数θ3、θ4缩减到接近于0即可。

假设房屋价格与面积间模型的损失函数为:
m i n θ 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 \underset{\theta}{min}\frac{1}{2m}\sum_{i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})^2 θmin2m1i=1m(hθ(x(i))y(i))2
这个损失函数是我们的优化目标,也就是说我们需要尽量减少损失函数的均方误差。
对于这个函数我们对它添加一些正则项,如加上10000乘以θ3的平方,再加上10000乘以θ4的平方,得到如下函数:
m i n θ 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 + 10000 ∗ θ 3 2 + 10000 ∗ θ 4 2 \underset{\theta}{min}\frac{1}{2m}\sum_{i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})^2+10000*\theta_3^2+10000*\theta_4^2 θmin2m1i=1m(hθ(x(i))y(i))2+10000θ32+10000θ42
这里取10000只是用来代表它是一个“大值”。现在,如果要最小化这个新的损失函数,应要让θ3和θ4尽可能的小。因为如果你在原有损失函数的基础上加上10000乘以θ3这一项,那么这个新的损失函数将变得很大,所以,当要最小化这个新的损失函数时,将使θ3的值接近于0,同样θ4的值也接近于0,就像我们所忽略的这两个值一样。如果做到这一点(θ3和θ4接近于0),那么将得到一个近似的二次函数:

在这里插入图片描述
传统意义上的正则化一般分为L0、L1、L2、L∞等。

PyTorch如何实现正则化呢?这里以实现L2为例,神经网络的L2正则化称为权重衰减(Weight Decay)。torch.optim集成了很多优化器,如SGD、Adadelta、Adam、Adagrad、RMSprop等,这些优化器自带的一个参数weight_decay,用于指定权值衰减率,相当于L2正则化中的λ参数,也就是下式中的λ:
m i n θ 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 + λ ∣ ∣ W ∣ ∣ 2 \underset{\theta}{min}\frac{1}{2m}\sum_{i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})^2+\lambda||W||^2 θmin2m1i=1m(hθ(x(i))y(i))2+λW2

Dropout正则化

Dropout的做法是在训练过程中按一定比例(比例参数可设置)随机忽略或屏蔽一些神经元。这些神经元会被随机“抛弃”,也就是说它们在正向传播过程中对于下游神经元的贡献效果暂时消失了,反向传播时该神经元也不
会有任何权重的更新。所以,通过传播过程,Dropout将产生和L2范数相同的收缩权重的效果。

随着神经网络模型的不断学习,神经元的权值会与整个网络的上下文相匹配。神经元的权重针对某些特征进行调优,进而产生一些特殊化。周围的神经元则会依赖于这种特殊化,但如果过于特殊化,模型会因为对训练数据的过拟合而变得脆弱不堪。神经元在训练过程中的这种依赖于上下文的现象被称为复杂的协同适应(Complex Co-Adaptations)。
加入了Dropout以后,输入的特征都是有可能会被随机清除的,所以该神经元不会再特别依赖于任何一个输入特征,也就是说不会给任何一个输入设置太大的权重。由于网络模型对神经元特定的权重不那么敏感。这反过来又提升了模型的泛化能力,不容易对训练数据过拟合。

Dropout训练的集成包括所有从基础网络除去非输出单元形成子网络:

Dropout在训练阶段和测试阶段是不同的,一般在训练中使用,测试时不使用。不过在测试时,为了平衡(因训练时舍弃了部分节点或输出),一般将输出按Dropout Rate比例缩小。

使用Dropout原则:

  • 通常丢弃率控制在20%~50%比较好,可以从20%开始尝试。如果比例太低则起不到效果,比例太高则会导致模型的欠学习。
  • 在大的网络模型上应用。
  • 在输入层和隐藏层都使用Dropout。对于不同的层,设置的keep_prob也不同,一般来说神经元较少的层,会设keep_prob为1.0或接近于1.0的数;神经元较多的层,则会将keep_prob设置得较小,如0.5或更小。
  • 增加学习速率和冲量。把学习速率扩大10~100倍,冲量值调高到0.9~0.99。
  • 限制网络模型的权重。

使用Dropout和不使用Dropout构建网络代码如下:

net1_overfitting = torch.nn.Sequential(
    torch.nn.Linear(13, 16),
    torch.nn.ReLU(),
    torch.nn.Linear(16, 32),
    torch.nn.ReLU(),
    torch.nn.Linear(32, 1),
)
net1_dropped = torch.nn.Sequential(
    torch.nn.Linear(13, 16),
    torch.nn.Dropout(0.5), # drop 50% of the neuron
    torch.nn.ReLU(),
    torch.nn.Linear(16, 32),
    torch.nn.Dropout(0.5), # drop 50% of the neuron
    torch.nn.ReLU(),
    torch.nn.Linear(32, 1),
)

批量正则化

在实际训练过程中,经常出现隐含层因数据分布不均,导致梯度消失或不起作用的情况。如采用sigmoid函数
或tanh函数为激活函数时,如果数据分布在两侧,这些激活函数的导数就接近于0。这样一来,BP算法得到的梯度也就消失了。如何解决这个问题?

Sergey Ioffe和Christian Szegedy两位学者提出了批标准化(Batch Normalization)方法。Batch Normalization不仅可以有效地解决梯度消失问题,而且还可以让调试超参数更加简单,在提高训练模型效率的同时,还可让神经网络模型更加“健壮”。

输入:微批次(mini-batch)数据:B={x1,x2,…,xm}
学习参数:γ,β类似于权重参数,可以通过梯度下降等算法求得。
其中xi并不是网络的训练样本,而是指原网络中任意一个隐藏层激活函数的输入,这些输入是训练样本在网络中前向传播得来的。
输出:{yi=NBγ,β(xi)}

求微批次样本均值:
μ B ← 1 m ∑ i = 1 m x i \mu_B\leftarrow \frac{1}{m} \sum_{i=1}^{m}x_i μBm1i=1mxi
求微批次样本方差:
σ 2 ← 1 m ∑ i = 1 m ( x i − μ B ) 2 \sigma^2\leftarrow\frac{1}{m}\sum_{i=1}^{m}(x_i-\mu_B)^2 σ2m1i=1m(xiμB)2
x i x_i xi进行标准化处理:
x ^ ← x i − μ B σ B 2 + ∈ \hat{x}\leftarrow\frac{x_i-\mu_B}{\sqrt{\sigma_B^2+\in}} x^σB2+ xiμB
反标准化操作:
y i = γ x 1 ^ + β ≡ N B γ , β ( x i ) y_i=\gamma \hat{x_1} + \beta \equiv NB_{\gamma,\beta}(x_i) yi=γx1^+βNBγ,β(xi)
BN是对隐藏层的标准化处理,它与输入的标准化处理Normalizing Inputs是有区别的。Normalizing Inputs是使所有输入的均值为0,方差为1。而Batch Normalization可使各隐藏层输入的均值和方差为任意值。实际上,从激活函数的角度来看,如果各隐藏层的输入均值在靠近0的区域,即处于激活函数的线性区域,这样不利于训练好的非线性神经网络,而且得到的模型效果也不会太好。式(6)就起这个作用,当然它还有将归一化后的x还原的功能。那么BN一般用在哪里呢?BN应作用在非线性映射前,即对x=Wu+b做规范化时,在每一个全连接和激励函数之间。

一般在神经网络训练时遇到收敛速度很慢,或梯度爆炸等无法训练的状况时,可以尝试用BN来解决。另外,在一般情况下,也可以加入BN来加快训练速度,提高模型精度,还可以大大地提高训练模型的效率。BN具体功能如下所示。

  • 可以选择比较大的初始学习率,让训练速度飙升。之前还需要慢慢地调整学习率,甚至在网络训练到一半的时候,还需要想着学习率进一步调小的比例选择多少比较合适。现在我们可以采用初始很大的学习率,然而学习率的衰减速度也很快,因为这个算法收敛很快。当然,这个算法即使你选择了较小的学习率,也比以前的收敛速度快,因为它具有快速训练收敛的特性。
  • 不用再去理会过拟合中Dropout、L2正则项参数的选择问题,采用BN算法后,你可以移除这两项参数,或者可以选择更小的L2正则约束参数了,因为BN具有提高网络泛化能力的特性。
  • 再也不需要使用局部响应归一化层。
  • 可以把训练数据彻底打乱。

代码:添加BN曾和不添加BN层

net1_overfitting = torch.nn.Sequential(
    torch.nn.Linear(13, 16),
    torch.nn.ReLU(),
    torch.nn.Linear(16, 32),
    torch.nn.ReLU(),
    torch.nn.Linear(32, 1),
)
net1_nb = torch.nn.Sequential(
    torch.nn.Linear(13, 16),
    nn.BatchNorm1d(num_features=16),#BN
    torch.nn.ReLU(),
    torch.nn.Linear(16, 32),
    nn.BatchNorm1d(num_features=32),#BN
    torch.nn.ReLU(),
    torch.nn.Linear(32, 1),
)

权重初始化

初始化能决定算法是否收敛,如果算法的初始化不适当,初始值过大可能会在前向传播或反向传播中产生爆炸的值;如果太小将导致丢失信息。对收敛的算法适当的初始化能加快收敛速度。初始值的选择将影响模型收敛局部最小值还是全局最小值。

常见的参数初始化有零值初始化、随机初始化、均匀分布初始、正态分布初始和正交分布初始等。一般采用正态分布或均匀分布的初始值,实践表明正态分布、正交分布、均匀分布的初始值能带来更好的效果。

选择合适的激活函数

激活函数各种信息:

在这里插入图片描述

在搭建神经网络时,如何选择激活函数?如果搭建的神经网络层数不多,选择sigmoid、tanh、relu、softmax都可以;而如果搭建的网络层次较多,那就需要小心,选择不当就可导致梯度消失问题。此时一般不宜选择sigmoid、tanh激活函数,因它们的导数都小于1,尤其是sigmoid的导数在[0,1/4]之间,多层叠加后,根据微积分链式法则,随着层数增多,导数或偏导将指数级变小。所以层数较多的激活函数需要考虑其导数不宜小于1当然也不能大于1,大于1将导致梯度爆炸,导数为1最好,而激活函数relu正好满足这个条件。所以,搭建比较深的神经网络时,一般使用relu激活函数,当然一般神经网络也可使用。此外,激活函数softmax由于 ∑ i σ i ( z ) = 1 \sum_{i}\sigma_i(z)=1 iσi(z)=1,常用于多分类神经网络输出层。

激活函数在PyTorch中使用示例:

import torch
import torch.nn as nn
m = nn.Sigmoid()
input = torch.randn(2)
output = m(input)

激活函数输入维度与输出维度是一样的。激活函数的输入维度一般包括批量数N,即输入数据的维度一般是4维,如(N,C,W,H)。

选择合适的损失函数

损失函数(Loss Function)在机器学习中非常重要,因为训练模型的过程实际就是优化损失函数的过程。损失函数对每个参数的偏导数就是梯度下降中提到的梯度,防止过拟合时添加的正则化项也是加在损失函数后面。损失函数用来衡量模型的好坏,损失函数越小说明模型和参数越符合训练样本。任何能够衡量模型预测值与真实值之间的差异的函数都可以叫作损失函数。在机器学习中常用的损失函数有两种,即交叉熵(Cross Entropy)和均方误差(Mean squared error,MSE),分别对应机器学习中的分类问题和回归问题。

对分类问题的损失函数一般采用交叉熵,交叉熵反应的两个概率分布的距离(不是欧氏距离)。分类问题进一步又可分为多目标分类,如一次要判断100张图是否包含10种动物,或单目标分类。

回归问题预测的不是类别,而是一个任意实数。在神经网络中一般只有一个输出节点,该输出值就是预测值。反应的预测值与实际值之间的距离可以用欧氏距离来表示,所以对这类问题通常使用均方差作为损失函数,均方差的定义如下:
M S E = ∑ i = 1 n ( y i − y i ′ ) 2 n MSE=\frac{\sum_{i=1}^{n}(y_{i}-y_{i}\prime)^2}{n} MSE=ni=1n(yiyi)2

torch.nn.MSELoss:

torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')

计算公式: l ( x , y ) = L = l 1 , l 2 , . . , l N , l n = ( x n − y n ) 2 l(x,y)=L={l_1,l_2,..,l_N},l_n=(x_n-y_n)^2 l(x,y)=L=l1,l2,..,lN,ln=(xnyn)2,N是批量大小。

如果参数reduction为非None(缺省值为’mean’),则:

在这里插入图片描述

x和y是任意形状的张量,每个张量都有n个元素,如果reduction取’none’, 将不是标量;如果取’sum’,则 只是差平方的和,但不会除以n。

主要看参数reduction,reduction可以取none、mean、sum,缺省值为mean。如果size_average、reduce取值,将覆盖reduction的取值。

实例:

import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(10)
loss = nn.MSELoss(reduction='mean')
input = torch.randn(1,2,requires_grad=True)
print(input)
target=torch.randn(1,2)
print(target)
output=loss(input,target)
print(output)
output.backward()

结果:

tensor([[-0.6014, -1.0122]], requires_grad=True)
tensor([[-0.3023, -1.2277]])
tensor(0.0680, grad_fn=<MseLossBackward0>)

torch.nn.CrossEntropyLoss

交叉熵损失(Cross-Entropy Loss)又称对数似然损失(Log-likelihood Loss)、对数损失;二分类时还可称之为逻辑回归损失(Logistic Loss)。在PyTroch里,它不是严格意义上的交叉熵损失函数,而是先将Input经过softmax激活函数,将向量“归一化”成概率形式,然后再与target计算严格意义上的交叉熵损失。在多分类任务中,经常采用softmax激活函数+交叉熵损失函数,因为交叉熵描述了两个概率分布的差异,然而神经网络输出的是向量,并不是概率分布的形式。所以需要softmax激活函数将一个向量进行“归一化”成概率分布的形式,再采用交叉熵损失函数计算loss。

格式:

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean)

公式:
l o s s ( x , c l a s s ) = − l o g ( e x p ( x [ c l a s s ] ) ∑ j e x p ( x [ j ] ) ) = − x [ c l a s s ] + l o g ( ∑ j e x p ( x [ j ] ) ) loss(x,class)=-log(\frac{exp(x[class])}{\sum_jexp(x[j])})=-x[class]+log(\sum_jexp(x[j])) loss(x,class)=log(jexp(x[j])exp(x[class]))=x[class]+log(jexp(x[j]))
如果带上权重weight,则:
l o s s ( x , c l a s s ) = w e i g h t [ c l a s s ] ( − x [ c l a s s ] + l o g ( ∑ j e x p ( x [ j ] ) ) ) loss(x,class)=weight[class](-x[class]+log(\sum_{j}exp(x[j]))) loss(x,class)=weight[class](x[class]+log(jexp(x[j])))
weight(Tensor)-为每个类别的loss设置权值,常用于类别不均衡问题。weight必须是float类型的tensor,其长度要与类别C一致,即每一个类别都要设置weight。

import torch
import torch.nn as nn
torch.manual_seed(10)

loss = nn.CrossEntropyLoss()
#假设类别数为5
input = torch.randn(3,5,requires_grad=True)
print(input)
#每个样本对应的类别索引,其值范围为[0,4]
target = torch.empty(3,dtype=torch.long).random_(5)
print(target)
output = loss(input,target)
print(output)
output.backward()

结果:

tensor([[-0.6014, -1.0122, -0.3023, -1.2277,  0.9198],
        [-0.3485, -0.8692, -0.9582, -1.1920,  1.9050],
        [-0.9373, -0.8465,  2.2678,  1.3615,  0.0157]], requires_grad=True)
tensor([4, 0, 3])
tensor(1.4795, grad_fn=<NllLossBackward0>)

选择合适优化器

传统梯度优化的不足

传统梯度更新算法为最常见、最简单的一种参数更新策略。其基本思想是:先设定一个学习率λ,参数沿梯度的反方向移动。假设需更新的参数为θ,梯度为g,则其更新策略可表示为:
θ ← θ − λ g \theta \leftarrow \theta-\lambda g θθλg
这种梯度更新算法简洁,当学习率取值恰当时,可以收敛到全面最优点(凸函数)或局部最优点(非凸函数)。但其不足也很明显,对超参数学习率比较敏感(过小导致收敛速度过慢,过大又越过极值点)。

在这里插入图片描述

学习率除了敏感,有时还会因其在迭代过程中保持不变,很容易造成算法被卡在鞍点的位置。

在这里插入图片描述

在这里插入图片描述

在较平坦区域,梯度接近于0,优化算法因误判而提前终止迭代。

动量算法

梯度下降法在遇到平坦或高曲率区域时,学习过程有时很慢。利用动量算法能比较好解决这个问题。

在这里插入图片描述

动量(Momentum)是模拟物理里动量的概念,具有物理上惯性的含义,一个物体在运动时具有惯性,把这个思想运用到梯度下降计算中,可以增加算法的收敛速度和稳定性。

在这里插入图片描述

动量算法每下降一步都是由前面下降方向的一个累积和当前点的梯度方向组合而成。

算法伪代码:

在这里插入图片描述

Nesterov Accelerated Gradient,简称NAG算法:这种预更新方法能防止大幅振荡,不会错过最小值,并会对参数更新更加敏感。

算法伪代码:

在这里插入图片描述

NAG动量法和经典动量法的差别就在B点和C点梯度的不同。

AdaGrad算法

动量算法在一定程度上缓解了对参数空间某些方向的问题,但需要新增一个参数,而且对学习率的控制还不是很理想。为了更好地驾驭这个超参数,人们想出来多种自适应优化算法,使用自适应优化算法,学习率不再是一个固定不变值,它会根据不同情况自动调整来适应相应的情况。

AdaGrad算法是通过参数来调整合适的学习率λ,是能独立地自动调整模型参数的学习率,对稀疏参数进行大幅更新和对频繁参数进行小幅更新。因此,Adagrad方法非常适合处理稀疏数据。

在这里插入图片描述

  • 随着迭代时间越长,累积梯度r越大,导致学习速率 λ σ + r \frac{\lambda}{\sigma+\sqrt{r}} σ+r λ随着时间减小,在接近目标值时,不会因为学习速率过大而越过极值点。
  • 不同参数之间的学习速率不同,因此,与前面固定学习速率相比,不容易在鞍点卡住。
  • 如果梯度累积参数r比较小,则学习速率会比较大,所以参数迭代的步长就会比较大。相反,如果梯度累积参数比较大,则学习速率会比较小,所以迭代的步长会比较小。

RMSProp算法

RMSProp算法通过修改AdaGrad得来,其目的是在非凸背景下效果更好。针对梯度平方和累计越来越大的问题,RMSProp指数加权的移动平均代替梯度平方和。RMSProp为了使用移动平均,还引入了一个新的超参数ρ,用来控制移动平均的长度范围。

在这里插入图片描述

Adam算法

Adam(Adaptive Moment Estimation)本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。
Adam是另一种学习速率自适应的深度神经网络方法,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习速率。Adam算法伪代码如下:

在这里插入图片描述

我们可以通过先使用Adam优化算法来进行训练,这将大大地节省训练时间,且不必担心初始化和参数调整,一旦用Adam训练获得较好的参数后,就可以切换到SGD+动量优化,以达到最佳性能。采用这种方法有时能达到很好的效果。如下图所示,迭代次数超过150后,用SGD效果好于Adam。

在这里插入图片描述

GPU加速

单GPU加速

把数据从内存转移到GPU,一般针对张量(我们需要的数据)和模型。对张量(类型为FloatTensor或者是LongTensor等),一律直接使用方法.to(device)或.cuda()。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#或device = torch.device("cuda:0")
device1 = torch.device("cuda:1")
for batch_idx, (img, label) in enumerate(train_loader):
img=img.to(device)
label=label.to(device)

对于模型来说,也是同样的方式,使用.to(device)或.cuda来将网络放到GPU显存。

#实例化网络
model = Net()
model.to(device) #使用序号为0的GPU
#或model.to(device1) #使用序号为1的GPU

多GPU加速

使用时直接用model传入torch.nn.DataParallel函数即可,代码如下所示:

net = torch.nn.DataParallel(model)
#假设有4个GPU,其id设置如下
device_ids =[0,1,2,3]
#对数据
input_data=input_data.to(device=device_ids[0])
#对于模型
net = torch.nn.DataParallel(model)
net.to(device)

使用GPU注意事项

  • GPU的数量尽量为偶数,奇数的GPU有可能会出现异常中断的情况;
  • GPU很快,但数据量较小时,效果可能没有单GPU好,甚至还不如CPU;
  • 如果内存不够大,使用多GPU训练的时候可设置pin_memory为False,当然使用精度稍微低一点的数据类型有时也有效果。

`

多GPU加速

使用时直接用model传入torch.nn.DataParallel函数即可,代码如下所示:

net = torch.nn.DataParallel(model)
#假设有4个GPU,其id设置如下
device_ids =[0,1,2,3]
#对数据
input_data=input_data.to(device=device_ids[0])
#对于模型
net = torch.nn.DataParallel(model)
net.to(device)

使用GPU注意事项

  • GPU的数量尽量为偶数,奇数的GPU有可能会出现异常中断的情况;
  • GPU很快,但数据量较小时,效果可能没有单GPU好,甚至还不如CPU;
  • 如果内存不够大,使用多GPU训练的时候可设置pin_memory为False,当然使用精度稍微低一点的数据类型有时也有效果。

参考书籍:《Python深度学习:基于PyTorch》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1100dp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值