如何使用 tf.keras 编写自定义标准层

How to write a custom stdandardization layer with tf.keras

目前我正在使用 tensorflow 和 keras 构建我的第一个神经网络 API。 我想写一个层来标准化输入,因为在预处理中这样做可能会导致在训练后使用模型时出错。 因此我想将我的训练数据集传递给该层的初始化函数并计算均值和标准差。

问题是我还想在训练后保存和加载模型。但是如果我调用 load_model(modelname) 我会得到一个错误,因为 init 函数需要训练数据作为参数。此外,我不确定将平均值和标准差指定为 tf.Variable 是否正确,或者是否有更好的方法,以便在使用 load_model/load_weights.[=12= 时加载这些值]

我很高兴得到每一个答案。

下面的代码代表了这种层的基本思想。

class stdLayer(tf.keras.layers.Layer):
    def __init__(self, train_x, trainable=False,**kwargs):
        super(stdLayer, self).__init__(trainable=trainable,**kwargs)
        means=np.mean(train_x,axis=0)
        stds=np.std(train_x,axis=0)
        self.means = tf.Variable(means,
                                dtype=tf.float32,
                                name="means",
                                trainable=False)
        self.stds = tf.Variable(stds,
                                dtype=tf.float32,
                                name="stds",
                                trainable=False)


    def call(self, input):
        input_st = (input-self.means)/self.stds
        return input_st

也许您可以在模型的开头添加一个 BatchNormalization 层。

不过,在所有情况下,您都需要生产数据的格式与训练数据的格式相同。


或者,不传递训练数据,只传递 meansstds

class StdLayer(tf.keras.layers.Layer):
    def __init__(self, means, stds, trainable=False,**kwargs):
        ...
        self.means_init = means
        self.stds_init = stds
        ...

    def build(self, input_shape):
        self.means = self.add_weight(name='means', 
                                      shape=self.means_init.shape,
                                      initializer='zeros',
                                      trainable=True) 
                                       #if you put false here, they will never be trainable
        self.stds =  self.add_weight(name='stds', 
                                      shape=self.stds_init.shape,
                                      initializer='ones',
                                      trainable=True)
                                      #if you put false here, they will never be trainable

        keras.backend.set_value(self.means, self.means_init)
        keras.backend.set_value(self.stds, self.stds)

        self.built = True

    def call(self, inputs):
        ...

    def compute_output_shape(self, input_shape):
        ...

    def get_config(self):
        config = {
            'means_init': self.means_init,
            'stds_init': self.stds_init,
        }
        base_config = super(StdLayer, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

老实说,我不确定是否可以将 numpy 数组传递给 config
您也许可以使用 __init__(self, means=None, stds=None, ...,并在 build 中放置一个 if 作为 set_values。找到另一种方法来计算 add_weight 中的形状,您可以摆脱 config 变量。