大家好,我是机器学习的新手,我想询问一下关于改变Sigmoid函数阈值的问题。
我知道Sigmoid函数的值在[0,1]范围内,0.5被用作阈值,如果h(theta) < 0.5,我们假设其值为0,如果h(theta) >= 0.5,则其值为1。
阈值只在网络的输出层使用,且仅在分类时使用。所以,如果你要在三个类别之间进行分类,你可以为每个类别设置不同的阈值(如0.2,0.4,0.4 – 分别对应每个类别)吗?或者你可以设定一个整体不同的阈值,比如0.8?我不确定如何在下面的代码中定义这些。任何指导都会被感激。
# Hyper Parametersinput_size = 14hidden_size = 40hidden_size2 = 30num_classes = 3num_epochs = 600batch_size = 34learning_rate = 0.01class Net(torch.nn.Module): def __init__(self, n_input, n_hidden, n_hidden2, n_output): super(Net, self).__init__() # define linear hidden layer output self.hidden = torch.nn.Linear(n_input, n_hidden) self.hidden2 = torch.nn.Linear(n_hidden, n_hidden2) # define linear output layer output self.out = torch.nn.Linear(n_hidden, n_output) def forward(self, x): """ In the forward function we define the process of performing forward pass, that is to accept a Variable of input data, x, and return a Variable of output data, y_pred. """ # get hidden layer input h_input1 = self.hidden(x) # define activation function for hidden layer h_output1 = torch.sigmoid(h_input1) # get hidden layer input h_input2 = self.hidden2(h_output1) # define activation function for hidden layer h_output2 = torch.sigmoid(h_input2) # get output layer output out = self.out(h_output2) return outnet = Net(input_size, hidden_size, hidden_size, num_classes)criterion = nn.CrossEntropyLoss()optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)all_losses = []for epoch in range(num_epochs): total = 0 correct = 0 total_loss = 0 for step, (batch_x, batch_y) in enumerate(train_loader): X = batch_x Y = batch_y.long() # Forward + Backward + Optimize optimizer.zero_grad() # zero the gradient buffer outputs = net(X) loss = criterion(outputs, Y) all_losses.append(loss.item()) loss.backward() optimizer.step() if epoch % 50 == 0: _, predicted = torch.max(outputs, 1) # calculate and print accuracy total = total + predicted.size(0) correct = correct + sum(predicted.data.numpy() == Y.data.numpy()) total_loss = total_loss + loss if epoch % 50 == 0: print( "Epoch [%d/%d], Loss: %.4f, Accuracy: %.2f %%" % (epoch + 1, num_epochs, total_loss, 100 * correct / total) )train_input = train_data.iloc[:, :input_size]train_target = train_data.iloc[:, input_size]inputs = torch.Tensor(train_input.values).float()targets = torch.Tensor(train_target.values - 1).long()outputs = net(inputs)_, predicted = torch.max(outputs, 1)
回答:
你可以使用你认为合适的任何阈值。
众所周知,神经网络往往过于自信(例如,对50个类别中的一个应用0.95),所以在你的情况下使用不同的阈值可能会有益。
你的训练过程很好,但你应该改变预测(最后两行),并像这样使用torch.nn.softmax
:
outputs = net(inputs) probabilities = torch.nn.functional.softmax(outputs, 1)
如其他答案中提到,你将得到每行概率之和为1
(之前你有未归一化的概率,即logits)。
现在,只需对这些概率使用你想要的阈值:
predictions = probabilities > 0.8
请注意,在某些情况下你可能会得到全零(例如,[0.2, 0.3, 0.5]
)。
这意味着根据你的标准,神经网络对结果不够自信,可能会减少错误的正预测数量(抽象地说,假设你正在预测一个患者是否没有三种互斥疾病中的一种。如果你没有足够的把握,最好不要做这样的预测)。
为每个类别设置不同的阈值
这也可以这样做:
thresholds = torch.tensor([0.1, 0.1, 0.8]).unsqueeze(0)predictions = probabilities > thresholds
最后的评论
请注意,在使用softmax
的情况下,只有一个类别应该是答案(如另一答案中指出的),这种方法(以及提到Sigmoid)可能表明你在进行多标签分类。
如果你想训练你的网络以同时预测多个类别,你应该使用sigmoid
并将损失函数更改为torch.nn.BCEWithLogitsLoss
。