1 optim 优化器
PyTorch神经网络优化器(optimizer)通过调整神经网络的参数(weight和bias)来最小化损失函数(Loss)。
学习链接:
https://pytorch.org/docs/stable/optim.html
1.1 优化器基类
使用时必须构造一个优化器对象,它将保存当前状态,并将根据计算的梯度(grad)更新参数。
调用优化器的step方法。
CLASS torch.optim.Optimizer(params, defaults)
- Optimizer - 优化器的优化算法。
- params (iterable) – torch的迭代器。张量s或dict s,指定应该优化什么张量。
- defaults – (dict): 包含优化选项默认值的字典(在参数组没有指定优化选项时使用)。每个Optimizer算法都有其独特的设置字典。
算法(Optimizer) | 说明 |
---|---|
Adadelta | 采用Adadelta算法。 |
Adagrad | 采用Adagrad算法。 |
Adam | 采用Adam算法。 |
AdamW | 采用AdamW算法。 |
SparseAdam | 采用适合稀疏张量的Adam算法的惰性版本。 |
Adamax | 采用Adamax算法(Adam基于无穷范数的变种)。 |
ASGD | 采用平均随机梯度下降。 |
LBFGS | 采用L-BFGS算法,深受minFunc的启发。 |
NAdam | 采用NAdam 算法。 |
RAdam | 采用RAdam 算法。 |
RMSprop | 采用RMSprop 算法。 |
Rprop | 采用有弹性的反向传播算法。 |
SGD | 采用随机梯度下降算法。 |
1.1.1 SGD 随机梯度下降算法
CLASS torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False, *, maximize=False, foreach=None, differentiable=False)
- params (iterable) – iterable参数优化或字典定义参数组。
- lr (float) – 学习率,需要用户输入。
- momentum (float, optional) – 动量系数(默认值为0)。
- weight_decay (float, optional) – 权重衰减(L2惩罚) (默认值为0)
。 - dampening (float, optional) – 动量阻尼(默认值为0)。
- nesterov (bool, optional) – 使能Nesterov动量(默认值为
False
)。
【Nesterov动量(Nesterov Momentum)是一种基于动量法的优化算法,用于加速神经网络的训练过程。它在随机梯度下降(SGD)的基础上进行改进,通过考虑参数更新前的动量信息来调整参数更新的方向。】 - maximize (bool, optional) – 根据目标最大化参数,而不是最小化参数(默认值为
False
)。 - foreach (bool, optional) – 是否使用foreach优化器的实现。如果用户未指定(foreach为
None
),我们将尝试在CUDA上的for循环实现上使用foreach,因为CUDA通常性能更高(默认值:None
)。 - differentiable (bool, optional) – 是否在训练中的优化器步骤中发生autograd。否则,step()函数在torch.no_grad()上下文中运行。设置为
True
会影响性能,所以如果你不打算通过这个实例运行autograd,请保留False
(默认值为False
)。
学习速率(lr)的取值,如果太大,则模型很不稳定;如果太小,学习速度非常缓慢。因此一般先设置较大的学习速率,然后降低学习速率。
python代码如下:
import torchvision
import torch
from torch import nn, optim
from torch.nn import Linear, Conv2d, MaxPool2d, Flatten, Sequential,CrossEntropyLoss
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
train=False,
transform=torchvision.transforms.ToTensor(),
download=False)
dataloader = DataLoader(dataset, batch_size=1)
class MYNN(nn.Module):
def __init__(self):
super(MYNN, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2, stride=1),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2, stride=1),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2, stride=1),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = CrossEntropyLoss()
mynn = MYNN()
opitm = optim.SGD(mynn.parameters(), lr=0.01) # 优化器
for data in dataloader:
imgs, targets = data
outputs = mynn(imgs)
result_loss = loss(outputs, targets)
# print(outputs) # 神经网络输出
# print(targets) # 目标
# print(result_loss) # 损失函数-交叉熵计算结果
opitm.zero_grad() # 梯度清零,设置断点
result_loss.backward() # 反向传播,求出每个节点的梯度,设置断点
opitm.step() # 对神经网络模型的参数进行调优,设置断点
设置断点,进入程序Debug:
(1)不断运行程序,能够观察到卷积层0的bias梯度变化:mynn -> Protected Attributes -> _modules -> ‘model1’ -> Protected Attributes -> _modules -> ‘0’ -> bias-> grad
(2)能观察到卷积层0的weight梯度变化:mynn -> Protected Attributes -> _modules -> ‘model1’ -> Protected Attributes -> _modules -> ‘0’ -> weight -> grad
(3)能观察到bias的变化:mynn -> Protected Attributes -> _modules -> ‘model1’ -> Protected Attributes -> _modules -> ‘0’ -> bias-> data
(4)能观察到weight的变化:mynn -> Protected Attributes -> _modules -> ‘model1’ -> Protected Attributes -> _modules -> ‘0’ -> weight-> data
(5)结论:运行opitm.zero_grad()后,清空weight和bias的梯度grad;运行result_loss.backward()后,计算得到新的weight和bias的梯度grad;运行opitm.step()后,调整weight和bias的值。
1.1.2 优化器多次循环
修改以上python代码,增加多次循环,观察总体损失值改变。
import torchvision
import torch
from torch import nn, optim
from torch.nn import Linear, Conv2d, MaxPool2d, Flatten, Sequential,CrossEntropyLoss
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10(root="G:\\Anaconda\\pycharm_pytorch\\learning_project\\dataset_CIFAR10",
train=False,
transform=torchvision.transforms.ToTensor(),
download=False)
dataloader = DataLoader(dataset, batch_size=1)
class MYNN(nn.Module):
def __init__(self):
super(MYNN, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2, stride=1),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2, stride=1),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2, stride=1),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = CrossEntropyLoss()
mynn = MYNN()
opitm = optim.SGD(mynn.parameters(), lr=0.01) # 优化器
for epoch in range(20):
running_loss = 0.0
for data in dataloader:
imgs, targets = data
outputs = mynn(imgs)
result_loss = loss(outputs, targets)
# print(outputs) # 神经网络输出
# print(targets) # 目标
# print(result_loss) # 损失函数-交叉熵计算结果
opitm.zero_grad() # 梯度清零
result_loss.backward() # 反向传播,求出每个节点的梯度
opitm.step() # 对神经网络模型的参数进行调优
running_loss = running_loss + result_loss#.data
print(running_loss)
运行结果:
tensor(18746.2012, grad_fn=<AddBackward0>)
tensor(16136.0107, grad_fn=<AddBackward0>)
tensor(15499.3203, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
tensor(nan, grad_fn=<AddBackward0>)
可以发现running_loss在一开始不断降低,但是以下的nan暂时不知道是什么原因。