logo

TensorFlow 网络层

王哲峰 / 2022-07-15


目录

深度学习模型一般由各种模型层组合而成,tf.keras.layers 内置了非常丰富的各种功能的模型层

如果这些内置模型层不能够满足需求,可以通过编写 tf.keras.Lambda 匿名模型层, 或继承 tf.keras.layers.Layer 基类构建自定义的模型层

内置模型层

模型层共有的方法

权重设置与获取

层属性获取

常用内置模型层

常用核心层

卷积网络相关层

循环网络相关层

自定义模型层

编写 tf.keras.Lambda 层

如果自定义模型层没有需要被训练的参数,一般推荐使用 Lambda 层实现。 Lambda 层由于没有需要被训练的参数,只需要定义正向传播逻辑即可,使用比 Layer 基类子类化更加简单。 Lambda 层的正向逻辑可以使用 Python 的 lambda 函数来表达,也可以使用 def 关键字定义函数来表达

import tensorflow as tf
from tensorflow.keras import layers, models, regularizers

mypower = layers.Lambda(lambda x: tf.math.pow(x, 2))
mypower(tf.range(5))

继承 tf.keras.layers.Layer 基类

如果自定义模型层有需要被训练的参数,则可以通过对 Layer 基类子类化实现。 通过 Layer 的子类化自定义层一般需要继承 tf.keras.layers.Layers 类, 并重写 __init__buildcall 三个方法

import numpy as np
import tensorflow as tf

class MyLayer(tf.keras.layers.Layer):
    def __init__(self):
        super().__init__()
        # 初始化代码
    
    def build(self, input_shape):
        """
        input_shape 是一个 TensorShape 类型对象, 提供输入的形状
        """
        # 在第一次使用该层的时候调用该部分代码, 
        # 在这里创建变量可以使得变量的形状自适应输入的形状
        # 而不需要使用者额外指定变量形状
        # 如果已经可以完全确定变量的形状, 也可以在 __init__ 部分创建变量
        self.variable_0 = self.add_weight(...)
        self.variable_1 = self.add_weight(...)
    
    def call(self, inputs):
        # 模型调用的代码(处理输入并返回输出)
        return output

线性层示例

import numpy as np
import tensorflow as tf

class Linear(tf.keras.layers.Layer):
    def __init__(self, units = 32, **kwargs):
        super(Linear, self).__init__(**kwargs)
        self.units = units
    
    def build(self, input_shape):
        """
        build 方法一般定义 Layer 需要被训练的参数
        """
        self.w = self.add_weight(
            name = "w", 
            shape = (input_shape[-1], self.units),  # [n, 1]
            initializer = tf.zeros_initializer(),
            trainable = True,
        )
        self.b = self.add_weight(
            name = "b",
            shape = (self.units),  # [1]
            initializer = tf.zeros_initializer(),
            trainable = True,
        )
        # 相当于设置 self.built = True
        super(Linear, self).build(input_shape)
    
    @tf.function
    def call(self, inputs):
        """
        call 方法一般定义正向传播运算逻辑,__call__ 方法调用了它
        """
        y_pred = tf.matmul(inputs, self.w) + self.b
        return y_pred
    
    def get_config(self):
        """
        如果要让自定义的 Layer 通过 Function API 
        组成模型时可以被保存成 h5 模型
        需要自定义 get_config 方法
        """
        config = super(Linear, self).get_config()
        config.update({
            "units": self.units,
        })
        return config


# ------------------------------
# 
# ------------------------------
# 模型实例化
linear = Linear(units = 8)
print(linear.built)

# 指定 input_shape,显式调用 build 方法,第 0 维代表样本数量,用 None 填充
linear.build(input_shape = (None, 16))
print(linear.built)
print(linear.compute_output_shape(input_shape = (None, 16)))


# ------------------------------
# 
# ------------------------------
linear = Linar(units = 16)
print(linear.built)

# 如果 built = False,调用 __call__ 时会先调用 build 方法,再调用 call 方法
linear(tf.random.uniform((100, 64)))
print(linear.built)

config = linear.get_config()
print(config)



# ------------------------------
# 模型构建
# ------------------------------
tf.keras.backend.clear_session()

model = models.Sequential()
model.add(
    Linear(units = 1, input_shape = (2,))
)
print(f"model.input_shape: {model.input_shape}")
print(f"model.output_shape: {model.output.shape}")
model.summary()

# ------------------------------
# 模型训练
# ------------------------------
model.compile(optimizer = "sgd", loss = "mse", metrics = ["mae"])
predictions = model.predict(tf.constant(
    [[3.0, 2.0], 
     [4.0, 5.0]]
))
print(predictions)

# ------------------------------
# 保存模型为 h5 模型
# ------------------------------
model.save("./models/linear_model.h5", save_format = "h5")
model_loaded_keras = tf.keras.models.load_model(
    "./models/linear_model.h5", 
    custom_objects = {"Linear": Linear},
)
predictions = model_loaded_keras.predict(tf.constant(
    [[3.0, 2.0], 
     [4.0, 5.0]]
))
# ------------------------------
# 保存模型成 tf 模型
# ------------------------------
model.save("./models/linear_model", save_format = "tf")
model_loaded_tf = tf.keras.models.load_model(
    "./models/linear_model"
)
predictions = model_loaded_tf.predict(tf.constant(
    [[3.0, 2.0], 
     [4.0, 5.0]]
))

模型层配置

model.add(Layer(
    # 输出、输出
    output_dim,
    input_dim,
    # 参数初始化
    kernel_initializer,
    bias_initializer,
    # 参数正则化
    kernel_regularizer,
    activity_regularizer,
    # 参数约束
    kernel_constraint,
    bias_constraint,
    # 层激活函数
    activation,
))

# 输入
inputs = Input()

# 激活函数
model.add(Activation)

输入

输出

激活函数

模型可用的激活函数

在模型中使用激活函数

在 TensorFlow Keras 模型中使用激活函数一般有两种方式

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras import layers, models

tf.keras.backend.clear_session()

model = models.Sequential()
model.add(layers.Dense(
    32, 
    input_shape = (None, 16), 
    activation = tf.nn.relu
))
model.add(layers.Dense(10))
model.add(layers.Activation(tf.nn.softmax))
model.summary()

正则化

正则化器允许在优化过程中对层的参数或层的激活函数情况进行惩罚, 并且神经网络优化的损失函数的惩罚项也可以使用

惩罚是以层为对象进行的。具体的 API 因层而异, 但 Dense, Conv1D, Conv2D 和 Conv3D 这些层具有统一的 API

Regularizers 的使用方法

可用的 Regularizers

自定义的 Regularizer

约束

constraints 模块的函数允许在优化期间对网络参数设置约束(例如非负性)

约束是以层为对象进行的。具体的 API 因层而异, 但 Dense, Conv1D, Conv2D 和 Conv3D 这些层具有统一的 API

Constraints 的使用方法

可用的 Constraints