0
点赞
收藏
分享

微信扫一扫

【pytorch】(五)优化模型参数



文章目录

  • 优化模型参数
  • 超参数
  • 循环优化
  • 损失函数
  • 优化器
  • 完整实现


优化模型参数

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

# ======================= 数据 =======================
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor()
)

test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor()
)

train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)


# ======================= 模型 =======================
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()

self.linear_relu_stack = nn.Sequential(
nn.Linear(28 * 28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)

def forward(self, x):
x = x.flatten(1)
logits = self.linear_relu_stack(x)
return logits

现在我们已经有模型和数据集了,是时候利用数据集来训练、验证和测试我们的模型了。训练模型是一个迭代过程;在每次迭代(称为​​epoch​​)中,数据输入模型;模型对输出进行估计;优化器根据估计值与真实值的误差(损失loss)计算其相对于模型参数的导数(如前一节所示),然后使用梯度下降优化模型的参数。

超参数

超参数是可调的参数,我们可以通过调整超参数来控制模型优化过程:超参数取不同值可能会影响模型训练和收敛速度。

我们为模型的训练定义以下超参数:

learning_rate = 1e-3
batch_size = 64
epochs = 10
  • Epochs:遍历整个数据集的次数
  • Batch Size:更新参数之前输入模型的数据样本数
  • 学习率(Learning Rate):在每个批次/epoch更新模型参数的程度。小的学习率会导致学习速度较慢,而较大的值可能会导致模型不收敛。

循环优化

一旦我们设置了超参数,我们就可以通过循环优化来训练和优化我们的模型。优化循环的每次迭代称为一个​​epoch​​。

每个​​epoch​​由两个主要部分组成:

(1) 训练循环(The Train Loop):迭代训练数据集,尝试着让模型参数收敛到最佳参数。

在训练环节中,优化分为三个步骤:

  • 调用​​optimizer.zero_grad()​​重置模型参数的梯度。默认情况下,梯度是累加的;为了防止重复计数,我们在每次迭代时显式地将它们归零。
  • 通过调用​​loss.backward()​​对预测损失进行反向传播。PyTorch将存储损失关于每个参数的梯度。
  • 一旦我们得到了梯度,我们就调用​​optimizer.step()​​,这将通过在反向传播中收集的梯度来调整参数。
def train_loop(dataloader, model, loss_fn, optimizer):
'''训练循环'''
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X = X.to(device)
y = y.to(device)
# 计算估计值与损失
pred = model(X)
loss = loss_fn(pred, y)

# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()

if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

(2) 验证/测试循环(The Validation/Test Loop):迭代测试数据集,检查模型性能是否正在改善。

def test_loop(dataloader, model, loss_fn):
'''测试循环'''
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss, correct = 0, 0

with torch.no_grad():
for X, y in dataloader:
X = X.to(device)
y = y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()

test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

让我们简单地熟悉一下上文训练循环中使用的一些概念。

损失函数

当输入一些训练数据时,未经训练的网络可能无法输出正确的答案。损失函数衡量估计值与目标值的差距,我们希望在训练过程中最小化损失。为了计算损失,我们使用给定数据样本作为输入进行预测,并将其与真实数据标签值进行比较。

常见的损失函数包括回归任务的​​nn.MSELoss​​​(均方误差)和用于分类的​​nn.NLLLoss​​​(负对数似然)。​​nn.CrossEntropyLoss​​​ 由​​nn.LogSoftmax​​​和​​nn.NLLLoss​​合成。(在后续文章再详细介绍。)

我们将模型的输出逻辑传递给​​nn.CrossEntropyLoss​​,它将规范化logits(模型的输出)并计算预测误差。

loss_fn = nn.CrossEntropyLoss()

优化器

优化是在每个训练步骤中调整模型参数以减少模型误差的过程。优化算法指定如何执行该过程(在本例中,我们使用随机梯度下降)。所有优化逻辑都封装在优化器对象中。这里,我们使用SGD优化器;此外,Pytorch中有许多不同的优化器,如Adam和RMSProp。(在后续文章再详细介绍。)

我们通过传递所需要训练的模型参数和学习率参数来初始化优化器。

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

完整实现

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

# ======================= 数据 =======================
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor()
)

test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor()
)

train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)


# ======================= 模型 =======================
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()

self.linear_relu_stack = nn.Sequential(
nn.Linear(28 * 28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)

def forward(self, x):
x = x.flatten(1)
logits = self.linear_relu_stack(x)
return logits


def train_loop(dataloader, model, loss_fn, optimizer):
'''训练循环'''
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X = X.to(device)
y = y.to(device)
# 计算估计值与损失
pred = model(X)
loss = loss_fn(pred, y)

# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()

if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

def test_loop(dataloader, model, loss_fn):
'''测试循环'''
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss, correct = 0, 0

with torch.no_grad():
for X, y in dataloader:
X = X.to(device)
y = y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()

test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

# 超参数
learning_rate = 1e-3
batch_size = 64
epochs = 10

# 模型实例
model = NeuralNetwork().to(device)
# 损失函数实例
loss_fn = nn.CrossEntropyLoss()
# 优化器实例
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

for t in range(epochs):
print(f"Epoch {t + 1}\n-------------------------------")
train_loop(train_dataloader, model, loss_fn, optimizer)
test_loop(test_dataloader, model, loss_fn)
print("Done!")

参考:

[1] https://pytorch.org/tutorials/beginner/basics/optimization_tutorial.html



举报

相关推荐

0 条评论