'How to avoid "keras_learning_phase" being added to model when revising?
I'm making a small program to convert model from .h5/.hdf5 to .pb.
(With changing it's input layer from its original shape to [None, None, c])
((c's value is same as its original model's input channel))
The reason why doing so is that I can use any shape to inference with the trained model.
So far, I can go through the whole process with two different codes:
code_1: convert .h5/.hdf5 to .pb
from keras.models import load_model
import tensorflow as tf
import os
import json
from keras import backend as K
from tensorflow.python.framework import graph_io
import Unet
from keras.layers import Input
def focal_loss(gamma=2., alpha=.25):
def focal_loss_fixed(y_true, y_pred):
pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1+ K.pow(10.0, -9)))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0+ K.pow(10.0, -9)))
return focal_loss_fixed
def IOU_calc():
def IOU_calc_fixed(y_true, y_pred):
smooth = 0.001
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return 2*(intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
return IOU_calc_fixed
def IOU_calc_loss():
return lambda x: -IOU_calc()
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
from tensorflow.python.framework.graph_util import convert_variables_to_constants
graph = session.graph
with graph.as_default():
freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
output_names = output_names or []
input_graph_def = graph.as_graph_def()
if clear_devices:
for node in input_graph_def.node:
node.device = ""
frozen_graph = convert_variables_to_constants(session, input_graph_def,
output_names, freeze_var_names)
# add for new test
frozen_graph = tf.graph_util.remove_training_nodes(frozen_graph)
return frozen_graph
def h5_to_pb(h5_model, output_dir, model_name, out_prefix = "output_"):
out_nodes = []
for i in range(len(h5_model.outputs)):
out_nodes.append(out_prefix + str(i + 1))
tf.identity(h5_model.output[i], out_prefix + str(i + 1))
# add for ignore dropout at inference process(?)
K.set_learning_phase(0)
sess = K.get_session()
from tensorflow.python.framework import graph_util,graph_io
init_graph = sess.graph.as_graph_def()
main_graph = graph_util.convert_variables_to_constants(sess, init_graph, out_nodes)
graph_io.write_graph(main_graph, output_dir, name = model_name, as_text = False)
if __name__ == '__main__':
config_path = r'unet_h5_to_pb_config.json'
with open(config_path) as config_buffer:
a = config_buffer.read()
a = a.replace('\\', '\\\\')
config = json.loads(a)
"""-------------------------Set Paths-----------------------------------"""
h5_model_path = config["h5_md_path"]
if "\\" in h5_model_path:
h5_name = h5_model_path.split("\\")[-1]
pb_model_name = h5_name.split(".")[0] + ".pb"
if len(config["pb_save_path"]) == 0:
output_path = h5_model_path.strip(h5_model_path.split("\\")[-1])
if h5_model_path[0] == ".":
output_path = "." + output_path
else:
output_path = config["pb_save_path"]
if os.path.exists(output_path) is False:
os.mkdir(output_path)
out_md_path = os.path.join(output_path, pb_model_name)
else:
h5_name = h5_model_path.split("/")[-1]
pb_model_name = h5_name.split(".")[0] + ".pb"
if len(config["pb_save_path"]) == 0:
output_path = h5_model_path.strip(h5_model_path.split("/")[-1])
if h5_model_path[0] == ".":
output_path = "." + output_path
else:
output_path = config["pb_save_path"]
if os.path.exists(output_path) is False:
os.mkdir(output_path)
out_md_path = os.path.join(output_path, pb_model_name)
"""---------------------------load h5 model-----------------------------"""
K.set_learning_phase(0)
try:
net_model = load_model(h5_model_path,
custom_objects={'IOU_calc': IOU_calc()})
print("***Handling model with structure***")
except ValueError as E:
if "Cannot create group in read only mode" in str(E):
print("***Handling model without structure***")
input_shape = tuple(config["input_shape"])
model_class = config["model_class"]
net_model = Unet.small_unet(input_shape, model_class)
net_model.load_weights(h5_model_path)
else:
print(E)
print('***input is :', net_model.input.name)
print('***output is:', net_model.output.name)
"""----------------------------save pb file-----------------------------"""
if config["name_output_node"]:
h5_to_pb(net_model, output_dir=output_path, model_name=pb_model_name)
else:
sess = K.get_session()
frozen_graph = freeze_session(K.get_session(),
output_names=[net_model.output.op.name])
graph_io.write_graph(frozen_graph,
output_path, pb_model_name, as_text=False)
print(f"===== FINISH converting model to pb file {out_md_path} =====")
code_2: change .pb input layer shape
# ref: http://digital-thinking.de/tensorflow-replace-tensors-of-a-savedmodel-or-frozengraph/
import tensorflow as tf
from keras.layers import Input
def load_graph(frozen_graph_filename):
with tf.gfile.GFile(frozen_graph_filename, "rb") as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
for n in graph_def.node:
if "input_" in n.name:
input_name = n.name + ":0"
input_channel = n.attr["shape"].shape.dim[3].size
with tf.Graph().as_default() as graph:
tf.import_graph_def(graph_def, name='')
return graph, input_name, input_channel
# ref:https://stackoverflow.com/a/56324805/10427809
def delete_ops_from_graph(graph_def, output_model_filepath):
# Delete nodes
nodes = []
input_count = 0
for node in graph_def.node:
if "input" in node.name and "dropout" not in node.name:
if input_count == 0:
nodes.append(node)
input_count += 1
else:
print('Drop', node.name)
else:
nodes.append(node)
mod_graph_def = tf.GraphDef()
mod_graph_def.node.extend(nodes)
# Delete references to deleted nodes
for node in mod_graph_def.node:
inp_names = []
for inp in node.input:
if 'Neg' in inp:
pass
else:
inp_names.append(inp)
del node.input[:]
node.input.extend(inp_names)
with open(output_model_filepath, 'wb') as f:
f.write(mod_graph_def.SerializeToString())
print(f"*** save new model at{output_model_filepath}")
if __name__ == "__main__":
tf_md_path = r'./pb/my_model_weights_480.pb'
out_md_path = tf_md_path.replace(".pb", "_dynamic.pb")
sess = tf.Session()
graph_model, input_name, C = load_graph(tf_md_path)
graph_model_def = graph_model.as_graph_def()
resize_val = (None, None, C)
rp_input = Input(resize_val)
tf.import_graph_def(graph_model_def, name='',
input_map={input_name: rp_input})
graph = tf.get_default_graph()
graph_def = graph.as_graph_def()
print(graph_def.node)
delete_ops_from_graph = delete_ops_from_graph(graph_def, out_md_path)
print("=== Finish update model with dynamic input size ===")
But when I try to combine the codes together(like this):
from keras.models import load_model
import tensorflow as tf
import os
import json
from keras import backend as K
from tensorflow.python.framework import graph_io
import Unet
from keras.layers import Input
def focal_loss(gamma=2., alpha=.25):
def focal_loss_fixed(y_true, y_pred):
pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1+ K.pow(10.0, -9)))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0+ K.pow(10.0, -9)))
return focal_loss_fixed
def IOU_calc():
def IOU_calc_fixed(y_true, y_pred):
smooth = 0.001
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return 2*(intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
return IOU_calc_fixed
def IOU_calc_loss():
return lambda x: -IOU_calc()
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
from tensorflow.python.framework.graph_util import convert_variables_to_constants
graph = session.graph
with graph.as_default():
freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
output_names = output_names or []
print(output_names)
input_graph_def = graph.as_graph_def()
if clear_devices:
for node in input_graph_def.node:
node.device = ""
frozen_graph = convert_variables_to_constants(session, input_graph_def,
output_names, freeze_var_names)
# add for new test
frozen_graph = tf.graph_util.remove_training_nodes(frozen_graph)
return frozen_graph
def h5_to_pb(h5_model, output_dir, model_name, out_prefix = "output_"):
out_nodes = []
for i in range(len(h5_model.outputs)):
out_nodes.append(out_prefix + str(i + 1))
tf.identity(h5_model.output[i], out_prefix + str(i + 1))
# add for ignore dropout at inference process(?)
K.set_learning_phase(0)
sess = K.get_session()
from tensorflow.python.framework import graph_util,graph_io
init_graph = sess.graph.as_graph_def()
main_graph = graph_util.convert_variables_to_constants(sess, init_graph, out_nodes)
graph_io.write_graph(main_graph, output_dir, name = model_name, as_text = False)
def load_graph(frozen_graph_filename):
with tf.gfile.GFile(frozen_graph_filename, "rb") as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
for n in graph_def.node:
if "input_" in n.name:
input_name = n.name + ":0"
with tf.Graph().as_default() as graph:
tf.import_graph_def(graph_def, name='')
return graph, input_name
def delete_ops_from_graph(graph_def, output_model_filepath):
# Delete nodes
nodes = []
input_count = 0
for node in graph_def.node:
if "input" in node.name and "dropout" not in node.name:
if "keras" not in node.name:
if input_count == 0:
nodes.append(node)
input_count += 1
else:
print('Drop', node.name)
else:
nodes.append(node)
else:
nodes.append(node)
mod_graph_def = tf.GraphDef()
mod_graph_def.node.extend(nodes)
# Delete references to deleted nodes
for node in mod_graph_def.node:
inp_names = []
for inp in node.input:
if 'Neg' in inp:
pass
else:
inp_names.append(inp)
del node.input[:]
node.input.extend(inp_names)
with open(output_model_filepath, 'wb') as f:
f.write(mod_graph_def.SerializeToString())
if __name__ == '__main__':
config_path = r'unet_h5_to_pb_config.json'
with open(config_path) as config_buffer:
a = config_buffer.read()
a = a.replace('\\', '\\\\')
config = json.loads(a)
"""-------------------------Set Paths-----------------------------------"""
h5_model_path = config["h5_md_path"]
if "\\" in h5_model_path:
h5_name = h5_model_path.split("\\")[-1]
pb_model_name = h5_name.split(".")[0] + ".pb"
if len(config["pb_save_path"]) == 0:
output_path = h5_model_path.strip(h5_model_path.split("\\")[-1])
if h5_model_path[0] == ".":
output_path = "." + output_path
else:
output_path = config["pb_save_path"]
if os.path.exists(output_path) is False:
os.mkdir(output_path)
out_md_path = os.path.join(output_path, pb_model_name)
else:
h5_name = h5_model_path.split("/")[-1]
pb_model_name = h5_name.split(".")[0] + ".pb"
if len(config["pb_save_path"]) == 0:
output_path = h5_model_path.strip(h5_model_path.split("/")[-1])
if h5_model_path[0] == ".":
output_path = "." + output_path
else:
output_path = config["pb_save_path"]
if os.path.exists(output_path) is False:
os.mkdir(output_path)
out_md_path = os.path.join(output_path, pb_model_name)
"""---------------------------load h5 model-----------------------------"""
K.set_learning_phase(0)
try:
net_model = load_model(h5_model_path,
custom_objects={'IOU_calc': IOU_calc()})
print("***Handling model with structure***")
except ValueError as E:
if "Cannot create group in read only mode" in str(E):
print("***Handling model without structure***")
input_shape = tuple(config["input_shape"])
model_class = config["model_class"]
net_model = Unet.small_unet(input_shape, model_class)
net_model.load_weights(h5_model_path)
else:
print(E)
print('***input is :', net_model.input.name)
print('***output is:', net_model.output.name)
"""----------------------------save pb file-----------------------------"""
if config["name_output_node"]:
h5_to_pb(net_model, output_dir=output_path, model_name=pb_model_name)
else:
sess = K.get_session()
frozen_graph = freeze_session(K.get_session(),
output_names=[net_model.output.op.name])
graph_io.write_graph(frozen_graph,
output_path, pb_model_name, as_text=False)
print(f"===== FINISH converting model to pb file {out_md_path} =====")
"""----------------------------revise input-----------------------------"""
K.clear_session()
if config["dynamic_input"]:
tf_md_path = os.path.join(output_path, pb_model_name)
out_pb_path = tf_md_path.replace(".pb", "_dynamic.pb")
resize_val = (None, None, config["model_inp_ch"])
graph_model, input_name = load_graph(tf_md_path)
graph_model_def = graph_model.as_graph_def()
rp_input = Input(resize_val)
tf.import_graph_def(graph_model_def, name='',
input_map={input_name: rp_input})
graph = tf.get_default_graph()
graph_def = graph.as_graph_def()
#print(graph_def.node)
delete_ops_from_graph = delete_ops_from_graph(graph_def, out_pb_path)
print("=== Finish update model with dynamic input size ===")
the part of changing .pb input layer shape will be added with two layer before input,
which is "keras_learning_phase/input:0" and "keras_learning_phase:0" with bool as input type.
Since if I run code_1 and code_2 separately, this situation won't happen,
I think it might be caused by keras backend stuff or K.set_learning_phase(0)(?)
I've added "K.clear_session()" after code_1's part before entering code_2's part,
but the result is still the same.
So I'm wondering is there still something I can do to avoid this happening?
(Thanks in advance for any help or suggestion!)
Solution 1:[1]
There is 2 solutions for this, but both must be executed inside the graph itself.
The easy one is set K.set_learning_phase(0)
inside a Graph that you import from your default graph.
If that does not work out. You can try this trick. Because you are converting the weights of the model. You can trip these keras_learning_phase
node from the graph by removing their connections to other nodes. You can follow this solution
However, for a quick demonstration for you:
def remove_keras_learning(od_graph_def):
for node in od_graph_def.node:
inp_names = []
for inp in node.input:
if not 'keras_learning_phase' in inp:
inp_names.append(inp)
del node.input[:]
node.input.extend(inp_names)
return od_graph_def
Here is the result:



Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | dtlam26 |