3

I've been teaching myself this since November and any help on this would be really appreciated, thank you for looking, as I seem to be going round in circles. I am trying to use a Pytorch CNN example that was used with the Mnist dataset. Now I am trying to modify the CNN for facial key point recognition. I am using the Kaggle dataset (CSV) of 7048 training images and key points (15 key points per face) and 1783 test images. I split training dataset and converted the images to jpeg, made separate file for the key points (shape 15, 2). I have made dataset and data loader and can iterate through and display images and plot key points. When I run the CNN I am getting this error.

> Net(
  (conv1): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (conv2_drop): Dropout2d(p=0.5)
  (fc1): Linear(in_features=589824, out_features=100, bias=True)
  (fc2): Linear(in_features=100, out_features=30, bias=True)
)
Data and target shape:  torch.Size([64, 96, 96])   torch.Size([64, 15, 2])
Data and target shape:  torch.Size([64, 1, 96, 96])   torch.Size([64, 15, 2])

Traceback (most recent call last):
  File "/home/keith/PycharmProjects/FacialLandMarks/WorkOut.py", line 416, in <module>
    main()
  File "/home/keith/PycharmProjects/FacialLandMarks/WorkOut.py", line 412, in main
    train(args, model, device, train_loader, optimizer, epoch)
  File "/home/keith/PycharmProjects/FacialLandMarks/WorkOut.py", line 324, in train
    loss = F.nll_loss(output, target)
  File "/home/keith/Desktop/PycharmProjects/fkp/FacialLandMarks/lib/python3.6/site-packages/torch/nn/functional.py", line 1788, in nll_loss
    .format(input.size(0), target.size(0)))
ValueError: Expected input batch_size (4) to match target batch_size (64).

Process finished with exit code 1

Here are some links I have read, I could not figure out the problem but may help some one else.

https://github.com/pytorch/pytorch/issues/11762 How do I modify this PyTorch convolutional neural network to accept a 64 x 64 image and properly output predictions? pytorch-convolutional-neural-network-to-accept-a-64-x-64-im Pytorch Validating Model Error: Expected input batch_size (3) to match target batch_size (4) model-error-expected-input-batch-size-3-to-match-target-ba

Here is my code:

    class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=5, stride=1, padding=(2, 2))
        self.conv2 = nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=(2, 2))
        self.conv2_drop = nn.Dropout2d()
        self.fc1 = nn.Linear(64 * 96 * 96, 100)
        self.fc2 = nn.Linear(100, 30)  # 30 is x and y key points

    def forward(self, x):
        x = F.relu(F.max_pool2d(self.conv1(x), 2))
        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
        x = x.view(-1, 64 * 96 * 96)
        # x = x.view(x.size(0), -1)
        # x = x.view(x.size()[0], 30, -1)
        x = F.relu(self.fc1(x))
        x = F.dropout(x, training=self.training)
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)


def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, batch in enumerate(train_loader):
        data = batch['image']
        target = batch['key_points']
        print('Data and target shape: ', data.shape, ' ', target.shape)
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        data = data.unsqueeze(1).float()

        print('Data and target shape: ', data.shape, ' ', target.shape)

        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))


# def test(args, model, device, test_loader):
#     model.eval()
#     test_loss = 0
#     correct = 0
#     with torch.no_grad():
#         for data, target in test_loader:
#             data, target = data.to(device), target.to(device)
#             output = model(data)
#             test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
#             pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
#             correct += pred.eq(target.view_as(pred)).sum().item()
#
#     test_loss /= len(test_loader.dataset)
#     print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
#         test_loss, correct, len(test_loader.dataset),
#         100. * correct / len(test_loader.dataset)))



