以下代码在TensorFlow版本1.13下运行通过。
tf.layers.Layer类是tf.layers里所有层都继承的基类,实现了通用的基础功能。用户只需要实例化它,就可以直接调用得到的实例。
Layer的子类一般这样子实现:
__init__():先初始化父类。然后在成员变量中保存配置。
build():一般用于初始化层内的参数和变量。在调用call()方法前,类会自动调用该方法。在该方法末尾需要设置self.built = True,保证build()方法只被调用一次。
call():用于定义层对输入张量的实际操作。
下面是我们自定义一个全连接层的例子。
# Python3
import tensorflow as tf
from tensorflow.python.framework import tensor_shape
class DenseLayer(tf.layers.Layer):
"""定义全连接层"""
def __init__(self, hidden_size, bias=None, activation=None):
super().__init__() # 初始化父类
self.hidden_size = hidden_size # 保存配置
self.bias = bias
self.activation = activation
def build(self, input_shape):
self.W = self.add_variable(
"weight", [input_shape[-1], self.hidden_size],
dtype=self.dtype, initializer=tf.glorot_normal_initializer()) # 添加全连接层核
if self.bias: # bias是可选的
self.bias = self.add_variable(
"bias", [self.hidden_size], dtype=self.dtype,
initializer=tf.glorot_normal_initializer())
self.built = True # 说明bulid方法已经被调用
def call(self, inputs):
tmp = tf.matmul(inputs, self.W)
if self.bias: # 判断是否要使用bias
tmp += self.bias
if self.activation: # 判断是否使用激活函数
tmp = self.activation(tmp)
return tmp
我们调用这个类进行实验,如下所示:
if __name__ == "__main__":
x = tf.reshape(tf.range(27, dtype=tf.float32), (9, 3))
dense1 = DenseLayer(5, True, tf.nn.relu)
dense2 = DenseLayer(4, True)
y1 = dense1(x)
y2 = dense2(x)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
y1_value, y2_value = sess.run([y1, y2])
pprint(y1_value)
pprint(y2_value)
然后我们得到这样的输出
array([[0.0000000e+00, 6.0458672e-01, 1.5364885e-01, 0.0000000e+00,
1.1281629e+00],
[2.8744671e-02, 0.0000000e+00, 1.7403680e+00, 0.0000000e+00,
5.2644248e+00],
[2.0210516e-01, 0.0000000e+00, 3.3270869e+00, 0.0000000e+00,
9.4006872e+00],
[3.7546554e-01, 0.0000000e+00, 4.9138060e+00, 0.0000000e+00,
1.3536949e+01],
[5.4882616e-01, 0.0000000e+00, 6.5005255e+00, 0.0000000e+00,
1.7673212e+01],
[7.2218633e-01, 0.0000000e+00, 8.0872440e+00, 7.0604742e-02,
2.1809473e+01],
[8.9554715e-01, 0.0000000e+00, 9.6739635e+00, 1.4449155e-01,
2.5945736e+01],
[1.0689070e+00, 0.0000000e+00, 1.1260683e+01, 2.1837932e-01,
3.0081997e+01],
[1.2422680e+00, 0.0000000e+00, 1.2847402e+01, 2.9226708e-01,
3.4218258e+01]], dtype=float32)
array([[-3.14725101e-01, -3.68262529e-02, -1.37817276e+00,
-1.94278789e+00],
[ 1.73463374e-02, -2.78897429e+00, -3.81491590e+00,
-4.29053593e+00],
[ 3.49417806e-01, -5.54112244e+00, -6.25165939e+00,
-6.63828325e+00],
[ 6.81489170e-01, -8.29327106e+00, -8.68840218e+00,
-8.98603058e+00],
[ 1.01356053e+00, -1.10454178e+01, -1.11251459e+01,
-1.13337784e+01],
[ 1.34563196e+00, -1.37975664e+01, -1.35618887e+01,
-1.36815262e+01],
[ 1.67770326e+00, -1.65497150e+01, -1.59986315e+01,
-1.60292740e+01],
[ 2.00977468e+00, -1.93018627e+01, -1.84353752e+01,
-1.83770218e+01],
[ 2.34184670e+00, -2.20540104e+01, -2.08721199e+01,
-2.07247677e+01]], dtype=float32)
对于TensorFlow我们只需要定义前向传播的计算图,它就会自动配置完成反向传播。我们上面定义的DenseLayer里的权重会被自动更新。