【问题标题】:Face alignment in pytorchpytorch中的人脸对齐
【发布时间】:2020-03-06 16:58:25
【问题描述】:

我正在尝试在 300W 数据集上进行人脸对齐。我正在使用 ResNet50 和 L1 损失进行训练。我的代码看起来像这样。

batch_size = 10
image_size = 128

net = torchvision.models.resnet50(pretrained=True)
num_ftrs = net.fc.in_features
net.fc = nn.Linear(num_ftrs, 136) # 136 because 68 points with 2 dim. so 136= 68*2

def train():
    device = torch.device("cuda:0" if torch.cuda.is_available() else 
           "cpu")

    optimiser = optim.Adam(net.parameters(), lr=0.001, 
            weight_decay=0.0005)

    criterion = L1Loss(reduction='sum')

    for epoch in range(int(0), 200000):
        for batch, data in enumerate(trainloader, 0):
            inputs, labels = data
            inputs, labels = inputs.to(device), labels.to(device)

            optimiser.zero_grad()

            outputs = net(inputs).reshape(-1, 68, 2)

            loss = criterion(outputs, labels)
            loss.backward()
            optimiser.step()
            running_loss += loss.item()


            sys.stdout.write(
            '\rTrain Epoch: {} Batch {} avg_Loss_per_batch: {:.2f} 
            '.format(epoch, batch, running_loss/(batch+1)))
            sys.stdout.flush()

trainloader 带有图像和点。基本事实的形状为 (batch, 68, 2)。我们在二维空间上有 68 个点。

论文表明,对于具有 L1 损失的 256*256 图像,ResNet50 应该得到 10(度量:像素)的误差。即使在 5000 个 epoch 之后,我也会在验证集上收到大约 500-800 的错误。

我正在训练具有 256*256 分辨率和 68 个点的基本事实的图像,例如 ((x1,y1),(x2,y2)....(x68,y68)),并且我已经训练了超过 5000 个 epoch许多学习率。我的验证码是这样的,

def validater(load_weights=False):
    device = torch.device("cuda:0" if torch.cuda.is_available() else 
          "cpu")
    net.eval()
    net.to(device)

    with torch.no_grad():
        for batch, data in enumerate(testloader, 0):
            inputs, labels = data
            inputs, labels  = inputs.to(device), labels.to(device)

            outputs = net(inputs).reshape(-1, 68, 2)

            loss = criterion(outputs, labels)

            loss2 = np.linalg.norm(labels.to('cpu') - outputs.to('cpu'))

            sys.stdout.write('\rTest Epoch: {} Batch {} total_L1_Loss: 
                {:.2f} avg_L1_Loss_per_img: {:.2f} total_norm_loss: 
                 {:.2f}'.format(
                0, batch, avg_loss, avg_loss/batch/batch_size, 
                avg_loss2))
            sys.stdout.flush()

    print()

我的代码有什么问题?

PS:我用下面的代码规范化了imgs

    img = cv2.normalize(img, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

在 4000 个 epoch 之后,我得到这样的输出,其中黄点是基本事实,蓝色点是预测的

【问题讨论】:

  • 对图像进行任何预处理?
  • 只是在 0 和 1 之间进行归一化
  • 不要在训练循环中定义优化器。违背了 Adam 优化器的目的。
  • 我在循环内外都试过了。在大幅降低错误率方面没有太大区别
  • 虽然您可能在其他地方遇到问题,但在训练循环中定义优化器绝对是不正确的。唯一可以接受的例外是,如果您使用动量 = 0 的 SGD。

标签: python computer-vision pytorch


【解决方案1】:

从您的输出图像中,您可以看出左上角地标上的误差较小,而朝向脸部右下角则增大。
您尝试预测的地标是相对于图像左上角的(x, y) 坐标。如您所见,模型的预测误差与每个坐标的范数成比例增长。这并不少见:当您模型预测靠近原点的地标(例如左眼)时,它会做出“小”预测,因为该地标的范数也很小,学习的权重很小,因此误差也很小.另一方面,当预测远离原点(嘴巴右侧)的地标时,模型需要进行“大”预测,因为这些地标的范数很大。因此,训练的权重更大,导致错误更粗。

为了缓解这种情况,您应该预处理数据(训练和测试)并将地标的坐标标准化为 1
1.相对于图像的中心
2.相对于图片大小
也就是说,不是(x, y) 范围内的[0, width]x[0, height] 坐标,而是[-1, 1]x[-1, 1] 范围内的地标。
预测后,要获得原始坐标,您只需将它们移动并按图像大小缩放即可。


1 我在这里假设训练集中的所有面孔的大小大致相同,并且大致位于图像的中心。如果您的设置是“在野外”,即图像中任何位置的人脸可以是任意大小,恐怕这将不起作用。

【讨论】:

  • 所以如果我理解正确,对于 10*10 的 2d 网格, (x,y)=(3,3) 变为 (-2,-2) 因为中心是 (5, 5)?
  • @FarshidRayhan 几乎变成了(-2/5, -2/5),因为中心是(5,5),宽度/高度是10,我们想映射到[-1, 1]而不是[-5, 5]的范围。
  • 现在每个时代之后,Val 集的错误似乎都在增加
  • @FarshidRayhan 尝试降低学习率。您是否尝试过查看地标在面部图像上的外观?错误是“统一的”还是对其中一个角落仍然存在“偏见”?
  • 会的。我的猜测是,现在在对地标进行归一化之后,这让 CNN 的问题变得更加困难。在此之前,它将在 2k 时期达到局部最优(如问题中的 img)。而现在,即使在 5k 之后,它似乎仍在学习。感谢帮助:)
猜你喜欢
  • 2019-02-10
  • 2015-10-13
  • 2019-07-18
  • 2020-12-15
  • 1970-01-01
  • 2012-08-16
  • 2019-06-11
  • 2017-10-11
  • 2015-09-13
相关资源
最近更新 更多