def main():
    # Training settings
    parser = argparse.ArgumentParser(description='Project')
    parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
                        help='input batch size for testing (default: 1000)')
    parser.add_argument('--epochs', type=int, default=10, metavar='N',   # ========  epoch
                        help='number of epochs to train (default: 10)')
    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                        help='learning rate (default: 0.01)')
    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                        help='SGD momentum (default: 0.5)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--log-interval', type=int, default=10, metavar='N',
                        help='how many batches to wait before logging training status')
    args = parser.parse_args()
    use_cuda = not args.no_cuda and torch.cuda.is_available()

    torch.manual_seed(args.seed)

    device = torch.device("cuda" if use_cuda else "cpu")

    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
    train_data_set = FaceKeyPointDataSet(csv_file='faces/Kep_points_and_id.csv',
                                         root_dir='faces/',
                                         transform=transforms.Compose([
                                             # Rescale(96),
                                             ToTensor()
                                         ]))

    train_loader = DataLoader(train_data_set, batch_size=args.batch_size,
                              shuffle=True)

    print('Number of samples: ', len(train_data_set))
    print('Number of train_loader: ', len(train_loader))

    model = Net().to(device)
    print(model)
    optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)

    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        # test(args, model, device, test_loader)

if __name__ == '__main__':
    main()
5
  • can you print the shape of output? I think you somehow manage to return output with batch size 4 instead of 64 Commented Feb 28, 2019 at 15:44
  • Hi, thanks for looking, no I cant, trying to now. Commented Feb 28, 2019 at 17:30
  • Yes, made a few changes and got this: Output shape: torch.Size([4, 30]). Commented Feb 28, 2019 at 17:38
  • I suspect the view(-1,...) in your code. check the dimension Commented Feb 28, 2019 at 17:40
  • Sorry I'm not sure what you mean. I've played about with these values and still not running. I thought the -1 would be OK because its if your unsure of the number of rows, however the length of the columns are not all the same, could this be the issue? Commented Feb 28, 2019 at 18:25

1 Answer 1

2

to understand what went wrong you can print shape after every step in forward :

# Input data
torch.Size([64, 1, 96, 96])
x = F.relu(F.max_pool2d(self.conv1(x), 2))
torch.Size([64, 32, 48, 48])
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
torch.Size([64, 64, 24, 24])
x = x.view(-1, 64 * 96 * 96)
torch.Size([4, 589824])
x = F.relu(self.fc1(x))
torch.Size([4, 100])
x = F.dropout(x, training=self.training)
torch.Size([4, 100])
x = self.fc2(x)
torch.Size([4, 30])
return F.log_softmax(x, dim=1)    
torch.Size([4, 30])
  • Your maxpool2d layers reduce the height and width of your feature maps.
  • The 'view' should be x = x.view(-1, 64 * 24 * 24)
  • the first linear layer of size : self.fc1 = nn.Linear(64 * 24 * 24, 100)

this will give your output = model(data) final shape of torch.Size([64, 30])

But this code will still face a problem in calculating the Negative Log Likelihood Loss :

The input is expected to contain scores for each class. input has to be a 2D Tensor of size (minibatch, C). This criterion expects a class index (0 to C-1) as the target for each value of a 1D tensor of size minibatch

where class indices are just labels :

values representing a class. For example:

0 - class0, 1 - class1,

Since your last nn layer outputs a softmax over 30 classes, i'm assuming that is the output classes you want to classify into, so transformation for target :

target = target.view(64, -1) # gives 64X30 ie, 30 values per channel
loss = F.nll_loss(x, torch.max(t, 1)[1]) # takes max amongst the 30 values as class label

This is when the target is a probability distribution over 30 classes, if not can do a soft-max before that. Thus the maximum value in the 30 values will represent the highest probability - thus that class which is exactly what your output represents and thus you calculate a nll between the two values. .

Sign up to request clarification or add additional context in comments.

9 Comments

Thank so much Saleem cant wait to get back home to try it, il post in about 12 hours
I made changes but getting this this now: RuntimeError: Expected object of scalar type Long but got scalar type Double for argument #2 'target' . I should have said I'm new to python too
Hi this is still not working I now get this error: RuntimeError: Input type (torch.cuda.LongTensor) and weight type (torch.cuda.FloatTensor) should be the same When I change input to float I then get this error: RuntimeError: Expected object of scalar type Long but got scalar type Float for argument #2 'target Any ideas would be appreciated
can you update question with current implementation of target transform ? input data to module layers should be float. target for nll loss should be long generally speaking
Saleem figured out last issue. I hadnt commented out my test method as i need to rewrite for loop. Silly mistake. Thank you for all your help. Really appreciated it
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.