PyTorch Con vNet случайным образом запоминает одну метку и застревает - PullRequest
1 голос
/ 21 апреля 2020

Я пытаюсь классифицировать два типа изображений (т.е. 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()))
...