Ожидаемый входной размер_пакета (18) соответствует целевому размеру_пакета (6)

Доступен ли RNN для классификации изображений только для серого изображения? Следующая программа работает для классификации серого изображения.

Если используются изображения RGB, у меня возникает эта ошибка:

Ожидаемый входной размер_пакета (18) соответствует целевому размеру_пакета (6)

в этой строке loss = criterion(outputs, labels).

Моя загрузка данных для поезда, действительного и тестового выглядит следующим образом.

input_size  = 300
inputH = 300
inputW = 300

#Data transform (normalization & data augmentation)
stats = ((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
train_resize_tfms = tt.Compose([tt.Resize((inputH, inputW), interpolation=2),
                         tt.ToTensor(),
                         tt.Normalize(*stats)])

train_tfms = tt.Compose([tt.Resize((inputH, inputW), interpolation=2),
                         tt.RandomHorizontalFlip(),                                                  
                         tt.ToTensor(),
                         tt.Normalize(*stats)])
valid_tfms = tt.Compose([tt.Resize((inputH, inputW), interpolation=2),
                         tt.ToTensor(), 
                         tt.Normalize(*stats)])
test_tfms = tt.Compose([tt.Resize((inputH, inputW), interpolation=2),
                        tt.ToTensor(), 
                        tt.Normalize(*stats)])

#Create dataset
train_ds = ImageFolder('./data/train', train_tfms)
valid_ds = ImageFolder('./data/valid', valid_tfms)
test_ds = ImageFolder('./data/test', test_tfms)

from torch.utils.data.dataloader import DataLoader
batch_size = 6

#Training data loader
train_dl = DataLoader(train_ds, batch_size, shuffle = True, num_workers = 8, pin_memory=True)
#Validation data loader
valid_dl = DataLoader(valid_ds, batch_size, shuffle = True, num_workers = 8, pin_memory=True)
#Test data loader
test_dl = DataLoader(test_ds, 1, shuffle = False, num_workers = 1, pin_memory=True)

Моя модель выглядит следующим образом.

num_steps = 300
hidden_size = 256 #size of hidden layers
num_classes = 5
num_epochs = 20
learning_rate = 0.001
# Fully connected neural network with one hidden layer
num_layers = 2 # 2 RNN layers are stacked  
class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes):
        super(RNN, self).__init__()
        self.num_layers = num_layers
        self.hidden_size = hidden_size
        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True, dropout=0.2)#batch must have first dimension
        #our inpyt needs to have shape
        #x -> (batch_size, seq, input_size)
        self.fc = nn.Linear(hidden_size, num_classes)#this fc is after RNN. So needs the last hidden size of RNN

    def forward(self, x):
        #according to ducumentation of RNN in pytorch
        #rnn needs input, h_0 for inputs at RNN (h_0 is initial hidden state)

        #the following one is initial hidden layer
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)#first one is number of layers and second one is batch size
        #output has two outputs. The first tensor contains the output features of the hidden last layer for all time steps
        #the second one is hidden state f
        out, _ = self.rnn(x, h0)
        #output has batch_size, num_steps, hidden size
        #we need to decode hidden state only the last time step
        #out (N, 30, 128)
        #Since we need only the last time step
        #Out (N, 128)
        out = out[:, -1, :] #-1 for last time step, take all for N and 128
        out = self.fc(out)
        return out


stacked_rnn_model = RNN(input_size, hidden_size, num_layers, num_classes).to(device)

# Loss and optimizer
criterion = nn.CrossEntropyLoss()#cross entropy has softmax at output
#optimizer = torch.optim.Adam(stacked_rnn_model.parameters(), lr=learning_rate) #optimizer used gradient optimization using Adam 
optimizer = torch.optim.SGD(stacked_rnn_model.parameters(), lr=learning_rate)
# Train the model
n_total_steps = len(train_dl)
    for epoch in range(num_epochs):
        t_losses=[]
        for i, (images, labels) in enumerate(train_dl):  
            # origin shape: [6, 3, 300, 300]
            # resized: [6, 300, 300]
            images = images.reshape(-1, num_steps, input_size).to(device)
            print('images shape')
            print(images.shape)
            labels = labels.to(device)
            
            # Forward pass
            outputs = stacked_rnn_model(images)
            print('outputs shape')
            print(outputs.shape)
            loss = criterion(outputs, labels)
            t_losses.append(loss)
            # Backward and optimize
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

