首页 > 解决方案 > 使用 CNN 的 IRIS 数据集精度极低

问题描述

作为初学者,我试图在 IRIS 数据集上实现我的 CNN,只考虑 2 个标签:

我使用 90% 的数据进行训练,使用 10% 的数据进行测试,使用 1D CNN 和 Adam 优化以及 0.001 的学习率。达到的准确率约为 40-50%,这也随着每次执行而变化。请建议应该做什么。

数据加载到数据加载器:

#Training data
class IrisDataset(T.utils.data.Dataset):

  def __init__(self, Iris):    
    sc = StandardScaler()    
    X_tr = sc.fit_transform(trainX)
    Y_tr = trainY     
    self.X_tr = torch.tensor(X_tr, dtype = torch.float32)
    self.Y_tr = torch.tensor(Y_tr, dtype = torch.float32)

  def __len__(self):
    return len(self.Y_tr)

  def __getitem__(self, idx):        
    return self.X_tr[idx], self.Y_tr[idx]

train_ds = IrisDataset(Iris)

bat_size = 1
# Leaving only labels 0 and 1 
idx = np.append(np.where(train_ds.Y_tr == 0)[0], 
                np.where(train_ds.Y_tr == 1)[0])
train_ds.X_tr = train_ds.X_tr[idx]
train_ds.Y_tr = train_ds.Y_tr[idx]

#len(train_ds)
train_ldr = T.utils.data.DataLoader(train_ds,
    batch_size=bat_size, shuffle=True)
batch = next(iter(train_ldr))

# and in the same way test data
#NETWORK CLASS

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv1d(1, 6, kernel_size=1)
        self.conv2 = nn.Conv1d(6, 16, kernel_size=1)
        self.dropout = nn.Dropout2d()
        self.fc1 = nn.Linear(64, 16)
        self.fc2 = nn.Linear(16, 1)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.relu(self.conv2(x))
        x = self.dropout(x)
        x = x.view(x.size(0), -1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return T.cat((x, 1 - x), -1)
# MODEL TRAINING 
model = Net()
optimizer = optim.Adam(model.parameters(), lr=0.001)
loss_func = nn.NLLLoss()
epochs = 2
loss_list = []

model.train()

for epoch in range(epochs):
    total_loss = []
    
    for X_tr, Y_tr in train_ldr:
       X_tr = X_tr.unsqueeze(0)
       optimizer.zero_grad()
 
       output = model(X_tr)
       pred = output.argmax(dim=1, keepdim=True)
       Y_tr = torch.tensor(Y_tr, dtype=torch.long)
       loss = loss_func(output, Y_tr.squeeze(1))
        # Backward pass
       loss.backward()
        # Optimize the weights
       optimizer.step()
        
       total_loss.append(loss.item())

    loss_list.append(sum(total_loss)/len(total_loss))
    print('Training [{:.0f}%]\tLoss: {:.4f}'.format(
         100. * (epoch + 1) / epochs, loss_list[-1]))

标签: pythondeep-learningpytorchconv-neural-network

解决方案


错误就在这里

def forward(self, x):
   x = F.relu(self.conv1(x))
   .
   .
   x = self.fc2(x)
   return T.cat((x, 1 - x), -1)
'''
The thing is that the output from the dense layer is not the probability and hence
you subtracting it form 1 also don't make any sense. It will become probability if 
you use sigmoid activation after it.
'''
def forward(self, x):
   x = F.relu(self.conv1(x))
   .
   .
   x = self.fc2(x) 
   x = torch.nn.functional.sigmoid(x)
   return T.cat((x, 1 - x), -1)

但我建议您将损失函数更改为 BCE,如下所示。这不太容易出错,并且在结果方面与上述相同。您还可以阅读NLL 的文档,并看到它说“通过在网络的最后一层添加 LogSoftmax 层可以轻松实现神经网络中的对数概率。如果您不想添加额外的一层。” 因此,您可以添加LogSoftmax或使用CrossEntropy.

# LogSoftmax
def forward(self, x):
   x = F.relu(self.conv1(x))
   .
   .
   x = self.fc2(x) 
   x = torch.nn.functional.log_softmax(x, dim=1)
   return x

loss_func = nn.NLLLoss()


# BCE
def forward(self, x):
   x = F.relu(self.conv1(x))
   .
   .
   x = self.fc2(x) 
   return x

loss_func = torch.nn.BCEWithLogitsLoss()

推荐阅读