3.8 多类别分类
目前你一直在创建二元分类器—从两个选择中进行挑选(马或者人,猫或者狗)。当创建多类别分类器时,模型几乎相同,但有一些重要的区别。不再是一个单独通过sigmoid激活的神经元,或者是二元激活的两个神经元,你的输出层现在需要n个神经元,这里n是要分类的类别个数。你还需要改变你的损失函数为适合多类别的。例如,虽然你目前在本章中创建的损失函数是二元交叉熵,如果你想将模型扩展到多个类别,则应该使用类别交叉熵。如果你正在使用ImageDataGenerator
来提供图像,则标签是自动添加的,因此多分类与二分类一样—ImageDataGenerator
会根据子文件夹的数量来自动标注数据。
以石头剪刀布这个游戏为例。如果你想训练一个数据集来识别不同的手势,则需要处理三种类别。幸运的是,这里有一个简单的数据集(https://oreil.ly/VHhmS)可供使用。
这里需要下载两个文件:一个包含许多不同手的训练集,有不同的大小、形状、颜色和指甲油等细节;一个同样多样化的测试集,它们在训练集中没有任何元素。
你可以在图3-19中看到一些例子。
图3-19:石头、剪刀、布的手势例子
使用这个数据集很简单。下载和解压缩它(排序好的子文件夹已经在ZIP文件里了),然后使用它来初始化ImageDataGenerator
:
值得注意的是,当你设置数据生成器时,必须指定类别模式是多类别的,这样Image-DataGenerator
才会使用超过两个文件夹:
当定义模型时,注意输入层和输出层,你希望确保输入与数据的形状(在这个例子中是150×150)相匹配,并且输出与类别的个数相匹配(现在是3):
最终,当编译模型时,你希望确保它使用的是多类别的损失函数,例如类别交叉熵。二元交叉熵对于超过两个类的情况无法工作:
训练与之前是一样的:
测试预测的代码同样需要做出一些更改。现在有三个输出神经元,并且它们会输出接近1的值来预测一个类别,输出接近0的值来预测其他类别。注意使用的激活函数是softmax
,它确保所有三个预测值加起来是1。例如,如果模型看到一个它不确定的东西,可能会输出.4, .4, .2;如果它看到非常确定的东西,可能会输出.98, .01, .01。
注意当使用ImageDataGenerator
时,类别是按照字母顺序加载的—因此你可能会期待输出神经元是根据游戏的名字顺序来输出的,但是事实上却是布、石头、剪刀。
在Colab中尝试运行执行预测的代码:
注意它并不会解析输出,只是打印类别。图3-20展示了它在实际使用中的样子。
图3-20:测试石头、剪刀、布分类器
你可以从文件的名字看出图像是什么。Paper1.png的输出结果是[1,0,0]
,这意味着第一个神经元被激活但其他的没有。类似地,Rock1.png的输出结果是[0,1,0]
,激活的是第二个神经元,并且Scissor2.png是[0,0,1]
。记住,神经元是根据标签的字母顺序排列的!
这里有一些测试图像你可以下载(https://oreil.ly/dEUpx)。当然,你也可以尝试自己的图像。注意,训练数据都在一个简单白色背景上,因此,如果你的照片的背景有很多细节,那么模型可能会感觉困惑。