Печать изображений и выходных форм

images shape
torch.Size([18, 300, 300])
outputs shape
torch.Size([18, 5])

Где ошибка?

Сколько стоит input_size и где определяется stacked_rnn_model?

Ivan 26.12.2020 11:29
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
368
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вкратце: вы сглаживаете первые две оси, а именно batch и channels.


Я не уверен, что вы выбрали правильный подход, но я напишу об этом слое.

В любом случае, давайте посмотрим на проблему, с которой вы столкнулись. У вас есть загрузчик данных, который создает (6, 3, 300, 300), то есть пакеты из 6 трехканальных 300x300 изображений. Судя по всему, вы хотите преобразовать каждый элемент пакета (3, 300, 300) в (step_size=300, -1).

Однако вместо этого вы воздействуете на первую ось, чего не должны делать, с помощью images.reshape(-1, num_steps, input_size). Это будет иметь желаемый эффект при работе с одноканальными изображениями, поскольку dim=1 не будет «осью канала». В вашем случае у вас есть 3 канала, поэтому результирующая форма: (6*3*300*300//300//300, 300, 300), которая (18, 300, 300), так как num_steps=300 и input_size=300. В результате у вас осталось 18 элементов пакета вместо 6.

Вместо этого вы хотите изменить форму с помощью (batch_size, num_steps, -1). Оставив последнюю ось (она же seq_length) переменного размера. В результате получится форма (6, 300, 900).


Вот исправленный и сокращенный фрагмент:

batch_size = 6
channels = 3
inputH, inputW = 300, 300
train_ds = TensorDataset(torch.rand(100, 3, inputH, inputW), torch.rand(100, 5))
train_dl = DataLoader(train_ds, batch_size)

class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes):
        super(RNN, self).__init__()
        # (batch_size, seq, input_size)
        self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
        # (batch_size, hidden_size)
        self.fc = nn.Linear(hidden_size, num_classes)
        # (batch_size, num_classes)

    def forward(self, x):
        out, _ = self.rnn(x)
        out = out[:, -1, :]
        out = self.fc(out)
        return out

num_steps = 300
input_size = inputH*inputW*channels//num_steps
hidden_size = 256
num_classes = 5
num_layers = 2

rnn = RNN(input_size, hidden_size, num_layers, num_classes)
for x, y in train_dl:
    print(x.shape, y.shape)
    images = images.reshape(batch_size, num_steps, -1)
    print(images.shape)
    outputs = rnn(images)
    print(outputs.shape)
    break

Как я сказал в начале, я немного настороженно отношусь к этому подходу, потому что вы, по сути, кормите свою RNN изображением RGB 300x300 в виде последовательности из 300 сплющенных векторов... Я не могу сказать, имеет ли это смысл и условия. обучение и сможет ли модель извлечь из этого уроки. Я могу ошибаться!

Имеет ли это смысл, если изображение в градациях серого?

batuman 26.12.2020 12:08

Возможно, так оно и есть, если вы считаете, что обрабатываете изображение построчно как последовательность 300 векторов размера 300. Я не уверен насчет RGB, вам нужно посмотреть, где каналы смешиваются в вашей последовательности ... если они последовательные или нет. В приведенном выше коде размер входных данных равен 3*300, то есть трехканальной пиксельной «линии», так что в конце концов это может сработать ... Вам нужно попробовать обучение и посмотреть, сможете ли вы получить с ним результаты. Я надеюсь, что смог помочь!

Ivan 26.12.2020 12:13

Да, это очень помогает, но почему вы считаете 6*3*300*300//300//300 в первом измерении. Не могли бы еще раз пояснить?

batuman 26.12.2020 12:15

Конечно. В своем коде вы вызвали reshape(-1, num_steps, input_size) тензор размера (6, 3, 300, 300) (общая длина: 6*3*300*300). Результирующий тензор будет иметь num_steps на dim=1 (т.е. 300) и input_size на dim=2 (то есть также 300). На dim=0 у вас есть -1, что означает «свести туда все оставшиеся компоненты». Размер оставшегося компонента равен total_size / product([size_dim for each other dim]) (в псевдокоде). Что соответствует 6*3*300*300/(300*300)=18. Поэтому длина стоит 18 на dim=0.

Ivan 26.12.2020 12:21

Да, именно поэтому размер ввода 900 не имеет никакого смысла. Теперь понял спасибо.

batuman 26.12.2020 12:25

Другие вопросы по теме