首页 > 解决方案 > 在 Tensorflow 2.0 中是否有更简单的方法来执行模型的层?

问题描述

假设我在 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 甚至更高呢?

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

我期待你的答案。先感谢您!

标签: pythontensorflowkerasdeep-learning

解决方案


您可以创建一个循环来一次创建多个层,然后使用 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>]

推荐阅读