问题描述
我试图让模型预测 75x75 图像的种族,但是每当我训练模型时,准确率始终完全保持在 53.2%。直到我在一些照片上实际运行它之前,我才意识到为什么。事实证明,无论照片是什么,它总会预测“其他”。我不完全确定为什么。
我从 the official PyTorch Quickstart tutorial 复制了代码,在该数据集或标准 MNIST 数据中,它运行良好。我将数据集更改为 UTKFace,然后它开始一直只预测一个标签。
这是我的代码:
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision.datasets import ImageFolder
from torchvision.transforms import ToTensor
import torch.nn.functional as F
training_data = ImageFolder(
root = "data_training/",transform = ToTensor(),)
testing_data = ImageFolder(
root = "data_testing/",transform = ToTensor()
)
training_DataLoader = DataLoader(training_data,batch_size=64,shuffle=True)
test_DataLoader = DataLoader(testing_data,shuffle=True)
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork,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(1296,1024)
self.fc2 = nn.Linear(1024,1024)
self.fc3 = nn.Linear(1024,512)
self.fc4 = nn.Linear(512,84)
self.fc5 = nn.Linear(84,5)
def forward(self,x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(x.size(0),-1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = F.relu(self.fc3(x))
x = F.relu(self.fc4(x))
x = self.fc5(x)
return x
model = NeuralNetwork().to("cpu")
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(),lr=1e-3)
def train(DataLoader,model,loss_fn,optimizer):
size = len(DataLoader.dataset)
for batch,(X,y) in enumerate(DataLoader):
X,y = X.to("cpu"),y.to("cpu")
# Compute prediction error
pred = model(X)
loss = loss_fn(pred,y)
# Backpropagation
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 tests(DataLoader,model):
size = len(DataLoader.dataset)
model.eval()
test_loss,correct = 0,0
with torch.no_grad():
for X,y in DataLoader:
X,y.to("cpu")
pred = model(X)
test_loss += loss_fn(pred,y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= size
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%,Avg loss: {test_loss:>8f} \n")
epochs = 10
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(training_DataLoader,optimizer)
tests(test_DataLoader,model)
torch.save(model.state_dict(),"model.pth")
训练日志:
Epoch 1
-------------------------------
loss: 1.628994 [ 0/23705]
loss: 1.620698 [ 6400/23705]
loss: 1.615423 [12800/23705]
loss: 1.596390 [19200/23705]
Test Error:
Accuracy: 53.2%,Avg loss: 0.024725
Epoch 2
-------------------------------
loss: 1.593613 [ 0/23705]
loss: 1.581375 [ 6400/23705]
loss: 1.583656 [12800/23705]
loss: 1.591942 [19200/23705]
Test Error:
Accuracy: 53.2%,Avg loss: 0.024165
Epoch 3
-------------------------------
loss: 1.541260 [ 0/23705]
loss: 1.592345 [ 6400/23705]
loss: 1.540908 [12800/23705]
loss: 1.540741 [19200/23705]
Test Error:
Accuracy: 53.2%,Avg loss: 0.023705
Epoch 4
-------------------------------
loss: 1.566888 [ 0/23705]
loss: 1.524875 [ 6400/23705]
loss: 1.540764 [12800/23705]
loss: 1.510044 [19200/23705]
Test Error:
Accuracy: 53.2%,Avg loss: 0.023323
Epoch 5
-------------------------------
loss: 1.530084 [ 0/23705]
loss: 1.498773 [ 6400/23705]
loss: 1.537755 [12800/23705]
loss: 1.508989 [19200/23705]
Test Error:
Accuracy: 53.2%,Avg loss: 0.022993
....
无论我给它设置了多少个 epoch,或者我添加了多少层来试图让它过拟合,它似乎总是一遍又一遍地猜测同样的事情,没有任何改进的迹象。
>我根据姓名的种族类别将 UTKFace 数据集分成多个文件夹。训练数据有23705张图片,测试数据有10134张。
我不确定为什么会发生这种情况。我的数据集不够大吗?层数不够?
解决方法
层数和数据集大小不能解释此示例的这种行为。你的 CNN 表现得像一个常数函数,到目前为止我不知道为什么,但这些可能是一些线索:
- 由于您已按标签将数据分隔到文件夹中,如果您仅使用这些文件夹中的一个来训练模型,您将获得一个常量函数。
- 你的神经网络的最后一层没有激活函数!也就是说,在方法
forward
中,您正在执行x = self.fc5(x)
而不是x = F.<function>(self.fc5(x))
。 - 加载训练数据时,您在哪里指示每个图像的标签?您确定
training_dataloader
正在加载带有正确标签的图像吗?
一些评论:
- 您是否检查了测试数据中的ground truth(形状可能不同)
- 您能否检查输出概率以查看预测是否一致? (顺便说一句,在这种情况下,你不一定需要最后的激活函数,因为 pytorch 交叉熵已经包含一个 logsoftmax)
- 您是否尝试过使用更多过滤器(例如 16,32 或 64)的 conv2d
- 错误的百分比看起来不错,就像您提供的链接一样,准确度约为 35% 不能过度拟合似乎有点奇怪。