https://blog.csdn.net/uncle_ll/article/details/82778750#_194
https://blog.csdn.net/leon_wzm/article/details/77650374
使用softmax和sigmoid激活函数来做多类分类和多标签分类
在实际应用中,一般将softmax用于多类分类的使用之中,而将sigmoid用于多标签分类之中,对于图像处理而言,网络模型抽取图像特征的结构基本相同,只是根据不同的任务改变全连接层后的输出层。下面介绍如何使用softmax和sigmoid完成对应的分类任务。
softmax激活函数应用于多类分类
假设神经网络模型的最后一层的全连接层输出的是一维向量logits=[1,2,3,4,5,6,7,8,9,10],这里假设总共类别数量为10,使用softmax分类器完成多类分类问题,并将损失函数设置为categorical_crossentropy损失函数:
用tensorflow实现:
tf.argmax(tf.softmax(logits))
首先用softmax将logits转换成一个概率分布,然后取概率值最大的作为样本的分类 。softmax的主要作用其实是在计算交叉熵上,将logits转换成一个概率分布后再来计算,然后取概率分布中最大的作为最终的分类结果,这就是将softmax激活函数应用于多分类中。
sigmoid激活函数应用于多标签分类
sigmoid一般不用来做多类分类,而是用来做二分类,它是将一个标量数字转换到[0,1]之间,如果大于一个概率阈值(一般是0.5),则认为属于某个类别,否则不属于某个类别。这一属性使得其适合应用于多标签分类之中,在多标签分类中,大多使用binary_crossentropy损失函数。它是将一个标量数字转换到[0,1]之间,如果大于一个概率阈值(一般是0.5),则认为属于某个类别。本质上其实就是针对logits中每个分类计算的结果分别作用一个sigmoid分类器,分别判定样本是否属于某个类别同样假设,神经网络模型最后的输出是这样一个向量logits=[1,2,3,4,5,6,7,8,9,10], 就是神经网络最终的全连接的输出。这里假设总共有10个分类。通过:
tf.sigmoid(logits)
sigmoid应该会将logits中每个数字都变成[0,1]之间的概率值,假设结果为[0.01, 0.05, 0.4, 0.6, 0.3, 0.1, 0.5, 0.4, 0.06, 0.8], 然后设置一个概率阈值,比如0.3,如果概率值大于0.3,则判定类别符合,那么该输入样本则会被判定为类别3、类别4、类别5、类别7及类别8。即一个样本具有多个标签。
在这里强调一点:将sigmoid激活函数应用于多标签分类时,其损失函数应设置为binary_crossentropy。
multi-class 和 multi-label的区别
multi-class是相对于binary二分类来说的,意思是需要分类的东西不止有两个类别,可能是3个类别取一个(如iris分类),或者是10个类别取一个(如手写数字识别mnist)。
而multi-label是更加general的一种情况了,它说为什么一个sample的标签只能有1个呢。为什么一张图片不是猫就是狗呢?难道我不能训练一个人工智能,它能告诉我这张图片既有猫又有狗呢?
其实关于多标签学习的研究,已经有很多成果了。
主要解法是
* 不扩展基础分类器的本来算法,只通过转换原始问题来解决多标签问题。如BR, LP等。
* 扩展基础分类器的本来算法来适配多标签问题。如ML-kNN, BP-MLL等。
这里不展开了。有兴趣的同学可以自己去研究一下。
keras的multi-label
废话不多说,直接上代码。这里假设大家是有keras的基础知识的,所以关键代码之外的代码请大家自行脑补。
def __create_model(self):
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
print("create model. feature_dim = %s, label_dim = %s" % (self.feature_dim, self.label_dim))
model.add(Dense(500, activation='relu', input_dim=self.feature_dim))
model.add(Dense(100, activation='relu'))
model.add(Dense(self.label_dim, activation='sigmoid'))
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
return model
稍微解说一下:
* 整个网络是fully connected全连接网络。
* 网络结构是输入层=你的特征的维度
* 隐藏层是500*100,激励函数都是relu。隐藏层的节点数量和深度请根据自己的数量来自行调整,这里只是举例。
* 输出层是你的label的维度。使用sigmoid作为激励,使输出值介于0-1之间。
* 训练数据的label请用0和1的向量来表示。0代表这条数据没有这个位的label,1代表这条数据有这个位的label。假设3个label的向量[天空,人,大海]的向量值是[1,1,0]的编码的意思是这张图片有天空,有人,但是没有大海。
* 使用binary_crossentropy来进行损失函数的评价,从而在训练过程中不断降低交叉商。实际变相的使1的label的节点的输出值更靠近1,0的label的节点的输出值更靠近0。