在图像分类任务中,卷积神经网络 (CNN) 是非常强大的神经网络架构。 然而,鲜为人知的是,它们同样能够执行图像回归任务。
图像分类和图像回归任务之间的基本区别在于分类任务中的目标变量(我们试图预测的东西)不是连续的,而回归任务中的目标变量是连续的。 例如,如果我们需要在不同的狗和猫品种之间进行分类,它将属于分类任务的范围。 然而,如果我们需要根据房屋图像来预测房价,这将是一个回归任务。
在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器
我在人寿保险行业工作,当今该行业在全球范围内发生的重大变化之一就是简化客户的入职流程。 不同的公司正在努力使保险销售过程变得更简单、直观和无麻烦。 在这个方向上,深度学习技术对于解决问题非常有用。 例如,如果深度学习模型可以预测一个人的年龄、性别、吸烟状况和体重指数(这些是计算给定承保金额的正确保费或拒绝/推迟承保的最关键因素), 保险公司可以为客户大大简化保险销售流程,并可能增加销售额。
我们知道,根据人的图像预测性别相对简单,这属于图像分类任务。如果你有兴趣,可以参考下这篇文章。
另一方面,图像回归任务(例如根据图像预测人的年龄)是相对难以完成的任务。 处理此任务的更简单方法是通过将不同年龄分组到一个桶中(即创建年龄范围)来使其成为分类任务。 然而,就保单销售而言,这并没有解决目的(通常死亡率或发病率因年龄和性别而异)。 因此,我尝试创建一个模型来预测该人的确切年龄。
1、偏差和数据选择问题
处理图像尤其是人物图像的主要问题是,公共领域免费提供的大多数数据源都存在明显的种族偏见。 Fastai 的杰里米·霍华德 (Jeremy Howard) 在他的一次深度学习课程讲座中谈到了这一点。 这些在公共领域提供的图像存在偏见,因为大多数捕获的图像都是白人,如果我们基于这些图像创建任何模型,那么它很可能不会在印度或亚洲血统的图像上表现良好 人们。
为了在一定程度上解决这个问题,我精心挑选了三个数据源(均在公共领域可用):
- IMDB-Wiki 人脸数据集
- UTK 人脸数据集
- Appa 真实人脸数据集
这些数据集是使用 0 到 100 岁之间所有年龄段的不同来源/图像创建的,如果我们将这些数据组合在一起,那么严重的种族偏见问题就会在一定程度上得到消除。
2、项目介绍
由于一些奇怪的原因,我为这个项目工作的 Kaggle Kernel 没有成功提交。 所以,我把笔记本放到了我的 GitHub 上。
以下是需要强调的几个要点:
- 使用 Fastai v1 模型并选择 CNN 架构 — ResNet34 来运行该模型。 我尝试使用更复杂的架构,例如 ResNet50,但发现验证错误更高。
- 在这个notebook中,我使用了图像调整大小技术,其中图像尺寸逐渐增加,这有助于获得更高的精度。 这是一项非常棒的技术,每次我们需要处理 CNN 时都必须使用它。
- 使用 L1 Smooth Loss(Huber 损失),其表现优于 L1 或 L2 损失。
- 在该项目期间,我学习了使用 Fastai 的判别学习技术,其中我们可以将 NN 架构拆分为不同的部分,并为 NN 架构的不同部分分配不同的权重衰减和学习率值。
- 最后,使用 Fastai Pytorch Hooks 和 Spotify Annoy 创建了图像相似度模型(在我看来效果不是很好。
年龄回归模型代码:
class AgeModel(nn.Module):
def __init__(self):
super().__init__()
layers = list(models.resnet34(pretrained=True).children())[:-2]
layers += [AdaptiveConcatPool2d(), Flatten()]
layers += [nn.BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)]
layers += [nn.Dropout(p=0.50)]
layers += [nn.Linear(1024, 512, bias=True), nn.ReLU(inplace=True)]
layers += [nn.BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)]
layers += [nn.Dropout(p=0.50)]
layers += [nn.Linear(512, 16, bias=True), nn.ReLU(inplace=True)]
layers += [nn.Linear(16,1)]
self.agemodel = nn.Sequential(*layers)
def forward(self, x):
return self.agemodel(x).squeeze(-1)
在这里,你可以看到,在ResNet34的架构中,在删除处理分类任务的层之后,我们添加了可以处理回归任务的部分。
损失函数代码:
class L1LossFlat(nn.SmoothL1Loss):
def forward(self, input:Tensor, target:Tensor) -> Rank0Tensor:
return super().forward(input.view(-1), target.view(-1))
使用平滑 L1 损失,其表现优于 L1 或 L2 损失。
学习器代码:
learn = Learner(data_wiki_small, model, model_dir = "/temp/model/", opt_func=opt_func, bn_wd=False, metrics=root_mean_squared_error,
callback_fns=[ShowGraph]).mixup(stack_y=False, alpha=0.2)
learn.loss_func = L1LossFlat()
现在,我们将看到模型的一些预测:
每张照片的第一行文字是真实年龄,第二行是模型预测的年龄
还不错!
3、结束语
这是我参与过的最长的项目之一,但我必须说我在这个过程中学到了很多东西。 其中很少有判别性学习技术、通过重构模型来构建合适模型的方法、图像调整大小技术等。
原文链接:用照片预测年龄 - BimAnt