Tensorflow:如何向现有图形中插入自定义输入?

5
我已经下载了一个实现VGG16 ConvNet的tensorflow GraphDef,我使用它来完成以下操作:
Pl['images'] = tf.placeholder(tf.float32, 
                          [None, 448, 448, 3],
                          name="images") #batch x width x height x channels
with open("tensorflow-vgg16/vgg16.tfmodel", mode='rb') as f: 
    fileContent = f.read()

graph_def = tf.GraphDef()
graph_def.ParseFromString(fileContent)
tf.import_graph_def(graph_def, input_map={"images": Pl['images']})

此外,我有图像特征,与"import/pool5/"的输出具有同质性。

如何告诉我的图形,不想使用它的输入"images",而是将张量"import/pool5/"作为输入?

谢谢!

编辑

好的,我意识到我没有表达清楚。这是情况:

我正在尝试使用这个实现的ROI池化,使用预训练的VGG16,我已经以GraphDef格式拥有它。所以这是我做的事情:

首先,我加载模型:

tf.reset_default_graph()
with open("tensorflow-vgg16/vgg16.tfmodel",
          mode='rb') as f:
    fileContent = f.read()
graph_def = tf.GraphDef()
graph_def.ParseFromString(fileContent)
graph = tf.get_default_graph()

然后,我创建我的占位符。
images = tf.placeholder(tf.float32, 
                              [None, 448, 448, 3],
                              name="images") #batch x width x height x channels
boxes = tf.placeholder(tf.float32, 
                             [None,5], # 5 = [batch_id,x1,y1,x2,y2]
                             name = "boxes")

我定义图的第一部分的输出为conv5_3/Relu

tf.import_graph_def(graph_def, 
                    input_map={'images':images})
out_tensor = graph.get_tensor_by_name("import/conv5_3/Relu:0")

因此,out_tensor 的形状为 [None,14,14,512]

然后,我进行 ROI 池化:

[out_pool,argmax] = module.roi_pool(out_tensor,
                                    boxes,
                                    7,7,1.0/1) 

有了out_pool.shape = N_Boxes_in_batch x 7 x 7 x 512,它与pool5相同。然后我想将out_pool作为输入提供给pool5之后的操作,所以它看起来像这样:

tf.import_graph_def(graph.as_graph_def(),
                    input_map={'import/pool5':out_pool})

但它不起作用,我有这个错误:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-89-527398d7344b> in <module>()
      5 
      6 tf.import_graph_def(graph.as_graph_def(),
----> 7                     input_map={'import/pool5':out_pool})
      8 
      9 final_out = graph.get_tensor_by_name("import/Relu_1:0")

/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/importer.py in import_graph_def(graph_def, input_map, return_elements, name, op_dict)
    333       # NOTE(mrry): If the graph contains a cycle, the full shape information
    334       # may not be available for this op's inputs.
--> 335       ops.set_shapes_for_outputs(op)
    336 
    337       # Apply device functions for this op.

/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/ops.py in set_shapes_for_outputs(op)
   1610       raise RuntimeError("No shape function registered for standard op: %s"
   1611                          % op.type)
-> 1612   shapes = shape_func(op)
   1613   if len(op.outputs) != len(shapes):
   1614     raise RuntimeError(

/home/hbenyounes/vqa/roi_pooling_op_grad.py in _roi_pool_shape(op)
     13   channels = dims_data[3]
     14   print(op.inputs[1].name, op.inputs[1].get_shape())
---> 15   dims_rois = op.inputs[1].get_shape().as_list()
     16   num_rois = dims_rois[0]
     17 

/usr/local/lib/python3.4/dist-packages/tensorflow/python/framework/tensor_shape.py in as_list(self)
    745       A list of integers or None for each dimension.
    746     """
--> 747     return [dim.value for dim in self._dims]
    748 
    749   def as_proto(self):

TypeError: 'NoneType' object is not iterable

任何线索?

input_map 可以在图中使用任意输入名称。我会打印 graph_def 来确定池化输出的确切名称。 - Yaroslav Bulatov
所以,如果我理解你的问题,你有一个操作,例如: y=tf.mul(x,W) 并且你想要修改它的输入x为来自另一个网络的另一个张量xprime? - jeandut
3个回答

3
通常,使用tf.train.export_meta_graph存储整个MetaGraph非常方便。然后,在恢复时,您可以使用tf.train.import_meta_graph,因为它会将所有附加参数传递给底层的import_scoped_meta_graph,后者具有input_map参数并在自己调用import_graph_def时利用它。
这个方法没有被记录,而且我花费了很长时间才找到它,但它确实有效!

2

我会做的事情大致如下:

-首先,检索代表VGG16中pool5后面的3个全连接层的权重和偏置的张量的名称。
为此,我会检查[n.name for n in graph.as_graph_def().node]。(它们可能看起来像import/locali/weight:0、import/locali/bias:0等)

-将它们放入Python列表中:

weights_names=["import/local1/weight:0" ,"import/local2/weight:0" ,"import/local3/weight:0"]
biases_names=["import/local1/bias:0" ,"import/local2/bias:0" ,"import/local3/bias:0"]

-定义一个类似于以下形式的函数:

def pool5_tofcX(input_tensor, layer_number=3):
  flatten=tf.reshape(input_tensor,(-1,7*7*512))
  tmp=flatten
  for i in xrange(layer_number):
    tmp=tf.matmul(tmp, graph.get_tensor_by_name(weights_name[i]))
    tmp=tf.nn.bias_add(tmp, graph.get_tensor_by_name(biases_name[i]))
    tmp=tf.nn.relu(tmp)
  return tmp

然后使用以下函数定义张量:
wanted_output=pool5_tofcX(out_pool) 

然后你就完成了!

看起来它能工作,谢谢!我只是把1414改成了77(因为它在最大池化之后),并在bias_add之后添加了ReLu。 - HediBY
是的,我忘了RELU了,我会进行更改! - jeandut

0

Jonan Georgiev在这里提供了一个很好的答案。同样的方法也在这个git问题的末尾被描述,但没有引起太多关注:https://github.com/tensorflow/tensorflow/issues/3389

下面是一个可运行的复制/粘贴示例,演示如何使用此方法来切换占位符以获取tf.data.Dataset get_next张量。

import tensorflow as tf


my_placeholder = tf.placeholder(dtype=tf.float32, shape=1, name='my_placeholder')
my_op = tf.square(my_placeholder, name='my_op')

# Save the graph to memory
graph_def = tf.get_default_graph().as_graph_def()

print('----- my_op before any remapping -----')
print([n for n in graph_def.node if n.name == 'my_op'])

tf.reset_default_graph()

ds = tf.data.Dataset.from_tensors(1.0)
next_tensor = tf.data.make_one_shot_iterator(ds).get_next(name='my_next_tensor')

# Restore the graph with a custom input mapping
tf.graph_util.import_graph_def(graph_def, input_map={'my_placeholder': next_tensor}, name='')

print('----- my_op after remapping -----')
print([n for n in tf.get_default_graph().as_graph_def().node if n.name == 'my_op'])

输出,我们可以清楚地看到正方形操作的输入已经改变。

----- my_op before any remapping -----
[name: "my_op"
op: "Square"
input: "my_placeholder"
attr {
  key: "T"
  value {
    type: DT_FLOAT
  }
}
]

----- my_op after remapping -----
[name: "my_op"
op: "Square"
input: "my_next_tensor"
attr {
  key: "T"
  value {
    type: DT_FLOAT
  }
}
]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接