Доступен ли 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])
Где ошибка?
Вкратце: вы сглаживаете первые две оси, а именно 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 сплющенных векторов... Я не могу сказать, имеет ли это смысл и условия. обучение и сможет ли модель извлечь из этого уроки. Я могу ошибаться!
Имеет ли это смысл, если изображение в градациях серого?
Возможно, так оно и есть, если вы считаете, что обрабатываете изображение построчно как последовательность 300
векторов размера 300
. Я не уверен насчет RGB, вам нужно посмотреть, где каналы смешиваются в вашей последовательности ... если они последовательные или нет. В приведенном выше коде размер входных данных равен 3*300
, то есть трехканальной пиксельной «линии», так что в конце концов это может сработать ... Вам нужно попробовать обучение и посмотреть, сможете ли вы получить с ним результаты. Я надеюсь, что смог помочь!
Да, это очень помогает, но почему вы считаете 6*3*300*300//300//300 в первом измерении. Не могли бы еще раз пояснить?
Конечно. В своем коде вы вызвали 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
.
Да, именно поэтому размер ввода 900 не имеет никакого смысла. Теперь понял спасибо.
Сколько стоит
input_size
и где определяетсяstacked_rnn_model
?