目前我正在使用VGG16 + Keras + Theano思想迁移学习方法来识别植物类。它工作得很好,给了我一个很好的准确性。但我要解决的下一个问题是找到一种方法来识别输入图像是否包含植物。我不想有另一个分类器来做这件事,因为它不是很有效。
所以我做了一些搜索,发现我们可以从最新的模型层(在激活层之前)获得激活并分析它。
from keras import backend as K
model = util.load_model() # VGG16 model
model.load_weights(path_to_weights)
def get_activations(m, layer, X_batch):
x = [m.layers[0].input, K.learning_phase()]
y = [m.get_layer(layer).output]
get_activations = K.function(x, y)
activations = get_activations([X_batch, 0])
# trying to get some features from activations
# to understand how can we identify if an image is relevant
for l in activations[0]:
not_nulls = [x for x in l if x > 0]
# shows percentage of activated neurons
c1 = float(len(not_nulls)) / len(l)
n_activated = len(not_nulls)
print 'c1:{}, n_activated:{}'.format(c1, n_activated)
return activations
get_activations(model, 'the_latest_layer_name', inputs)
从上面的代码中我注意到,当我们有非常不相关的图像时,激活的神经元数量比包含植物的图像大:
- 用于模型训练的图像,激活神经元数19%-23%
- 对于包含未知植物种类的图像20%-26%
- 不相关图片24%-28%
如果一个图像相关的百分比值相交,这不是一个很好的特性。
那么,有没有解决这个问题的好方法呢?
感谢Feras在上面评论中的想法。经过一些试验,我想出了最终的解决方案,可以解决这个问题,准确率高达99.99%。
步骤:
- 在数据集上训练你的模型;
- 通过使用前一步训练的模型预测相关和非相关图像来存储激活(参见上面如何获取它们的方法)。您应该从倒数第二层获得激活。对于VGG16,它是两个Dense(4096)中的最后一个,对于InceptionV3 -一个额外的倒数第二个Dense(1024)层,对于resnet50 -一个额外的倒数第二个Dense(2048)层。
- 使用存储的激活数据解决二进制问题。我试过一个简单的平面神经网络和逻辑回归。两者在准确性上都很好(平面神经网络更准确),但我选择了逻辑回归,因为它更简单,更快,消耗更少的内存和CPU/GPU。
这个过程应该在你的模型每次重新训练后重复,因为每次CNN的最终权重都是不同的,并且以前工作的东西下次将会不同。
因此我们有了另一个解决问题的小模型。