在pytorch中实现的vgg16的训练损失不会减少

时间:2019-08-22 08:27:53

标签: pytorch vgg-net

我想在火炬中尝试一些玩具示例,但训练损失不会减少。

此处提供了一些信息:

  • 模型为vgg16,由13个转换层和3个密集层组成。
  • 数据为pytorch中的cifar100。
  • 我选择交叉熵作为损失函数。

代码如下

# encoding: utf-8

import torch
import torch.optim as optim
import torch.nn as nn
import torch.nn.functional as F
import torchvision.transforms as transforms
import torchvision

import numpy as np


class VGG16(torch.nn.Module):
    def __init__(self, n_classes):
        super(VGG16, self).__init__()

        # construct model
        self.conv1_1 = nn.Conv2d(3, 64, 3, padding=1)
        self.conv1_2 = nn.Conv2d(64, 64, 3, padding=1)
        self.conv2_1 = nn.Conv2d(64, 128, 3, padding=1)
        self.conv2_2 = nn.Conv2d(128, 128, 3, padding=1)
        self.conv3_1 = nn.Conv2d(128, 256, 3, padding=1)
        self.conv3_2 = nn.Conv2d(256, 256, 3, padding=1)
        self.conv3_3 = nn.Conv2d(256, 256, 3, padding=1)
        self.conv4_1 = nn.Conv2d(256, 512, 3, padding=1)
        self.conv4_2 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv4_3 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv5_1 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv5_2 = nn.Conv2d(512, 512, 3, padding=1)
        self.conv5_3 = nn.Conv2d(512, 512, 3, padding=1)

        self.fc6 = nn.Linear(512, 512)
        self.fc7 = nn.Linear(512, 512)
        self.fc8 = nn.Linear(512, n_classes)

    def forward(self, x):
        x = F.relu(self.conv1_1(x))
        x = F.relu(self.conv1_2(x))
        x = F.max_pool2d(x, (2, 2))

        x = F.relu(self.conv2_1(x))
        x = F.relu(self.conv2_2(x))
        x = F.max_pool2d(x, (2, 2))

        x = F.relu(self.conv3_1(x))
        x = F.relu(self.conv3_2(x))
        x = F.relu(self.conv3_3(x))
        x = F.max_pool2d(x, (2, 2))

        x = F.relu(self.conv4_1(x))
        x = F.relu(self.conv4_2(x))
        x = F.relu(self.conv4_3(x))
        x = F.max_pool2d(x, (2, 2))

        x = F.relu(self.conv5_1(x))
        x = F.relu(self.conv5_2(x))
        x = F.relu(self.conv5_3(x))
        x = F.max_pool2d(x, (2, 2))

        x = x.view(-1, self.num_flat_features(x))

        x = F.relu(self.fc6(x))
        x = F.relu(self.fc7(x))
        x = self.fc8(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]

        num_features = 1
        for s in size:
            num_features *= s
        return num_features


if __name__ == '__main__':

    BATCH_SIZE = 128
    LOG_INTERVAL = 5

    # data
    transform = transforms.Compose([
        transforms.ToTensor()
    ])

    trainset = torchvision.datasets.CIFAR100(
        root='./data',
        train=True,
        download=True,
        transform=transform
    )

    testset = torchvision.datasets.CIFAR100(
        root='./data',
        train=False,
        download=True,
        transform=transform
    )

    trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True)
    testloader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE, shuffle=False)

    # model
    vgg16 = VGG16(100)
    vgg16.cuda()

    # optimizer
    optimizer = optim.SGD(vgg16.parameters(), lr=0.01)

    # loss
    criterion = nn.CrossEntropyLoss()

    print('———— Train Start —————')
    for epoch in range(20):
        running_loss = 0.
        for step, (batch_x, batch_y) in enumerate(trainloader):
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

            # 
            optimizer.zero_grad()

            output = vgg16(batch_x)
            loss = criterion(output, batch_y)
            loss.backward()
            optimizer.step()

            running_loss += loss.item()

            if step % LOG_INTERVAL == 0:
                print('[%d, %4d] loss: %.4f' % (epoch, step, running_loss / LOG_INTERVAL))
                running_loss = 0.

        def test():
            print('———— Test Start ————')
            correct = 0
            total = 0

            # 
            with torch.no_grad():
                for test_x, test_y in testloader:
                    images, labels = test_x.cuda(), test_y.cuda()
                    output = vgg16(images)
                    _, predicted = torch.max(output.data, 1)
                    total += labels.size(0)
                    correct += (predicted == labels).sum().item()

            accuracy = 100 * correct / total
            print('Accuracy of the network is: %.4f %%' % accuracy)
            print('———— Test Finish ————')

        test()

    print('———— Train Finish —————')

损失保持在4.6060附近,并且从未减少。我尝试了不同的学习率,但没有用。

1 个答案:

答案 0 :(得分:1)

我注意到您在卷积层之间没有使用批处理规范化。我添加了批处理规范化层,它似乎可以工作。以下是修改后的代码:

<form method="post" action="" name="form-$i" class="commentForm">

但是,可以找到更优雅的版本here