
2.2.2 使用TensorFlow自带的API实现全连接层
程序2-9演示了全连接层的计算方法,可以看到全连接本质就是由一个特征空间线性变换到另一个特征空间。目标空间的任一维(隐藏层的一个节点)都认为会受到源空间每一维的影响。可以不那么严谨地说,目标向量是源向量的加权和。
全连接层一般是接在特征提取网络之后,用作对特征的分类器。全连接常出现在最后几层,用于对前面设计的特征做加权和。前面的网络部分可以看作特征抽取,而后加的全连接层相当于特征加权计算。
提示
具体的神经网络差值反馈算法将在第3章介绍。
下面我们使用自定义的方法,实现某一个可以加载到model中的“自定义全连接层”。
1.自定义层的继承
在TensorFlow中,任何一个自定义的层都继承自tf.keras.layers.Layer的,我们将其称为“父层”,如图2.12所示。这里所谓的自定义层实际上是父层的一个具体实现。

图2.12 父层
从图2.12可以看到,Layer层中又是由多个函数构成的,因此基于继承的关系,如果想要实现自定义的层,那么必须实现其中的函数。
2.“父层”函数介绍
所谓的“父层”,就是指这里自定义的层继承自哪里,告诉TensorFlow可以使用父类中定义好的函数或者添加自定义的其他函数。。
Layer层中需要自定义的函数有很多,但是在实际使用时一般只需要定义那些必须使用的函数。例如build、call函数,以及初始化所必需的__init__函数。
(1)__init__函数:首先是一些必要参数的初始化,这些参数的初始化写在def __init__(self,)中,然后是一些参数的初始化。写法如下:

可以看到,init函数中最重要的就是显式地确定所需要的一些参数。特别值得注意的是,对于输入的init中的参数,输入Tensor不会在这里进行标注,init值初始化的是模型参数。输入值不属于“模型参数”。
(2)build函数:build函数的内容主要是声明需要更新的参数部分,如权重等,一般使用self.kernel = tf.Variable(shape=[ ])等来声明需要更新的参数变量。

build函数参数中的input_shape形参是固定不变的写法,读者不要修改即可,其中自定义的参数需要加上self,表明是在类中使用的全局参数。
对于代码最后的super(MyLayer, self).build(input_shape),目前只需要记得这种写法,在build的最后确定参数定义结束。
(3)call函数:最重要的函数,这部分代码包含了主要层的实现。
init是对参数做定义和声明,build函数是对权重可变参数做声明。这两个函数只是定义了一些初始化的参数以及一些需要更新的参数变量,而真正实现所定义类的作用是在call方法中。

可以看到call中的一系列操作是对__init__和build中变量参数的应用,所有的计算都在call函数中完成,并且需要注意的是输入的参数也在这里出现,经过计算后将计算值返回。

下面我们使用自定义的层修改iris模型。程序如下所示。
【程序2-10】

我们首先定义了MyLayer作为全连接层,之后正如使用TensorFlow自带的层一样,直接生成类函数并显式指定输入参数,最终将所有的层加入model中。最终打印结果如图2.13所示。

图2.13 打印结果