Как изменить эту сверточную нейронную сеть PyTorch, чтобы она принимала изображение размером 64 x 64 и правильно выводила прогнозы? - PullRequest
0 голосов
/ 20 декабря 2018

Я взял эту сверточную нейронную сеть (CNN) от здесь .Он принимает 32 х 32 изображения и по умолчанию 10 классов.Тем не менее, у меня есть 64 х 64 изображения с 500 классами.Когда я передаю 64 x 64 изображения (размер пакета остается неизменным на уровне 32), я получаю следующую ошибку:

ValueError: Expected input batch_size (128) to match target batch_size (32).

Трассировка стека начинается со строки loss = loss_fn(outputs, labels).outputs.shape - [128, 500], а labels.shape - [32].

Код приведен здесь для полноты.

class Unit(nn.Module):
    def __init__(self,in_channels,out_channels):
        super(Unit,self).__init__()
        self.conv = nn.Conv2d(in_channels=in_channels,kernel_size=3,out_channels=out_channels,stride=1,padding=1)
        self.bn = nn.BatchNorm2d(num_features=out_channels)
        self.relu = nn.ReLU()

    def forward(self,input):
        output = self.conv(input)
        output = self.bn(output)
        output = self.relu(output)
        return output

class SimpleNet(nn.Module):
    def __init__(self,num_classes=10):
        super(SimpleNet,self).__init__()

        self.unit1 = Unit(in_channels=3,out_channels=32)
        self.unit2 = Unit(in_channels=32, out_channels=32)
        self.unit3 = Unit(in_channels=32, out_channels=32)

        self.pool1 = nn.MaxPool2d(kernel_size=2)

        self.unit4 = Unit(in_channels=32, out_channels=64)
        self.unit5 = Unit(in_channels=64, out_channels=64)
        self.unit6 = Unit(in_channels=64, out_channels=64)
        self.unit7 = Unit(in_channels=64, out_channels=64)

        self.pool2 = nn.MaxPool2d(kernel_size=2)

        self.unit8 = Unit(in_channels=64, out_channels=128)
        self.unit9 = Unit(in_channels=128, out_channels=128)
        self.unit10 = Unit(in_channels=128, out_channels=128)
        self.unit11 = Unit(in_channels=128, out_channels=128)

        self.pool3 = nn.MaxPool2d(kernel_size=2)

        self.unit12 = Unit(in_channels=128, out_channels=128)
        self.unit13 = Unit(in_channels=128, out_channels=128)
        self.unit14 = Unit(in_channels=128, out_channels=128)

        self.avgpool = nn.AvgPool2d(kernel_size=4)

        self.net = nn.Sequential(self.unit1, self.unit2, self.unit3, self.pool1, self.unit4, self.unit5, self.unit6
                                 ,self.unit7, self.pool2, self.unit8, self.unit9, self.unit10, self.unit11, self.pool3,
                                 self.unit12, self.unit13, self.unit14, self.avgpool)

        self.fc = nn.Linear(in_features=128,out_features=num_classes)

    def forward(self, input):
        output = self.net(input)
        output = output.view(-1,128)
        output = self.fc(output)
        return output

Любые идеи о том, как изменить этот CNN дляпринять и правильно вернуть результаты?

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Проблема в несовместимом изменении формы (представление) в конце.

В конце вы используете своего рода «выравнивание», которое отличается от «глобального объединения».Оба действительны для CNN, но только глобальные пулы совместимы с любым размером изображения.

Сглаженная сетка (ваш случай)

В вашем случае, когда выровняете, вам нужно отслеживать все размеры изображения, чтобы знать, как изменить форму в конце.

Итак:

  • Введите с 64x64
  • Пул от 1 до 32x32
  • Пул от 2 до 16x16
  • Пул от 3 до 8x8
  • AvgPool to 2x2

Затем в конце вы получите форму (batch, 128, 2, 2).Четырехкратное окончательное число, если изображение было 32х32.

Тогда ваше окончательное изменение формы должно быть output = output.view(-1,128*2*2).

Это другая сеть с другим классификационным слоем, потому что in_features=512.

Сеть глобального пула

С другой стороны, вы можете использовать ту же модель, те же слои и тот же вес для любого размера изображения> = 32, если заменить последний пул глобальным пулом:

def flatChannels(x):
    size = x.size()
    return x.view(size[0],size[1],size[2]*size[3])

def globalAvgPool2D(x):        
    return flatChannels(x).mean(dim=-1)

def globalMaxPool2D(x):
    return flatChannels(x).max(dim=-1)

Окончание модели:

    #removed the pool from here to put it in forward
    self.net = nn.Sequential(self.unit1, self.unit2, self.unit3, self.pool1, self.unit4, 
                             self.unit5, self.unit6, self.unit7, self.pool2, self.unit8, 
                             self.unit9, self.unit10, self.unit11, self.pool3, 
                             self.unit12, self.unit13, self.unit14)

    self.fc = nn.Linear(in_features=128,out_features=num_classes)


def forward(self, input):
    output = self.net(input)
    output = globalAvgPool2D(output) #or globalMaxPool2D
    output = self.fc(output)
    return output
0 голосов
/ 21 декабря 2018

Вам необходимо использовать модуль преобразований перед обучением нейронной сети (вот ссылка https://pytorch.org/docs/stable/torchvision/transforms.html).

У вас есть несколько вариантов:

  1. преобразований.Resize (32),

  2. transforms.ResizedCrop (32) - наиболее предпочтительно, потому что вы можете увеличить ваши данные и таким образом предотвратить переобучение.

  3. transforms.CenterCrop (32) и т. Д.

Более того, вы можете составить преобразованные объекты в один объект с помощью transforms.Compose).

Наслаждайтесь.

PS.Конечно, вы можете реорганизовать свою архитектуру нейронной сети, позволяя ей получать изображения размером 64 x 64.

...