将训练好的 keras 模型的批量大小设置为 1

问题描述 投票:0回答:3

我正在使用我自己的数据集训练一个 keras 模型。然而,加载权重后,摘要显示 None 作为第一个维度(批量大小)。

我想知道将形状修复为批量大小为 1 的过程,因为我必须修复它,以便我可以将模型转换为具有 GPU 支持的 tflite。

tensorflow keras deep-learning
3个回答
2
投票

对我有用的是指定输入层的批量大小,如下所示:

input = layers.Input(shape=input_shape, batch_size=1, dtype='float32', name='images')

然后这将贯穿其余各层。

坏消息是,尽管进行了“修复”,tfl 运行时仍然抱怨动态张量。 logcat 运行时我收到这些非致命错误:

E/tflite: third_party/tensorflow/lite/core/subgraph.cc:801 tensor.data.raw != nullptr was not true.
E/tflite: Attempting to use a delegate that only supports static-sized tensors with a graph that has dynamic-sized tensors (tensor#26 is a dynamic-sized tensor).
E/tflite: Ignoring failed application of the default TensorFlow Lite delegate indexed at 0.

好消息是,尽管存在这些错误,但根据性能测试,它似乎仍在使用 GPU。

我正在使用:

tensorflow-lite-support:0.2.0'    
tensorflow-lite-metadata:0.2.1'    
tensorflow-lite:2.6.0'    
tensorflow:tensorflow-lite-gpu:2.3.0'

希望他们能够修复运行时问题,这样批量大小是否为“无”并不重要。进行推理应该没有关系。


1
投票

我遇到了同样的问题,但在任何地方都找不到解决方案。不过,我设法通过一些解决方法解决了这个问题。

首先,您需要获取模型的配置:

model.get_config() 

你会看到一个

batch_input_shape

{'name': 'sequential',
 'layers': [{'class_name': 'InputLayer',
   'config': {'batch_input_shape': (None, 28, 28, 1),
    'dtype': 'float32',
    'sparse': False,
    ...

接下来,您需要将

None
值更改为所需的批量大小。例如这样(改为1):

for layer in conf['layers']:
    if 'batch_input_shape' in layer['config']:
        shape = layer['config']['batch_input_shape']
        shape = (1, *shape[1:])
        layer['config']['batch_input_shape'] = shape

现在配置字典应该如下所示:

{'name': 'sequential',
 'layers': [{'class_name': 'InputLayer',
   'config': {'batch_input_shape': (1, 28, 28, 1),
    'dtype': 'float32',
    'sparse': False,
    ...

最后一步是根据新配置创建模型并根据初始模型设置权重。

new_model = model.from_config(conf)
new_model.set_weights(model.get_weights())

查看摘要,我们发现它有效:

Model: "sequential"
_________________________________________________________________
 Layer (type)                  Output Shape            Param #   
=================================================================
 conv2d (Conv2D)               (1, 26, 26, 32)         320       
                                                                 
 max_pooling2d (MaxPooling2D)  (1, 13, 13, 32)         0         
                                                          

0
投票

@maciek97x 的答案帮助我找到了类似问题的替代方案,但它不适用于我试图在另一个场景中训练的预训练模型。此外,仅更改输入形状图层是不够的。我用TF测试过

2.15.0

正如您提到的,您使用自己的数据集训练了模型,我假设您拥有可用的模型定义。所以,对我有用的是:

  1. 加载预训练模型和自定义对象(如果适用)。

    import re
    import tensorflow as tf
    
    # Model with old batch size
    pre_trained_model = tf.keras.models.load_model(path_to_model_folder, custom_objects={"SomeCustomLayer": SomeCustomLayer})
    
  2. 生成具有相同定义的另一个模型,但将自定义层之外的操作替换为 TF 版本,例如将“+”和“*”替换为

    tf.add(..)
    tf.multiply(...)

    batch_size = 1
    data_input_layer = tf.keras.layers.Input(
        shape=[128, 128, 3],
        batch_size=batch_size,
    )
    # model definition ...
    
    new_model = tf.keras.Model(
        inputs=[data_input_layer],
        outputs=[output],
    )
    
  3. 将预训练的权重加载到新模型中

    layer_dict = dict([(layer.name, layer) for layer in pre_trained_model.layers])
    
    for i, layer in enumerate(model_full.layers):
        # Check if there is any weights for the layer
        if layer.get_weights():
            # Get name without '_1', '_2', that can happen when you create two models with the same definition        
            name_filtered = re.sub(r'_\d+', '', layer.name)
    
            pre_trained_weights = layer_dict[name_filtered].get_weights()
            new_model.get_layer(layer.name).set_weights(pre_trained_weights)
    
© www.soinside.com 2019 - 2024. All rights reserved.