Я пытаюсь классифицировать два типа изображений (т.е. 2 метки). У меня есть более 30 тыс. Изображений для моего учебного набора данных, и я создал CNN, который описан ниже.
Вот странная часть - я обучил эту сеть более 20 раз, и у меня два совершенно разных поведения -
1. Сеть фактически "научится" , потери уменьшатся, и примерно через 10 эпох я правильно классифицирую около 80% своего тестового набора данных.
2. После просмотра ~ 1 тыс. Изображений (даже не одной эпохи), сеть «решит» всегда классифицировать изображения только как одну из меток! Потеря получения застряла и ничего не происходит
Странная часть - это точно такой же кусок кода! ничего не меняется. Я пытался отлаживать в течение стольких часов и дошел до того, что не имею понятия, что происходит.
Единственное, что я заметил, - это когда сеть не в состоянии учиться, тогда начальный вывод сети (без выполнения даже одной итерации backprop) является чем-то вроде -
model = MyNetwork()
images, labels = iter(train_dataset_loader).next()
fw_pass_output = model(images)
print(fw_pass_output[:5])
---
tensor([[9.4696e-09, 1.0000e+00],
[2.8105e-08, 1.0000e+00],
[7.4285e-09, 1.0000e+00],
[4.3701e-09, 1.0000e+00],
[4.4942e-08, 1.0000e+00]], grad_fn=<SliceBackward>)
С другой стороны, когда сеть преуспевает в обучении, она будет выглядеть следующим образом -
tensor([[0.4982, 0.5018],
[0.4353, 0.5647],
[0.3051, 0.6949],
[0.4823, 0.5177],
[0.4342, 0.5658]], grad_fn=<SliceBackward>)
Итак, как вы можете видеть - когда сети удается научиться, кажется, что первоначальная инициализация веса позволяет более сбалансированные результаты, в то время как в другом случае он просто произвольно назначит все для одного из классов, и оттуда ему никогда не удастся чему-то научиться.
Я пытался переключаться между Adam / SGD, множеством разных уровней обучения , разные значения затухания веса, ничего не помогло ...
Чего мне не хватает? Что вызывает это поведение? Это ошибка в моем коде или концепция, которую я упускаю?
class MyNetwork(nn.Module):
def __init__(self):
super(MyNetwork, self).__init__()
self.conv1_layer = nn.Conv2d(3, 32, 5)
self.conv2_layer = nn.Conv2d(32, 16, 3)
self.conv3_layer = nn.Conv2d(16, 8, 2)
self.layer_size_after_convs = 8 * 5 * 5
TOTAL_NUM_OF_CLASSES = 2
self.fc1 = nn.Linear(self.layer_size_after_convs, TOTAL_NUM_OF_CLASSES)
def forward(self, x):
"""
Perform a forward pass on the network
"""
x = F.relu(self.conv1_layer(x))
x = F.max_pool2d(x, (3, 3))
x = F.relu(self.conv2_layer(x))
x = F.max_pool2d(x, (2, 2))
x = F.relu(self.conv3_layer(x))
x = F.max_pool2d(x, (2, 2))
x = x.view(-1, self.layer_size_after_convs)
x = self.fc1(x)
x = F.softmax(x, dim=1)
return x
model = MyNetwork()
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, weight_decay=0.1)
total_steps = len(train_dataset_loader)
epochs = 100
for epoch_num in range(epochs):
for i, (img_batch, labels) in enumerate(train_dataset_loader):
optimizer.zero_grad()
fw_pass_output = model(img_batch)
loss_values = loss_func(fw_pass_output, labels)
loss_values.backward()
optimizer.step()
print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch_num+1, epochs, i+1, total_steps, loss_values.item()))