TensorFlow 多模型加载融合的诸多坑点

多模型加载过程中遇到的问题以及自己的解决方案

目录

场景:

问题一:如何“理论加载”两个已经训练好的模型?

问题二:需要加载模型的结构,又不能直接将该网络模型的架构直接铺设一遍,pkl在我的理解范围内没办法去这么做,怎么办?

问题三:如何获取存储模型中的参数?

问题四:模型的入口如果直接是一个函数的形参,怎么办,没有placeholder?

问题五:模型的出口如果使用了一些将tensor进行np操作整合,如何获得出口?


场景:

加载多个TensorFlow已经训练好的神经网络模型,这里以加载两个项目为例(因为加载三个四个五个和加载两个原理上是一样的),此处增加难度,模型A的存储模式是cpkt,模型B的存储模式是pkl。

目标:同时使用这两个神经网络模型,进行一些想要的处理工作。

模型A:

checkpoint
xxx.ckpt.data-00000-of-00001
xxx.ckpt.index
xxx.ckpt.meta

模型B:

xxx.pkl

问题一:如何“理论加载”两个已经训练好的模型?

如果想要使用已经训练好的模型,首先要在TensorFlow中铺设好”管道“(各种tensor和op),然后通过saver.restore(),函数来加载相应的模型参数,然后feed占位符数据。

如果要是在一个.py文件中同时加载两个模型,不能直接restore两次,那样会出现变量冲突,导致加载失败,因为所有的变量都加载到了当前会话所采用的默认图中。所以我们要做的就是,建立不同的图,创建不同的会话。可以采用class来解决这个问题。

class ImportGraph():
    def __init__(self, meta_path, ckpt_path, class_model):
        self.class_model = class_model
        self.graph = tf.Graph()
        gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.2)
        config = tf.ConfigProto(allow_soft_placement=True, gpu_options=gpu_options)
        
        with self.graph.as_default():
            # 加载模型的结构,拼接“管道”
            self.saver = tf.train.import_meta_graph(meta_path)
        # 创建会话并且指定graph
        self.sess = tf.Session(graph=self.graph, config=config)
        # 加载模型的数据
        self.saver.restore(self.sess, ckpt_path)

        with self.graph.as_default():
            if self.class_model == A:
                # 得到模型A的入口
                # 这里tensor的名字是随便起的具体怎么用,下文讲解
                self.INPUT = self.graph.get_tensor_by_name('Placeholder:0')
                self.OUTPUT = self.graph.get_tensor_by_name('Relu:0') 
            else:
                # 得到模型B的入口

    def run(self, input):
        if class_model == A:
            # 返回模型A的结果
            result = self.sess.run(self.OUTPUT, feed_dict={self.INPUT: input})
            return result
        else:
            # 返回模型B的结果


# 使用模型
# 加载模型结构、参数
model_A = ImportGraph(A_meta_path, A_ckpt_path, A)
model_B = ImportGraph(B_meta_path, B_ckpt_path, B)

# 使用模型进行相关预测
resA = model_A.run(inputA)
resB = model_B.run(inputB)

问题二:需要加载模型的结构,又不能直接将该网络模型的架构直接铺设一,pkl在我的理解范围内没办法去这么做,怎么办?

在单独只加载pkl模型参数的时候,我是知道如何加载模型,我的解决方案是,使用单模型加载pkl网络,然后用saver.save()保存为cpkt形式(及其脑残)。这样就可以同时得到两个文件的cpkt模型,这样就可以用上面个的类去加载两个不同的神经网络模型了。

问题三:如何获取存储模型中的参数?

这里我们得到模型中的op名字和values是为了解决上述代码中的该部分问题:

self.INPUT = self.graph.get_tensor_by_name('Placeholder:0')
self.OUTPUT = self.graph.get_tensor_by_name('Relu:0') 

这里得到的tensor是在run中需要feed真是数据流量的入口,所以一定要找到。然后我们通过run函数得到我们需要的模型预测结果,所以我们一定也要找到模型的出口(这里的出口是指我们需要的那一部分结果,不一定要走完整个模型)。

下面的代码用来返回模型中的所有op操作的名字和values

op_list = self.sess.graph.get_operations()
for op in op_list:
    print(op.name)
    print(op.values())

