我正在训练一个基于DenseNet的特征提取器,模型结构如下:
# 导入Sequential模型和层
from keras.models import Sequential
import keras
import tensorflow as tf
from keras.layers import Conv2D, MaxPooling2D, Lambda, Dropout, Concatenate
from keras.layers import Activation, Dropout, Flatten, Dense
import pandas as pd
from sklearn import preprocessing
import ast
from keras.callbacks import EarlyStopping
from keras.callbacks import ModelCheckpoint
size = 256
class DenseNetBase(tf.keras.Model):
def __init__(self, size, include_top = True):
super(DenseNetBase, self).__init__()
self.include_top = include_top
# 基础模型
self.base = tf.keras.applications.DenseNet201(weights='imagenet',include_top=False, pooling='avg',input_shape = (size,size,3))
# 最终层
self.dense = Dense(1, activation='sigmoid', name='predictions')
def call(self, input_tensor):
input_image = input_tensor[0]
input_metafeatures = input_tensor[1]
# 模型
x = self.base(input_image)
if self.include_top:
x = self.dense(x)
return x
def build_graph(self):
x = self.base.input
y = tf.keras.Input(shape=(3,))
return tf.keras.Model(inputs=[x,y], outputs=self.call([x,y]))
我想接着使用DenseNetBase,保留已训练的权重,但移除最终的Dense层,以便用于提取特征。简化的DenseClassifier看起来像这样:
class DenseClassifier(tf.keras.Model):
def __init__(self, size, feature_extractor):
super(DenseClassifier, self).__init__()
# 基础 tf.keras.layers.Input(shape=(size,size,3))
self.feature_extractor = tf.keras.Model(inputs = tf.keras.Input(shape=(size,size,3)), outputs = feature_extractor.layers[-2].output)
# 最终层
self.dense = Dense(1, activation='sigmoid', name='prediction')
def call(self, input_tensor):
input_image = input_tensor[0]
input_metafeatures = input_tensor[1]
# 模型
x = self.feature_extractor(input_image)
return self.dense(x)
def build_graph(self):
x = self.base.input
y = tf.keras.Input(shape=(3,))
return tf.keras.Model(inputs=[x,y], outputs=self.call([x,y]))
将它们结合起来:
# 构建我们已经训练过的DenseNet特征提取器
denseBase = DenseNetBase(256, include_top = True)
denseBase.build([(None, 256, 256, 3), (None,3)])
denseBase.load_weights('./models/DenseBaseSimple.h5')
# 这行不起作用
DenseClassifier = DenseClassifier(size = 256, feature_extractor = denseBase)
在上面的例子中,我得到了一个输入错误,但我不确定为什么。期望的行为是,我可以构建后面的模型,并编译,使用DenseNetBase的现有权重进行特征提取。
我尝试用inputs = feature_extractor.layers[-2].input
替换输入部分,这确实可以编译,但似乎没有达到与denseBase相同的准确度,尽管它使用了相同的权重(在上述没有额外层的简单示例中)。
我的目标/问题:
- 如何加载预训练的denseBase的权重,但移除最后的Dense层(因此输出是(None, 1920),就像没有顶部的DenseNet但使用我的权重一样)。
- 然后如何将这个没有Dense层的模型加载到另一个子类模型中,如上所述,以提取特征。
谢谢!
回答:
为了回答我自己的问题,我做了一些测试,查看初始化权重的值,使用了来自这里的逻辑:
这是预期的结果。DenseBaseClassifier(使用denseBase)和使用imagenet权重都具有相似的预测权重初始化。这是由于这两层都是随机初始化的且未训练,而denseBase中的预测层已被优化,因此不同。
对于denseNet部分,DenseBaseClassifier(使用denseBase) == denseBase(由于只保存权重,有些噪音),而原始的imagenet权重是不同的。
使用denseBase_featureextractor = tf.keras.Model(inputs = denseBase.layers[-2].input, outputs = denseBase.layers[-2].output)
确实保留了权重。
但不确定为什么self.feature_extractor = tf.keras.Model(inputs = tf.keras.Input(shape=(size,size,3)), outputs = feature_extractor.layers[-2].output)
不起作用。