Tensorflow2.0 Keras之自定义网络

Tensorflow2.0 Keras之自定义网络


尽管 Keras 提供了很多的常用网络层类,但深度学习可以使用的网络层远远不止这些。科研工作者一般是自行实现了较为新颖的网络层,经过大量实验验证有效后,深度学习框架才会跟进,内置对这些网络层的支持。因此掌握自定义网络层、网络的实现非常重要。

对于需要创建自定义逻辑的网络层,可以通过自定义类来实现。在创建自定义网络层类时,需要继承自layers.Layer 基类;创建自定义的网络类时,需要继承自keras.Model 基类,这样建立的自定义类才能够方便的利用Layer/Model 基类提供的参数管理等功能,同时也能够与其他的标准网络层类交互使用。

自定义网络层

对于自定义的网络层,至少需要实现初始化__init__方法和前向传播逻辑call 方法。我们以某个具体的自定义网络层为例,假设需要一个没有偏置向量的全连接层,即bias 为0,同时固定激活函数为ReLU 函数。尽管这可以通过标准的Dense 层创建,但我们还是通过实现这个“特别的”网络层类来阐述如何实现自定义网络层。

首先创建类,并继承自Layer 基类。创建初始化方法,并调用母类的初始化函数,由于是全连接层,因此需要设置两个参数:输入特征的长度inp_dim 和输出特征的长度outp_dim,并通过self.add_variable(name, shape)创建shape 大小,名字为name 的张量𝑾,并设置为需要优化。代码如下:

class MyDense(layers.Layer):
	# 自定义网络层
	def __init__(self, inp_dim, outp_dim):
		super(MyDense, self).__init__()
		# 创建权值张量并添加到类管理列表中,设置为需要优化
		self.kernel = self.add_variable('w', [inp_dim, outp_dim],
		trainable=True)

需要注意的是,self.add_variable 会返回张量𝑾的Python 引用,而变量名name 由TensorFlow 内部维护,使用的比较少。我们实例化MyDense 类,并查看其参数列表,例如:

