【发布时间】:2021-02-24 11:03:10
【问题描述】:
我正在使用 ssd_mobilenet 开发 object_detection 网络管道。该网络包含 tf Object_Detection API 和 ssd_keras repo(没关系)。
现在的问题是我想保存和加载整个模型,包括 weights、optimizer、loss_infos 所以我想使用model.save .但是当我使用tf.keras.models.load_model('save_path') 时,会引发此错误。
这是我的模型定义:
#! /usr/bin/python3
# this script is define the ssd_mobilenet model
# from object_dection and keras-ssd models
from __future__ import division
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Lambda, Activation, Conv2D, MaxPooling2D, ZeroPadding2D, Reshape, Concatenate
from tensorflow.keras.regularizers import l2
import tensorflow.keras.backend as K
from my_model.feature_extractors import choose_feature_extractor
import numpy as np
from ssd_keras.keras_layers.keras_layer_AnchorBoxes import AnchorBoxes
from ssd_keras.keras_layers.keras_layer_L2Normalization import L2Normalization
from ssd_keras.keras_layers.keras_layer_DecodeDetections import DecodeDetections
from ssd_keras.keras_layers.keras_layer_DecodeDetectionsFast import DecodeDetectionsFast
# to enable the version problem
# don't know why
config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.Session(config=config)
L2_REG = 0.00004
def class_conf(out_dim, name, **kwargs):
# predict n_classes confidence values for each box
if not kwargs:
return Conv2D(out_dim, (3,3), padding='same',
kernel_initializer='he_normal', kernel_regularizer=l2(L2_REG), name=name)
return Conv2D(out_dim, (3,3), padding='same',
kernel_initializer='he_normal', kernel_regularizer=l2(L2_REG), name=name)(kwargs['input'])
def box_cord(out_dim, name, **kwargs):
# predict 4 box coordinates for each box
if not kwargs:
return Conv2D(out_dim, (3,3), padding='same',
kernel_initializer='he_normal', kernel_regularizer=l2(L2_REG), name=name)
return Conv2D(out_dim, (3,3), padding='same',
kernel_initializer='he_normal', kernel_regularizer=l2(L2_REG), name=name)(kwargs['input'])
def ssd_model(image_size,
n_classes,
base_model,
is_training=True,
aspect_ratios_global=None,
two_boxes_for_ar1=True,
scales=None,
aspect_ratios_per_layer=None,
steps=[8,6,32,64,100,300],
clip_boxes=False,
variances=[0.1, 0.1, 0.2, 0.2],
coords='centroids',
normalize_coords=True,
offsets=None,
iou_threshold=0.50,
confidence_thresh=0.01,
top_k=200,
nms_max_output_size=400,
fine_tuning=False):
n_predictor_layers = 6
n_classes += 1
img_height, img_width, img_channels = image_size[0], image_size[1], image_size[2]
# define aspect_ratios and num_boxes
if aspect_ratios_per_layer:
aspect_ratios = aspect_ratios_per_layer
else:
aspect_ratios = [aspect_ratios_global] * n_predictor_layers
if aspect_ratios_per_layer:
n_boxes = []
for ar in aspect_ratios_per_layer:
if (1 in ar) & two_boxes_for_ar1:
n_boxes.append(len(ar) + 1) # +1 for the second box for aspect ratio 1
else:
n_boxes.append(len(ar))
else: # If only a global aspect ratio list was passed, then the number of boxes is the same for each predictor layer
if (1 in aspect_ratios_global) & two_boxes_for_ar1:
n_boxes = len(aspect_ratios_global) + 1
else:
n_boxes = len(aspect_ratios_global)
n_boxes = [n_boxes] * n_predictor_layers
# used to instantiate a keras tensorm, a symbolic tensor object
X = Input(shape=(img_height, img_width, img_channels))
# Backbone
feature_extractor = choose_feature_extractor(base_model=base_model,
is_training=is_training,
fine_tuning=fine_tuning)
resized_image = feature_extractor.preprocess(X)
feature_maps = feature_extractor(resized_image)
conf_1 = class_conf(out_dim=n_boxes[0]*n_classes, name='conf_1', input=feature_maps[0])
conf_2 = class_conf(out_dim=n_boxes[1]*n_classes, name='conf_2', input=feature_maps[1])
conf_3 = class_conf(out_dim=n_boxes[2]*n_classes, name='conf_3', input=feature_maps[2])
conf_4 = class_conf(out_dim=n_boxes[3]*n_classes, name='conf_4', input=feature_maps[3])
conf_5 = class_conf(out_dim=n_boxes[4]*n_classes, name='conf_5', input=feature_maps[4])
conf_6 = class_conf(out_dim=n_boxes[5]*n_classes, name='conf_6', input=feature_maps[5])
loc_1 = box_cord(out_dim=n_boxes[0]*4, name='loc_1', input=feature_maps[0])
loc_2 = box_cord(out_dim=n_boxes[1]*4, name='loc_2', input=feature_maps[1])
loc_3 = box_cord(out_dim=n_boxes[2]*4, name='loc_3', input=feature_maps[2])
loc_4 = box_cord(out_dim=n_boxes[3]*4, name='loc_4', input=feature_maps[3])
loc_5 = box_cord(out_dim=n_boxes[4]*4, name='loc_5', input=feature_maps[4])
loc_6 = box_cord(out_dim=n_boxes[5]*4, name='loc_6', input=feature_maps[5])
box_1 = AnchorBoxes(img_height, img_width, this_scale=scales[0], next_scale=scales[1], aspect_ratios=aspect_ratios[0],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[0], this_offsets=offsets[0], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_1')(loc_1)
box_2 = AnchorBoxes(img_height, img_width, this_scale=scales[1], next_scale=scales[2], aspect_ratios=aspect_ratios[1],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[1], this_offsets=offsets[1], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_2')(loc_2)
box_3 = AnchorBoxes(img_height, img_width, this_scale=scales[2], next_scale=scales[3], aspect_ratios=aspect_ratios[2],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[2], this_offsets=offsets[2], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_3')(loc_3)
box_4 = AnchorBoxes(img_height, img_width, this_scale=scales[3], next_scale=scales[4], aspect_ratios=aspect_ratios[3],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[3], this_offsets=offsets[3], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_4')(loc_4)
box_5 = AnchorBoxes(img_height, img_width, this_scale=scales[4], next_scale=scales[5], aspect_ratios=aspect_ratios[4],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[4], this_offsets=offsets[4], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_5')(loc_5)
box_6 = AnchorBoxes(img_height, img_width, this_scale=scales[5], next_scale=scales[6], aspect_ratios=aspect_ratios[5],
two_boxes_for_ar1=two_boxes_for_ar1, this_steps=steps[5], this_offsets=offsets[5], clip_boxes=clip_boxes,
variances=variances, coords=coords, normalize_coords=normalize_coords, name='box_6')(loc_6)
# reshape
confs = [conf_1, conf_2, conf_3, conf_4, conf_5, conf_6]
locs = [loc_1, loc_2, loc_3, loc_4, loc_5, loc_6]
boxes = [box_1, box_2, box_3, box_4, box_5, box_6]
for i, value in enumerate(confs):
confs[i] = Reshape((-1, n_classes), name='conf_reshape_'+str(i))(value)
for i, value in enumerate(locs):
locs[i] = Reshape((-1, 4), name='loc_reshape_'+str(i))(value)
for i,value in enumerate(boxes):
boxes[i] = Reshape((-1, 8), name='box_reshape_'+str(i))(value)
mbox_conf = Concatenate(axis=1, name='mbox_conf')(confs)
mbox_loc = Concatenate(axis=1, name='mbox_loc')(locs)
mbox_priorbox = Concatenate(axis=1, name='mbox_priorbox')(boxes)
mbox_conf_softmax = Activation('softmax', name='mbox_conf_softmax')(mbox_conf)
predictions = Concatenate(axis=2, name='predictions')([mbox_conf_softmax, mbox_loc, mbox_priorbox])
if is_training:
model = Model(inputs=X, outputs=predictions)
return model
并且 feature_extractor 是 ssd_mobilenet_v2_keras_feature_extractor.py 中定义的 object_detection API 中的一个子类模型。
我注意到要启用model.save(),我需要覆盖模型子类中的 get_config() 函数。但是我不知道要添加什么,所以我只是在 self.parameters 中添加参数遵循一些教程,像这样:
## in ssd_meta_arch.SSDKerasFeatureExtractor
def get_config(self):
return {'is_training': self._is_training,
'depth_multiplier': self._depth_multiplier,
'min_depth': self._min_depth,
'pad_to_multiple': self._pad_to_multiple,
# 'conv_hyperparams': self._conv_hyperparams, # raise TypeError: 'Not JSON Serializable:'
'freeze_batchnorm': self._freeze_batchnorm,
'inplace_batchnorm_update': self._inplace_batchnorm_update,
'use_explicit_padding': self._use_explicit_padding,
'use_depthwise': self._use_depthwise,
'num_layers': self._num_layers,
'override_base_feature_extractor_hyperparams': self._override_base_feature_extractor_hyperparams}
## in SSDMobileNetV2KerasFeatureExtractor
def get_config(self):
config = super(SSDMobileNetV2KerasFeatureExtractor, self).get_config()
config.update({'fine_tuning':self.fine_tuning,
# 'classification_backbone':self.classification_backbone,
# 'feature_map_generator':self.feature_map_generator
})
return config
我可以通过ModelCheckpoint(save_weights_only=False,...) 保存模型,但是在加载时我遇到了这个错误:
Traceback (most recent call last):
File "train.py", line 37, in <module>
model = tf.keras.models.load_model(args.load_checkpoint)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/save.py", line 207, in load_model
return saved_model_load.load(filepath, compile, options)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/saved_model/load.py", line 158, in load
keras_loader.finalize_objects()
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/saved_model/load.py", line 623, in finalize_objects
self._reconstruct_all_models()
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/saved_model/load.py", line 642, in _reconstruct_all_models
self._reconstruct_model(model_id, model, layers)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/saved_model/load.py", line 689, in _reconstruct_model
config, created_layers={layer.name: layer for layer in layers})
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/functional.py", line 1295, in reconstruct_from_config
process_node(layer, node_data)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/functional.py", line 1243, in process_node
output_tensors = layer(input_tensors, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py", line 965, in __call__
input_list)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py", line 1104, in _functional_construction_call
inputs, input_masks, args, kwargs)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py", line 834, in _keras_tensor_symbolic_call
return self._infer_output_signature(inputs, args, kwargs, input_masks)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/base_layer.py", line 875, in _infer_output_signature
outputs = call_fn(inputs, *args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/layers/core.py", line 916, in call
result = self.function(inputs, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/util/dispatch.py", line 210, in wrapper
result = dispatch(wrapper, args, kwargs)
TypeError: 'module' object is not callable
有点复杂(笑),感谢您的帮助。
【问题讨论】:
-
请查看如何创建minimal, reproducible example。
标签: tensorflow keras object-detection-api