之前做图像分类的项目的时候一直在寻找一个行之有效的迁移学习的实现方法,但是寻找了许久都没有找到。经过我们团队的努力实践最近终于探索出一个有效的方法,这里拿出来跟大家一起探讨一下看看还有那些地方需要改进的。
一,背景
首先因为迁移学习其实没有理论性的一个定义,所以先解析一下我们所需要实现的迁移学习,我们的图像分类是现实分类中的其中一类物体的垂直分类,细分到具体型号的。然后我们是基于DenseNet201创建训练模型,一开始分类数从0到100,因为imageNet的分类跟我们需要的分类不一样所以即使是拿它训练好的模型也是起不来多大的提升作用。项目一直在进行,分类数再从100提升到了500,这时候从0开始训练也是可以接受,因为跨度大之前训练好的模型的分类数相对新增加的分类的分类数占比低。再下去我们再从500增加到600,600增加到630,现在我们在想如果这样子的增加幅度也是要从0开始的话,之前的训练时间就相当于是浪费了,所以就想到了用迁移学习这样的方法把之前训练好的模型的权重集成过来,再在这个基础上训练新加的分类。虽然不知道这个是不是属于真正的迁移学习的范畴,但是在实践中的确比从0开始训练要节省时间。
二,实现
就第一点我们遇到的问题从500增加到600,600增加到630的分类数怎么样有效的利用之前训练好的模型主要有下面两个问题
1. 如何继承前一个模型的权重
2. 如何继承前一个模型的权重之后加上新的分类数
下面先直接上一段代码
#create a DenseNet201 and then load the weigth from existing model
densenet = DenseNet201(include_top=False, weights='imagenet',input_tensor=None, input_shape=(299, 299, 3), pooling='avg')
output = densenet.get_layer(index=-1).output
output = Dropout(0.3)(output)
output = Dense(500, activation='softmax', name='predictions')(output)
model = Model(outputs=output, inputs=densenet.input)
model.load_weights(best_model_file)
#get the old model`s last dense weight and then add new classies into the last dense layer
output = model.get_layer(index=-2).output
old_dense = model.get_layer(index=-1)
weight_list = old_dense.get_weights()
new_weight_0 = np.concatenate((weight_list[0], np.random.randn(old_dense.get_weights()[0].shape[0], 100)), axis=1)
new_weight_1 = np.concatenate((weight_list[1], np.random.randn(100)), axis=1)
old_dense.set_weight([new_weight_0,new_weight_1])
new_dense = old_dense.output
#output the new model to do the trainningmodel = Model(outputs=new_dense, inputs=densenet.input)
上面的伪代码主要有三部分
第一步先用Keras的已拥有的model.load_weights(best_model_file)的方法把之前训练好的500分类的模型的权重先加载进来,现在的模型是就的500分类的模型;
第二步是在最后一层的全连接层里在原有的500分类的权重基础上,再在张量矩阵里面加上100新添加分类数的随机数矩阵。这样子就可以使用之前已经训练好的500的分类的权重,又可以在新的训练里面添加上新的分类数。
第三步把新的全连接放到Model的outputs里面创造一个全新的模型作为训练使用。
这样子下来,得到的新的训练模型体现在训练时间上比从0开始训效果要好,具体数据暂时没有记录下来以后有机会再补充。