【tensorflow2.0】11.自定义层

    今天讲解的内容是自定义层,和我们之前所学的构建层的方法相比,自定义层要复杂一些,而且要多一些注意事项,同时对python的要求也提高了不少,下边我们根据老师给出的案例代码进行讲解(注释)。

#首先说一下自定义层的三种方法
import tensorflow as tf
#自定义全连接层
class Linear(tf.keras.layers.Layer):
	#在__init__中进行所有与输入无关的初始化,定义相关的层,这里我们定义一个神经元,维度是4的输入
    def __init__(self, units=1, input_dim=4):
        super(Linear, self).__init__() 
        #初始化权重w和偏差b,权重的维度是(输入维度,神经元个数),偏差的维度(神经元个数,)
        w_init = tf.random_normal_initializer()
        self.w = tf.Variable(initial_value=w_init(shape=(input_dim, units),
                                                  dtype='float32'), 
                             trainable=True)
        b_init = tf.zeros_initializer()
        self.b = tf.Variable(initial_value=b_init(shape=(units,),dtype='float32'),trainable=True)
	#call是前向传播,也就是y = w * x + b
    def call(self, inputs):
    	#tf.matmul相当与矩阵的乘积  这里w * x的维度和b是不同的 但是因为tf封装了numpy的广播机制,
    	#所以可以相加,[广播](https://www.cnblogs.com/jiaxin359/p/9021726.html)
        return tf.matmul(inputs, self.w) + self.b

x = tf.constant(data) #(150,4)
linear_layer = Linear(units = 1, input_dim=4) #()
y = linear_layer(x)
print(y.shape) #(150,1)
"""
Python中,如果在创建class的时候写了call()方法, 那么该class实例化出实例后, 实例名()就是调用call()方法,所以这里y = linear_layer(x)直接执行call函数。
"""
#方法二,相当于第一种方法的简化版,推荐!
class Linear(tf.keras.layers.Layer):

    def __init__(self, units=1, input_dim=4):
        super(Linear, self).__init__()

        self.w = self.add_weight(shape=(input_dim, units),
                                 initializer='random_normal',
                                 trainable=True)
        self.b = self.add_weight(shape=(units,),
                                 initializer='zeros',
                                 trainable=True)

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b


x = tf.constant(data)
linear_layer = Linear(units = 1, input_dim=4)
y = linear_layer(x)
print(y.shape)
#方法三:添加了build方法:指导输入张量的形状可以进行其余的初始化
class Linear(tf.keras.layers.Layer):

    def __init__(self, units=32):
        super(Linear, self).__init__()
        self.units = units

    def build(self, input_shape): #(150,4)
        self.w = self.add_weight(shape=(input_shape[-1], self.units),
                                 initializer='random_normal',
                                 trainable=True,
                                 name = 'w')
        self.b = self.add_weight(shape=(self.units,),
                                 initializer='random_normal',
                                 trainable=True,
                                 name = 'b')
        #相当于设置self.built = True
        super(Linear,self).build(input_shape)

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

x = tf.constant(data) #150*4
linear_layer = Linear(units = 1)
y = linear_layer(x)
print(y.shape)

#可以打印出所有参数、可训练参数、不可训练参数
print('weight:', linear_layer.weights)
print('non-trainable weight:', linear_layer.non_trainable_weights)
print('trainable weight:', linear_layer.trainable_weights)

    下边说一下自定义层的注意事项:

'''
    1.如果要让自定义的Layer通过Functional API 组合成模型时可以序列化,需要自定义get_config方法。
    get_config的作用是获取该层的参数配置,以便模型保存时候使用。
'''
    def get_config(self):  
        config = super(MyDense, self).get_config()
        config.update({'units': self.units})
        return config

'''
    2.使用model.save保存模型时候,如果自定义层中有build方法,一定要写name属性,否则会报错
'''
def build(self, input_shape): 
        self.w = self.add_weight(shape=(input_shape[-1], self.units),
                                 initializer='random_normal',
                                 trainable=True,
                                 name='w')

'''
	3.当我们自定义网络层并且有效保存模型后,希望使用tf.keras.models.load_model进行模型加载时建立一个字典,该字典的键是自定
义网络层时设定该层的名字,其值为该自定义网络层的类名,该字典将用于加载模型时使用!然后,在tf.keras.models.load_model内传入
custom_objects告知如何解析重建自定义网络层,其方法如下:	
'''

_custom_objects = {
    "MyDense" :  MyDense,    
}
new_model = tf.keras.models.load_model("keras_model_tf_version.h5",custom_objects=_custom_objects)

'''
	4.自定义层的时候网络层的名字不能与默认的tf.keras网络层一样,否则会报错。
	5.实现自定义网络层的时候,最好统一在初始化时传入可变参数**kwargs这是因为在model推理时,有时我们需要对所有构成该
模型的网络层进行统一的传参。
'''
class MyDense(tf.keras.layers.Layer):
    def __init__(self, units=32, **kwargs):
        self.units = units
        super(MyDense, self).__init__(**kwargs)

你可能感兴趣的:(tensorflow,深度学习)