本文讲解了Dodo Pizza(俄罗斯最大的披萨连锁店)首席数据科学家Arthur Kuzin如何开发AI进行披萨质量控制。深入了解如何教AI评估你的披萨!本文重点关注以下内容:1)仅从少数有标签的样本中标记完整数据集;2)将拉伸边界框分割掩模对象(将边界框的方形掩模应用于任何形状)。
Dodo披萨有许多活跃的顾客,他们同意分享他们对披萨质量的看法。为了简化反馈循环及其处理,Dbrain开发了一个AI驱动的应用程序来检查披萨质量。这个应用程序在Telegram中实现为一个聊天机器人,客户可以上传照片并打分(1~10)。
当我们收到请求后,我开始开发一种可以直观地确定面团质量的算法。问题的本质是确定披萨烘焙过程何时中断。饼皮上的白色气泡与劣质品相关。
该数据集包括披萨烘焙的照片,也包括不相关的图像。如果配方不当,饼皮上会出现白色气泡。此外,专家还对面团质量进行了二元标记。因此,算法的开发只是时间问题。
这些照片是在不同的手机上,在不同的光线条件下,从不同的角度拍摄的。图片总数为6万张,披萨1.7万张。
由于任务非常简单,我们可以检查处理数据的不同方法。下面是我们需要解决的问题:
1.选择看到披萨饼皮的照片;
2.从背景中区分所选照片中的饼皮区域;
3.在选定区域训练神经网络。
我自己标记了一小部分照片,因为,如果你想要做得好,就要自己动手。我是这样做的:
1.标记了50张用饼皮的照片,50张照片没有饼皮:
2.使用在imagenet11k上经过places365预训练的ResNet-152提取全局平均池化后的特征。
3.将两个类的特征的平均值作为锚点。
4.计算从该锚点到所有剩余6万图片的特征的距离。
5.确定前300接近正样本,后500是负样本。
6.根据这些样本对LightGBM进行特征训练。
7.使用此模型在整个数据集上派生标记。
这与我在kaggle竞赛中使用的基线方法大致相同。
大约一年前,我和Evgeny Nizhibitsky一起参加了“Sea Lions” kaggle比赛。任务是根据从无人驾驶飞机上拍摄的照片来计算海狮的数量。标记为海狮的坐标,但在某些时候,Nizhibitsky用边界框标记它们。
我决定通过分割来解决这个任务,在第一阶段只以海豹的边界框作为目标。经过几次训练后,很容易找到一些很糟糕的样本。
对于此示例,你可以选择看不清海狮的较大区域,手动将掩模(mask)设置为零,还可以添加到训练集。这样,Evgeny和我训练的模型甚至已经学会了分类完整海狮的鳍。
让我们继续研究披萨。为了识别所选和过滤的照片上的披萨饼皮,最佳选择是将任务交给标记。一般来说,对于相同的样本,不同的人的标记是不同的,但当时我们已经对这种情况应用了一致性算法(consensus algorithm)并将其用于边界框。所以,我只是做了几个例子然后把它交给了标记者。最后,我获得了500个样本,特别突出了饼皮区域。
为了识别所选过滤照片上的饼皮,我为标记者做了几个例子。
然后我将Kaggle比赛“Sea Lions”中的代码应用到当前程序中。在第一次训练之后,模型错误明显。预测的置信度定义如下:
1 - (灰色区域的面积)/(掩模的面积)
接下来,为了进行将掩模接近边框的下一次迭代,小的集成用TTA预测掩模。这在某种程度上可以被认为是很棒的知识蒸馏,但更准确的说法是叫它伪标签(Pseudo-Labelling)。
然后,我有了手动设置我们用于形成新训练集的置信度阈值。它也是可选的标记出集成失败的最复杂样本。我觉得这很有用,我自己做了大约20张照片的标记。
为了准备样本,我用掩模提取了饼皮区域。此外,我稍微放大掩模并将其应用于图片以去除背景,来略微充气掩模,因为它不应包含有关面团质量情况的任何信息。然后我对Imagenet中的几个模型进行了微调。我总共收集了大约1.4万的合适样本。因此,我没有训练整个神经网络,而只训练最后一组卷积层以防止过拟合。
最好的单一模型结果是Inception-Resnet-v2,单倍的ROC-AUC是0.700。如果你没有选择任何东西并在没有掩模的原始照片上训练网络,那么ROC-AUC将为0.58。
在我开发解决方案时,DODO披萨获得了又一批数据,我们可以测试整个管道。我们测试了整个管道并得到ROC-AUC 0.83。
但是,我们还是会犯错。为思考错误出现的原因,我再一次训练了模型并获取阳性成果。我们现在看一下错误:
最高的假阳性
在这里可以看出,它们与披萨饼皮标记错误有关,因为有明显迹象表明面团变质了。
最佳假阴性
这里的错误是由于第一个模型未能选择正确的角度,这导致难以确定面团质量的关键特征。
我的同事有时取笑我通过Unet分割解决几乎所有的任务。但我仍然希望他们会喜欢它,因为这是一种强大且方便的方法。它可以可视化模型错误并自信地预测它们,这有时真的可以节省时间。此外,整个管道看起来非常简单。现在对于任何框架,都有一堆存储库可用。