#python #deep-learning #pytorch #prediction #loss-function
#python #глубокое обучение #pytorch #прогнозирование #потеря-функция
Вопрос:
У меня есть очень простая сеть resnet18, которую я пытаюсь обучить с нуля для задачи оценки ориентиров (у меня есть 4 ориентира):
num_classes = 4 * 2 #4 coordinates X and Y flattened --> 4 of 2D keypoints or landmarks
class Network(nn.Module):
def __init__(self,num_classes=8):
super().__init__()
self.model_name = 'resnet18'
self.model = models.resnet18()
self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)
def forward(self, x):
x = x.float()
out = self.model(x)
return out
Для следующего фрагмента кода:
network = Network()
network.cuda()
criterion = nn.MSELoss()
optimizer = optim.Adam(network.parameters(), lr=0.0001)
loss_min = np.inf
num_epochs = 1
start_time = time.time()
for epoch in range(1,num_epochs 1):
loss_train = 0
loss_test = 0
running_loss = 0
network.train()
print('size of train loader is: ', len(train_loader))
for step in range(1,len(train_loader) 1):
batch = next(iter(train_loader))
images, landmarks = batch['image'], batch['landmarks']
#RuntimeError: Given groups=1, weight of size [64, 3, 7, 7], expected input[64, 600, 800, 3] to have 3 channels, but got 600 channels instead
#using permute to fix the above error
images = images.permute(0,3,1,2)
images = images.cuda()
landmarks = landmarks.view(landmarks.size(0),-1).cuda()
##images = torchvision.transforms.Normalize(images) #find the args later
##landmarks = torchvision.transforms.Normalize(landmarks) #find the args later
predictions = network(images)
# clear all the gradients before calculating them
optimizer.zero_grad()
print('predictions are: ', predictions.float())
print('landmarks are: ', landmarks.float())
# find the loss for the current step
loss_train_step = criterion(predictions.float(), landmarks.float())
loss_train_step = loss_train_step.to(torch.float32)
print("loss_train_step before backward: ", loss_train_step)
# calculate the gradients
loss_train_step.backward()
# update the parameters
optimizer.step()
print("loss_train_step after backward: ", loss_train_step)
loss_train = loss_train_step.item()
print("loss_train: ", loss_train)
running_loss = loss_train/step
print('step: ', step)
print('running loss: ', running_loss)
print_overwrite(step, len(train_loader), running_loss, 'train')
network.eval()
with torch.no_grad():
for step in range(1,len(test_loader) 1):
batch = next(iter(train_loader))
images, landmarks = batch['image'], batch['landmarks']
images = images.permute(0,3,1,2)
images = images.cuda()
landmarks = landmarks.view(landmarks.size(0),-1).cuda()
predictions = network(images)
# find the loss for the current step
loss_test_step = criterion(predictions, landmarks)
loss_test = loss_test_step.item()
running_loss = loss_test/step
print_overwrite(step, len(test_loader), running_loss, 'Validation')
loss_train /= len(train_loader)
loss_test /= len(test_loader)
print('n--------------------------------------------------')
print('Epoch: {} Train Loss: {:.4f} Valid Loss: {:.4f}'.format(epoch, loss_train, loss_test))
print('--------------------------------------------------')
if loss_test < loss_min:
loss_min = loss_test
torch.save(network.state_dict(), '../moth_landmarks.pth')
print("nMinimum Valid Loss of {:.4f} at epoch {}/{}".format(loss_min, epoch, num_epochs))
print('Model Savedn')
print('Training Complete')
print("Total Elapsed Time : {} s".format(time.time()-start_time))
Я получаю этот NAN, а также очень большие потери MSE (показаны только для одного шага):
size of train loader is: 90
predictions are: tensor([[-0.0380, -0.1871, 0.0729, -0.3570, -0.2153, 0.3066, 1.1273, -0.0558],
[-0.0316, -0.1876, 0.0317, -0.3613, -0.2333, 0.3023, 1.0940, -0.0665],
[-0.0700, -0.1882, 0.0068, -0.3201, -0.1884, 0.2953, 1.0516, -0.0567],
[-0.0844, -0.2009, 0.0573, -0.3166, -0.2597, 0.3127, 1.0343, -0.0573],
[-0.0486, -0.2333, 0.0535, -0.3245, -0.2310, 0.2818, 1.0590, -0.0716],
[-0.0240, -0.1989, 0.0572, -0.3135, -0.2435, 0.2912, 1.0612, -0.0560],
[-0.0942, -0.2439, 0.0277, -0.3147, -0.2368, 0.2978, 1.0110, -0.0874],
[-0.0356, -0.2285, 0.0064, -0.3179, -0.2432, 0.3083, 1.0300, -0.0756]],
device='cuda:0', grad_fn=<AddmmBackward>)
landmarks are: tensor([[501.9200, 240.1600, 691.0000, 358.0000, 295.0000, 294.0000, 488.6482,
279.6466],
[495.6300, 246.0600, 692.0000, 235.0000, 286.0000, 242.0000, 464.0000,
339.0000],
[488.7100, 240.8900, 613.4007, 218.3425, 281.0000, 220.0000, 415.9966,
338.4796],
[502.5721, 245.4983, 640.0000, 131.0000, 360.0000, 143.0000, 542.9840,
321.8463],
[505.1393, 246.4364, 700.0000, 306.0000, 303.0000, 294.0000, 569.6925,
351.8367],
[501.0900, 244.0100, 724.0000, 251.0000, 302.0000, 276.0000, 504.6415,
291.7443],
[495.9500, 244.2800, 608.0000, 127.0000, 323.0000, 166.0000, 491.0000,
333.0000],
[490.2500, 241.3400, 699.0000, 304.0000, 398.6197, 313.8339, 429.1374,
303.8483]], device='cuda:0')
loss_train_step before backward: tensor(166475.6875, device='cuda:0', grad_fn=<MseLossBackward>)
loss_train_step after backward: tensor(166475.6875, device='cuda:0', grad_fn=<MseLossBackward>)
loss_train: 166475.6875
step: 1
running loss: 166475.6875
Другая вещь, помимо сети, к которой я также отношусь с подозрением, — это преобразования:
Вот преобразования, которые я использую:
transformed_dataset = MothLandmarksDataset(csv_file='moth_gt.csv',
root_dir='.',
transform=transforms.Compose(
[
Rescale(256),
RandomCrop(224),
ToTensor()#,
##transforms.Normalize(mean = [ 0.485, 0.456, 0.406 ],
## std = [ 0.229, 0.224, 0.225 ])
]
)
)
Как я могу это исправить? Кроме того, при нормализации я все еще сталкиваюсь с той же проблемой (NAN и очень большие значения потерь, поскольку прогнозы очень неверны).
Как я могу в принципе отладить, почему прогнозы очень плохие?
Комментарии:
1. Я вижу, вы используете только 1 эпоху, вы пробовали больше?
2. ну, это еще хуже. Я показываю одну эпоху только для иллюстрации.
Ответ №1:
Я думаю, что есть проблема с тем, как вы используете DataLoader
. iter(train_loader)
создает итератор из загрузчика данных, и вызов next
должен дать вам следующий пример из dataset. Но вы вызываете next(iter(train_loader))
на каждой итерации, которая каждый раз создает новый итератор из train_loader
и возвращает следующий пример, который по сути будет первым примером в вашем наборе данных. Поэтому я думаю, что таким образом вы заканчиваете обучение (и проверку) на одном и том же примере на каждой итерации. Даже если ваш загрузчик данных каждый раз перетасовывает набор данных, вы в конечном итоге будете тренироваться на некоторых случайных выборках из набора данных (поскольку каждый раз будет использоваться только первая случайная выборка), а не на полном наборе данных. Попробуйте изменить свой код таким образом, чтобы вы использовали iter(train_loader)
только один раз и и вызывали next
на каждой итерации:
train_iter = iter(train_loader)
for step in range(1, len(train_loader) 1):
batch = next(train_iter)
# now batch contains (step)th batch (assuming 1-based indexing)
Или еще лучше измените свой for
цикл, чтобы выполнить итерацию train_loader
самого:
for step, batch in enumerate(train_loader):
# now batch contains (step)th batch (assuming 0-based indexing)
Аналогичное изменение также потребуется для проверки или оценки. Дайте мне знать, если это решит вашу проблему или поможет каким-либо образом.