【问题标题】:Detect channels first/last of tensorflow saved model?检测张量流保存模型的第一个/最后一个通道?
【发布时间】:2021-07-27 12:51:36
【问题描述】:

有没有什么方法可以检测到加载为model=tf.saved_model.load(path)的TF保存模型的通道第一或最后格式?

在 Keras 中,可以通过 model.layers 并检查层 l l.data_format == 'channels_last'

TF 保存的模型有类似的东西吗?我找不到任何合适的 TF 模型细节文档 - 一切都回到 Keras。

【问题讨论】:

  • 请问,为什么不直接加载模型并检查层的data_format?通常,处理已保存模型的最佳方式是加载它,然后对其进行处理。
  • @ibarrond 因为 Keras 模型中存在层的data_format。我说的是 Tesnotflow SavedModel 格式。
  • 我明白了。我可能对如何做有提示,但我需要一个小例子来玩它。你认为你可以创建一个微小的 TF 模型,保存并加载它吗?
  • tf.saved_model.save(tf.keras.applications.MobileNet(),'/path/to/dir') m=tf.saved_model.load('/path/to/dir')
  • 你可以对保存的模型格式做同样的事情。

标签: tensorflow inference


【解决方案1】:

在 tf.saved_model.load 的 tensorflow documentation 中声明:

"Keras 模型是可追踪的,因此可以保存到 SavedModel。tf.saved_model.load 返回的对象不是 Keras 对象(即没有 .fit、.predict 等方法)。一些属性和函数仍然可用:.variables、.trainable_variables 和 .call。"

我建议您尝试使用 .variables 属性提取通道数,然后与模型架构进行比较(我假设您大致了解输入/输出大小是多少以及应该在第一层)

# channel last format
input_shape = (32,32,3)
# build model in keras
model = keras.Sequential(
    [
        keras.layers.InputLayer(input_shape=input_shape),
        layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
        layers.Flatten(),
        layers.Dropout(0.5),
        layers.Dense(2, activation="softmax"),
    ]
)
model.save('model')

然后用 tf 加载模型

loaded_model = tf.saved_model.load('model')

并得到第一层的输出形状:

loaded_model.variables[0].shape

输出:

TensorShape([3, 3, 3, 32])

如果我们了解模型架构并且第一层的输出有 32 个通道,那么现在很明显模型最后保存在通道中。 但是,如果您对模型的结构一无所知,则可能会更加棘手,并且这种解决方案还不够。

【讨论】:

  • 我不是在寻找启发式方法。我可以自己做。即使我的净输入是 3x3x3,我也想要具体的定义...
  • 我想这很棘手!我猜你必须编写一个算法,通过对网络中变量的有效性检查来检查权重的哪个维度表示通道,因为只有。我很想知道它是否以更简单的方式仅适用于 tf.saved_model.load 中提供的变量
  • 请参阅:TF 知道如何在加载模型时计算它 - 所以应该有关于它的信息。问题是如何访问一个。
【解决方案2】:

我确信有比这更好的答案,但如果我只是想快速解决这个问题...

如果我已经知道图像大小,我会尝试

# Arrange.

tf.saved_model.save(tf.keras.applications.MobileNet(),'/path/to/dir') 
m=tf.saved_model.load('/path/to/dir')
image_size = (224,224) # 

# Act
try:
  m(tf.zeros((1,) + image_size + (3,))
  format='channels_last'
except ValueError:
  try:
    m(tf.zeros((1,3) + image_size)
    format='channels_first'
  except ValueError:
    raise ValueError('input shape is neither None,224,224,3 nor None,3,224,224')

如果我不知道图片大小,我会考虑:

  1. 循环使用常见尺寸,例如 29x29、32x32、224x224、256x256 和 299x299。

  2. 暴力搜索所有 2 ** 20 种图像尺寸组合,最大为 1024x1024

  3. 调用m(None) 并使用正则表达式解析ValueError 中的str。它打印出输入形状的 TensorSpec:

>>> m(tf.zeros((1,1,1,3)))
Traceback (most recent call last):
[...]
ValueError: Could not find matching function to call loaded from the SavedModel. Got:
  Positional arguments (3 total):
    * Tensor("inputs:0", shape=(1, 1, 1, 3), dtype=float32)
    * False
    * None
  Keyword arguments: {}

Expected these arguments to match one of the following 4 option(s):

Option 1:
  Positional arguments (3 total):
    * TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name='input_1')
    * True
    * None
  Keyword arguments: {}

Option 2:
  Positional arguments (3 total):
    * TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name='input_1')
    * False
    * None
  Keyword arguments: {}

Option 3:
  Positional arguments (3 total):
    * TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name='inputs')
    * True
    * None
  Keyword arguments: {}

Option 4:
  Positional arguments (3 total):
    * TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name='inputs')
    * False
    * None
  Keyword arguments: {}

【讨论】:

  • 这都是启发式的。我正在寻找一些明确的东西。 TF 在加载时知道网络是 CF 还是 CL。所以应该有一个 API/元数据。
  • 是的,我看到您关于其他解决方案的说明只是一种启发式方法。您是对的,例如,如果您的图像大小为 HWC = 333,则仅查看形状将不起作用。我查看了尝试查看图表的方法,但没有找到任何明显的解决方案。 FWIW 可能是 tf.nn.conv 在内部是 NHWC,并且在该操作之前和之后应用转置来处理 NCHW。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 1970-01-01
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多