大体形式是这样的:(截取一小部分)一行op名字,一行op的内容,只要是在网络架构中用到tf.的都有相应的存储结果。

input_image
(<tf.Tensor 'input_image:0' shape=(?, 368, 368, 3) dtype=float32>,)
center_map
(<tf.Tensor 'center_map:0' shape=(?, 368, 368, 1) dtype=float32>,)
pooled_center_map/center_map/AvgPool
(<tf.Tensor 'pooled_center_map/center_map/AvgPool:0' shape=(?, 46, 46, 1) dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/shape
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/shape:0' shape=(4,) dtype=int32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/min
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/min:0' shape=() dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/max
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/max:0' shape=() dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/RandomUniform
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/RandomUniform:0' shape=(3, 3, 3, 64) dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/sub
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/sub:0' shape=() dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform/mul
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform/mul:0' shape=(3, 3, 3, 64) dtype=float32>,)
sub_stages/sub_conv1/weights/Initializer/random_uniform
(<tf.Tensor 'sub_stages/sub_conv1/weights/Initializer/random_uniform:0' shape=(3, 3, 3, 64) dtype=float32>,)
sub_stages/sub_conv1/weights
(<tf.Tensor 'sub_stages/sub_conv1/weights:0' shape=(3, 3, 3, 64) dtype=float32_ref>,)
sub_stages/sub_conv1/weights/Assign
(<tf.Tensor 'sub_stages/sub_conv1/weights/Assign:0' shape=(3, 3, 3, 64) dtype=float32_ref>,)
sub_stages/sub_conv1/weights/read
(<tf.Tensor 'sub_stages/sub_conv1/weights/read:0' shape=(3, 3, 3, 64) dtype=float32>,)
sub_stages/sub_conv1/biases/Initializer/zeros
(<tf.Tensor 'sub_stages/sub_conv1/biases/Initializer/zeros:0' shape=(64,) dtype=float32>,)
sub_stages/sub_conv1/biases
(<tf.Tensor 'sub_stages/sub_conv1/biases:0' shape=(64,) dtype=float32_ref>,)
sub_stages/sub_conv1/biases/Assign
(<tf.Tensor 'sub_stages/sub_conv1/biases/Assign:0' shape=(64,) dtype=float32_ref>,)
sub_stages/sub_conv1/biases/read
(<tf.Tensor 'sub_stages/sub_conv1/biases/read:0' shape=(64,) dtype=float32>,)
sub_stages/sub_conv1/dilation_rate
(<tf.Tensor 'sub_stages/sub_conv1/dilation_rate:0' shape=(2,) dtype=int32>,)
sub_stages/sub_conv1/Conv2D
(<tf.Tensor 'sub_stages/sub_conv1/Conv2D:0' shape=(?, 368, 368, 64) dtype=float32>,)
sub_stages/sub_conv1/BiasAdd
(<tf.Tensor 'sub_stages/sub_conv1/BiasAdd:0' shape=(?, 368, 368, 64) dtype=float32>,)
sub_stages/sub_conv1/Relu
(<tf.Tensor 'sub_stages/sub_conv1/Relu:0' shape=(?, 368, 368, 64) dtype=float32>,)

问题四:模型的入口如果直接是一个函数的形参,怎么办,没有placeholder?

模型被写在了一个函数里面,然后模型的参数保存了函数里面的参数,如果在单独只加载一个模型的情况下,是可以通过定义一占位符,然后将其作为形参,调用模型函数的,但是多模型情况下,没法找到占位符,就没办法去feed数据流,我的方法是,在加载单模型的情况下,再保存一遍模型参数,这样子,我们定义的占位符就也将作为模型参数的一部分。

问题五:模型的出口如果使用了一些将tensor进行np操作整合,如何获得出口?

有的模型是将一些tensor进行整合,例如[tensor1, tensor2, tensor3]---list中,但是这个操作再模型中是不存在的,所以再多模型条件下没有办法直接获得想要的输出,我的解决方法是,将最后需要整合的所有tensor的op名字找出,将这些tensor作为出口,然后将sess.run()的返回值推入到一个空list中,得到想要的结果。

 

 

 

发布了331 篇原创文章 · 获赞 135 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/103150745