在 Tensorflow 2.0 中是不是有更简单的方法来执行模型层?

Posted

技术标签:

【中文标题】在 Tensorflow 2.0 中是不是有更简单的方法来执行模型层?【英文标题】:Are there easier ways to excute model's layers in Tensorflow 2.0?在 Tensorflow 2.0 中是否有更简单的方法来执行模型层? 【发布时间】:2020-12-27 11:59:27 【问题描述】:

假设我使用 Tensorflow 2.0 中的 Keras 子类化 API 制作了一个自定义模型,如下所示。

class MyModel(Model):
  def __init__(self):
    super(MyModel, self).__init__()
    self.conv1 = Conv2D(32, 3, activation='relu')
    self.flatten = Flatten()
    self.d1 = Dense(128, activation='relu')
    self.d2 = Dense(10, activation='softmax')

  def call(self, x):
    x = self.conv1(x)
    x = self.flatten(x)
    x = self.d1(x)
    return self.d2(x)

model = MyModel()

如果层数不多,写类的'def call'也没那么烦。

我只需要像上面那样写下 3~4 行图层。

但是如果层数增加 50~60 甚至更高呢?

我必须输入所有这些图层吗?不知道有没有更好的方法?

期待您的回答。提前谢谢!

【问题讨论】:

我没有密切关注TF,但上次看到Keras,有Sequential。没有了吗? @dedObed 它还有Sequential。感谢您的评论! 【参考方案1】:

您可以创建一个循环来一次创建多个层,然后使用 for 循环调用它们。

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
import tensorflow as tf
from functools import partial

x = tf.random.uniform((5, 2), 0, 1)

class MyModel(tf.keras.Model):
  def __init__(self):
    super(MyModel, self).__init__()
    dense_layer = partial(tf.keras.layers.Dense, units=3, activation='relu')
    self.layer_list = [dense_layer(name=f'layer_i') for i in range(3)]
    self.out = tf.keras.layers.Dense(1, activation='sigmoid')

  def call(self, x, training=None, **kwargs):
    for layer in self.layer_list:
        x = layer(x)
    x = self.out(x)
    return x

model = MyModel()
model.build(input_shape=(5, 2))
print(list(map(lambda x: x.name, model.layer_list)))
['layer_0', 'layer_1', 'layer_2']
model(x)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[0.51850706],
       [0.5285746 ],
       [0.51396513],
       [0.5171388 ],
       [0.50938624]], dtype=float32)>

有些架构会重复自己(例如,连续多次的卷积层和最大池化层),因此您可以创建返回多个层的函数,然后使用循环来创建其中的许多层。为避免重复所有内容,我使用了functools.partial,它使用默认参数创建了一个可调用对象。

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
import tensorflow as tf
from functools import partial

x = tf.random.uniform((5, 256, 256, 3), 0, 1)

def conv_block(units):
    conv = partial(tf.keras.layers.Conv2D, kernel_size=(3, 3), activation='relu')
    pool = partial(tf.keras.layers.MaxPooling2D, pool_size=(2, 2))
    layer_dict = 
        'conv1': conv(units),
        'pool1': pool(),
        'conv2': conv(units*2),
        'pool2': pool(),
        'conv3': conv(units*3)
    
    return layer_dict

class MyModel(tf.keras.Model):
  def __init__(self):
    super(MyModel, self).__init__()
    self.block_list = [conv_block(i) for i in range(1, 3)]
    self.flat = tf.keras.layers.Flatten()
    self.out = tf.keras.layers.Dense(1, activation='sigmoid')

  def call(self, x, training=None, **kwargs):
    for block in self.block_list:
        for layer in block.values():
            x = layer(x)
    x = self.flat(x)
    x = self.out(x)
    return x

model = MyModel()
model.build(input_shape=(5, 256, 256, 3))

model(x)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy=
array([[0.48275623],
       [0.48887327],
       [0.49217385],
       [0.48883903],
       [0.48933515]], dtype=float32)>

如你所见,我生成了两次这个块:

model.layers
[<tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b404f47b08>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b40be6cb48>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b40d6eab88>,
 <tensorflow.python.keras.layers.pooling.MaxPooling2D at 0x1b40be6cb08>,
 <tensorflow.python.keras.layers.pooling.MaxPooling2D at 0x1b40d6ddc08>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b40d6f2188>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b40d6f2bc8>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x1b40d6f0648>,
 <tensorflow.python.keras.layers.pooling.MaxPooling2D at 0x1b40d6f2748>,
 <tensorflow.python.keras.layers.pooling.MaxPooling2D at 0x1b40d6f01c8>,
 <tensorflow.python.keras.layers.core.Flatten at 0x1b40d6f8cc8>,
 <tensorflow.python.keras.layers.core.Dense at 0x1b40d6ee248>]

【讨论】:

这与我正在寻找的答案有点接近。谢谢!【参考方案2】:

在 TF 2.0 中创建类更容易与 Pytorch 和其他深度学习框架竞争。但是,如果您的模型是顺序的,将层堆叠在一起,您仍然可以通过 example 应用它。

对于需要执行多个输出的模型,像SSD或YOLO这样的并行计算,像类一样全面编写更好,或者您可以通过将多个输入和多个输出传递给模型来直接使用Model(example)

【讨论】:

但我建议您应该坚持使用类继承模型以进行进一步的高级开发 你为什么这么认为? 对于更高的模型,您需要一次声明多个并行模型。当您编写顺序时,它会很容易但过于庞大。这就是为什么 Pytorch 非常受欢迎的原因。有时间你应该试试 哦,我明白了。再次感谢您的建议! 我可能是错的,但我根本不明白这如何回答这个问题......

以上是关于在 Tensorflow 2.0 中是不是有更简单的方法来执行模型层?的主要内容,如果未能解决你的问题,请参考以下文章

Anaconda 安装 TensorFlow 1.15 而不是 2.0

tensorflow 2.0中是不是有mtcnn人脸检测的实现?

在 Tensorflow 2.0 中的简单 LSTM 层之上添加注意力

如何简单粗暴地上手 TensorFlow 2.0?

社区分享 | Spark 玩转 TensorFlow 2.0

解读:TensorFlow 2.0中即将到来的所有新特性