详解model.train()和model.eval()两种模式的原理与用法
在PyTorch中,训练过程和评估过程存在不同的模式。这两种模式分别由model.train()
和model.eval()
方法控制,在训练和评估深度学习模型时,这两种模式之间的切换非常重要。
model.train()的原理和用法
当我们在训练模型时,我们可以使用model.train()
方法来将模型切换到训练模式。在训练模式下,模型会启用一些特定的功能,如Dropout和BatchNormalization等。
Dropout是一种在训练过程中防止过拟合的正则化技术。它在每个训练迭代中随机删除一些神经元,以便训练期间强制模型不依赖于特定的输入特征。BatchNormalization是一种技术,用于加速模型的训练和提高其性能。它标准化模型中的每个层的输入并使其具有零均值和单位方差。
在调用model.train()
方法后,如下所示:
model.train()
可以使模型切换到训练模式。在这种模式下,计算图记录每个操作,以便在反向传播期间进行梯度计算。
model.eval()的原理和用法
当我们要评估模型时,我们可以使用model.eval()
方法将模型切换到评估模式。在评估模式下,模型不会应用Dropout和BatchNormalization等正则化技术。
可能会问,为什么需要这种不同的行为方式?
Dropout和BatchNormalization在训练模型时可有效降低过拟合,但在评估模型时不需要。因此,在进行模型评估时,需要将模型切换为评估模式以禁用这些特定的正则化技术。
在调用model.eval()
方法后,如下所示:
model.eval()
可以使模型切换到评估模式。在这种模式下,计算图不会记录每个操作,因为我们不会训练模型。评估模式将模型切换为在评估阶段使用的模式。
下面是一个简单的示例,说明了如何在训练模式和评估模式之间切换:
import torch.nn as nn
# 创建一个模型
model = nn.Linear(10, 1)
# 将模型切换到训练模式
model.train()
# 训练模型...
for epoch in range(10):
# 前向传播
y_pred = model(X)
# 计算损失
loss = criterion(y_pred, y)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 将模型切换到评估模式
model.eval()
# 在评估模式下测试模型...
with torch.no_grad():
y_pred = model(X_test)
test_loss = criterion(y_pred, y_test)
print("测试损失为:{:.4f}".format(test_loss.item()))
在这个示例中,我们训练了一个线性模型,并使用model.train()
方法将模型切换到训练模式。然后,我们在一个简单的for循环中执行了一些训练迭代。
在完成了一些训练迭代后,我们使用model.eval()
方法将模型切换到评估模式,并使用with torch.no_grad()
来禁止梯度计算。在这种模式下,我们在测试数据集上执行了一些测试,并计算了测试损失。
另一个使用示例
下面是另一个使用示例,更具体地说明了model.train()和model.eval()方法之间的区别,在这个示例中,我们使用了nn.BatchNorm2d函数和Dropout层。这个模型使用CIFAR-10数据集进行训练和测试。
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torchvision.datasets import CIFAR10
# 定义CNN模型:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
self.dropout = nn.Dropout(p=0.2)
self.bn1 = nn.BatchNorm2d(6)
self.bn2 = nn.BatchNorm2d(16)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.pool(nn.functional.relu(x))
x = self.conv2(x)
x = self.bn2(x)
x = self.pool(nn.functional.relu(x))
x = x.view(-1, 16 * 5 * 5)
x = nn.functional.relu(self.fc1(x))
x = self.dropout(x)
x = nn.functional.relu(self.fc2(x))
x = self.dropout(x)
x = self.fc3(x)
return x
# 数据预处理并加载CIFAR-10数据集:
transform_train = transforms.Compose([
transforms.RandomCrop(32, padding=4),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
])
transform_test = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
])
trainset = CIFAR10(root='./data', train=True, download=True, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset = CIFAR10(root='./data', train=False, download=True, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
# 定义优化方法和损失函数:
net = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# 训练过程:
def train(epoch):
print('\n第 {} 次训练'.format(epoch))
net.train()
for batch_idx, (inputs, targets) in enumerate(trainloader):
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
if batch_idx % 5000 == 0:
print('\n批处理 {} 的损失为: {:.3f}'.format(
batch_idx, loss.item()))
# 测试过程
def test():
net.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for inputs, targets in testloader:
outputs = net(inputs)
loss = criterion(outputs, targets)
test_loss += loss.item()
_, predicted = outputs.max(1)
correct += predicted.eq(targets).sum().item()
test_loss /= len(testloader.dataset)
print('\n测试集的损失为: {:.4f}'.format(test_loss))
print('\n测试集的准确率为:{}/{} ( {:.2f}% )'.format(
correct, len(testloader.dataset),
100. * correct / len(testloader.dataset)))
# 执行训练和测试过程:
for epoch in range(1, 11):
train(epoch)
test()
在这个示例中,我们定义了一个CNN模型,并使用Dropout和BatchNorm2d函数来在训练模式下应用Dropout和BatchNormalization。
在训练模式下,我们使用net.train()
方法将模型切换为训练模式,并在每个训练迭代中应用Dropout和BatchNormalization正则化技术。
在测试模式下,我们使用net.eval()
方法将模型切换为评估模式,并在测试数据集上执行评估过程。因此,我们不应用Dropout或BatchNorm2d,因为这些正则化技术在测试模式下不需要。
最后,在这个示例中进行了10次训练迭代,并在每次训练迭代完成后对模型进行一次评估,以查看模型的性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解model.train()和model.eval()两种模式的原理与用法 - Python技术站