PyTorch Multi Class Class使用 CrossEntropyLoss 的化 - 不收敛
PyTorch Multi Class Classification using CrossEntropyLoss - not converging
我正在尝试建立一个简单的网络来输出一个数字属于三个 class 之一的概率。这些是小于 1.1、介于 1.1 和 1.5 之间以及大于 1.5。我正在使用带有 class 标签 0、1 和 2 的交叉熵损失,但无法解决问题。
每次我训练时,无论输入如何,网络都会输出 class 2 的最大概率。我似乎能够达到的最低损失是 0.9ish。任何关于我哪里出错的建议将不胜感激!所有代码如下。
class gating_net(nn.Module):
def __init__(self, input_dim, output_dim):
super(gating_net, self).__init__()
self.linear1 = nn.Linear(input_dim, 32)
self.linear2 = nn.Linear(32, output_dim)
def forward(self, x):
# The original input (action) is used as the residual.
x = F.relu(self.linear1(x))
x = F.sigmoid(self.linear2(x))
return x
learning_rate = 0.01
batch_size = 64
epochs = 500
test = 1
gating_network = gating_net(1,3)
optimizer = torch.optim.SGD(gating_network.parameters(), lr=learning_rate, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, mode='max', factor=0.5, patience=20, verbose=True)
for epoch in range (epochs):
input_ = []
label_ = []
for i in range (batch_size):
scale = random.randint(10,20)/10
input = scale
if scale < 1.1:
label = np.array([0])
elif 1.1 < scale < 1.5:
label = np.array([1])
else:
label = np.array([2])
input_.append(np.array([input]))
label_.append(label)
optimizer.zero_grad()
# get output from the model, given the inputs
output = gating_network.forward(torch.FloatTensor(input_))
old_label = torch.FloatTensor(label_)
# get loss for the predicted output
loss = nn.CrossEntropyLoss()(output, old_label.squeeze().long())
# get gradients w.r.t to parameters
loss.backward()
# update parameters
optimizer.step()
scheduler.step(loss)
print('epoch {}, loss {}'.format(epoch, loss.item()))
if loss.item() < 0.01:
print("########## Solved! ##########")
torch.save(mod_network.state_dict(), './supervised_learning/run_{}.pth'.format(test))
break
# save every 500 episodes
if epoch % 100 == 0:
torch.save(gating_network.state_dict(), './run_{}.pth'.format(test))
- 您的代码每个时期(在本例中也是每个批次)生成训练数据。这是非常多余的,但并不意味着代码无法运行。然而, 影响训练的一件事是 class 之间训练数据的不平衡。使用您的代码,大部分训练数据始终标记为
2
。所以直觉上,你的网络总是会更多地了解 class 2
。这就是为什么对于非常小的 500 纪元,网络 class 将所有 classes 化为 2
,因为这是降低损失的快速简便的方法。然而,当网络无法通过应用有关标签 2
的知识来降低损失时,它也会学习 1
和 0
。所以可以训练网络,虽然效率不高。
- 接上一期,使用
ReduceLROnPlateau
也是效率不高的,因为在网络开始学习标签0
和1
时,学习率已经小(直观地说)。并不意味着它无法训练,但可能会花费很多时间。
CrossEntropyLoss
在内部计算 LogSoftmax
,因此在网络末端有 Sigmoid
意味着在 Sigmoid
层之后有一个 Softmax
层,这可能不是你想要的。我认为网络不一定'wrong',但它会更难训练。
- 实际上比例
1.1
被标记为 2
因为你有 <1.1
和 >1.1
。
TL;DR
删除 sigmoid
和 scheduler
。
我能够在大约 15000 个纪元的某个地方获得 Solved!
(学习率和批量大小与您的代码相同)。
我正在尝试建立一个简单的网络来输出一个数字属于三个 class 之一的概率。这些是小于 1.1、介于 1.1 和 1.5 之间以及大于 1.5。我正在使用带有 class 标签 0、1 和 2 的交叉熵损失,但无法解决问题。
每次我训练时,无论输入如何,网络都会输出 class 2 的最大概率。我似乎能够达到的最低损失是 0.9ish。任何关于我哪里出错的建议将不胜感激!所有代码如下。
class gating_net(nn.Module):
def __init__(self, input_dim, output_dim):
super(gating_net, self).__init__()
self.linear1 = nn.Linear(input_dim, 32)
self.linear2 = nn.Linear(32, output_dim)
def forward(self, x):
# The original input (action) is used as the residual.
x = F.relu(self.linear1(x))
x = F.sigmoid(self.linear2(x))
return x
learning_rate = 0.01
batch_size = 64
epochs = 500
test = 1
gating_network = gating_net(1,3)
optimizer = torch.optim.SGD(gating_network.parameters(), lr=learning_rate, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, mode='max', factor=0.5, patience=20, verbose=True)
for epoch in range (epochs):
input_ = []
label_ = []
for i in range (batch_size):
scale = random.randint(10,20)/10
input = scale
if scale < 1.1:
label = np.array([0])
elif 1.1 < scale < 1.5:
label = np.array([1])
else:
label = np.array([2])
input_.append(np.array([input]))
label_.append(label)
optimizer.zero_grad()
# get output from the model, given the inputs
output = gating_network.forward(torch.FloatTensor(input_))
old_label = torch.FloatTensor(label_)
# get loss for the predicted output
loss = nn.CrossEntropyLoss()(output, old_label.squeeze().long())
# get gradients w.r.t to parameters
loss.backward()
# update parameters
optimizer.step()
scheduler.step(loss)
print('epoch {}, loss {}'.format(epoch, loss.item()))
if loss.item() < 0.01:
print("########## Solved! ##########")
torch.save(mod_network.state_dict(), './supervised_learning/run_{}.pth'.format(test))
break
# save every 500 episodes
if epoch % 100 == 0:
torch.save(gating_network.state_dict(), './run_{}.pth'.format(test))
- 您的代码每个时期(在本例中也是每个批次)生成训练数据。这是非常多余的,但并不意味着代码无法运行。然而, 影响训练的一件事是 class 之间训练数据的不平衡。使用您的代码,大部分训练数据始终标记为
2
。所以直觉上,你的网络总是会更多地了解 class2
。这就是为什么对于非常小的 500 纪元,网络 class 将所有 classes 化为2
,因为这是降低损失的快速简便的方法。然而,当网络无法通过应用有关标签2
的知识来降低损失时,它也会学习1
和0
。所以可以训练网络,虽然效率不高。 - 接上一期,使用
ReduceLROnPlateau
也是效率不高的,因为在网络开始学习标签0
和1
时,学习率已经小(直观地说)。并不意味着它无法训练,但可能会花费很多时间。 CrossEntropyLoss
在内部计算LogSoftmax
,因此在网络末端有Sigmoid
意味着在Sigmoid
层之后有一个Softmax
层,这可能不是你想要的。我认为网络不一定'wrong',但它会更难训练。- 实际上比例
1.1
被标记为2
因为你有<1.1
和>1.1
。
TL;DR
删除 sigmoid
和 scheduler
。
我能够在大约 15000 个纪元的某个地方获得 Solved!
(学习率和批量大小与您的代码相同)。