In [5]: net = MyDense(4,3) # 创建输入为4,输出为3 节点的自定义层
net.variables,net.trainable_variables # 查看自定义层的参数列表
Out[5]:
# 类的全部参数列表
([<tf.Variable 'w:0' shape=(4, 3) dtype=float32, numpy=# 类的待优化参数列表
[<tf.Variable 'w:0' shape=(4, 3) dtype=float32, numpy=

可以看到𝑾张量被自动纳入类的参数列表。
通过修改为self.kernel = self.add_variable(‘w’, [inp_dim, outp_dim], trainable=False),我们可以设置𝑾张量不需要被优化,此时再来观测张量的管理状态:

([<tf.Variable 'w:0' shape=(4, 3) dtype=float32, numpy=], # 类的全部参数列表
[])# 类的不需要优化参数列表

可以看到,此时张量并不会被trainable_variables 管理。此外,类初始化中创建为tf.Variable类型的类成员变量也会自动纳入张量管理中,例如:

	# 通过tf.Variable 创建的类成员也会自动加入类参数列表
	self.kernel = tf.Variable(tf.random.normal([inp_dim, outp_dim]),
							  trainable=False)

打印出管理的张量列表如下:

# 类的参数列表
([<tf.Variable 'Variable:0' shape=(4, 3) dtype=float32, numpy=],
[])# 类的不需要优化参数列表

完成自定义类的初始化工作后,我们来设计自定义类的前向运算逻辑,对于这个例
子,只需要完成𝑶 = 𝑿@𝑾矩阵运算,并通过固定的ReLU 激活函数即可,代码如下:

    def call(self, inputs, training=None):
        # X@W
        out = inputs @ self.kernel
        # 执行激活函数运算
        out = tf.nn.relu(out)
        return out

如上所示,自定义类的前向运算逻辑实现在call(inputs, training=None)函数中,其中inputs代表输入,由用户在调用时传入;training 参数用于指定模型的状态:training 为True 时执行训练模式,training 为False 时执行测试模式,默认参数为None,即测试模式。由于全连接层的训练模式和测试模式逻辑一致,此处不需要额外处理。对于部份测试模式和训练模式不一致的网络层,需要根据training 参数来设计需要执行的逻辑。

自定义网络

在完成了自定义的全连接层类实现之后,我们基于上述的“无偏置的全连接层”来实现MNIST 手写数字图片模型的创建。
自定义网络类可以和其他标准类一样,通过Sequential 容器方便地封装成一个网络模型:

network = Sequential([MyDense(784, 256), # 使用自定义的层
					MyDense(256, 128),
					MyDense(128, 64),
					MyDense(64, 32),
					MyDense(32, 10)])
network.build(input_shape=(None, 28*28))
network.summary()

可以看到,通过堆叠我们的自定义网络层类,一样可以实现5 层的全连接层网络,每层全连接层无偏置张量,同时激活函数固定地使用ReLU 函数。

Sequential 容器适合于数据按序从第一层传播到第二层,再从第二层传播到第三层,以此规律传播的网络模型。对于复杂的网络结构,例如第三层的输入不仅是第二层的输出,还有第一层的输出,此时使用自定义网络更加灵活。下面我们来创建自定义网络类,首先创建类,并继承自Model 基类,分别创建对应的网络层对象,代码如下:

class MyModel(keras.Model):
	# 自定义网络类,继承自Model 基类
	def __init__(self):
		super(MyModel, self).__init__()
		# 完成网络内需要的网络层的创建工作
		self.fc1 = MyDense(28*28, 256)
		self.fc2 = MyDense(256, 128)
		self.fc3 = MyDense(128, 64)
		self.fc4 = MyDense(64, 32)
		self.fc5 = MyDense(32, 10)

然后实现自定义网络的前向运算逻辑,代码如下:

	def call(self, inputs, training=None):
		# 自定义前向运算逻辑
		x = self.fc1(inputs)
		x = self.fc2(x)
		x = self.fc3(x)
		x = self.fc4(x)
		x = self.fc5(x)
		return x

这个例子可以直接使用第一种方式,即Sequential 容器包裹实现。但自定义网络的前向计算逻辑可以自由定义,更为通用

自定义网络的实战在我的另一篇博客当中有进行讲解,有兴趣的去看一看吧
https://blog.csdn.net/python_LC_nohtyp/article/details/104123126

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Dropout层是一种常见的正则化技术,它在训练过程中随机地将一些神经元的输出设置为0,以减少过拟合。在TensorFlow 2.0中,我们可以使用Keras API来自定义这个层。 下面是一个使用Keras API实现Dropout层的示例代码: ```python import tensorflow as tf class CustomDropout(tf.keras.layers.Layer): def __init__(self, rate, **kwargs): super(CustomDropout, self).__init__(**kwargs) self.rate = rate def call(self, inputs, training=None): if training: return tf.nn.dropout(inputs, rate=self.rate) return inputs def get_config(self): config = super(CustomDropout, self).get_config() config.update({'rate': self.rate}) return config ``` 在这个自定义层中,我们继承了Keras的Layer类,并实现了call方法来定义正向传递的操作。在这个方法中,我们使用了TensorFlow的tf.nn.dropout函数来实现Dropout操作。 我们还实现了get_config方法来返回这个层的配置信息。这将允许我们在保存和加载模型时正确地恢复Dropout层的状态。 现在我们可以使用这个自定义层来构建Keras模型: ```python from tensorflow.keras import layers model = tf.keras.Sequential([ layers.Dense(64, activation='relu'), CustomDropout(0.5), layers.Dense(10, activation='softmax') ]) ``` 在这个模型中,我们在第一个全连接层后添加了我们自定义的Dropout层。在训练过程中,这个层将随机地将一些神经元的输出设置为0。 现在我们可以像使用任何其他Keras层一样使用这个自定义层来构建模型并进行训练。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值